mirror of
https://github.com/rizinorg/cutter.git
synced 2025-01-18 18:38:51 +00:00
Show a tooltip with Asm\Hex preview on search hits (#1480)
* implement search preview tooltip
This commit is contained in:
parent
f1fa05e647
commit
d0458597d1
@ -2571,6 +2571,42 @@ QList<DisassemblyLine> CutterCore::disassembleLines(RVA offset, int lines)
|
||||
return r;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief return hexdump of <size> from an <offset> by a given formats
|
||||
* @param address - the address from which to print the hexdump
|
||||
* @param size - number of bytes to print
|
||||
* @param format - the type of hexdump (qwords, words. decimal, etc)
|
||||
*/
|
||||
QString CutterCore::hexdump(RVA address, int size, HexdumpFormats format)
|
||||
{
|
||||
QString command = "px";
|
||||
switch (format) {
|
||||
case HexdumpFormats::Normal:
|
||||
break;
|
||||
case HexdumpFormats::Half:
|
||||
command += "h";
|
||||
break;
|
||||
case HexdumpFormats::Word:
|
||||
command += "w";
|
||||
break;
|
||||
case HexdumpFormats::Quad:
|
||||
command += "q";
|
||||
break;
|
||||
case HexdumpFormats::Signed:
|
||||
command += "d";
|
||||
break;
|
||||
case HexdumpFormats::Octal:
|
||||
command += "o";
|
||||
break;
|
||||
}
|
||||
|
||||
return cmd(QString("%1 %2 @ %3")
|
||||
.arg(command)
|
||||
.arg(size)
|
||||
.arg(address));
|
||||
}
|
||||
|
||||
QByteArray CutterCore::hexStringToBytes(const QString &hex)
|
||||
{
|
||||
QByteArray hexChars = hex.toUtf8();
|
||||
@ -2672,3 +2708,62 @@ BasicBlockHighlighter* CutterCore::getBBHighlighter()
|
||||
{
|
||||
return bbHighlighter;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief get a compact disassembly preview for tooltips
|
||||
* @param address - the address from which to print the disassembly
|
||||
* @param num_of_lines - number of instructions to print
|
||||
*/
|
||||
QStringList CutterCore::getDisassemblyPreview(RVA address, int num_of_lines)
|
||||
{
|
||||
QList<DisassemblyLine> disassemblyLines;
|
||||
{
|
||||
// temporarily simplify the disasm output to get it colorful and simple to read
|
||||
TempConfig tempConfig;
|
||||
tempConfig
|
||||
.set("scr.color", COLOR_MODE_16M)
|
||||
.set("asm.lines", false)
|
||||
.set("asm.var", false)
|
||||
.set("asm.comments", false)
|
||||
.set("asm.bytes", false)
|
||||
.set("asm.lines.fcn", false)
|
||||
.set("asm.lines.out", false)
|
||||
.set("asm.lines.bb", false)
|
||||
.set("asm.bb.line", false);
|
||||
|
||||
disassemblyLines = disassembleLines(address, num_of_lines + 1);
|
||||
}
|
||||
QStringList disasmPreview;
|
||||
for (const DisassemblyLine &line : disassemblyLines) {
|
||||
disasmPreview << line.text;
|
||||
if (disasmPreview.length() >= num_of_lines) {
|
||||
disasmPreview << "...";
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!disasmPreview.isEmpty()) {
|
||||
return disasmPreview;
|
||||
} else {
|
||||
return QStringList();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief get a compact hexdump preview for tooltips
|
||||
* @param address - the address from which to print the hexdump
|
||||
* @param size - number of bytes to print
|
||||
*/
|
||||
QString CutterCore::getHexdumpPreview(RVA address, int size)
|
||||
{
|
||||
// temporarily simplify the disasm output to get it colorful and simple to read
|
||||
TempConfig tempConfig;
|
||||
tempConfig
|
||||
.set("scr.color", COLOR_MODE_16M)
|
||||
.set("asm.offset", true)
|
||||
.set("hex.header", false)
|
||||
.set("hex.cols", 16);
|
||||
return ansiEscapeToHtml(hexdump(address, size, HexdumpFormats::Normal)).replace(QLatin1Char('\n'), "<br>");
|
||||
}
|
||||
|
||||
|
||||
|
@ -78,6 +78,7 @@ public:
|
||||
QString cmdFunctionAt(QString addr);
|
||||
QString cmdFunctionAt(RVA addr);
|
||||
QString createFunctionAt(RVA addr, QString name);
|
||||
QStringList getDisassemblyPreview(RVA address, int num_of_lines);
|
||||
|
||||
/* Flags */
|
||||
void delFlag(RVA addr);
|
||||
@ -184,7 +185,7 @@ public:
|
||||
QString getConfig(const QString &k) { return getConfig(k.toUtf8().constData()); }
|
||||
QList<QString> getColorThemes();
|
||||
|
||||
/* Assembly related methods */
|
||||
/* Assembly\Hexdump related methods */
|
||||
QByteArray assemble(const QString &code);
|
||||
QString disassemble(const QByteArray &data);
|
||||
QString disassembleSingleInstruction(RVA addr);
|
||||
@ -192,6 +193,9 @@ public:
|
||||
|
||||
static QByteArray hexStringToBytes(const QString &hex);
|
||||
static QString bytesToHexString(const QByteArray &bytes);
|
||||
enum class HexdumpFormats { Normal, Half, Word, Quad, Signed, Octal };
|
||||
QString hexdump(RVA offset, int size, HexdumpFormats format);
|
||||
QString getHexdumpPreview(RVA offset, int size);
|
||||
|
||||
void setCPU(QString arch, QString cpu, int bits);
|
||||
void setEndianness(bool big);
|
||||
|
@ -198,37 +198,9 @@ QVariant FunctionModel::data(const QModelIndex &index, int role) const
|
||||
return static_cast<int>(Qt::AlignLeft | Qt::AlignVCenter);
|
||||
|
||||
case Qt::ToolTipRole: {
|
||||
QList<DisassemblyLine> disassemblyLines;
|
||||
{
|
||||
// temporarily simplify the disasm output to get it colorful and simple to read
|
||||
TempConfig tempConfig;
|
||||
tempConfig
|
||||
.set("scr.color", COLOR_MODE_16M)
|
||||
.set("asm.lines", false)
|
||||
.set("asm.var", false)
|
||||
.set("asm.comments", false)
|
||||
.set("asm.bytes", false)
|
||||
.set("asm.lines.fcn", false)
|
||||
.set("asm.lines.out", false)
|
||||
.set("asm.lines.bb", false)
|
||||
.set("asm.bb.line", false);
|
||||
|
||||
disassemblyLines = Core()->disassembleLines(function.offset, kMaxTooltipDisasmPreviewLines + 1);
|
||||
}
|
||||
QStringList disasmPreview;
|
||||
for (const DisassemblyLine &line : disassemblyLines) {
|
||||
if (!function.contains(line.offset)) {
|
||||
break;
|
||||
}
|
||||
disasmPreview << line.text;
|
||||
if (disasmPreview.length() >= kMaxTooltipDisasmPreviewLines) {
|
||||
disasmPreview << "...";
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
QStringList disasmPreview = Core()->getDisassemblyPreview(function.offset, kMaxTooltipDisasmPreviewLines);
|
||||
const QStringList &summary = Core()->cmdList(QString("pdsf @ %1").arg(function.offset));
|
||||
|
||||
const QFont &fnt = Config()->getFont();
|
||||
QFontMetrics fm{ fnt };
|
||||
|
||||
|
@ -8,6 +8,14 @@
|
||||
#include <QComboBox>
|
||||
#include <QShortcut>
|
||||
|
||||
namespace {
|
||||
|
||||
static const int kMaxTooltipWidth = 500;
|
||||
static const int kMaxTooltipDisasmPreviewLines = 10;
|
||||
static const int kMaxTooltipHexdumpBytes = 64;
|
||||
|
||||
}
|
||||
|
||||
static const QMap<QString, QString> kSearchBoundariesValues {
|
||||
{"io.maps", "All maps"},
|
||||
{"io.map", "Current map"},
|
||||
@ -58,6 +66,31 @@ QVariant SearchModel::data(const QModelIndex &index, int role) const
|
||||
default:
|
||||
return QVariant();
|
||||
}
|
||||
case Qt::ToolTipRole: {
|
||||
|
||||
QString previewContent = QString();
|
||||
// if result is CODE, show disassembly
|
||||
if (!exp.code.isEmpty()) {
|
||||
previewContent = Core()->getDisassemblyPreview(exp.offset, kMaxTooltipDisasmPreviewLines)
|
||||
.join("<br>");
|
||||
// if result is DATA or Disassembly is N/A
|
||||
} else if (!exp.data.isEmpty() || previewContent.isEmpty()) {
|
||||
previewContent = Core()->getHexdumpPreview(exp.offset, kMaxTooltipHexdumpBytes);
|
||||
}
|
||||
|
||||
const QFont &fnt = Config()->getFont();
|
||||
QFontMetrics fm{ fnt };
|
||||
|
||||
QString toolTipContent = QString("<html><div style=\"font-family: %1; font-size: %2pt; white-space: nowrap;\">")
|
||||
.arg(fnt.family())
|
||||
.arg(qMax(6, fnt.pointSize() - 1)); // slightly decrease font size, to keep more text in the same box
|
||||
|
||||
toolTipContent += tr("<div style=\"margin-bottom: 10px;\"><strong>Preview</strong>:<br>%1</div>")
|
||||
.arg(previewContent);
|
||||
|
||||
toolTipContent += "</div></html>";
|
||||
return toolTipContent;
|
||||
}
|
||||
case SearchDescriptionRole:
|
||||
return QVariant::fromValue(exp);
|
||||
default:
|
||||
@ -130,6 +163,7 @@ SearchWidget::SearchWidget(MainWindow *main, QAction *action) :
|
||||
ui(new Ui::SearchWidget)
|
||||
{
|
||||
ui->setupUi(this);
|
||||
setStyleSheet(QString("QToolTip { max-width: %1px; opacity: 230; }").arg(kMaxTooltipWidth));
|
||||
|
||||
ui->searchInCombo->blockSignals(true);
|
||||
QMap<QString, QString>::const_iterator mapIter;
|
||||
|
Loading…
Reference in New Issue
Block a user