mirror of
https://github.com/rizinorg/cutter.git
synced 2024-12-18 10:56:11 +00:00
Fix graph export commands to use c api
This commit is contained in:
parent
20801f7fe6
commit
7a96fad546
@ -4515,3 +4515,68 @@ QStringList CutterCore::getConfigVariableSpaces(const QString &key)
|
||||
rz_list_free(list);
|
||||
return stringList;
|
||||
}
|
||||
|
||||
char *CutterCore::getTextualGraphAt(RzCoreGraphType type, RzCoreGraphFormat format, RVA address)
|
||||
{
|
||||
CORE_LOCK();
|
||||
char *string = nullptr;
|
||||
RzGraph *graph = rz_core_graph(core, type, address);
|
||||
if (!graph) {
|
||||
if (address == RVA_INVALID) {
|
||||
qWarning() << "Cannot get global graph";
|
||||
} else {
|
||||
qWarning() << "Cannot get graph at " << RzAddressString(address);
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
core->graph->is_callgraph = type == RZ_CORE_GRAPH_TYPE_FUNCALL;
|
||||
|
||||
switch (format) {
|
||||
case RZ_CORE_GRAPH_FORMAT_CMD: {
|
||||
string = rz_graph_drawable_to_cmd(graph);
|
||||
break;
|
||||
}
|
||||
case RZ_CORE_GRAPH_FORMAT_DOT: {
|
||||
string = rz_core_graph_to_dot_str(core, graph);
|
||||
break;
|
||||
}
|
||||
case RZ_CORE_GRAPH_FORMAT_JSON:
|
||||
/* fall-thru */
|
||||
case RZ_CORE_GRAPH_FORMAT_JSON_DISASM: {
|
||||
string = rz_graph_drawable_to_json_str(graph, true);
|
||||
break;
|
||||
}
|
||||
case RZ_CORE_GRAPH_FORMAT_GML: {
|
||||
string = rz_graph_drawable_to_gml(graph);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
rz_graph_free(graph);
|
||||
|
||||
if (!string) {
|
||||
qWarning() << "Failed to generate graph";
|
||||
}
|
||||
|
||||
return string;
|
||||
}
|
||||
|
||||
void CutterCore::writeGraphvizGraphToFile(QString path, QString format, RzCoreGraphType type,
|
||||
RVA address)
|
||||
{
|
||||
TempConfig tempConfig;
|
||||
tempConfig.set("scr.color", false);
|
||||
tempConfig.set("graph.gv.format", format);
|
||||
|
||||
CORE_LOCK();
|
||||
auto filepath = path.toUtf8();
|
||||
|
||||
if (!rz_core_graph_write(core, address, type, filepath)) {
|
||||
if (address == RVA_INVALID) {
|
||||
qWarning() << "Cannot get global graph";
|
||||
} else {
|
||||
qWarning() << "Cannot get graph at " << RzAddressString(address);
|
||||
}
|
||||
}
|
||||
}
|
@ -720,6 +720,25 @@ public:
|
||||
*/
|
||||
bool isWriteModeEnabled();
|
||||
|
||||
/**
|
||||
* @brief Returns the textual version of global or specific graph.
|
||||
* @param type Graph type, example RZ_CORE_GRAPH_TYPE_FUNCALL or RZ_CORE_GRAPH_TYPE_IMPORT
|
||||
* @param format Graph format, example RZ_CORE_GRAPH_FORMAT_DOT or RZ_CORE_GRAPH_FORMAT_GML
|
||||
* @param address The object address (if global set it to RVA_INVALID)
|
||||
* @return The textual graph string.
|
||||
*/
|
||||
char *getTextualGraphAt(RzCoreGraphType type, RzCoreGraphFormat format, RVA address);
|
||||
|
||||
/**
|
||||
* @brief Writes a graphviz graph to a file.
|
||||
* @param path The file output path
|
||||
* @param format The output format (see graph.gv.format)
|
||||
* @param type The graph type, example RZ_CORE_GRAPH_TYPE_FUNCALL or
|
||||
* RZ_CORE_GRAPH_TYPE_IMPORT
|
||||
* @param address The object address (if global set it to RVA_INVALID)
|
||||
*/
|
||||
void writeGraphvizGraphToFile(QString path, QString format, RzCoreGraphType type, RVA address);
|
||||
|
||||
signals:
|
||||
void refreshAll();
|
||||
|
||||
|
@ -7,7 +7,9 @@
|
||||
#include <QJsonObject>
|
||||
|
||||
CallGraphWidget::CallGraphWidget(MainWindow *main, bool global)
|
||||
: MemoryDockWidget(MemoryWidgetType::CallGraph, main), graphView(new CallGraphView(this, main, global)), global(global)
|
||||
: MemoryDockWidget(MemoryWidgetType::CallGraph, main),
|
||||
graphView(new CallGraphView(this, main, global)),
|
||||
global(global)
|
||||
{
|
||||
setObjectName(main ? main->getUniqueObjectName(getWidgetType()) : getWidgetType());
|
||||
this->setWindowTitle(getWindowTitle());
|
||||
@ -53,7 +55,7 @@ void CallGraphView::showExportDialog()
|
||||
} else {
|
||||
defaultName = QString("callgraph_%1").arg(RzAddressString(address));
|
||||
}
|
||||
showExportGraphDialog(defaultName, global ? "agC" : "agc", address);
|
||||
showExportGraphDialog(defaultName, RZ_CORE_GRAPH_TYPE_FUNCALL, global ? RVA_INVALID : address);
|
||||
}
|
||||
|
||||
void CallGraphView::showAddress(RVA address)
|
||||
@ -80,7 +82,6 @@ static inline bool isBetween(ut64 a, ut64 x, ut64 b)
|
||||
return (a == UT64_MAX || a <= x) && (b == UT64_MAX || x <= b);
|
||||
}
|
||||
|
||||
|
||||
void CallGraphView::loadCurrentGraph()
|
||||
{
|
||||
blockContent.clear();
|
||||
|
@ -152,7 +152,7 @@ void CutterGraphView::zoomReset()
|
||||
|
||||
void CutterGraphView::showExportDialog()
|
||||
{
|
||||
showExportGraphDialog("graph", "", RVA_INVALID);
|
||||
showExportGraphDialog("global_funcall", RZ_CORE_GRAPH_TYPE_FUNCALL, RVA_INVALID);
|
||||
}
|
||||
|
||||
void CutterGraphView::updateColors()
|
||||
@ -318,12 +318,12 @@ void CutterGraphView::mouseMoveEvent(QMouseEvent *event)
|
||||
emit graphMoved();
|
||||
}
|
||||
|
||||
void CutterGraphView::exportGraph(QString filePath, GraphExportType type, QString graphCommand,
|
||||
RVA address)
|
||||
void CutterGraphView::exportGraph(QString filePath, GraphExportType exportType,
|
||||
RzCoreGraphType graphType, RVA address)
|
||||
{
|
||||
bool graphTransparent = Config()->getBitmapTransparentState();
|
||||
double graphScaleFactor = Config()->getBitmapExportScaleFactor();
|
||||
switch (type) {
|
||||
switch (exportType) {
|
||||
case GraphExportType::Png:
|
||||
this->saveAsBitmap(filePath, "png", graphScaleFactor, graphTransparent);
|
||||
break;
|
||||
@ -335,56 +335,55 @@ void CutterGraphView::exportGraph(QString filePath, GraphExportType type, QStrin
|
||||
break;
|
||||
|
||||
case GraphExportType::GVDot:
|
||||
exportRzTextGraph(filePath, graphCommand + "d", address);
|
||||
exportRzTextGraph(filePath, graphType, RZ_CORE_GRAPH_FORMAT_DOT, address);
|
||||
break;
|
||||
case GraphExportType::RzJson:
|
||||
exportRzTextGraph(filePath, graphCommand + "j", address);
|
||||
exportRzTextGraph(filePath, graphType, RZ_CORE_GRAPH_FORMAT_JSON, address);
|
||||
break;
|
||||
case GraphExportType::RzGml:
|
||||
exportRzTextGraph(filePath, graphCommand + "g", address);
|
||||
break;
|
||||
case GraphExportType::RzSDBKeyValue:
|
||||
exportRzTextGraph(filePath, graphCommand + "k", address);
|
||||
exportRzTextGraph(filePath, graphType, RZ_CORE_GRAPH_FORMAT_GML, address);
|
||||
break;
|
||||
|
||||
case GraphExportType::GVJson:
|
||||
exportRizinGraphvizGraph(filePath, "json", graphCommand, address);
|
||||
Core()->writeGraphvizGraphToFile(filePath, "json", graphType, address);
|
||||
break;
|
||||
case GraphExportType::GVGif:
|
||||
exportRizinGraphvizGraph(filePath, "gif", graphCommand, address);
|
||||
Core()->writeGraphvizGraphToFile(filePath, "gif", graphType, address);
|
||||
break;
|
||||
case GraphExportType::GVPng:
|
||||
exportRizinGraphvizGraph(filePath, "png", graphCommand, address);
|
||||
Core()->writeGraphvizGraphToFile(filePath, "png", graphType, address);
|
||||
break;
|
||||
case GraphExportType::GVJpeg:
|
||||
exportRizinGraphvizGraph(filePath, "jpg", graphCommand, address);
|
||||
Core()->writeGraphvizGraphToFile(filePath, "jpg", graphType, address);
|
||||
break;
|
||||
case GraphExportType::GVPostScript:
|
||||
exportRizinGraphvizGraph(filePath, "ps", graphCommand, address);
|
||||
Core()->writeGraphvizGraphToFile(filePath, "ps", graphType, address);
|
||||
break;
|
||||
case GraphExportType::GVSvg:
|
||||
exportRizinGraphvizGraph(filePath, "svg", graphCommand, address);
|
||||
Core()->writeGraphvizGraphToFile(filePath, "svg", graphType, address);
|
||||
break;
|
||||
case GraphExportType::GVPdf:
|
||||
Core()->writeGraphvizGraphToFile(filePath, "pdf", graphType, address);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void CutterGraphView::exportRizinGraphvizGraph(QString filePath, QString type, QString graphCommand,
|
||||
RVA address)
|
||||
void CutterGraphView::exportRzTextGraph(QString filePath, RzCoreGraphType type,
|
||||
RzCoreGraphFormat format, RVA address)
|
||||
{
|
||||
TempConfig tempConfig;
|
||||
tempConfig.set("graph.gv.format", type);
|
||||
qWarning() << Core()->cmdRawAt(QString("%0w \"%1\"").arg(graphCommand).arg(filePath), address);
|
||||
}
|
||||
|
||||
void CutterGraphView::exportRzTextGraph(QString filePath, QString graphCommand, RVA address)
|
||||
{
|
||||
QFile file(filePath);
|
||||
if (!file.open(QIODevice::WriteOnly | QIODevice::Text)) {
|
||||
qWarning() << "Can't open file";
|
||||
char *string = Core()->getTextualGraphAt(type, format, address);
|
||||
if (!string) {
|
||||
return;
|
||||
}
|
||||
QTextStream fileOut(&file);
|
||||
fileOut << Core()->cmdRawAt(QString("%0").arg(graphCommand), address);
|
||||
|
||||
QFile file(filePath);
|
||||
if (file.open(QIODevice::WriteOnly | QIODevice::Text)) {
|
||||
QTextStream fileOut(&file);
|
||||
fileOut << string;
|
||||
} else {
|
||||
qWarning() << "Can't open or create file: " << filePath;
|
||||
}
|
||||
free(string);
|
||||
}
|
||||
|
||||
bool CutterGraphView::graphIsBitamp(CutterGraphView::GraphExportType type)
|
||||
@ -403,40 +402,39 @@ bool CutterGraphView::graphIsBitamp(CutterGraphView::GraphExportType type)
|
||||
|
||||
Q_DECLARE_METATYPE(CutterGraphView::GraphExportType);
|
||||
|
||||
void CutterGraphView::showExportGraphDialog(QString defaultName, QString graphCommand, RVA address)
|
||||
void CutterGraphView::showExportGraphDialog(QString defaultName, RzCoreGraphType type, RVA address)
|
||||
{
|
||||
qWarning() << defaultName << " - " << type << " addr " << RzAddressString(address);
|
||||
QVector<MultitypeFileSaveDialog::TypeDescription> types = {
|
||||
{ tr("PNG (*.png)"), "png", QVariant::fromValue(GraphExportType::Png) },
|
||||
{ tr("JPEG (*.jpg)"), "jpg", QVariant::fromValue(GraphExportType::Jpeg) },
|
||||
{ tr("SVG (*.svg)"), "svg", QVariant::fromValue(GraphExportType::Svg) }
|
||||
};
|
||||
|
||||
bool rzGraphExports = !graphCommand.isEmpty();
|
||||
if (rzGraphExports) {
|
||||
types.append({
|
||||
{ tr("Graphviz dot (*.dot)"), "dot", QVariant::fromValue(GraphExportType::GVDot) },
|
||||
{ tr("Graph Modelling Language (*.gml)"), "gml",
|
||||
QVariant::fromValue(GraphExportType::RzGml) },
|
||||
{ tr("RZ JSON (*.json)"), "json", QVariant::fromValue(GraphExportType::RzJson) },
|
||||
{ tr("SDB key-value (*.txt)"), "txt",
|
||||
QVariant::fromValue(GraphExportType::RzSDBKeyValue) },
|
||||
});
|
||||
bool hasGraphviz = !QStandardPaths::findExecutable("dot").isEmpty()
|
||||
|| !QStandardPaths::findExecutable("xdot").isEmpty();
|
||||
if (hasGraphviz) {
|
||||
types.append({ { tr("Graphviz json (*.json)"), "json",
|
||||
QVariant::fromValue(GraphExportType::GVJson) },
|
||||
{ tr("Graphviz gif (*.gif)"), "gif",
|
||||
QVariant::fromValue(GraphExportType::GVGif) },
|
||||
{ tr("Graphviz png (*.png)"), "png",
|
||||
QVariant::fromValue(GraphExportType::GVPng) },
|
||||
{ tr("Graphviz jpg (*.jpg)"), "jpg",
|
||||
QVariant::fromValue(GraphExportType::GVJpeg) },
|
||||
{ tr("Graphviz PostScript (*.ps)"), "ps",
|
||||
QVariant::fromValue(GraphExportType::GVPostScript) },
|
||||
{ tr("Graphviz svg (*.svg)"), "svg",
|
||||
QVariant::fromValue(GraphExportType::GVSvg) } });
|
||||
}
|
||||
types.append({
|
||||
{ tr("Graphviz dot (*.dot)"), "dot", QVariant::fromValue(GraphExportType::GVDot) },
|
||||
{ tr("Graph Modelling Language (*.gml)"), "gml",
|
||||
QVariant::fromValue(GraphExportType::RzGml) },
|
||||
{ tr("RZ JSON (*.json)"), "json", QVariant::fromValue(GraphExportType::RzJson) },
|
||||
});
|
||||
|
||||
bool hasGraphviz = !QStandardPaths::findExecutable("dot").isEmpty()
|
||||
|| !QStandardPaths::findExecutable("xdot").isEmpty();
|
||||
if (hasGraphviz) {
|
||||
types.append({ { tr("Graphviz json (*.json)"), "json",
|
||||
QVariant::fromValue(GraphExportType::GVJson) },
|
||||
{ tr("Graphviz gif (*.gif)"), "gif",
|
||||
QVariant::fromValue(GraphExportType::GVGif) },
|
||||
{ tr("Graphviz png (*.png)"), "png",
|
||||
QVariant::fromValue(GraphExportType::GVPng) },
|
||||
{ tr("Graphviz jpg (*.jpg)"), "jpg",
|
||||
QVariant::fromValue(GraphExportType::GVJpeg) },
|
||||
{ tr("Graphviz PostScript (*.ps)"), "ps",
|
||||
QVariant::fromValue(GraphExportType::GVPostScript) },
|
||||
{ tr("Graphviz svg (*.svg)"), "svg",
|
||||
QVariant::fromValue(GraphExportType::GVSvg) },
|
||||
{ tr("Graphviz pdf (*.pdf)"), "pdf",
|
||||
QVariant::fromValue(GraphExportType::GVPdf) } });
|
||||
}
|
||||
|
||||
MultitypeFileSaveDialog dialog(this, tr("Export Graph"));
|
||||
@ -470,5 +468,5 @@ void CutterGraphView::showExportGraphDialog(QString defaultName, QString graphCo
|
||||
}
|
||||
|
||||
QString filePath = dialog.selectedFiles().first();
|
||||
exportGraph(filePath, exportType, graphCommand, address);
|
||||
exportGraph(filePath, exportType, type, address);
|
||||
}
|
||||
|
@ -32,48 +32,38 @@ public:
|
||||
GVJpeg,
|
||||
GVPostScript,
|
||||
GVSvg,
|
||||
GVPdf,
|
||||
RzGml,
|
||||
RzSDBKeyValue,
|
||||
RzJson
|
||||
};
|
||||
/**
|
||||
* @brief Export graph to a file in the specified format
|
||||
* @param filePath
|
||||
* @param type export type, GV* and Rz* types require \p graphCommand
|
||||
* @param graphCommand rizin graph printing command without type, not required for direct image
|
||||
* export
|
||||
* @param address object address for commands like agf
|
||||
* @param filePath - output file path
|
||||
* @param exportType - export type, GV* and Rz* types require \p graphCommand
|
||||
* @param graphType - graph type, example RZ_CORE_GRAPH_TYPE_FUNCALL or
|
||||
* RZ_CORE_GRAPH_TYPE_IMPORT
|
||||
* @param address - object address (if global set it to RVA_INVALID)
|
||||
*/
|
||||
void exportGraph(QString filePath, GraphExportType type, QString graphCommand = "",
|
||||
void exportGraph(QString filePath, GraphExportType exportType, RzCoreGraphType graphType,
|
||||
RVA address = RVA_INVALID);
|
||||
/**
|
||||
* @brief Export image using rizin ag*w command and graphviz.
|
||||
* Requires graphviz dot executable in the path.
|
||||
*
|
||||
* @param filePath output file path
|
||||
* @param type image format as expected by "e graph.gv.format"
|
||||
* @param graphCommand rizin command without type, for example agf
|
||||
* @param address object address if required by command
|
||||
*/
|
||||
void exportRizinGraphvizGraph(QString filePath, QString type, QString graphCommand,
|
||||
RVA address);
|
||||
|
||||
/**
|
||||
* @brief Export graph in one of the text formats supported by rizin json, gml, SDB key-value
|
||||
* @param filePath output file path
|
||||
* @param graphCommand graph command including the format, example "agfd" or "agfg"
|
||||
* @param address object address if required by command
|
||||
* @param filePath - output file path
|
||||
* @param type - graph type, example RZ_CORE_GRAPH_TYPE_FUNCALL or RZ_CORE_GRAPH_TYPE_IMPORT
|
||||
* @param format - graph format, example RZ_CORE_GRAPH_FORMAT_DOT or RZ_CORE_GRAPH_FORMAT_GML
|
||||
* @param address - object address (if global set it to RVA_INVALID)
|
||||
*/
|
||||
void exportRzTextGraph(QString filePath, QString graphCommand, RVA address);
|
||||
void exportRzTextGraph(QString filePath, RzCoreGraphType type, RzCoreGraphFormat format,
|
||||
RVA address);
|
||||
static bool graphIsBitamp(GraphExportType type);
|
||||
/**
|
||||
* @brief Show graph export dialog.
|
||||
* @param defaultName - default file name in the export dialog
|
||||
* @param graphCommand - rizin graph commmand with graph type and without export type, for
|
||||
* example afC. Leave empty for non-rizin graphs. In such case only direct image export will be
|
||||
* available.
|
||||
* @param address - object address if relevant for \p graphCommand
|
||||
* @param type - graph type, example RZ_CORE_GRAPH_TYPE_FUNCALL or RZ_CORE_GRAPH_TYPE_IMPORT
|
||||
* @param address - object address (if global set it to RVA_INVALID)
|
||||
*/
|
||||
void showExportGraphDialog(QString defaultName, QString graphCommand = "",
|
||||
void showExportGraphDialog(QString defaultName, RzCoreGraphType type,
|
||||
RVA address = RVA_INVALID);
|
||||
|
||||
public slots:
|
||||
|
@ -194,6 +194,7 @@ void DisassemblerGraphView::loadCurrentGraph()
|
||||
|
||||
windowTitle = tr("Graph");
|
||||
if (fcn && RZ_STR_ISNOTEMPTY(fcn->name)) {
|
||||
currentFcnAddr = fcn->addr;
|
||||
auto fcnName = fromOwned(rz_str_escape_utf8_for_json(fcn->name, -1));
|
||||
windowTitle += QString("(%0)").arg(fcnName.get());
|
||||
} else {
|
||||
@ -891,6 +892,11 @@ void DisassemblerGraphView::contextMenuEvent(QContextMenuEvent *event)
|
||||
|
||||
void DisassemblerGraphView::showExportDialog()
|
||||
{
|
||||
if (currentFcnAddr == RVA_INVALID) {
|
||||
qWarning() << "Cannot find current function.";
|
||||
return;
|
||||
}
|
||||
|
||||
QString defaultName = "graph";
|
||||
if (auto f = Core()->functionIn(currentFcnAddr)) {
|
||||
QString functionName = f->name;
|
||||
@ -901,7 +907,7 @@ void DisassemblerGraphView::showExportDialog()
|
||||
defaultName = functionName;
|
||||
}
|
||||
}
|
||||
showExportGraphDialog(defaultName, "agf", currentFcnAddr);
|
||||
showExportGraphDialog(defaultName, RZ_CORE_GRAPH_TYPE_BLOCK_FUN, currentFcnAddr);
|
||||
}
|
||||
|
||||
void DisassemblerGraphView::blockDoubleClicked(GraphView::GraphBlock &block, QMouseEvent *event,
|
||||
|
Loading…
Reference in New Issue
Block a user