Skip to content

Commit

Permalink
add setting to disable branches in disassembler
Browse files Browse the repository at this point in the history
sometimes there are too many branches, this patch allows the user to
disable them

fixes: #516
  • Loading branch information
lievenhey committed Oct 19, 2023
1 parent ab06e32 commit b68e608
Show file tree
Hide file tree
Showing 9 changed files with 141 additions and 10 deletions.
4 changes: 4 additions & 0 deletions src/models/disassemblymodel.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,8 @@ QVariant DisassemblyModel::headerData(int section, Qt::Orientation orientation,

if (section == AddrColumn)
return tr("Address");
else if (section == BranchColumn)
return tr("Branches");
else if (section == DisassemblyColumn)
return tr("Assembly / Disassembly");

Expand Down Expand Up @@ -116,6 +118,8 @@ QVariant DisassemblyModel::data(const QModelIndex& index, int role) const
if (!data.addr)
return {};
return QString::number(data.addr, 16);
} else if (index.column() == BranchColumn) {
return data.branchVisualisation;
} else if (index.column() == DisassemblyColumn) {
const auto block = m_document->findBlockByLineNumber(index.row());
if (role == SyntaxHighlightRole)
Expand Down
1 change: 1 addition & 0 deletions src/models/disassemblymodel.h
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ class DisassemblyModel : public QAbstractTableModel
enum Columns
{
AddrColumn,
BranchColumn,
DisassemblyColumn,
COLUMN_COUNT
};
Expand Down
20 changes: 18 additions & 2 deletions src/models/disassemblyoutput.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,11 @@ QString findBinaryForSymbol(const QStringList& debugPaths, const QStringList& ex
return {};
}

bool isHexCharacter(QChar c)
{
return (c >= QLatin1Char('0') && c <= QLatin1Char('9')) || (c >= QLatin1Char('a') && c <= QLatin1Char('f'));
}

ObjectdumpOutput objdumpParse(const QByteArray& output)
{
QVector<DisassemblyOutput::DisassemblyLine> disassemblyLines;
Expand Down Expand Up @@ -199,8 +204,19 @@ ObjectdumpOutput objdumpParse(const QByteArray& output)
assembly = asmLine;
}

disassemblyLines.push_back(
{addr, assembly, extractLinkedFunction(asmLine), {currentSourceFileName, sourceCodeLine}});
// format is the following:
// /- a5 54 12 ...
// | 64 a3 ....
// \-> 65 23 ....
// so we can simply skip all characters until we meet a letter or a number
const auto branchVisualisationRange =
std::distance(assembly.cbegin(), std::find_if(assembly.cbegin(), assembly.cend(), isHexCharacter));

disassemblyLines.push_back({addr,
assembly.mid(branchVisualisationRange),
branchVisualisationRange ? assembly.left(branchVisualisationRange) : QString {},
extractLinkedFunction(asmLine),
{currentSourceFileName, sourceCodeLine}});
}
return {disassemblyLines, sourceFileName};
}
Expand Down
1 change: 1 addition & 0 deletions src/models/disassemblyoutput.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ struct DisassemblyOutput
{
quint64 addr = 0;
QString disassembly;
QString branchVisualisation;
LinkedFunction linkedFunction;
Data::FileLine fileLine;
};
Expand Down
9 changes: 8 additions & 1 deletion src/resultsdisassemblypage.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,6 @@ ResultsDisassemblyPage::ResultsDisassemblyPage(CostContextMenu* costContextMenu,
connect(settings, &Settings::sourceCodePathsChanged, this, [this](const QString&) { showDisassembly(); });

connect(ui->assemblyView, &QTreeView::entered, this, updateFromDisassembly);

connect(ui->sourceCodeView, &QTreeView::entered, this, updateFromSource);

ui->sourceCodeView->setContextMenuPolicy(Qt::CustomContextMenu);
Expand Down Expand Up @@ -253,6 +252,12 @@ ResultsDisassemblyPage::ResultsDisassemblyPage(CostContextMenu* costContextMenu,
ui->disasmSearchWidget, ui->disasmSearchEdit, ui->assemblyView, ui->disasmEndReachedWidget,
m_disassemblyModel, &m_currentDisasmSearchIndex, 0);

ui->assemblyView->setColumnHidden(DisassemblyModel::BranchColumn, !settings->showBranches());

connect(settings, &Settings::showBranchesChanged, this, [this](bool showBranches) {
ui->assemblyView->setColumnHidden(DisassemblyModel::BranchColumn, !showBranches);
});

#if KFSyntaxHighlighting_FOUND
QStringList schemes;

Expand Down Expand Up @@ -308,7 +313,9 @@ void ResultsDisassemblyPage::setupAsmViewModel()

ui->assemblyView->header()->setStretchLastSection(false);
ui->assemblyView->header()->setSectionResizeMode(DisassemblyModel::AddrColumn, QHeaderView::ResizeToContents);
ui->assemblyView->header()->setSectionResizeMode(DisassemblyModel::BranchColumn, QHeaderView::ResizeToContents);
ui->assemblyView->header()->setSectionResizeMode(DisassemblyModel::DisassemblyColumn, QHeaderView::Stretch);
ui->assemblyView->setItemDelegateForColumn(DisassemblyModel::BranchColumn, m_disassemblyDelegate);
ui->assemblyView->setItemDelegateForColumn(DisassemblyModel::DisassemblyColumn, m_disassemblyDelegate);

for (int col = DisassemblyModel::COLUMN_COUNT; col < m_disassemblyModel->columnCount(); col++) {
Expand Down
22 changes: 18 additions & 4 deletions src/settings.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -191,10 +191,6 @@ void Settings::loadFromFile()
sharedConfig->group("PathSettings").writeEntry("userPaths", this->userPaths());
sharedConfig->group("PathSettings").writeEntry("systemPaths", this->systemPaths());
});
setSourceCodePaths(sharedConfig->group("PathSettings").readEntry("sourceCodePaths", QString()));
connect(this, &Settings::sourceCodePathsChanged, this, [sharedConfig](const QString& paths) {
sharedConfig->group("PathSettings").writeEntry("sourceCodePaths", paths);
});

