Initial heap dock widget with glibc support (#2705)

This commit is contained in:
Pulak Malhotra 2021-06-28 01:51:06 +05:30 committed by GitHub
parent 04894b4757
commit 771fa6102c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
16 changed files with 789 additions and 12 deletions

2
rizin

@ -1 +1 @@
Subproject commit e60f06775ebffc7e91903d0b21ad8fee1c86c1ac
Subproject commit 92ad8bef001843df5882e71c23761987cfa3d9f4

View File

@ -141,6 +141,9 @@ set(SOURCES
widgets/AddressableDockWidget.cpp
dialogs/preferences/AnalOptionsWidget.cpp
common/DecompilerHighlighter.cpp
dialogs/GlibcHeapInfoDialog.cpp
widgets/HeapDockWidget.cpp
widgets/GlibcHeapWidget.cpp
)
set(HEADER_FILES
core/Cutter.h
@ -294,6 +297,9 @@ set(HEADER_FILES
widgets/AddressableDockWidget.h
dialogs/preferences/AnalOptionsWidget.h
common/DecompilerHighlighter.h
dialogs/GlibcHeapInfoDialog.h
widgets/HeapDockWidget.h
widgets/GlibcHeapWidget.h
)
set(UI_FILES
dialogs/AboutDialog.ui
@ -360,6 +366,9 @@ set(UI_FILES
dialogs/LayoutManager.ui
widgets/RizinGraphWidget.ui
dialogs/preferences/AnalOptionsWidget.ui
dialogs/GlibcHeapInfoDialog.ui
widgets/HeapDockWidget.ui
widgets/GlibcHeapWidget.ui
)
set(QRC_FILES
resources.qrc

View File

@ -1556,6 +1556,69 @@ QJsonDocument CutterCore::getProcessThreads(int pid)
}
}
QVector<Chunk> CutterCore::getHeapChunks(RVA arena_addr)
{
CORE_LOCK();
QVector<Chunk> chunks_vector;
ut64 m_arena;
if (!arena_addr) {
// if arena_addr is zero get base address of main arena
RzList *arenas = rz_heap_arenas_list(core);
if (arenas->length == 0) {
rz_list_free(arenas);
return chunks_vector;
}
m_arena = ((RzArenaListItem *)arenas->head->data)->addr;
rz_list_free(arenas);
} else {
m_arena = arena_addr;
}
// Get chunks using api and store them in a chunks_vector
RzList *chunks = rz_heap_chunks_list(core, m_arena);
RzListIter *iter;
RzHeapChunkListItem *data;
CutterRListForeach(chunks, iter, RzHeapChunkListItem, data)
{
Chunk chunk;
chunk.offset = data->addr;
chunk.size = (int)data->size;
chunk.status = QString(data->status);
chunks_vector.append(chunk);
}
rz_list_free(chunks);
return chunks_vector;
}
QVector<Arena> CutterCore::getArenas()
{
CORE_LOCK();
QVector<Arena> arena_vector;
// get arenas using API and store them in arena_vector
RzList *arenas = rz_heap_arenas_list(core);
RzListIter *iter;
RzArenaListItem *data;
CutterRListForeach(arenas, iter, RzArenaListItem, data)
{
Arena arena;
arena.offset = data->addr;
arena.type = QString(data->type);
arena_vector.append(arena);
}
rz_list_free(arenas);
return arena_vector;
}
RzHeapChunkSimple *CutterCore::getHeapChunk(ut64 addr)
{
CORE_LOCK();
return rz_heap_chunk(core, addr);
}
QJsonDocument CutterCore::getChildProcesses(int pid)
{
// Return the currently debugged process and it's children
@ -1803,6 +1866,7 @@ void CutterCore::attachRemote(const QString &uri)
emit toggleDebugView();
}
currentlyRemoteDebugging = true;
emit codeRebased();
emit attachedRemote(true);
emit debugTaskStateChanged();
@ -1873,6 +1937,7 @@ void CutterCore::stopDebug()
currentlyDebugging = false;
currentlyTracing = false;
currentlyRemoteDebugging = false;
emit debugTaskStateChanged();
if (currentlyEmulating) {

View File

@ -397,6 +397,28 @@ public:
*/
QJsonDocument getChildProcesses(int pid);
QJsonDocument getBacktrace();
/**
* @brief Get a list of heap chunks
* Uses RZ_API rz_heap_chunks_list to get vector of chunks
* If arena_addr is zero return the chunks for main arena
* @param arena_addr base address for the arena
* @return Vector of heap chunks for the given arena
*/
QVector<Chunk> getHeapChunks(RVA arena_addr);
/**
* @brief Get a list of heap arenas
* Uses RZ_API rz_heap_arenas_list to get list of arenas
* @return Vector of arenas
*/
QVector<Arena> getArenas();
/**
* @brief Get detailed information about a heap chunk
* Uses RZ_API rz_heap_chunk
* @return RzHeapChunkSimple struct pointer for the heap chunk
*/
RzHeapChunkSimple *getHeapChunk(ut64 addr);
void startDebug();
void startEmulation();
/**
@ -456,6 +478,7 @@ public:
bool currentlyDebugging = false;
bool currentlyEmulating = false;
bool currentlyTracing = false;
bool currentlyRemoteDebugging = false;
int currentlyAttachedToPID = -1;
QString currentlyOpenFile;

View File

@ -364,6 +364,19 @@ struct RegisterRefValueDescription
QString ref;
};
struct Chunk
{
RVA offset;
QString status;
int size;
};
struct Arena
{
RVA offset;
QString type;
};
Q_DECLARE_METATYPE(FunctionDescription)
Q_DECLARE_METATYPE(ImportDescription)
Q_DECLARE_METATYPE(ExportDescription)

View File

@ -71,6 +71,7 @@
#include "widgets/HexWidget.h"
#include "widgets/RizinGraphWidget.h"
#include "widgets/CallGraph.h"
#include "widgets/HeapDockWidget.h"
// Qt Headers
#include <QActionGroup>
@ -374,12 +375,15 @@ void MainWindow::initDocks()
commentsDock = new CommentsWidget(this);
stringsDock = new StringsWidget(this);
QList<CutterDockWidget *> debugDocks = {
stackDock = new StackWidget(this), threadsDock = new ThreadsWidget(this),
processesDock = new ProcessesWidget(this), backtraceDock = new BacktraceWidget(this),
registersDock = new RegistersWidget(this), memoryMapDock = new MemoryMapWidget(this),
breakpointDock = new BreakpointWidget(this), registerRefsDock = new RegisterRefsWidget(this)
};
QList<CutterDockWidget *> debugDocks = { stackDock = new StackWidget(this),
threadsDock = new ThreadsWidget(this),
processesDock = new ProcessesWidget(this),
backtraceDock = new BacktraceWidget(this),
registersDock = new RegistersWidget(this),
memoryMapDock = new MemoryMapWidget(this),
breakpointDock = new BreakpointWidget(this),
registerRefsDock = new RegisterRefsWidget(this),
heapDock = new HeapDockWidget(this) };
QList<CutterDockWidget *> infoDocks = {
classesDock = new ClassesWidget(this),
@ -709,7 +713,8 @@ RzProjectErr MainWindow::saveProjectAs(bool *canceled)
QFileDialog fileDialog(this);
// Append 'rzdb' suffix if it does not exist
fileDialog.setDefaultSuffix("rzdb");
QString file = fileDialog.getSaveFileName(this, tr("Save Project"), projectFile, PROJECT_FILE_FILTER);
QString file =
fileDialog.getSaveFileName(this, tr("Save Project"), projectFile, PROJECT_FILE_FILTER);
if (file.isEmpty()) {
if (canceled) {
*canceled = true;
@ -918,6 +923,7 @@ void MainWindow::restoreDocks()
tabifyDockWidget(stackDock, backtraceDock);
tabifyDockWidget(backtraceDock, threadsDock);
tabifyDockWidget(threadsDock, processesDock);
tabifyDockWidget(processesDock, heapDock);
for (auto dock : pluginDocks) {
dockOnMainArea(dock);
@ -928,7 +934,7 @@ bool MainWindow::isDebugWidget(QDockWidget *dock) const
{
return dock == stackDock || dock == registersDock || dock == backtraceDock
|| dock == threadsDock || dock == memoryMapDock || dock == breakpointDock
|| dock == processesDock || dock == registerRefsDock;
|| dock == processesDock || dock == registerRefsDock || dock == heapDock;
}
bool MainWindow::isExtraMemoryWidget(QDockWidget *dock) const
@ -1264,9 +1270,13 @@ void MainWindow::showZenDocks()
void MainWindow::showDebugDocks()
{
const QList<QDockWidget *> debugDocks = { functionsDock, stringsDock, searchDock,
stackDock, registersDock, backtraceDock,
threadsDock, memoryMapDock, breakpointDock };
QList<QDockWidget *> debugDocks = {
functionsDock, stringsDock, searchDock, stackDock, registersDock,
backtraceDock, threadsDock, memoryMapDock, breakpointDock,
};
if (QSysInfo::kernelType() == "linux" || Core()->currentlyRemoteDebugging) {
debugDocks.append(heapDock);
}
functionDockWidthToRestore = functionsDock->maximumWidth();
functionsDock->setMaximumWidth(200);
auto registerWidth = qhelpers::forceWidth(registersDock, std::min(500, this->width() / 4));

View File

@ -54,6 +54,7 @@ class DecompilerWidget;
class OverviewWidget;
class RizinGraphWidget;
class CallGraphWidget;
class HeapWidget;
namespace Ui {
class MainWindow;
@ -259,6 +260,7 @@ private:
RizinGraphWidget *rzGraphDock = nullptr;
CallGraphWidget *callGraphDock = nullptr;
CallGraphWidget *globalCallGraphDock = nullptr;
CutterDockWidget *heapDock = nullptr;
QMenu *disassemblyContextMenuExtensions = nullptr;
QMenu *addressableContextMenuExtensions = nullptr;

View File

@ -0,0 +1,53 @@
#include "GlibcHeapInfoDialog.h"
#include <utility>
#include "ui_GlibcHeapInfoDialog.h"
GlibcHeapInfoDialog::GlibcHeapInfoDialog(RVA offset, QString status, QWidget *parent)
: QDialog(parent), ui(new Ui::GlibcHeapInfoDialog), offset(offset), status(std::move(status))
{
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);
this->setWindowTitle(QString("Chunk @ ") + RAddressString(offset)
+ QString("(" + this->status + ")"));
updateFields();
}
GlibcHeapInfoDialog::~GlibcHeapInfoDialog()
{
delete ui;
}
void GlibcHeapInfoDialog::updateFields()
{
// get data about the heap chunk from the API
RzHeapChunkSimple *chunk = Core()->getHeapChunk(offset);
if (!chunk) {
return;
}
// Update the information in the widget
this->ui->baseEdit->setText(RAddressString(offset));
this->ui->sizeEdit->setText(RHexString(chunk->size));
this->ui->bkEdit->setText(RAddressString(chunk->bk));
this->ui->fdEdit->setText(RAddressString(chunk->fd));
this->ui->bknsEdit->setText(RAddressString(chunk->bk_nextsize));
this->ui->fdnsEdit->setText(RAddressString(chunk->fd_nextsize));
this->ui->prevSizeEdit->setText(RHexString(chunk->prev_size));
if (chunk->is_mmapped) {
this->ui->rbIM->setChecked(true);
}
if (chunk->prev_inuse) {
this->ui->rbPI->setChecked(true);
}
if (chunk->non_main_arena) {
this->ui->rbNMA->setChecked(true);
}
free(chunk);
}

View File

@ -0,0 +1,26 @@
#ifndef HEAPINFODIALOG_H
#define HEAPINFODIALOG_H
#include <QDialog>
#include "core/Cutter.h"
namespace Ui {
class GlibcHeapInfoDialog;
}
class GlibcHeapInfoDialog : public QDialog
{
Q_OBJECT
public:
explicit GlibcHeapInfoDialog(RVA offset, QString status, QWidget *parent = nullptr);
~GlibcHeapInfoDialog();
private:
Ui::GlibcHeapInfoDialog *ui;
void updateFields();
RVA offset;
QString status;
};
#endif // HEAPINFODIALOG_H

View File

@ -0,0 +1,196 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>GlibcHeapInfoDialog</class>
<widget class="QDialog" name="GlibcHeapInfoDialog">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>453</width>
<height>263</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>Base</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QLineEdit" name="baseEdit">
<property name="toolTip">
<string>Base address of the chunk</string>
</property>
<property name="readOnly">
<bool>true</bool>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="label_4">
<property name="text">
<string>Size</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QLineEdit" name="sizeEdit">
<property name="toolTip">
<string>Size of the heap chunk including metadata</string>
</property>
<property name="readOnly">
<bool>true</bool>
</property>
</widget>
</item>
<item row="3" column="0">
<widget class="QLabel" name="label_2">
<property name="text">
<string>Fd</string>
</property>
</widget>
</item>
<item row="3" column="1">
<widget class="QLineEdit" name="fdEdit">
<property name="toolTip">
<string>Link to next free chunk in bin's linked list</string>
</property>
<property name="readOnly">
<bool>true</bool>
</property>
</widget>
</item>
<item row="4" column="0">
<widget class="QLabel" name="label_5">
<property name="text">
<string>Bk</string>
</property>
</widget>
</item>
<item row="4" column="1">
<widget class="QLineEdit" name="bkEdit">
<property name="toolTip">
<string>Link to previous free chunk in bin's linked list</string>
</property>
<property name="readOnly">
<bool>true</bool>
</property>
</widget>
</item>
<item row="5" column="1">
<widget class="QLineEdit" name="fdnsEdit">
<property name="toolTip">
<string>Link to next larger free chunk (only for large chunks)</string>
</property>
<property name="readOnly">
<bool>true</bool>
</property>
</widget>
</item>
<item row="5" column="0">
<widget class="QLabel" name="label_3">
<property name="text">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Fd-nextsize&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
</widget>
</item>
<item row="6" column="0">
<widget class="QLabel" name="label_6">
<property name="text">
<string>Bk-nextsize</string>
</property>
</widget>
</item>
<item row="6" column="1">
<widget class="QLineEdit" name="bknsEdit">
<property name="toolTip">
<string>Link to next smaller free chunk (for large chunks)</string>
</property>
<property name="readOnly">
<bool>true</bool>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QLineEdit" name="prevSizeEdit">
<property name="toolTip">
<string>Size of previous chunk (if free)</string>
</property>
<property name="readOnly">
<bool>true</bool>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QLabel" name="label_7">
<property name="text">
<string>PrevSize</string>
</property>
</widget>
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_2">
<item>
<widget class="QRadioButton" name="rbNMA">
<property name="toolTip">
<string>If the chunk was obtained from a non-main arena</string>
</property>
<property name="text">
<string>NON_MAIN_ARENA</string>
</property>
<property name="checkable">
<bool>true</bool>
</property>
<property name="autoExclusive">
<bool>false</bool>
</property>
</widget>
</item>
<item>
<widget class="QRadioButton" name="rbIM">
<property name="toolTip">
<string>The chunk was obtained with mmap()</string>
</property>
<property name="text">
<string>IS_MMAPED</string>
</property>
<property name="checkable">
<bool>true</bool>
</property>
<property name="autoExclusive">
<bool>false</bool>
</property>
</widget>
</item>
<item>
<widget class="QRadioButton" name="rbPI">
<property name="toolTip">
<string>Previous adjacent chunk is in use</string>
</property>
<property name="text">
<string>PREV_INUSE</string>
</property>
<property name="checkable">
<bool>true</bool>
</property>
<property name="autoExclusive">
<bool>false</bool>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
<resources/>
<connections/>
</ui>

View File

@ -0,0 +1,204 @@
#include "GlibcHeapWidget.h"
#include "ui_GlibcHeapWidget.h"
#include "core/MainWindow.h"
#include "QHeaderView"
#include "dialogs/GlibcHeapInfoDialog.h"
GlibcHeapWidget::GlibcHeapWidget(MainWindow *main, QWidget *parent)
: QWidget(parent),
ui(new Ui::GlibcHeapWidget),
addressableItemContextMenu(this, main),
main(main)
{
ui->setupUi(this);
viewHeap->setFont(Config()->getFont());
viewHeap->setModel(modelHeap);
viewHeap->verticalHeader()->hide();
// change the scroll mode to ScrollPerPixel
viewHeap->setHorizontalScrollMode(QAbstractItemView::ScrollPerPixel);
viewHeap->setVerticalScrollMode(QAbstractItemView::ScrollPerPixel);
ui->verticalLayout->addWidget(viewHeap);
ui->verticalLayout->addWidget(arenaSelectorView);
chunkInfoAction = new QAction(tr("Detailed Chunk Info"), this);
viewHeap->setContextMenuPolicy(Qt::CustomContextMenu);
connect(Core(), &CutterCore::refreshAll, this, &GlibcHeapWidget::updateContents);
connect(Core(), &CutterCore::debugTaskStateChanged, this, &GlibcHeapWidget::updateContents);
connect(viewHeap, &QAbstractItemView::doubleClicked, this, &GlibcHeapWidget::onDoubleClicked);
connect<void (QComboBox::*)(int)>(arenaSelectorView, &QComboBox::currentIndexChanged, this,
&GlibcHeapWidget::onArenaSelected);
connect(viewHeap, &QWidget::customContextMenuRequested, this,
&GlibcHeapWidget::customMenuRequested);
connect(viewHeap->selectionModel(), &QItemSelectionModel::currentChanged, this,
&GlibcHeapWidget::onCurrentChanged);
connect(chunkInfoAction, &QAction::triggered, this, &GlibcHeapWidget::viewChunkInfo);
addressableItemContextMenu.addAction(chunkInfoAction);
addActions(addressableItemContextMenu.actions());
refreshDeferrer = dynamic_cast<CutterDockWidget *>(parent)->createRefreshDeferrer(
[this]() { updateContents(); });
}
GlibcHeapWidget::~GlibcHeapWidget()
{
delete ui;
}
GlibcHeapModel::GlibcHeapModel(QObject *parent) : QAbstractTableModel(parent) {}
void GlibcHeapWidget::updateArenas()
{
arenas = Core()->getArenas();
// store the currently selected arena's index
int currentIndex = arenaSelectorView->currentIndex();
arenaSelectorView->clear();
// add the new arenas to the arena selector
for (auto &arena : arenas) {
arenaSelectorView->addItem(RAddressString(arena.offset)
+ QString(" (" + arena.type + " Arena)"));
}
// check if arenas reduced or invalid index and restore the previously selected arena
if (arenaSelectorView->count() < currentIndex || currentIndex == -1) {
currentIndex = 0;
}
arenaSelectorView->setCurrentIndex(currentIndex);
}
void GlibcHeapWidget::onArenaSelected(int index)
{
if (index == -1) {
modelHeap->arena_addr = 0;
} else {
modelHeap->arena_addr = arenas[index].offset;
}
updateChunks();
}
void GlibcHeapWidget::updateContents()
{
if (!refreshDeferrer->attemptRefresh(nullptr) || Core()->isDebugTaskInProgress()) {
return;
}
updateArenas();
updateChunks();
}
void GlibcHeapWidget::updateChunks()
{
modelHeap->reload();
viewHeap->resizeColumnsToContents();
}
void GlibcHeapWidget::customMenuRequested(QPoint pos)
{
addressableItemContextMenu.exec(viewHeap->viewport()->mapToGlobal(pos));
}
void GlibcHeapModel::reload()
{
beginResetModel();
values.clear();
values = Core()->getHeapChunks(arena_addr);
endResetModel();
}
int GlibcHeapModel::columnCount(const QModelIndex &) const
{
return ColumnCount;
}
int GlibcHeapModel::rowCount(const QModelIndex &) const
{
return this->values.size();
}
QVariant GlibcHeapModel::data(const QModelIndex &index, int role) const
{
if (!index.isValid() || index.row() >= values.count())
return QVariant();
const auto &item = values.at(index.row());
switch (role) {
case Qt::DisplayRole:
switch (index.column()) {
case OffsetColumn:
return RAddressString(item.offset);
case SizeColumn:
return RHexString(item.size);
case StatusColumn:
return item.status;
default:
return QVariant();
}
default:
return QVariant();
}
}
QVariant GlibcHeapModel::headerData(int section, Qt::Orientation orientation, int role) const
{
Q_UNUSED(orientation);
switch (role) {
case Qt::DisplayRole:
switch (section) {
case OffsetColumn:
return tr("Offset");
case SizeColumn:
return tr("Size");
case StatusColumn:
return tr("Status");
default:
return QVariant();
}
default:
return QVariant();
}
}
void GlibcHeapWidget::onDoubleClicked(const QModelIndex &index)
{
if (!index.isValid()) {
return;
}
int column = index.column();
if (column == GlibcHeapModel::OffsetColumn) {
QString item = index.data().toString();
Core()->seek(item);
main->showMemoryWidget(MemoryWidgetType::Hexdump);
}
}
void GlibcHeapWidget::onCurrentChanged(const QModelIndex &current, const QModelIndex &prev)
{
Q_UNUSED(current)
Q_UNUSED(prev)
auto currentIndex = viewHeap->selectionModel()->currentIndex();
QString offsetString = currentIndex.sibling(currentIndex.row(), GlibcHeapModel::OffsetColumn)
.data()
.toString();
addressableItemContextMenu.setTarget(Core()->math(offsetString));
}
void GlibcHeapWidget::viewChunkInfo()
{
auto currentIndex = viewHeap->selectionModel()->currentIndex();
QString offsetString = currentIndex.sibling(currentIndex.row(), GlibcHeapModel::OffsetColumn)
.data()
.toString();
QString status = currentIndex.sibling(currentIndex.row(), GlibcHeapModel::StatusColumn)
.data()
.toString();
GlibcHeapInfoDialog heapInfoDialog(Core()->math(offsetString), status, this);
heapInfoDialog.exec();
}

View File

@ -0,0 +1,61 @@
#ifndef GLIBCHEAPWIDGET_H
#define GLIBCHEAPWIDGET_H
#include <QDockWidget>
#include "CutterDockWidget.h"
#include "core/Cutter.h"
#include <QTableView>
#include <QComboBox>
#include <AddressableItemContextMenu.h>
namespace Ui {
class GlibcHeapWidget;
}
class GlibcHeapModel : public QAbstractTableModel
{
Q_OBJECT
public:
explicit GlibcHeapModel(QObject *parent = nullptr);
enum Column { OffsetColumn = 0, SizeColumn, StatusColumn, ColumnCount };
void reload();
int rowCount(const QModelIndex &parent) const override;
int columnCount(const QModelIndex &parent) const override;
QVariant data(const QModelIndex &index, int role) const override;
QVariant headerData(int section, Qt::Orientation orientation, int role) const override;
RVA arena_addr = 0;
private:
QVector<Chunk> values;
};
class GlibcHeapWidget : public QWidget
{
Q_OBJECT
public:
explicit GlibcHeapWidget(MainWindow *main, QWidget *parent);
~GlibcHeapWidget();
private slots:
void updateContents();
void onDoubleClicked(const QModelIndex &index);
void onArenaSelected(int index);
void customMenuRequested(QPoint pos);
void onCurrentChanged(const QModelIndex &current, const QModelIndex &previous);
void viewChunkInfo();
private:
void updateArenas();
void updateChunks();
Ui::GlibcHeapWidget *ui;
QTableView *viewHeap = new QTableView(this);
QComboBox *arenaSelectorView = new QComboBox(this);
GlibcHeapModel *modelHeap = new GlibcHeapModel(this);
QVector<Arena> arenas;
QAction *chunkInfoAction;
AddressableItemContextMenu addressableItemContextMenu;
RefreshDeferrer *refreshDeferrer {};
MainWindow *main;
};
#endif // GLIBCHEAPWIDGET_H

View File

@ -0,0 +1,20 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>GlibcHeapWidget</class>
<widget class="QWidget" name="GlibcHeapWidget">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>400</width>
<height>300</height>
</rect>
</property>
<property name="windowTitle">
<string>Form</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout"/>
</widget>
<resources/>
<connections/>
</ui>

View File

@ -0,0 +1,41 @@
#include "HeapDockWidget.h"
#include "ui_HeapDockWidget.h"
#include "widgets/GlibcHeapWidget.h"
HeapDockWidget::HeapDockWidget(MainWindow *main)
: CutterDockWidget(main), ui(new Ui::HeapDockWidget), main(main)
{
ui->setupUi(this);
ui->allocatorSelector->addItem("Glibc Heap");
ui->verticalLayout->setMargin(0);
connect<void (QComboBox::*)(int)>(ui->allocatorSelector, &QComboBox::currentIndexChanged, this,
&HeapDockWidget::onAllocatorSelected);
// select Glibc heap by default
onAllocatorSelected(0);
}
HeapDockWidget::~HeapDockWidget()
{
delete ui;
}
void HeapDockWidget::onAllocatorSelected(int index)
{
if (index >= AllocatorCount)
return;
// remove the current heap widget from layout
if (currentHeapWidget) {
ui->verticalLayout->removeWidget(currentHeapWidget);
delete currentHeapWidget;
}
// change widget depending upon selected allocator
if (index == Glibc) {
currentHeapWidget = new GlibcHeapWidget(main, this);
}
ui->verticalLayout->addWidget(currentHeapWidget);
}

View File

@ -0,0 +1,28 @@
#ifndef HEAPDOCKWIDGET_H
#define HEAPDOCKWIDGET_H
#include <QDockWidget>
#include "CutterDockWidget.h"
namespace Ui {
class HeapDockWidget;
}
class HeapDockWidget : public CutterDockWidget
{
Q_OBJECT
public:
explicit HeapDockWidget(MainWindow *main);
~HeapDockWidget();
private slots:
void onAllocatorSelected(int index);
private:
enum Allocator { Glibc = 0, AllocatorCount };
Ui::HeapDockWidget *ui;
MainWindow *main;
QWidget* currentHeapWidget = nullptr;
};
#endif // HEAPDOCKWIDGET_H

View File

@ -0,0 +1,26 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>HeapDockWidget</class>
<widget class="QDockWidget" name="HeapDockWidget">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>400</width>
<height>300</height>
</rect>
</property>
<property name="windowTitle">
<string>Heap</string>
</property>
<widget class="QWidget" name="dockWidgetContents">
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QComboBox" name="allocatorSelector"/>
</item>
</layout>
</widget>
</widget>
<resources/>
<connections/>
</ui>