Merge 'dev' branch into stable

This commit is contained in:
Florian Märkl 2022-06-25 10:06:14 +02:00
commit e73a4c60e3
13 changed files with 257 additions and 74 deletions

View File

@ -92,7 +92,7 @@ JSDecDecompiler::JSDecDecompiler(QObject *parent) : Decompiler("jsdec", "jsdec",
bool JSDecDecompiler::isAvailable()
{
return Core()->cmdList("es").contains("jsdec");
return Core()->getConfigVariableSpaces().contains("jsdec");
}
void JSDecDecompiler::decompileAt(RVA addr)

View File

@ -129,8 +129,11 @@ static QString fromOwnedCharPtr(char *str)
static bool reg_sync(RzCore *core, RzRegisterType type, bool write)
{
if (rz_core_is_debug(core)) {
return rz_debug_reg_sync(core->dbg, type, write);
}
return true;
}
RzCoreLocked::RzCoreLocked(CutterCore *core) : core(core)
{
@ -644,6 +647,10 @@ bool CutterCore::loadFile(QString path, ut64 baddr, ut64 mapaddr, int perms, int
bool CutterCore::tryFile(QString path, bool rw)
{
if (path.isEmpty()) {
// opening no file is always possible
return true;
}
CORE_LOCK();
RzCoreFile *cf;
int flags = RZ_PERM_R;
@ -758,10 +765,14 @@ QString CutterCore::getInstructionOpcode(RVA addr)
return fromOwnedCharPtr(ret);
}
void CutterCore::editInstruction(RVA addr, const QString &inst)
void CutterCore::editInstruction(RVA addr, const QString &inst, bool fillWithNops)
{
CORE_LOCK();
if (fillWithNops) {
rz_core_write_assembly_fill(core, addr, inst.trimmed().toStdString().c_str());
} else {
rz_core_write_assembly(core, addr, inst.trimmed().toStdString().c_str());
}
emit instructionChanged(addr);
}
@ -1199,7 +1210,21 @@ void CutterCore::message(const QString &msg, bool debug)
QString CutterCore::getConfig(const char *k)
{
CORE_LOCK();
return QString(rz_config_get(core->config, k));
return { rz_config_get(core->config, k) };
}
QStringList CutterCore::getConfigOptions(const char *k)
{
CORE_LOCK();
RzConfigNode *node = rz_config_node_get(core->config, k);
if (!(node && node->options)) {
return {};
}
QStringList list;
for (const auto &s : CutterRzList<char>(node->options)) {
list << s;
}
return list;
}
void CutterCore::setConfig(const char *k, const QVariant &v)
@ -1492,6 +1517,17 @@ RefDescription CutterCore::formatRefDesc(const QSharedPointer<AddrRefs> &refItem
return desc;
}
RzReg *CutterCore::getReg()
{
CORE_LOCK();
if (currentlyDebugging && currentlyEmulating) {
return core->analysis->reg;
} else if (currentlyDebugging) {
return core->dbg->reg;
}
return core->analysis->reg;
}
QList<RegisterRef> CutterCore::getRegisterRefs(int depth)
{
QList<RegisterRef> ret;
@ -1500,7 +1536,7 @@ QList<RegisterRef> CutterCore::getRegisterRefs(int depth)
}
CORE_LOCK();
RzList *ritems = rz_core_reg_filter_items_sync(core, core->dbg->reg, reg_sync, nullptr);
RzList *ritems = rz_core_reg_filter_items_sync(core, getReg(), reg_sync, nullptr);
if (!ritems) {
return ret;
}
@ -1508,7 +1544,7 @@ QList<RegisterRef> CutterCore::getRegisterRefs(int depth)
RzRegItem *ri;
CutterRzListForeach (ritems, it, RzRegItem, ri) {
RegisterRef reg;
reg.value = rz_reg_get_value(core->dbg->reg, ri);
reg.value = rz_reg_get_value(getReg(), ri);
reg.ref = getAddrRefs(reg.value, depth);
reg.name = ri->name;
ret.append(reg);
@ -1525,7 +1561,7 @@ QList<AddrRefs> CutterCore::getStack(int size, int depth)
}
CORE_LOCK();
RVA addr = rz_debug_reg_get(core->dbg, "SP");
RVA addr = rz_core_reg_getv_by_role_or_name(core, "SP");
if (addr == RVA_INVALID) {
return stack;
}
@ -1574,7 +1610,7 @@ AddrRefs CutterCore::getAddrRefs(RVA addr, int depth)
// Check if the address points to a register
RzFlagItem *fi = rz_flag_get_i(core->flags, addr);
if (fi) {
RzRegItem *r = rz_reg_get(core->dbg->reg, fi->name, -1);
RzRegItem *r = rz_reg_get(getReg(), fi->name, -1);
if (r) {
refs.reg = r->name;
}
@ -1830,7 +1866,7 @@ QVector<RegisterRefValueDescription> CutterCore::getRegisterRefValues()
{
QVector<RegisterRefValueDescription> result;
CORE_LOCK();
RzList *ritems = rz_core_reg_filter_items_sync(core, core->dbg->reg, reg_sync, nullptr);
RzList *ritems = rz_core_reg_filter_items_sync(core, getReg(), reg_sync, nullptr);
if (!ritems) {
return result;
}
@ -1839,8 +1875,8 @@ QVector<RegisterRefValueDescription> CutterCore::getRegisterRefValues()
CutterRzListForeach (ritems, it, RzRegItem, ri) {
RegisterRefValueDescription desc;
desc.name = ri->name;
ut64 value = rz_reg_get_value(core->dbg->reg, ri);
desc.value = QString::number(value);
ut64 value = rz_reg_get_value(getReg(), ri);
desc.value = "0x" + QString::number(value, 16);
desc.ref = rz_core_analysis_hasrefs(core, value, true);
result.push_back(desc);
}
@ -1854,14 +1890,14 @@ QString CutterCore::getRegisterName(QString registerRole)
return "";
}
CORE_LOCK();
return rz_reg_get_name_by_type(core->dbg->reg, registerRole.toUtf8().constData());
return rz_reg_get_name_by_type(getReg(), registerRole.toUtf8().constData());
}
RVA CutterCore::getProgramCounterValue()
{
if (currentlyDebugging) {
CORE_LOCK();
return rz_debug_reg_get(core->dbg, "PC");
return rz_core_reg_getv_by_role_or_name(core, "PC");
}
return RVA_INVALID;
}
@ -1873,7 +1909,7 @@ void CutterCore::setRegister(QString regName, QString regValue)
}
CORE_LOCK();
ut64 val = rz_num_math(core->num, regValue.toUtf8().constData());
rz_core_reg_assign_sync(core, core->dbg->reg, reg_sync, regName.toUtf8().constData(), val);
rz_core_reg_assign_sync(core, getReg(), reg_sync, regName.toUtf8().constData(), val);
emit registersChanged();
emit refreshCodeViews();
}
@ -2874,8 +2910,17 @@ bool CutterCore::isGraphEmpty()
void CutterCore::getOpcodes()
{
CORE_LOCK();
this->opcodes = cmdList("?O");
this->regs = cmdList("drp~[1]");
this->regs = {};
const RzList *rs = rz_reg_get_list(getReg(), RZ_REG_TYPE_ANY);
if (!rs) {
return;
}
for (const auto &r : CutterRzList<RzRegItem>(rs)) {
this->regs.push_back(r->name);
}
}
void CutterCore::setSettings()
@ -3393,7 +3438,6 @@ QList<SectionDescription> CutterCore::getAllSections()
section.entropy = rz_str_get(entropy);
ht_pp_free(digests);
}
section.entropy = "";
sections << section;
}
@ -3451,6 +3495,7 @@ QList<SegmentDescription> CutterCore::getAllSegments()
segDesc.size = segment->size;
segDesc.vsize = segment->vsize;
segDesc.perm = perms_str(segment->perm);
ret << segDesc;
}
rz_list_free(segments);
@ -3461,6 +3506,9 @@ QList<EntrypointDescription> CutterCore::getAllEntrypoint()
{
CORE_LOCK();
RzBinFile *bf = rz_bin_cur(core->bin);
if (!bf) {
return {};
}
bool va = core->io->va || core->bin->is_debugger;
ut64 baddr = rz_bin_get_baddr(core->bin);
ut64 laddr = rz_bin_get_laddr(core->bin);
@ -4298,14 +4346,15 @@ void CutterCore::commitWriteCache()
// Temporarily disable cache mode
TempConfig tempConfig;
tempConfig.set("io.cache", false);
if (!isWriteModeEnabled()) {
rz_core_io_file_reopen(core, core->io->desc->fd, RZ_PERM_RW);
rz_io_cache_commit(core->io, 0, UT64_MAX);
rz_core_block_read(core);
rz_core_io_file_open(core, core->io->desc->fd);
} else {
auto desc = core->io->desc;
bool reopen = !isWriteModeEnabled() && desc;
if (reopen) {
rz_core_io_file_reopen(core, desc->fd, RZ_PERM_RW);
}
rz_io_cache_commit(core->io, 0, UT64_MAX);
rz_core_block_read(core);
if (reopen) {
rz_core_io_file_open(core, desc->fd);
}
}
@ -4327,13 +4376,16 @@ void CutterCore::setWriteMode(bool enabled)
CORE_LOCK();
// Change from read-only to write-mode
RzIODesc *desc = core->io->desc;
if (desc) {
if (enabled) {
if (!writeModeState) {
rz_core_io_file_reopen(core, core->io->desc->fd, RZ_PERM_RW);
rz_core_io_file_reopen(core, desc->fd, RZ_PERM_RW);
}
} else {
// Change from write-mode to read-only
rz_core_io_file_open(core, core->io->desc->fd);
rz_core_io_file_open(core, desc->fd);
}
}
// Disable cache mode because we specifically set write or
// read-only modes.
@ -4434,3 +4486,23 @@ QByteArray CutterCore::ioRead(RVA addr, int len)
return array;
}
QStringList CutterCore::getConfigVariableSpaces(const QString &key)
{
CORE_LOCK();
QStringList stringList;
for (const auto &node : CutterRzList<RzConfigNode>(core->config->nodes)) {
stringList.push_back(node->name);
}
if (!key.isEmpty()) {
stringList = stringList.filter(QRegularExpression(QString("^%0\\..*").arg(key)));
std::transform(stringList.begin(), stringList.end(), stringList.begin(),
[](const QString &x) { return x.split('.').last(); });
} else {
std::transform(stringList.begin(), stringList.end(), stringList.begin(),
[](const QString &x) { return x.split('.').first(); });
}
stringList.removeDuplicates();
return stringList;
}