// fix build error in app image build
const auto colorScheme = KColorScheme(QPalette::Normal, KColorScheme::View, sharedConfig);
Expand Down Expand Up @@ -237,6 +233,16 @@ void Settings::loadFromFile()
connect(this, &Settings::lastUsedEnvironmentChanged, this, [sharedConfig](const QString& envName) {
sharedConfig->group("PerfPaths").writeEntry("lastUsed", envName);
});

setSourceCodePaths(sharedConfig->group("Disassembly").readEntry("sourceCodePaths", QString()));
connect(this, &Settings::sourceCodePathsChanged, this, [sharedConfig](const QString& paths) {
sharedConfig->group("Disassembly").writeEntry("sourceCodePaths", paths);
});

setShowBranches(sharedConfig->group("Disassembly").readEntry("showBranches", true));
connect(this, &Settings::showBranchesChanged, [sharedConfig](bool showBranches) {
sharedConfig->group("Disassembly").writeEntry("showBranches", showBranches);
});
}

void Settings::setSourceCodePaths(const QString& paths)
Expand All @@ -254,3 +260,11 @@ void Settings::setPerfPath(const QString& path)
emit perfPathChanged(m_perfPath);
}
}

void Settings::setShowBranches(bool showBranches)
{
if (m_showBranches != showBranches) {
m_showBranches = showBranches;
emit showBranchesChanged(m_showBranches);
}
}
8 changes: 8 additions & 0 deletions src/settings.h
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,11 @@ class Settings : public QObject
return m_perfPath;
}

bool showBranches() const
{
return m_showBranches;
}

void loadFromFile();

signals:
Expand All @@ -176,6 +181,7 @@ class Settings : public QObject
void lastUsedEnvironmentChanged(const QString& envName);
void sourceCodePathsChanged(const QString& paths);
void perfPathChanged(const QString& perfPath);
void showBranchesChanged(bool showBranches);

public slots:
void setPrettifySymbols(bool prettifySymbols);
Expand All @@ -199,6 +205,7 @@ public slots:
void setLastUsedEnvironment(const QString& envName);
void setSourceCodePaths(const QString& paths);
void setPerfPath(const QString& path);
void setShowBranches(bool showBranches);

private:
Settings() = default;
Expand All @@ -222,6 +229,7 @@ public slots:
QString m_objdump;
QString m_sourceCodePaths;
QString m_perfMapPath;
bool m_showBranches = true;

QString m_lastUsedEnvironment;

Expand Down
11 changes: 8 additions & 3 deletions src/settingsdialog.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -327,13 +327,18 @@ void SettingsDialog::addSourcePathPage()

disassemblyPage->setupUi(page);

