Switch to widget on seek change (#3597)

* Seek to other widgets if the address type matches
* Open the correct widget on undo or redo actions
* Don't seek to the last on Unknown
* Only switch to other widgets from Graph
* Create getSectionAddressAt(RVA addr)
* Remove on_core_seekChanged
* Use virtual address in rz_bin_get_section_at
* Move address == RVA_INVALID check to the correct place
This commit is contained in:
Pavel Potemkin 2026-04-16 10:35:53 +07:00 committed by GitHub
parent 1de599c11b
commit a9e2a7909c
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
6 changed files with 122 additions and 7 deletions

View file

@ -75,14 +75,14 @@ void CutterSeekable::seekToReference(RVA offset)
// Try first call
for (auto &ref : refs) {
if (ref.to != RVA_INVALID && ref.type == "CALL") {
seek(ref.to);
Core()->seekAndShow(ref.to);
return;
}
}
// Fallback to first valid, if any
for (auto &ref : refs) {
if (ref.to != RVA_INVALID) {
seek(ref.to);
Core()->seekAndShow(ref.to);
return;
}
}

View file

@ -1009,13 +1009,13 @@ void CutterCore::showMemoryWidget()
void CutterCore::seekAndShow(ut64 offset)
{
seek(offset);
showMemoryWidget();
emit showAddressRequested(offset);
}
void CutterCore::seekAndShow(QString offset)
{
seek(offset);
showMemoryWidget();
emit showAddressRequested(math(offset));
}
void CutterCore::seek(QString thing)
@ -1150,6 +1150,30 @@ void CutterCore::setConfig(const char *k, const QString &v)
rz_config_set(core->config, k, v.toUtf8().constData());
}
AddressTypeHint CutterCore::getAddressType(RVA addr)
{
CORE_LOCK();
if (functionIn(addr)) {
return AddressTypeHint::Function;
}
auto section = getSectionAtAddress(addr);
if (section.name.isEmpty()) {
return AddressTypeHint::Unknown;
}
if (section.perm.contains('x', Qt::CaseInsensitive)) {
return AddressTypeHint::Code;
}
if (section.perm.contains('r', Qt::CaseInsensitive)
|| section.perm.contains('w', Qt::CaseInsensitive)) {
return AddressTypeHint::Data;
}
return AddressTypeHint::Unknown;
}
void CutterCore::setConfig(const char *k, int v)
{
CORE_LOCK();
@ -3507,6 +3531,42 @@ QList<FlagDescription> CutterCore::getAllFlags(QString flagspace)
return flags;
}
SectionDescription CutterCore::getSectionAtAddress(RVA addr)
{
CORE_LOCK();
RzBinObject *o = rz_bin_cur_object(core->bin);
if (!o) {
return {};
}
RzBinSection *section = rz_bin_get_section_at(o, addr, true);
if (!section) {
return {};
}
RzList *hashnames = rz_list_newf(free);
if (!hashnames) {
return {};
}
SectionDescription desc;
desc.vaddr = section->vaddr;
desc.paddr = section->paddr;
desc.size = section->size;
desc.name = section->name;
desc.vsize = section->vsize;
desc.perm = rz_str_rwx_i(section->perm);
if (desc.size > 0) {
HtSS *digests = rz_core_bin_create_digests(core, desc.paddr, desc.size, hashnames);
if (!digests) {
return {};
}
const char *entropy = (const char *)ht_ss_find(digests, "entropy", NULL);
desc.entropy = rz_str_get(entropy);
ht_ss_free(digests);
}
return desc;
}
QList<SectionDescription> CutterCore::getAllSections()
{
CORE_LOCK();

View file

@ -79,6 +79,8 @@ enum class SearchKind {
MagicSignature,
};
enum class AddressTypeHint { Function, Code, Data, Unknown };
class CUTTER_EXPORT CutterCore : public QObject
{
Q_OBJECT
@ -236,6 +238,7 @@ public:
RVA getFunctionEnd(RVA addr);
RVA getLastFunctionInstruction(RVA addr);
QString flagAt(RVA addr, bool getClosestFlag = true);
AddressTypeHint getAddressType(RVA addr);
void createFunctionAt(RVA addr);
void createFunctionAt(RVA addr, QString name);
QStringList getDisassemblyPreview(RVA address, int num_of_lines);
@ -559,6 +562,12 @@ public:
bool isBreakpoint(const QList<RVA> &breakpoints, RVA addr);
QList<RVA> getBreakpointsAddresses();
/**
* @brief Get the section at the given address
* @param addr Address to get the section for
* @return SectionDescription of the section at the given address
*/
SectionDescription getSectionAtAddress(RVA addr);
/**
* @brief Sets the RzRun profile directives by writing them to a file
* If a profile path is already set in 'dbg.profile', this method overwrites that file
@ -924,6 +933,7 @@ signals:
void newDebugMessage(const QString &msg);
void showMemoryWidgetRequested();
void showAddressRequested(RVA addr);
/**
* @brief emitted when a specific type is requested to be shown in the Types Widget

View file

@ -203,6 +203,7 @@ void MainWindow::initUI()
connect(core, &CutterCore::showMemoryWidgetRequested, this,
static_cast<void (MainWindow::*)()>(&MainWindow::showMemoryWidget));
connect(core, &CutterCore::showAddressRequested, this, &MainWindow::showAddress);
connect(core, &CutterCore::showTypeRequested, typesDock, [this](const QString &typeName) {
typesDock->toggleDockWidget(true);
@ -1020,6 +1021,28 @@ void MainWindow::showMemoryWidget(MemoryWidgetType type)
memoryDockWidget->raiseMemoryWidget();
}
MemoryDockWidget *MainWindow::getOrCreateMemoryWidget(MemoryWidgetType type, RVA address,
bool synchronized)
{
if (address == RVA_INVALID) {
address = Core()->getOffset();
}
for (auto &dock : dockWidgets) {
if (auto memoryWidget = qobject_cast<MemoryDockWidget *>(dock)) {
if (memoryWidget->getType() == type
&& memoryWidget->getSeekable()->isSynchronized() == synchronized) {
if (address != RVA_INVALID) {
memoryWidget->getSeekable()->seek(address);
}
return memoryWidget;
}
}
}
return addNewMemoryWidget(type, address, synchronized);
}
QMenu *MainWindow::createShowInMenu(QWidget *parent, RVA address, AddressTypeHint addressType)
{
QMenu *menu = new QMenu(parent);
@ -1084,6 +1107,26 @@ MemoryDockWidget *MainWindow::getLastMemoryWidget()
return lastMemoryWidget;
}
void MainWindow::showAddress(RVA addr)
{
if (lastMemoryWidget && lastMemoryWidget->getType() == MemoryWidgetType::Graph) {
AddressTypeHint addressType = core->getAddressType(addr);
MemoryWidgetType targetType;
if (addressType == AddressTypeHint::Data) {
targetType = MemoryWidgetType::Hexdump;
} else if (addressType == AddressTypeHint::Function) {
targetType = MemoryWidgetType::Graph;
} else {
targetType = MemoryWidgetType::Disassembly;
}
auto memoryWidget = getOrCreateMemoryWidget(targetType, addr, true);
memoryWidget->tryRaiseMemoryWidget();
setCurrentMemoryWidget(memoryWidget);
}
}
MemoryDockWidget *MainWindow::addNewMemoryWidget(MemoryWidgetType type, RVA address,
bool synchronized)
{

View file

@ -116,11 +116,12 @@ public:
QString getUniqueObjectName(const QString &widgetType) const;
void showMemoryWidget();
void showMemoryWidget(MemoryWidgetType type);
enum class AddressTypeHint { Function, Data, Unknown };
QMenu *createShowInMenu(QWidget *parent, RVA address,
AddressTypeHint addressType = AddressTypeHint::Unknown);
void setCurrentMemoryWidget(MemoryDockWidget *memoryWidget);
MemoryDockWidget *getLastMemoryWidget();
MemoryDockWidget *getOrCreateMemoryWidget(MemoryWidgetType type, RVA address = RVA_INVALID,
bool synchronized = true);
/* Context menu plugins */
enum class ContextMenuType { Disassembly, Addressable };
@ -133,6 +134,7 @@ public:
public slots:
void finalizeOpen();
void showAddress(RVA addr);
void refreshAll();
void seekToFunctionLastInstruction();

View file

@ -575,7 +575,7 @@ void DecompilerContextMenu::updateTargetMenuActions()
if (annotationHere->type == RZ_CODE_ANNOTATION_TYPE_GLOBAL_VARIABLE
|| annotationHere->type == RZ_CODE_ANNOTATION_TYPE_CONSTANT_VARIABLE) {
menu = mainWindow->createShowInMenu(this, annotationHere->reference.offset,
MainWindow::AddressTypeHint::Data);
AddressTypeHint::Data);
RVA var_addr = annotationHere->reference.offset;
RzFlagItem *flagDetails = rz_flag_get_i(core->flags, var_addr);
if (flagDetails) {
@ -585,7 +585,7 @@ void DecompilerContextMenu::updateTargetMenuActions()
}
} else if (annotationHere->type == RZ_CODE_ANNOTATION_TYPE_FUNCTION_NAME) {
menu = mainWindow->createShowInMenu(this, annotationHere->reference.offset,
MainWindow::AddressTypeHint::Function);
AddressTypeHint::Function);
name = tr("%1 (%2)").arg(QString(annotationHere->reference.name),
RzAddressString(annotationHere->reference.offset));
}