View File

@ -259,7 +259,7 @@ public:
/* Edition functions */
QString getInstructionBytes(RVA addr);
QString getInstructionOpcode(RVA addr);
void editInstruction(RVA addr, const QString &inst);
void editInstruction(RVA addr, const QString &inst, bool fillWithNops = false);
void nopInstruction(RVA addr);
void jmpReverse(RVA addr);
void editBytes(RVA addr, const QString &inst);
@ -393,10 +393,12 @@ public:
QString getConfig(const char *k);
QString getConfig(const QString &k) { return getConfig(k.toUtf8().constData()); }
QString getConfigDescription(const char *k);
QStringList getConfigOptions(const char *k);
QStringList getColorThemes();
QHash<QString, QColor> getTheme();
QStringList getThemeKeys();
bool setColor(const QString &key, const QString &color);
QStringList getConfigVariableSpaces(const QString &key = "");
/* Assembly\Hexdump related methods */
QByteArray assemble(const QString &code);
@ -660,6 +662,10 @@ public:
QList<SearchDescription> getAllSearch(QString searchFor, QString space, QString in);
QList<BreakpointDescription> getBreakpoints();
QList<ProcessDescription> getAllProcesses();
/**
* @brief Get the right RzReg object based on the cutter state (debugging vs emulating)
*/
RzReg *getReg();
/**
* @brief returns a list of reg values and their telescoped references
* @param depth telescoping depth

View File

@ -25,7 +25,8 @@
(char *)it != (char *)(vec)->a + ((vec)->len * (vec)->elem_size); \
it = (type *)((char *)it + (vec)->elem_size))
template<typename T> class CutterPVector
template<typename T>
class CutterPVector
{
private:
const RzPVector *const vec;
@ -39,8 +40,17 @@ public:
public:
iterator(T **p) : p(p) {}
iterator(const iterator &o) : p(o.p) {}
iterator &operator++() { p++; return *this; }
iterator operator++(int) { iterator tmp(*this); operator++(); return tmp; }
iterator &operator++()
{
p++;
return *this;
}
iterator operator++(int)
{
iterator tmp(*this);
operator++();
return tmp;
}
bool operator==(const iterator &rhs) const { return p == rhs.p; }
bool operator!=(const iterator &rhs) const { return p != rhs.p; }
T *operator*() { return *p; }
@ -51,6 +61,57 @@ public:
iterator end() const { return iterator(reinterpret_cast<T **>(vec->v.a) + vec->v.len); }
};
template<typename T>
class CutterRzList
{
private:
const RzList *const list;
public:
class iterator : public std::iterator<std::input_iterator_tag, T *>
{
private:
RzListIter *iter;
public:
explicit iterator(RzListIter *iter) : iter(iter) {}
iterator(const iterator &o) : iter(o.iter) {}
iterator &operator++()
{
if (!iter) {
return *this;
}
iter = iter->n;
return *this;
}
iterator operator++(int)
{
iterator tmp(*this);
operator++();
return tmp;
}
bool operator==(const iterator &rhs) const { return iter == rhs.iter; }
bool operator!=(const iterator &rhs) const { return iter != rhs.iter; }
T *operator*()
{
if (!iter) {
return nullptr;
}
return reinterpret_cast<T *>(iter->data);
}
};
explicit CutterRzList(const RzList *l) : list(l) {}
iterator begin() const
{
if (!list) {
return iterator(nullptr);
}
return iterator(list->head);
}
iterator end() const { return iterator(nullptr); }
};
// Global information for Cutter
#define APPNAME "Cutter"

View File

@ -641,7 +641,11 @@ void MainWindow::finalizeOpen()
core->updateSeek();
refreshAll();
// Add fortune message
core->message("\n" + core->cmdRaw("fo"));
char *fortune = rz_core_fortune_get_random(core->core());
if (fortune) {
core->message("\n" + QString(fortune));
free(fortune);
}
// hide all docks before showing window to avoid false positive for refreshDeferrer
for (auto dockWidget : dockWidgets) {

View File

@ -2,12 +2,20 @@
#include "ui_EditInstructionDialog.h"
#include "core/Cutter.h"
#include <QCheckBox>
EditInstructionDialog::EditInstructionDialog(InstructionEditMode editMode, QWidget *parent)
: QDialog(parent), ui(new Ui::EditInstructionDialog), editMode(editMode)
{
ui->setupUi(this);
ui->lineEdit->setMinimumWidth(400);
ui->instructionLabel->setWordWrap(true);
if (editMode == EDIT_TEXT) {
ui->fillWithNops->setVisible(true);
ui->fillWithNops->setCheckState(Qt::Checked);
} else {
ui->fillWithNops->setVisible(false);
}
setWindowFlags(windowFlags() & (~Qt::WindowContextHelpButtonHint));
connect(ui->lineEdit, &QLineEdit::textEdited, this, &EditInstructionDialog::updatePreview);
@ -22,6 +30,15 @@ void EditInstructionDialog::on_buttonBox_rejected()
close();
}
bool EditInstructionDialog::needsNops() const
{
if (editMode != EDIT_TEXT) {
return false;
}
return ui->fillWithNops->checkState() == Qt::Checked;
}
QString EditInstructionDialog::getInstruction() const
{
return ui->lineEdit->text();

View File

@ -20,18 +20,18 @@ public:
QString getInstruction() const;
void setInstruction(const QString &instruction);
bool needsNops() const;
private slots:
void on_buttonBox_accepted();
void on_buttonBox_rejected();
void updatePreview(const QString &input);
private:
std::unique_ptr<Ui::EditInstructionDialog> ui;
InstructionEditMode
editMode; // true if editing intruction **bytes**; false if editing instruction **text**
// defines if the user is editing bytes or asm
InstructionEditMode editMode;
};
#endif // EDITINSTRUCTIONDIALOG_H

View File

@ -7,7 +7,7 @@
<x>0</x>
<y>0</y>
<width>400</width>
<height>118</height>
<height>151</height>
</rect>
</property>
<property name="windowTitle">
@ -37,6 +37,18 @@
</property>
<item>
<layout class="QVBoxLayout" name="verticalLayout">
<property name="leftMargin">
<number>5</number>
</property>
<property name="topMargin">
<number>5</number>
</property>
<property name="rightMargin">
<number>5</number>
</property>
<property name="bottomMargin">
<number>5</number>
</property>
<item>
<spacer name="verticalSpacer">
<property name="orientation">
@ -82,6 +94,16 @@
</item>
</layout>
</item>
<item>
<widget class="QCheckBox" name="fillWithNops">
<property name="text">
<string>Fill all remaining bytes with NOP opcodes</string>
</property>
<property name="checked">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<spacer name="verticalSpacer_1">
<property name="orientation">

View File

@ -40,7 +40,7 @@ InitialOptionsDialog::InitialOptionsDialog(MainWindow *main)
updateCPUComboBox();
// os combo box
for (const auto &plugin : core->cmdList("e asm.os=?")) {
for (const auto &plugin : Core()->getConfigOptions("asm.os")) {
ui->kernelComboBox->addItem(plugin, plugin);
}

View File

@ -16,7 +16,7 @@ AsmOptionsWidget::AsmOptionsWidget(PreferencesDialog *dialog)
ui->setupUi(this);
ui->syntaxComboBox->blockSignals(true);
for (const auto &syntax : Core()->cmdList("e asm.syntax=?"))
for (const auto &syntax : Core()->getConfigOptions("asm.syntax"))
ui->syntaxComboBox->addItem(syntax, syntax);
ui->syntaxComboBox->blockSignals(false);

View File

@ -524,15 +524,19 @@ void DisassemblyContextMenu::aboutToShowSlot()
structureOffsetMenu->menuAction()->setVisible(true);
structureOffsetMenu->clear();
// Get the possible offsets using the "ahts" command
// TODO: add ahtj command to Rizin and then use it here
QStringList ret = Core()->cmdList("ahts " + QString::number(memDisp));
for (const QString &val : ret) {
if (val.isEmpty()) {
RzCoreLocked core(Core());
RzList *typeoffs = rz_type_db_get_by_offset(core->analysis->typedb, memDisp);
if (typeoffs) {
for (const auto &ty : CutterRzList<RzTypePath>(typeoffs)) {
if (RZ_STR_ISEMPTY(ty->path)) {
continue;
}
structureOffsetMenu->addAction("[" + memBaseReg + " + " + val + "]")->setData(val);
structureOffsetMenu->addAction("[" + memBaseReg + " + " + ty->path + "]")
->setData(ty->path);
}
rz_list_free(typeoffs);
}
if (structureOffsetMenu->isEmpty()) {
// No possible offset was found so hide the menu
structureOffsetMenu->menuAction()->setVisible(false);
@ -704,9 +708,10 @@ void DisassemblyContextMenu::on_actionEditInstruction_triggered()
e.setInstruction(oldInstructionOpcode);
if (e.exec()) {
bool fillWithNops = e.needsNops();
QString userInstructionOpcode = e.getInstruction();
if (userInstructionOpcode != oldInstructionOpcode) {
Core()->editInstruction(offset, userInstructionOpcode);
Core()->editInstruction(offset, userInstructionOpcode, fillWithNops);
}
}
}

View File

@ -220,8 +220,7 @@ bool CommentsProxyModel::lessThan(const QModelIndex &left, const QModelIndex &ri
case CommentsModel::OffsetColumn:
return leftComment.offset < rightComment.offset;
case CommentsModel::FunctionColumn:
return Core()->flagAt(leftComment.offset)
< Core()->flagAt(rightComment.offset);
return Core()->flagAt(leftComment.offset) < Core()->flagAt(rightComment.offset);
case CommentsModel::CommentColumn:
return leftComment.name < rightComment.name;
default:

View File

@ -63,9 +63,9 @@ void Dashboard::updateContents()
setPlainText(ui->subsysEdit, binInfo ? binInfo->subsystem : "");
setPlainText(ui->compilerEdit, binInfo ? binInfo->compiler : "");
setPlainText(ui->bitsEdit, binInfo ? QString::number(binInfo->bits) : "");
setPlainText(ui->baddrEdit, binInfo ? RzAddressString(rz_bin_file_get_baddr(bf)) : "");
setPlainText(ui->sizeEdit, binInfo ? qhelpers::formatBytecount(bf->size) : "");
setPlainText(ui->fdEdit, binInfo ? QString::number(bf->fd) : "");
setPlainText(ui->baddrEdit, bf ? RzAddressString(rz_bin_file_get_baddr(bf)) : "");
setPlainText(ui->sizeEdit, bf ? qhelpers::formatBytecount(bf->size) : "");
setPlainText(ui->fdEdit, bf ? QString::number(bf->fd) : "");
// Setting the value of "Endianness"
const char *endian = binInfo ? (binInfo->big_endian ? "BE" : "LE") : "";
@ -78,7 +78,7 @@ void Dashboard::updateContents()
int static_value = rz_bin_is_static(core->bin);
setPlainText(ui->staticEdit, tr(setBoolText(static_value)));
RzList *hashes = rz_bin_file_compute_hashes(core->bin, bf, UT64_MAX);
RzList *hashes = bf ? rz_bin_file_compute_hashes(core->bin, bf, UT64_MAX) : nullptr;
// Delete hashesWidget if it isn't null to avoid duplicate components
if (hashesWidget) {
@ -122,12 +122,6 @@ void Dashboard::updateContents()
setPlainText(ui->codeSizeLineEdit, QString::number(analinfo["codesz"].toSt64()) + " bytes");
setPlainText(ui->percentageLineEdit, QString::number(analinfo["percent"].toSt64()) + "%");
QStringList libs = Core()->cmdList("il");
if (!libs.isEmpty()) {
libs.removeFirst();
libs.removeLast();
}
// dunno: why not label->setText(lines.join("\n")?
while (ui->verticalLayout_2->count() > 0) {
QLayoutItem *item = ui->verticalLayout_2->takeAt(0);
@ -141,13 +135,16 @@ void Dashboard::updateContents()
}
}
for (const QString &lib : libs) {
QLabel *label = new QLabel(this);
const RzList *libs = bf ? rz_bin_object_get_libs(bf->o) : nullptr;
if (libs) {
for (const auto &lib : CutterRzList<char>(libs)) {
auto *label = new QLabel(this);
label->setText(lib);
label->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred);
label->setTextInteractionFlags(Qt::TextSelectableByMouse);
ui->verticalLayout_2->addWidget(label);
}
}
QSpacerItem *spacer = new QSpacerItem(1, 1, QSizePolicy::Fixed, QSizePolicy::Expanding);
ui->verticalLayout_2->addSpacerItem(spacer);