auto settings = Settings::instance();

const auto colon = QLatin1Char(':');
connect(Settings::instance(), &Settings::sourceCodePathsChanged, this,
connect(settings, &Settings::sourceCodePathsChanged, this,
[this, colon](const QString& paths) { disassemblyPage->sourcePaths->setItems(paths.split(colon)); });

setupMultiPath(disassemblyPage->sourcePaths, disassemblyPage->label, buttonBox()->button(QDialogButtonBox::Ok));

connect(buttonBox(), &QDialogButtonBox::accepted, this, [this, colon] {
Settings::instance()->setSourceCodePaths(disassemblyPage->sourcePaths->items().join(colon));
disassemblyPage->showBranches->setChecked(settings->showBranches());

connect(buttonBox(), &QDialogButtonBox::accepted, this, [this, colon, settings] {
settings->setSourceCodePaths(disassemblyPage->sourcePaths->items().join(colon));
settings->setShowBranches(disassemblyPage->showBranches->isChecked());
});
}
75 changes: 75 additions & 0 deletions tests/modeltests/tst_disassemblyoutput.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
#include <QDebug>
#include <QObject>
#include <QProcess>
#include <QRegularExpression>
#include <QStandardPaths>
#include <QString>
#include <QStringList>
Expand Down Expand Up @@ -189,6 +190,80 @@ private slots:
QCOMPARE(findSourceCodeFile(QStringLiteral("./liba/lib.c"), {tempDir.path()}, QString()),
tempDir.path() + QDir::separator() + QStringLiteral("liba/lib.c"));
}

void testDetectBranches()
{
if (!supportsVisualizeJumps()) {
QSKIP("--visualize-jumps is not supported");
}

const auto lib = QFileInfo(findLib(QStringLiteral("libfib.so")));
auto [address, size] = findAddressAndSizeOfFunc(lib.absoluteFilePath(), QStringLiteral("_Z3fibi"));

const Data::Symbol symbol = {QStringLiteral("fib(int)"), address, size, QStringLiteral("libfib.so")};

const QString objdump = QStandardPaths::findExecutable(QStringLiteral("objdump"));
const auto result =
DisassemblyOutput::disassemble(objdump, {}, QStringList {lib.absolutePath()}, {}, {}, {}, symbol);
QVERIFY(result.errorMessage.isEmpty());

auto isHex = [](const QChar c) {
return (c >= QLatin1Char('0') && c < QLatin1Char('9')) || (c >= QLatin1Char('a') && c <= QLatin1Char('f'));
};

for (const auto& line : result.disassemblyLines) {
QVERIFY(!line.branchVisualisation.isEmpty());
if (!line.disassembly.isEmpty()) {
QVERIFY(isHex(line.disassembly[0]));
}
}
}

private:
std::tuple<quint64, quint64> findAddressAndSizeOfFunc(const QString& library, const QString& name)
{
QRegularExpression regex(QStringLiteral("[ ]+[0-9]+: ([0-9a-f]+)[ ]+([0-9]+)[0-9 a-zA-Z]+%1\\n").arg(name));

QProcess readelf;
readelf.setProgram(QStringLiteral("readelf"));
readelf.setArguments({QStringLiteral("-s"), library});

readelf.start();
readelf.waitForFinished();

const auto output = readelf.readAllStandardOutput();
Q_ASSERT(!output.isEmpty());

auto match = regex.match(QString::fromUtf8(output));
Q_ASSERT(match.hasMatch());

bool ok = false;
const quint64 address = match.captured(1).toInt(&ok, 16);
Q_ASSERT(ok);
const quint64 size = match.captured(2).toInt(&ok, 10);
Q_ASSERT(ok);
return {address, size};
}

bool supportsVisualizeJumps()
{
const QString objdump = QStandardPaths::findExecutable(QStringLiteral("objdump"));

if (objdump.isEmpty()) {
qWarning() << "objdump not found";
return false;
}

QProcess process;
process.setProcessChannelMode(QProcess::ForwardedErrorChannel);
process.start(objdump, {QStringLiteral("-H")});
if (!process.waitForFinished(1000)) {
qWarning() << "failed to query objdump output";
return false;
}
const auto help = process.readAllStandardOutput();
return help.contains("--visualize-jumps");
}
};

QTEST_GUILESS_MAIN(TestDisassemblyOutput)
Expand Down

0 comments on commit b68e608

Please sign in to comment.