Heap widget wrapup (#2716)

This commit is contained in:
Pulak Malhotra 2021-07-16 19:18:10 +05:30 committed by GitHub
parent e29585c672
commit 60343fa8b5
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
17 changed files with 370 additions and 43 deletions

2
rizin

@ -1 +1 @@
Subproject commit 381f22d7cc81bf2eb6663a690a715ff4f8f09373 Subproject commit 254c5119e3563d05d02665cabbcba003c921cee8

View File

@ -146,6 +146,7 @@ set(SOURCES
widgets/GlibcHeapWidget.cpp widgets/GlibcHeapWidget.cpp
dialogs/GlibcHeapBinsDialog.cpp dialogs/GlibcHeapBinsDialog.cpp
widgets/HeapBinsGraphView.cpp widgets/HeapBinsGraphView.cpp
dialogs/ArenaInfoDialog.cpp
) )
set(HEADER_FILES set(HEADER_FILES
core/Cutter.h core/Cutter.h
@ -304,6 +305,7 @@ set(HEADER_FILES
widgets/GlibcHeapWidget.h widgets/GlibcHeapWidget.h
dialogs/GlibcHeapBinsDialog.h dialogs/GlibcHeapBinsDialog.h
widgets/HeapBinsGraphView.h widgets/HeapBinsGraphView.h
dialogs/ArenaInfoDialog.h
) )
set(UI_FILES set(UI_FILES
dialogs/AboutDialog.ui dialogs/AboutDialog.ui
@ -374,6 +376,7 @@ set(UI_FILES
widgets/HeapDockWidget.ui widgets/HeapDockWidget.ui
widgets/GlibcHeapWidget.ui widgets/GlibcHeapWidget.ui
dialogs/GlibcHeapBinsDialog.ui dialogs/GlibcHeapBinsDialog.ui
dialogs/ArenaInfoDialog.ui
) )
set(QRC_FILES set(QRC_FILES
resources.qrc resources.qrc

View File

@ -1592,6 +1592,12 @@ QVector<Chunk> CutterCore::getHeapChunks(RVA arena_addr)
return chunks_vector; return chunks_vector;
} }
int CutterCore::getArchBits()
{
CORE_LOCK();
return core->dbg->bits;
}
QVector<Arena> CutterCore::getArenas() QVector<Arena> CutterCore::getArenas()
{ {
CORE_LOCK(); CORE_LOCK();
@ -1606,6 +1612,12 @@ QVector<Arena> CutterCore::getArenas()
Arena arena; Arena arena;
arena.offset = data->addr; arena.offset = data->addr;
arena.type = QString(data->type); arena.type = QString(data->type);
arena.last_remainder = data->arena->last_remainder;
arena.top = data->arena->top;
arena.next = data->arena->next;
arena.next_free = data->arena->next_free;
arena.system_mem = data->arena->system_mem;
arena.max_system_mem = data->arena->max_system_mem;
arena_vector.append(arena); arena_vector.append(arena);
} }
@ -1653,10 +1665,30 @@ QVector<RzHeapBin *> CutterCore::getHeapBins(ut64 arena_addr)
} }
bins_vector.append(bin); bins_vector.append(bin);
} }
// get tcache bins
RzList *tcache_bins = rz_heap_tcache_content(core, arena_addr);
RzListIter *iter;
RzHeapBin *bin;
CutterRListForeach(tcache_bins, iter, RzHeapBin, bin)
{
if (!bin) {
continue;
}
if (!rz_list_length(bin->chunks)) {
rz_heap_bin_free_64(bin);
continue;
}
bins_vector.append(bin);
}
return bins_vector; return bins_vector;
} }
bool CutterCore::writeHeapChunk(RzHeapChunkSimple *chunk_simple)
{
CORE_LOCK();
return rz_heap_write_chunk(core, chunk_simple);
}
QJsonDocument CutterCore::getChildProcesses(int pid) QJsonDocument CutterCore::getChildProcesses(int pid)
{ {
// Return the currently debugged process and it's children // Return the currently debugged process and it's children

View File

@ -419,7 +419,20 @@ public:
* @return RzHeapChunkSimple struct pointer for the heap chunk * @return RzHeapChunkSimple struct pointer for the heap chunk
*/ */
RzHeapChunkSimple *getHeapChunk(ut64 addr); RzHeapChunkSimple *getHeapChunk(ut64 addr);
/**
* @brief Get heap bins of an arena with given base address
* (including large, small, fast, unsorted, tcache)
* @param arena_addr Base address of the arena
* @return QVector of non empty RzHeapBin pointers
*/
QVector<RzHeapBin *> getHeapBins(ut64 arena_addr); QVector<RzHeapBin *> getHeapBins(ut64 arena_addr);
/**
* @brief Write the given chunk header to memory
* @param chunkSimple RzHeapChunkSimple pointer of the chunk to be written
* @return true if the write succeeded else false
*/
bool writeHeapChunk(RzHeapChunkSimple *chunkSimple);
int getArchBits();
void startDebug(); void startDebug();
void startEmulation(); void startEmulation();
/** /**

View File

@ -375,6 +375,12 @@ struct Arena
{ {
RVA offset; RVA offset;
QString type; QString type;
ut64 top;
ut64 last_remainder;
ut64 next;
ut64 next_free;
ut64 system_mem;
ut64 max_system_mem;
}; };
Q_DECLARE_METATYPE(FunctionDescription) Q_DECLARE_METATYPE(FunctionDescription)

View File

@ -0,0 +1,25 @@
#include "ArenaInfoDialog.h"
#include "ui_ArenaInfoDialog.h"
ArenaInfoDialog::ArenaInfoDialog(Arena &arena, QWidget *parent)
: arena(arena), QDialog(parent), ui(new Ui::ArenaInfoDialog)
{
ui->setupUi(this);
setWindowTitle("Arena @ " + RAddressString(arena.offset));
updateContents();
}
void ArenaInfoDialog::updateContents()
{
ui->lineEditTop->setText(RAddressString(arena.top));
ui->lineEditLastRem->setText(RAddressString(arena.last_remainder));
ui->lineEditNext->setText(RAddressString(arena.next));
ui->lineEditNextfree->setText(RAddressString(arena.next_free));
ui->lineEditSysMem->setText(RAddressString(arena.system_mem));
ui->lineEditMaxMem->setText(RAddressString(arena.max_system_mem));
}
ArenaInfoDialog::~ArenaInfoDialog()
{
delete ui;
}

View File

@ -0,0 +1,25 @@
#ifndef ARENAINFODIALOG_H
#define ARENAINFODIALOG_H
#include <QDialog>
#include <CutterDescriptions.h>
namespace Ui {
class ArenaInfoDialog;
}
class ArenaInfoDialog : public QDialog
{
Q_OBJECT
public:
explicit ArenaInfoDialog(Arena &arena, QWidget *parent = nullptr);
~ArenaInfoDialog();
void updateContents();
private:
Ui::ArenaInfoDialog *ui;
Arena arena;
};
#endif // ARENAINFODIALOG_H

View File

@ -0,0 +1,109 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>ArenaInfoDialog</class>
<widget class="QDialog" name="ArenaInfoDialog">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>400</width>
<height>202</height>
</rect>
</property>
<property name="windowTitle">
<string>Dialog</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<layout class="QFormLayout" name="formLayout">
<item row="0" column="0">
<widget class="QLabel" name="label">
<property name="text">
<string>Top</string>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="label_2">
<property name="text">
<string>Next</string>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QLabel" name="label_3">
<property name="text">
<string>Next free</string>
</property>
</widget>
</item>
<item row="3" column="0">
<widget class="QLabel" name="label_4">
<property name="text">
<string>System Memory</string>
</property>
</widget>
</item>
<item row="4" column="0">
<widget class="QLabel" name="label_5">
<property name="text">
<string>Max Memory</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QLineEdit" name="lineEditTop">
<property name="readOnly">
<bool>true</bool>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QLineEdit" name="lineEditNext">
<property name="readOnly">
<bool>true</bool>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QLineEdit" name="lineEditNextfree">
<property name="readOnly">
<bool>true</bool>
</property>
</widget>
</item>
<item row="3" column="1">
<widget class="QLineEdit" name="lineEditSysMem">
<property name="readOnly">
<bool>true</bool>
</property>
</widget>
</item>
<item row="4" column="1">
<widget class="QLineEdit" name="lineEditMaxMem">
<property name="readOnly">
<bool>true</bool>
</property>
</widget>
</item>
<item row="5" column="0">
<widget class="QLabel" name="label_6">
<property name="text">
<string>Last Remainder</string>
</property>
</widget>
</item>
<item row="5" column="1">
<widget class="QLineEdit" name="lineEditLastRem">
<property name="readOnly">
<bool>true</bool>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
<resources/>
<connections/>
</ui>

View File

@ -4,10 +4,10 @@
<widget class="QDialog" name="GlibcHeapBinsDialog"> <widget class="QDialog" name="GlibcHeapBinsDialog">
<property name="geometry"> <property name="geometry">
<rect> <rect>
<x>0</x> <x>0</x>
<y>0</y> <y>0</y>
<width>883</width> <width>883</width>
<height>544</height> <height>544</height>
</rect> </rect>
</property> </property>
<property name="windowTitle"> <property name="windowTitle">
@ -27,7 +27,11 @@
</widget> </widget>
</item> </item>
<item> <item>
<widget class="QPlainTextEdit" name="chainInfoEdit"/> <widget class="QPlainTextEdit" name="chainInfoEdit">
<property name="readOnly">
<bool>true</bool>
</property>
</widget>
</item> </item>
<item> <item>
<layout class="QHBoxLayout" name="horizontalLayout3"> <layout class="QHBoxLayout" name="horizontalLayout3">

View File

@ -8,11 +8,6 @@ GlibcHeapInfoDialog::GlibcHeapInfoDialog(RVA offset, QString status, QWidget *pa
{ {
ui->setupUi(this); ui->setupUi(this);
// disable all the radio buttons for flag field so they are not user editable
this->ui->rbIM->setEnabled(false);
this->ui->rbNMA->setEnabled(false);
this->ui->rbPI->setEnabled(false);
// set window title // set window title
QString windowTitle = tr("Chunk @ ") + RAddressString(offset); QString windowTitle = tr("Chunk @ ") + RAddressString(offset);
if (!this->status.isEmpty()) { if (!this->status.isEmpty()) {
@ -20,6 +15,8 @@ GlibcHeapInfoDialog::GlibcHeapInfoDialog(RVA offset, QString status, QWidget *pa
} }
this->setWindowTitle(windowTitle); this->setWindowTitle(windowTitle);
connect(ui->saveButton, &QPushButton::clicked, this, &GlibcHeapInfoDialog::saveChunkInfo);
updateFields(); updateFields();
} }
@ -46,13 +43,69 @@ void GlibcHeapInfoDialog::updateFields()
this->ui->prevSizeEdit->setText(RHexString(chunk->prev_size)); this->ui->prevSizeEdit->setText(RHexString(chunk->prev_size));
if (chunk->is_mmapped) { if (chunk->is_mmapped) {
this->ui->rbIM->setChecked(true); this->ui->rbIM->setChecked(true);
} else {
this->ui->rbIM->setChecked(false);
} }
if (chunk->prev_inuse) { if (chunk->prev_inuse) {
this->ui->rbPI->setChecked(true); this->ui->rbPI->setChecked(true);
} else {
this->ui->rbPI->setChecked(false);
} }
if (chunk->non_main_arena) { if (chunk->non_main_arena) {
this->ui->rbNMA->setChecked(true); this->ui->rbNMA->setChecked(true);
} else {
this->ui->rbNMA->setChecked(false);
} }
free(chunk); free(chunk);
} }
void GlibcHeapInfoDialog::saveChunkInfo()
{
QMessageBox msgBox;
msgBox.setText("Do you want to overwrite chunk metadata?");
msgBox.setInformativeText(
"Any field which cannot be converted to a valid integer will be saved as zero");
msgBox.setStandardButtons(QMessageBox::Save | QMessageBox::Cancel);
msgBox.setDefaultButton(QMessageBox::Save);
int ret = msgBox.exec();
switch (ret) {
case QMessageBox::Save:
// Save was clicked
RzHeapChunkSimple chunkSimple;
chunkSimple.size = Core()->math(ui->sizeEdit->text());
chunkSimple.fd = Core()->math(ui->fdEdit->text());
chunkSimple.bk = Core()->math(ui->bkEdit->text());
chunkSimple.fd_nextsize = Core()->math(ui->fdnsEdit->text());
chunkSimple.bk_nextsize = Core()->math(ui->bknsEdit->text());
chunkSimple.addr = offset;
if (ui->rbIM->isChecked()) {
chunkSimple.is_mmapped = true;
} else {
chunkSimple.is_mmapped = false;
}
if (ui->rbNMA->isChecked()) {
chunkSimple.non_main_arena = true;
} else {
chunkSimple.non_main_arena = false;
}
if (ui->rbPI->isChecked()) {
chunkSimple.prev_inuse = true;
} else {
chunkSimple.prev_inuse = false;
}
if (Core()->writeHeapChunk(&chunkSimple)) {
updateFields();
QMessageBox::information(this, tr("Chunk saved"),
tr("Chunk header successfully overwritten"));
} else {
QMessageBox::information(this, tr("Chunk not saved"),
tr("Chunk header not successfully overwritten"));
}
break;
case QMessageBox::Cancel:
// Cancel was clicked
break;
}
}

View File

@ -16,6 +16,9 @@ public:
explicit GlibcHeapInfoDialog(RVA offset, QString status, QWidget *parent = nullptr); explicit GlibcHeapInfoDialog(RVA offset, QString status, QWidget *parent = nullptr);
~GlibcHeapInfoDialog(); ~GlibcHeapInfoDialog();
private slots:
void saveChunkInfo();
private: private:
Ui::GlibcHeapInfoDialog *ui; Ui::GlibcHeapInfoDialog *ui;
void updateFields(); void updateFields();

View File

@ -46,7 +46,7 @@
<string>Size of the heap chunk including metadata</string> <string>Size of the heap chunk including metadata</string>
</property> </property>
<property name="readOnly"> <property name="readOnly">
<bool>true</bool> <bool>false</bool>
</property> </property>
</widget> </widget>
</item> </item>
@ -63,7 +63,7 @@
<string>Link to next free chunk in bin's linked list</string> <string>Link to next free chunk in bin's linked list</string>
</property> </property>
<property name="readOnly"> <property name="readOnly">
<bool>true</bool> <bool>false</bool>
</property> </property>
</widget> </widget>
</item> </item>
@ -80,7 +80,7 @@
<string>Link to previous free chunk in bin's linked list</string> <string>Link to previous free chunk in bin's linked list</string>
</property> </property>
<property name="readOnly"> <property name="readOnly">
<bool>true</bool> <bool>false</bool>
</property> </property>
</widget> </widget>
</item> </item>
@ -90,7 +90,7 @@
<string>Link to next larger free chunk (only for large chunks)</string> <string>Link to next larger free chunk (only for large chunks)</string>
</property> </property>
<property name="readOnly"> <property name="readOnly">
<bool>true</bool> <bool>false</bool>
</property> </property>
</widget> </widget>
</item> </item>
@ -114,7 +114,7 @@
<string>Link to next smaller free chunk (for large chunks)</string> <string>Link to next smaller free chunk (for large chunks)</string>
</property> </property>
<property name="readOnly"> <property name="readOnly">
<bool>true</bool> <bool>false</bool>
</property> </property>
</widget> </widget>
</item> </item>
@ -124,7 +124,7 @@
<string>Size of previous chunk (if free)</string> <string>Size of previous chunk (if free)</string>
</property> </property>
<property name="readOnly"> <property name="readOnly">
<bool>true</bool> <bool>false</bool>
</property> </property>
</widget> </widget>
</item> </item>
@ -189,6 +189,13 @@
</item> </item>
</layout> </layout>
</item> </item>
<item>
<widget class="QPushButton" name="saveButton">
<property name="text">
<string>Save</string>
</property>
</widget>
</item>
</layout> </layout>
</widget> </widget>
<resources/> <resources/>

View File

@ -1,4 +1,5 @@
#include <dialogs/GlibcHeapBinsDialog.h> #include <dialogs/GlibcHeapBinsDialog.h>
#include <dialogs/ArenaInfoDialog.h>
#include "GlibcHeapWidget.h" #include "GlibcHeapWidget.h"
#include "ui_GlibcHeapWidget.h" #include "ui_GlibcHeapWidget.h"
#include "core/MainWindow.h" #include "core/MainWindow.h"
@ -38,6 +39,7 @@ GlibcHeapWidget::GlibcHeapWidget(MainWindow *main, QWidget *parent)
connect(chunkInfoAction, &QAction::triggered, this, &GlibcHeapWidget::viewChunkInfo); connect(chunkInfoAction, &QAction::triggered, this, &GlibcHeapWidget::viewChunkInfo);
connect(binInfoAction, &QAction::triggered, this, &GlibcHeapWidget::viewBinInfo); connect(binInfoAction, &QAction::triggered, this, &GlibcHeapWidget::viewBinInfo);
connect(ui->binsButton, &QPushButton::clicked, this, &GlibcHeapWidget::viewBinInfo); connect(ui->binsButton, &QPushButton::clicked, this, &GlibcHeapWidget::viewBinInfo);
connect(ui->arenaButton, &QPushButton::clicked, this, &GlibcHeapWidget::viewArenaInfo);
addressableItemContextMenu.addAction(chunkInfoAction); addressableItemContextMenu.addAction(chunkInfoAction);
addressableItemContextMenu.addAction(binInfoAction); addressableItemContextMenu.addAction(binInfoAction);
@ -214,3 +216,18 @@ void GlibcHeapWidget::viewBinInfo()
GlibcHeapBinsDialog heapBinsDialog(modelHeap->arena_addr, main, this); GlibcHeapBinsDialog heapBinsDialog(modelHeap->arena_addr, main, this);
heapBinsDialog.exec(); heapBinsDialog.exec();
} }
void GlibcHeapWidget::viewArenaInfo()
{
// find the active arena
Arena currentArena;
for (auto &arena : arenas) {
if (arena.offset == modelHeap->arena_addr) {
currentArena = arena;
break;
}
}
ArenaInfoDialog arenaInfoDialog(currentArena, this);
arenaInfoDialog.exec();
}

View File

@ -44,6 +44,7 @@ private slots:
void onCurrentChanged(const QModelIndex &current, const QModelIndex &previous); void onCurrentChanged(const QModelIndex &current, const QModelIndex &previous);
void viewChunkInfo(); void viewChunkInfo();
void viewBinInfo(); void viewBinInfo();
void viewArenaInfo();
private: private:
void updateArenas(); void updateArenas();

View File

@ -19,25 +19,38 @@
</item> </item>
<item> <item>
<layout class="QHBoxLayout" name="horizontalLayout"> <layout class="QHBoxLayout" name="horizontalLayout">
<item> <item>
<widget class="QComboBox" name="arenaSelector"/> <widget class="QComboBox" name="arenaSelector"/>
</item> </item>
<item> <item>
<widget class="QPushButton" name="binsButton"> <widget class="QPushButton" name="arenaButton">
<property name="sizePolicy"> <property name="sizePolicy">
<sizepolicy hsizetype="Maximum" vsizetype="Fixed"> <sizepolicy hsizetype="Maximum" vsizetype="Fixed">
<horstretch>0</horstretch> <horstretch>0</horstretch>
<verstretch>0</verstretch> <verstretch>0</verstretch>
</sizepolicy> </sizepolicy>
</property> </property>
<property name="toolTip"> <property name="text">
<string>View bins info for an arena</string> <string>Arena</string>
</property> </property>
<property name="text"> </widget>
<string>Bins</string> </item>
</property> <item>
</widget> <widget class="QPushButton" name="binsButton">
</item> <property name="sizePolicy">
<sizepolicy hsizetype="Maximum" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="toolTip">
<string>View bins info for an arena</string>
</property>
<property name="text">
<string>Bins</string>
</property>
</widget>
</item>
</layout> </layout>
</item> </item>
</layout> </layout>

View File

@ -11,6 +11,8 @@ HeapBinsGraphView::HeapBinsGraphView(QWidget *parent, RzHeapBin *bin, MainWindow
connect(chunkInfoAction, &QAction::triggered, this, &HeapBinsGraphView::viewChunkInfo); connect(chunkInfoAction, &QAction::triggered, this, &HeapBinsGraphView::viewChunkInfo);
bits = Core()->getArchBits();
enableAddresses(true); enableAddresses(true);
} }
@ -30,7 +32,8 @@ void HeapBinsGraphView::loadCurrentGraph()
QVector<GraphHeapChunk> chunks; QVector<GraphHeapChunk> chunks;
// if the bin is a fastbin or not // if the bin is a fastbin or not
bool fast = QString(heapBin->type) == QString("Fast"); bool singleLinkedBin = QString(heapBin->type) == QString("Fast")
|| QString(heapBin->type) == QString("Tcache");
// store info about the chunks in a vector for easy access // store info about the chunks in a vector for easy access
CutterRListForeach(heapBin->chunks, iter, RzHeapChunkListItem, item) CutterRListForeach(heapBin->chunks, iter, RzHeapChunkListItem, item)
@ -45,7 +48,7 @@ void HeapBinsGraphView::loadCurrentGraph()
+ RHexString(chunkInfo->size) + "\nFd: " + RAddressString(chunkInfo->fd); + RHexString(chunkInfo->size) + "\nFd: " + RAddressString(chunkInfo->fd);
// fastbins lack bk pointer // fastbins lack bk pointer
if (!fast) { if (!singleLinkedBin) {
content += "\nBk: " + RAddressString(chunkInfo->bk); content += "\nBk: " + RAddressString(chunkInfo->bk);
} }
graphHeapChunk.fd = chunkInfo->fd; graphHeapChunk.fd = chunkInfo->fd;
@ -55,8 +58,8 @@ void HeapBinsGraphView::loadCurrentGraph()
free(chunkInfo); free(chunkInfo);
} }
// fast bins have single linked list and other bins have double linked list // fast and tcache bins have single linked list and other bins have double linked list
if (fast) { if (singleLinkedBin) {
display_single_linked_list(chunks); display_single_linked_list(chunks);
} else { } else {
display_double_linked_list(chunks); display_double_linked_list(chunks);
@ -68,19 +71,31 @@ void HeapBinsGraphView::loadCurrentGraph()
void HeapBinsGraphView::display_single_linked_list(QVector<GraphHeapChunk> chunks) void HeapBinsGraphView::display_single_linked_list(QVector<GraphHeapChunk> chunks)
{ {
bool tcache = QString(heapBin->type) == QString("Tcache");
int ptrSize = bits;
// add the graph block for the bin // add the graph block for the bin
GraphLayout::GraphBlock gbBin; GraphLayout::GraphBlock gbBin;
gbBin.entry = 1; gbBin.entry = 1;
gbBin.edges.emplace_back(heapBin->fd); gbBin.edges.emplace_back(heapBin->fd);
QString content = tr(heapBin->type) + tr("bin ") + QString::number(heapBin->bin_num); QString content = tr(heapBin->type) + tr("bin ") + QString::number(heapBin->bin_num);
content += "\nFd: " + RAddressString(heapBin->fd); if (tcache) {
content += "\nEntry: " + RAddressString(heapBin->fd);
} else {
content += "\nFd: " + RAddressString(heapBin->fd);
}
addBlock(gbBin, content); addBlock(gbBin, content);
// add the graph blocks for the chunks // add the graph blocks for the chunks
for (int i = 0; i < chunks.size(); i++) { for (int i = 0; i < chunks.size(); i++) {
GraphLayout::GraphBlock gbChunk; GraphLayout::GraphBlock gbChunk;
gbChunk.entry = chunks[i].addr; gbChunk.entry = chunks[i].addr;
gbChunk.edges.emplace_back(chunks[i].fd);
if (tcache && chunks[i].fd) {
// base_address = address - 2 * PTR_SIZE
gbChunk.edges.emplace_back(chunks[i].fd - 2 * ptrSize);
} else {
gbChunk.edges.emplace_back(chunks[i].fd);
}
if (i == chunks.size() - 1 && heapBin->message) { if (i == chunks.size() - 1 && heapBin->message) {
chunks[i].content += "\n" + QString(heapBin->message); chunks[i].content += "\n" + QString(heapBin->message);

View File

@ -33,6 +33,7 @@ private:
void display_double_linked_list(QVector<GraphHeapChunk>); void display_double_linked_list(QVector<GraphHeapChunk>);
QAction *chunkInfoAction; QAction *chunkInfoAction;
RVA selectedBlock; RVA selectedBlock;
int bits;
}; };
#endif // CUTTER_HEAPBINSGRAPHVIEW_H #endif // CUTTER_HEAPBINSGRAPHVIEW_H