mirror of
https://github.com/rizinorg/rizin.git
synced 2026-10-12 02:21:57 +00:00
Restore changes not included in initial absint merge
This commit is contained in:
@@ -0,0 +1,261 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="1366" height="768" viewBox="0 0 1366 768">
|
||||
<defs>
|
||||
<marker id="arrow" viewBox="0 0 10 10" refX="8" refY="5" markerWidth="8" markerHeight="8" orient="auto-start-reverse">
|
||||
<path d="M 0 0 L 10 5 L 0 10 z" fill="#222"/>
|
||||
</marker>
|
||||
<style>
|
||||
.line { stroke:#222; stroke-width:2.2; fill:none; stroke-linecap:round; stroke-linejoin:round; }
|
||||
.thin { stroke:#222; stroke-width:1.4; fill:none; stroke-linecap:round; stroke-linejoin:round; }
|
||||
.text { font-family: Arial, Helvetica, sans-serif; fill:#111; font-size:18px; }
|
||||
.small { font-size:16px; }
|
||||
.title { font-size:22px; font-weight:600; }
|
||||
.center { text-anchor:middle; dominant-baseline:middle; }
|
||||
.left { text-anchor:start; dominant-baseline:middle; }
|
||||
|
||||
.dashFill { fill:#f4d03f; stroke:#222; stroke-width:2; }
|
||||
.circleFill { fill:#5dade2; stroke:#222; stroke-width:2; }
|
||||
.triFill { fill:#58d68d; stroke:#222; stroke-width:2; }
|
||||
.tFill { fill:#ec7063; }
|
||||
.whiteTri { fill:#fff; stroke:#222; stroke-width:2.2; stroke-linejoin:round; }
|
||||
.tBox { fill:#e53935; stroke:#222; stroke-width:2.5; rx:5; ry:5; }
|
||||
|
||||
.stateStroke { stroke:#222; stroke-width:2.2; fill:none; }
|
||||
.stateText { font-family: Arial, Helvetica, sans-serif; font-size:20px; fill:#111; text-anchor:middle; dominant-baseline:middle; }
|
||||
</style>
|
||||
</defs>
|
||||
|
||||
<!-- ===================== LEFT TABLE ===================== -->
|
||||
<g transform="translate(80,65)">
|
||||
<!-- verticals -->
|
||||
<line x1="0" y1="0" x2="0" y2="460" class="line"/>
|
||||
<line x1="36" y1="0" x2="36" y2="460" class="line"/>
|
||||
<line x1="84" y1="0" x2="84" y2="460" class="line"/>
|
||||
<line x1="90" y1="0" x2="90" y2="460" class="line"/>
|
||||
<line x1="150" y1="0" x2="150" y2="460" class="line"/>
|
||||
<line x1="220" y1="0" x2="220" y2="460" class="line"/>
|
||||
<line x1="300" y1="0" x2="300" y2="460" class="line"/>
|
||||
<line x1="410" y1="0" x2="410" y2="460" class="line"/>
|
||||
|
||||
<!-- horizontals -->
|
||||
<line x1="0" y1="32" x2="410" y2="32" class="line"/>
|
||||
<line x1="0" y1="78" x2="410" y2="78" class="line"/>
|
||||
<line x1="0" y1="125" x2="410" y2="125" class="line"/>
|
||||
<line x1="0" y1="172" x2="410" y2="172" class="line"/>
|
||||
<line x1="0" y1="219" x2="410" y2="219" class="line"/>
|
||||
<line x1="0" y1="266" x2="410" y2="266" class="line"/>
|
||||
<line x1="0" y1="313" x2="410" y2="313" class="line"/>
|
||||
<line x1="0" y1="406" x2="410" y2="406" class="line"/>
|
||||
|
||||
<!-- headers -->
|
||||
<text x="18" y="16" class="text center">ls</text>
|
||||
<text x="60" y="16" class="text center">exp</text>
|
||||
<text x="365" y="16" class="text center title">Error</text>
|
||||
|
||||
<!-- row centers: 55, 101, 148, 195, 242, 289, 359, 437 -->
|
||||
|
||||
<!-- helper symbols in first two columns -->
|
||||
<!-- Row 1: 1,1 -->
|
||||
<g transform="translate(18,55)">
|
||||
<rect x="-9" y="-15" width="18" height="30" rx="5" class="dashFill"/>
|
||||
<line x1="-5" y1="0" x2="5" y2="0" class="thin"/>
|
||||
</g>
|
||||
<g transform="translate(60,55)">
|
||||
<rect x="-9" y="-15" width="18" height="30" rx="5" class="dashFill"/>
|
||||
<line x1="-5" y1="0" x2="5" y2="0" class="thin"/>
|
||||
</g>
|
||||
<text x="120" y="55" class="text center">B I</text>
|
||||
<text x="169" y="55" class="text center">→</text>
|
||||
<g transform="translate(193,55)">
|
||||
<circle r="12" class="circleFill"/>
|
||||
</g>
|
||||
<text x="340" y="55" class="text center">→</text>
|
||||
<g transform="translate(365,55)">
|
||||
<rect x="-12" y="-14" width="24" height="28" class="tBox"/>
|
||||
<text class="stateText tFill" x="0" y="1">T</text>
|
||||
</g>
|
||||
|
||||
<!-- Row 2: 1,0 -->
|
||||
<g transform="translate(18,101)">
|
||||
<rect x="-9" y="-15" width="18" height="30" rx="5" class="dashFill"/>
|
||||
<line x1="-5" y1="0" x2="5" y2="0" class="thin"/>
|
||||
</g>
|
||||
<g transform="translate(60,101)">
|
||||
<circle r="12" class="circleFill"/>
|
||||
</g>
|
||||
<text x="120" y="101" class="text center">wait</text>
|
||||
<text x="365" y="101" class="text center">-</text>
|
||||
|
||||
<!-- Row 3: 1,T -->
|
||||
<g transform="translate(18,148)">
|
||||
<rect x="-9" y="-15" width="18" height="30" rx="5" class="dashFill"/>
|
||||
<line x1="-5" y1="0" x2="5" y2="0" class="thin"/>
|
||||
</g>
|
||||
<g transform="translate(60,148)">
|
||||
<rect x="-12" y="-14" width="24" height="28" class="tBox"/>
|
||||
<text class="stateText tFill" x="0" y="1">T</text>
|
||||
</g>
|
||||
<text x="120" y="148" class="text center">wait</text>
|
||||
<text x="365" y="148" class="text center">-</text>
|
||||
|
||||
<!-- Row 4: 0,0 -->
|
||||
<g transform="translate(18,195)">
|
||||
<circle r="12" class="circleFill"/>
|
||||
</g>
|
||||
<g transform="translate(60,195)">
|
||||
<circle r="12" class="circleFill"/>
|
||||
</g>
|
||||
<text x="120" y="195" class="text center">B II</text>
|
||||
<text x="185" y="195" class="text center">B III</text>
|
||||
<text x="250" y="195" class="text center">→</text>
|
||||
<g transform="translate(272,195)">
|
||||
<circle r="12" class="circleFill"/>
|
||||
</g>
|
||||
<text x="345" y="195" class="text center">→</text>
|
||||
<g transform="translate(370,195)">
|
||||
<polygon points="0,-14 -12,10 12,10" class="triFill"/>
|
||||
</g>
|
||||
|
||||
<!-- Row 5: 0,triangle -->
|
||||
<g transform="translate(18,242)">
|
||||
<circle r="12" class="circleFill"/>
|
||||
</g>
|
||||
<g transform="translate(60,242)">
|
||||
<polygon points="0,-14 -12,10 12,10" class="triFill"/>
|
||||
</g>
|
||||
<text x="120" y="242" class="text center">wait</text>
|
||||
<text x="365" y="242" class="text center">-</text>
|
||||
|
||||
<!-- Row 6: triangle,triangle -->
|
||||
<g transform="translate(18,289)">
|
||||
<polygon points="0,-14 -12,10 12,10" class="triFill"/>
|
||||
</g>
|
||||
<g transform="translate(60,289)">
|
||||
<polygon points="0,-14 -12,10 12,10" class="triFill"/>
|
||||
</g>
|
||||
<text x="120" y="289" class="text center">clear</text>
|
||||
<text x="185" y="289" class="text center">open</text>
|
||||
<text x="260" y="289" class="text center">B IV</text>
|
||||
<text x="344" y="289" class="text center">→</text>
|
||||
<g transform="translate(373,289)">
|
||||
<rect x="-12" y="-14" width="24" height="28" class="tBox"/>
|
||||
<text class="stateText tFill" x="0" y="1">T</text>
|
||||
</g>
|
||||
|
||||
<!-- Row 7: triangle,1 -->
|
||||
<g transform="translate(18,359)">
|
||||
<polygon points="0,-14 -12,10 12,10" class="triFill"/>
|
||||
</g>
|
||||
<g transform="translate(60,359)">
|
||||
<rect x="-9" y="-15" width="18" height="30" rx="5" class="dashFill"/>
|
||||
<line x1="-5" y1="0" x2="5" y2="0" class="thin"/>
|
||||
</g>
|
||||
<text x="120" y="359" class="text center">wait</text>
|
||||
<text x="365" y="359" class="text center">-</text>
|
||||
|
||||
<!-- Row 8: triangle,0 -->
|
||||
<g transform="translate(18,437)">
|
||||
<polygon points="0,-14 -12,10 12,10" class="triFill"/>
|
||||
</g>
|
||||
<g transform="translate(60,437)">
|
||||
<circle r="12" class="circleFill"/>
|
||||
</g>
|
||||
<text x="120" y="437" class="text center">clear</text>
|
||||
<text x="185" y="437" class="text center">B IV</text>
|
||||
<text x="344" y="437" class="text center">→</text>
|
||||
<g transform="translate(373,437)">
|
||||
<rect x="-12" y="-14" width="24" height="28" class="tBox"/>
|
||||
<text class="stateText tFill" x="0" y="1">T</text>
|
||||
</g>
|
||||
|
||||
|
||||
<!-- side note -->
|
||||
<g transform="translate(-40,12)">
|
||||
<text x="455" y="416" class="text small left">emulation</text>
|
||||
<text x="455" y="438" class="text small left">error</text>
|
||||
</g>
|
||||
|
||||
</g>
|
||||
|
||||
<!-- ===================== CENTER LEGEND ===================== -->
|
||||
<g transform="translate(640,80)">
|
||||
<!-- Dash -->
|
||||
<g>
|
||||
<g transform="translate(18,55)">
|
||||
<rect x="-9" y="-15" width="18" height="30" rx="5" class="dashFill"/>
|
||||
<line x1="-5" y1="0" x2="5" y2="0" class="thin"/>
|
||||
</g>
|
||||
<path d="M48,10 L48,165 M48,10 q0,0 8,0 M48,165 q0,0 8,0" class="line"/>
|
||||
<text x="60" y="40" class="text small left" transform="rotate(90 60 40)">init</text>
|
||||
<text x="170" y="70" class="text left">B I - Get entry point</text>
|
||||
</g>
|
||||
|
||||
<!-- Circle -->
|
||||
<g transform="translate(0,190)">
|
||||
<circle cx="20" cy="100" r="16" class="circleFill"/>
|
||||
<path d="M48,0 L48,195 M48,0 q0,0 8,0 M48,195 q0,0 8,0" class="line"/>
|
||||
<text x="60" y="55" class="text small left" transform="rotate(90 60 55)">emulation</text>
|
||||
<text x="170" y="45" class="text left">B II</text>
|
||||
<text x="225" y="45" class="text left">memory</text>
|
||||
<text x="170" y="100" class="text left">B III</text>
|
||||
<text x="230" y="100" class="text left">basic block</text>
|
||||
</g>
|
||||
|
||||
<!-- Triangle -->
|
||||
<g transform="translate(0,470)">
|
||||
<g transform="translate(0,-35)">
|
||||
<polygon points="20,80 8,102 32,102" class="triFill"/>
|
||||
</g>
|
||||
<path d="M48,0 L48,118 M48,0 q0,0 8,0 M48,118 q0,0 8,0" class="line"/>
|
||||
<text x="60" y="30" class="text small left" transform="rotate(90 60 30)">clean</text>
|
||||
<text x="170" y="55" class="text left">B IV</text>
|
||||
<text x="265" y="57" class="text small left">sync</text>
|
||||
</g>
|
||||
|
||||
<!-- T -->
|
||||
<g transform="translate(0,635)">
|
||||
<g transform="translate(20,20)">
|
||||
<rect x="-12" y="-14" width="24" height="28" class="tBox"/>
|
||||
<text class="stateText tFill" x="0" y="1">T</text>
|
||||
</g>
|
||||
<path d="M48,0 L48,78 M48,0 q0,0 8,0 M48,78 q0,0 8,0" class="line"/>
|
||||
<text x="60" y="18" class="text small left" transform="rotate(90 60 18)">term</text>
|
||||
</g>
|
||||
</g>
|
||||
|
||||
<!-- ===================== RIGHT STATE GRAPH ===================== -->
|
||||
<g transform="translate(1060,170)">
|
||||
<!-- blue state -->
|
||||
<g transform="translate(165,95)">
|
||||
<circle r="16" class="circleFill"/>
|
||||
</g>
|
||||
|
||||
<!-- self loop on blue state -->
|
||||
<path d="M150,72 C138,40 192,34 191,73" class="line" marker-end="url(#arrow)"/>
|
||||
|
||||
<!-- triangle state -->
|
||||
<g transform="translate(230,155)">
|
||||
<polygon points="0,-18 -16,12 16,12" class="triFill"/>
|
||||
</g>
|
||||
|
||||
<!-- yellow dash state -->
|
||||
<g transform="translate(70,165)">
|
||||
<rect x="-10" y="-18" width="20" height="36" rx="6" class="dashFill"/>
|
||||
<line x1="-6" y1="0" x2="6" y2="0" class="thin"/>
|
||||
</g>
|
||||
|
||||
<!-- Start state pointer -->
|
||||
<polygon points="46,165 28,154.608 28,175.392" class="whiteTri"/>
|
||||
|
||||
<!-- T state -->
|
||||
<g transform="translate(125,260)">
|
||||
<rect x="-12" y="-14" width="24" height="28" class="tBox"/>
|
||||
<text class="stateText tFill" x="0" y="1">T</text>
|
||||
</g>
|
||||
|
||||
<!-- arrows -->
|
||||
<path d="M88,151 L150,108" class="line" marker-end="url(#arrow)"/>
|
||||
<path d="M180,111 L217,143" class="line" marker-end="url(#arrow)"/>
|
||||
<path d="M212,170 L92,175" class="line" marker-end="url(#arrow)"/>
|
||||
<path d="M76,184 L118,244" class="line" marker-end="url(#arrow)"/>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 10 KiB |
@@ -993,6 +993,77 @@ RZ_API bool rz_analysis_op_is_call(RZ_NONNULL const RzAnalysisOp *op) {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Checks if \p op changes the control flow.
|
||||
* It checks op->type, op->eob for it. So any jump, call, trap, or illegal
|
||||
* instruction.
|
||||
* It also returns true for conditional instructions.
|
||||
*
|
||||
* \return True if \p op changes the control flow. False otherwise.
|
||||
*/
|
||||
RZ_API bool rz_analysis_op_changes_control_flow(RZ_NONNULL const RzAnalysisOp *op) {
|
||||
rz_return_val_if_fail(op, false);
|
||||
switch (op->type & RZ_ANALYSIS_OP_TYPE_MASK) {
|
||||
case RZ_ANALYSIS_OP_TYPE_JMP:
|
||||
case RZ_ANALYSIS_OP_TYPE_UJMP:
|
||||
case RZ_ANALYSIS_OP_TYPE_RJMP:
|
||||
case RZ_ANALYSIS_OP_TYPE_IJMP:
|
||||
case RZ_ANALYSIS_OP_TYPE_IRJMP:
|
||||
case RZ_ANALYSIS_OP_TYPE_CJMP:
|
||||
case RZ_ANALYSIS_OP_TYPE_RCJMP:
|
||||
case RZ_ANALYSIS_OP_TYPE_MJMP:
|
||||
case RZ_ANALYSIS_OP_TYPE_MCJMP:
|
||||
case RZ_ANALYSIS_OP_TYPE_UCJMP:
|
||||
case RZ_ANALYSIS_OP_TYPE_CALL:
|
||||
case RZ_ANALYSIS_OP_TYPE_UCALL:
|
||||
case RZ_ANALYSIS_OP_TYPE_RCALL:
|
||||
case RZ_ANALYSIS_OP_TYPE_ICALL:
|
||||
case RZ_ANALYSIS_OP_TYPE_IRCALL:
|
||||
case RZ_ANALYSIS_OP_TYPE_CCALL:
|
||||
case RZ_ANALYSIS_OP_TYPE_UCCALL:
|
||||
case RZ_ANALYSIS_OP_TYPE_RET:
|
||||
case RZ_ANALYSIS_OP_TYPE_CRET:
|
||||
case RZ_ANALYSIS_OP_TYPE_ILL:
|
||||
case RZ_ANALYSIS_OP_TYPE_UNK:
|
||||
case RZ_ANALYSIS_OP_TYPE_TRAP:
|
||||
case RZ_ANALYSIS_OP_TYPE_SWI:
|
||||
case RZ_ANALYSIS_OP_TYPE_CSWI:
|
||||
case RZ_ANALYSIS_OP_TYPE_LEAVE:
|
||||
case RZ_ANALYSIS_OP_TYPE_SWITCH:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Returns true if the \p op is a direct call.
|
||||
*/
|
||||
RZ_API bool rz_analysis_op_is_direct_call(RZ_NONNULL const RzAnalysisOp *op) {
|
||||
rz_return_val_if_fail(op, false);
|
||||
switch (op->type & RZ_ANALYSIS_OP_TYPE_MASK) {
|
||||
case RZ_ANALYSIS_OP_TYPE_CALL:
|
||||
case RZ_ANALYSIS_OP_TYPE_CCALL:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Returns true if the \p op is a direct call.
|
||||
*/
|
||||
RZ_API bool rz_analysis_op_is_direct_jump(RZ_NONNULL const RzAnalysisOp *op) {
|
||||
rz_return_val_if_fail(op, false);
|
||||
switch (op->type & RZ_ANALYSIS_OP_TYPE_MASK) {
|
||||
case RZ_ANALYSIS_OP_TYPE_JMP:
|
||||
case RZ_ANALYSIS_OP_TYPE_CJMP:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
RZ_API void rz_analysis_purge(RzAnalysis *analysis) {
|
||||
rz_analysis_hint_clear(analysis);
|
||||
rz_interval_tree_fini(&analysis->meta);
|
||||
|
||||
@@ -1854,6 +1854,30 @@ RZ_API RzAnalysisFunction *rz_analysis_get_function_byname(RzAnalysis *a, const
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Adds a basic block to the RzAnalysis.
|
||||
* It disassembles it to determine the instructions and their offset.
|
||||
*/
|
||||
RZ_API bool rz_analysis_add_bb(RzAnalysis *a, ut64 addr, ut64 size) {
|
||||
rz_return_val_if_fail(a && size > 0, false);
|
||||
if (size > a->opt.bb_max_size) {
|
||||
RZ_LOG_ERROR("Cannot allocate such big bb of %" PFMT64d " bytes at 0x%08" PFMT64x "\n", (st64)size, addr);
|
||||
rz_warn_if_reached();
|
||||
return false;
|
||||
}
|
||||
RzAnalysisBlock *block = rz_analysis_get_block_at(a, addr);
|
||||
if (block) {
|
||||
rz_analysis_delete_block(block);
|
||||
}
|
||||
|
||||
block = rz_analysis_create_block(a, addr, size);
|
||||
if (!block) {
|
||||
return false;
|
||||
}
|
||||
rz_analysis_block_analyze_ops(block);
|
||||
return true;
|
||||
}
|
||||
|
||||
/* rename RzAnalysisFunctionBB.add() */
|
||||
RZ_API bool rz_analysis_fcn_add_bb(RzAnalysis *a, RzAnalysisFunction *fcn, ut64 addr, ut64 size, ut64 jump, ut64 fail) {
|
||||
if (size == 0) {
|
||||
|
||||
@@ -30,6 +30,7 @@ RZ_API int hexagon_v6_op(RzAnalysis *analysis, RzAnalysisOp *op, ut64 addr, cons
|
||||
hexagon_reverse_opcode(&rev, addr, NULL, analysis);
|
||||
HexPkt *p = hex_get_pkt(rev.state, addr);
|
||||
if (p) {
|
||||
op->hexagon_pkt_addr = p->pkt_addr;
|
||||
rev.pkt_fully_decoded = p->is_valid;
|
||||
if (mask & RZ_ANALYSIS_OP_MASK_INSN_PKT) {
|
||||
op->size = rz_list_length(p->bin) * HEX_INSN_SIZE;
|
||||
|
||||
@@ -216,6 +216,8 @@ RZ_API const char *rz_analysis_xrefs_type_tostring(RzAnalysisXRefType type) {
|
||||
return "STRING";
|
||||
case RZ_ANALYSIS_XREF_TYPE_MEM_WRITE:
|
||||
return "MEM_WRITE";
|
||||
case RZ_ANALYSIS_XREF_TYPE_RETURN:
|
||||
return "RETURN";
|
||||
case RZ_ANALYSIS_XREF_TYPE_NULL:
|
||||
default:
|
||||
return "UNKNOWN";
|
||||
@@ -310,6 +312,87 @@ RZ_API const char *rz_analysis_ref_type_tostring(RzAnalysisXRefType t) {
|
||||
return "string";
|
||||
case RZ_ANALYSIS_XREF_TYPE_MEM_WRITE:
|
||||
return "write";
|
||||
case RZ_ANALYSIS_XREF_TYPE_CALL_RET:
|
||||
return "call_ret_pt";
|
||||
case RZ_ANALYSIS_XREF_TYPE_RETURN:
|
||||
return "return";
|
||||
}
|
||||
return "unknown";
|
||||
}
|
||||
|
||||
static bool read_up_to(RzAnalysis *analysis, ut64 addr, ut8 *buf, size_t buf_size) {
|
||||
rz_mem_set_num(buf, buf_size, 0);
|
||||
do {
|
||||
if (analysis->iob.read_at(analysis->iob.io, addr, buf, buf_size) > 0) {
|
||||
return true;
|
||||
}
|
||||
buf_size--;
|
||||
} while (buf_size > 0);
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Returns all control flow targets of call/jmp instructions within the \p sections.
|
||||
* NOTE: This function disassembles all instructions within the boundaries and checks for calls/jmps.
|
||||
* It DOES NOT use the existing xrefs.
|
||||
*
|
||||
* \param analysis The analysis plugin.
|
||||
* \param sections The RzBinSections to disassemble to find call/jmp instructions.
|
||||
* \param include_call_return_pts If true, it will add addresses after a call instruction as well.
|
||||
* \param cf_targets The found call targets of all disassemble calls.
|
||||
*
|
||||
* \return True in case of success, false otherwise.
|
||||
*/
|
||||
RZ_API bool rz_analysis_get_all_cf_targets(RzAnalysis *analysis,
|
||||
const RzPVector /*<RzBinSection *>*/ *sections,
|
||||
bool include_call_return_pts,
|
||||
RZ_NONNULL RZ_OUT RzSetU *cf_targets) {
|
||||
rz_return_val_if_fail(analysis && analysis->cur && sections && cf_targets, false);
|
||||
size_t buf_size = (analysis->cur->bits / 8) * 16;
|
||||
ut8 *buf = RZ_NEWS0(ut8, buf_size);
|
||||
if (!buf_size || !buf) {
|
||||
return false;
|
||||
}
|
||||
|
||||
RzAnalysisOp op = { 0 };
|
||||
void **it;
|
||||
rz_pvector_foreach (sections, it) {
|
||||
RzBinSection *sec = *it;
|
||||
if (!(sec->perm & RZ_PERM_X)) {
|
||||
continue;
|
||||
}
|
||||
ut64 addr = sec->vaddr;
|
||||
while (addr < sec->vaddr + sec->size) {
|
||||
if (!read_up_to(analysis, addr, buf, buf_size)) {
|
||||
RZ_LOG_WARN("Failed to read memory at 0x%" PFMT64x " size: %" PFMTSZu ".\n", addr, buf_size);
|
||||
rz_analysis_op_fini(&op);
|
||||
break;
|
||||
}
|
||||
if (rz_analysis_op(analysis, &op, addr, buf, buf_size, RZ_ANALYSIS_OP_MASK_BASIC) <= 0) {
|
||||
rz_analysis_op_fini(&op);
|
||||
addr += op.size;
|
||||
continue;
|
||||
}
|
||||
// Only add jump targets going to executable regions.
|
||||
bool op_is_call = rz_analysis_op_is_direct_call(&op);
|
||||
bool op_is_jump = rz_analysis_op_is_direct_jump(&op);
|
||||
if ((op_is_call || op_is_jump) && op.jump != UT64_MAX) {
|
||||
rz_set_u_add(cf_targets, op.jump);
|
||||
if (op.fail != UT64_MAX) {
|
||||
if (op_is_jump) {
|
||||
rz_set_u_add(cf_targets, op.fail);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (include_call_return_pts && op_is_call) {
|
||||
// If it is a call, also add the following instruction as reference.
|
||||
// Because it is likely a return point.
|
||||
rz_set_u_add(cf_targets, op.addr + op.size);
|
||||
}
|
||||
addr += op.size;
|
||||
rz_analysis_op_fini(&op);
|
||||
}
|
||||
}
|
||||
free(buf);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -2028,6 +2028,13 @@ RzPVector /*<RzBinMap *>*/ *MACH0_(get_maps)(RzBinFile *bf) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
static bool is_linking_related_section(ut64 sec_type) {
|
||||
return sec_type & S_SYMBOL_STUBS ||
|
||||
sec_type & S_LAZY_SYMBOL_POINTERS ||
|
||||
sec_type & S_NON_LAZY_SYMBOL_POINTERS ||
|
||||
sec_type & S_LAZY_DYLIB_SYMBOL_POINTERS;
|
||||
}
|
||||
|
||||
RzPVector /*<RzBinSection *>*/ *MACH0_(get_segments)(RzBinFile *bf) {
|
||||
struct MACH0_(obj_t) *bin = bf->o->bin_obj;
|
||||
if (bin->sections_cache) {
|
||||
@@ -2077,6 +2084,9 @@ RzPVector /*<RzBinSection *>*/ *MACH0_(get_segments)(RzBinFile *bf) {
|
||||
s->flags = bin->sects[i].flags & 0xFFFFFF00;
|
||||
// XXX flags
|
||||
s->paddr = (ut64)bin->sects[i].offset;
|
||||
if (is_linking_related_section(s->type)) {
|
||||
s->layout.role = RZ_BIN_SECTION_ROLE_LINKING;
|
||||
}
|
||||
int segment_index = 0;
|
||||
// s->perm =prot2perm (bin->segs[j].initprot);
|
||||
for (j = 0; j < bin->nsegs; j++) {
|
||||
|
||||
@@ -857,6 +857,12 @@ static RzPVector /*<RzBinSection *>*/ *sections_obj(ELFOBJ *obj, size_t psize) {
|
||||
ptr->layout.element_size = sizeof(Elf_(Addr));
|
||||
ptr->layout.count = section->size / sizeof(Elf_(Addr));
|
||||
}
|
||||
if (section->type == SHT_RELA ||
|
||||
section->type == SHT_DYNAMIC ||
|
||||
section->type == SHT_DYNSYM ||
|
||||
(section->name && strstr(section->name, ".plt"))) {
|
||||
ptr->layout.role = RZ_BIN_SECTION_ROLE_LINKING;
|
||||
}
|
||||
ptr->size = section->type != SHT_NOBITS ? section->size : 0;
|
||||
ptr->vsize = section->size;
|
||||
ptr->paddr = section->offset;
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
// SPDX-FileCopyrightText: 2009-2020 nibble <[email protected]>
|
||||
// SPDX-License-Identifier: LGPL-3.0-only
|
||||
|
||||
#include <rz_inquiry/rz_absint.h>
|
||||
#include <rz_types.h>
|
||||
#include <rz_list.h>
|
||||
#include <rz_flag.h>
|
||||
|
||||
@@ -2126,9 +2126,11 @@ RZ_IPI RzCmdStatus rz_analysis_function_xrefs_handler(RzCore *core, int argc, co
|
||||
rz_cons_printf("0x%08" PFMT64x " ", xref->to);
|
||||
break;
|
||||
case RZ_ANALYSIS_XREF_TYPE_MEM_WRITE:
|
||||
case RZ_ANALYSIS_XREF_TYPE_CALL_RET:
|
||||
case RZ_ANALYSIS_XREF_TYPE_CODE:
|
||||
case RZ_ANALYSIS_XREF_TYPE_CALL:
|
||||
case RZ_ANALYSIS_XREF_TYPE_DATA:
|
||||
case RZ_ANALYSIS_XREF_TYPE_RETURN:
|
||||
rz_cons_printf("0x%08" PFMT64x " ", xref->to);
|
||||
rz_core_seek(core, xref->from, 1);
|
||||
rz_core_print_disasm_instructions(core, 0, 1);
|
||||
|
||||
@@ -12,3 +12,99 @@ RZ_IPI RzCmdStatus rz_inquiry_analyze_all_handler(RzCore *core, int argc, const
|
||||
rz_return_val_if_fail(core->analysis && core->io && core->bin->cur && core->bin->cur->o, RZ_CMD_STATUS_ERROR);
|
||||
return rz_core_inquiry_analyze_all(core) ? RZ_CMD_STATUS_OK : RZ_CMD_STATUS_ERROR;
|
||||
}
|
||||
|
||||
static RzVector /*<RzInterval>*/ *get_ignored_code_regions(
|
||||
const RzPVector /*<RzBinSymbol *>*/ *symbols,
|
||||
RzPVector /*<RzBinSection *>*/ *sections,
|
||||
const RzPVector /*<RzIOMap *>*/ *io_maps) {
|
||||
void **it;
|
||||
RzVector *v = rz_vector_new(sizeof(RzInterval), NULL, NULL);
|
||||
rz_pvector_foreach (sections, it) {
|
||||
RzBinSection *sec = *it;
|
||||
if (sec->layout.role == RZ_BIN_SECTION_ROLE_LINKING || !(sec->perm & RZ_PERM_X)) {
|
||||
RzInterval itv = { .addr = sec->vaddr, .size = sec->vsize };
|
||||
rz_vector_push(v, &itv);
|
||||
}
|
||||
}
|
||||
rz_pvector_free(sections);
|
||||
|
||||
rz_pvector_foreach (io_maps, it) {
|
||||
RzIOMap *map = *it;
|
||||
if (!(map->perm & RZ_PERM_X)) {
|
||||
RzInterval itv = { .addr = map->itv.addr, .size = map->itv.size };
|
||||
rz_vector_push(v, &itv);
|
||||
}
|
||||
}
|
||||
|
||||
rz_pvector_foreach (symbols, it) {
|
||||
RzBinSymbol *sym = *it;
|
||||
if (sym->is_imported) {
|
||||
RzInterval itv = { .addr = sym->vaddr, .size = sym->size };
|
||||
rz_vector_push(v, &itv);
|
||||
}
|
||||
}
|
||||
return v;
|
||||
}
|
||||
|
||||
RZ_IPI RzCmdStatus rz_inquiry_interpreter_prototype_handler(RzCore *core, int argc, const char **argv) {
|
||||
rz_return_val_if_fail(core->analysis && core->io && core->bin->cur && core->bin->cur->o, RZ_CMD_STATUS_ERROR);
|
||||
RzSetU *entry_points = rz_set_u_new();
|
||||
if (!entry_points) {
|
||||
return RZ_CMD_STATUS_ERROR;
|
||||
}
|
||||
bool run_fcn_detection = RZ_STR_EQ(argv[1], "-f");
|
||||
|
||||
ut64 entry_point;
|
||||
if (argc == (run_fcn_detection ? 2 : 1)) {
|
||||
// No specific entry point given. Pick the one provided by the bin plugin.
|
||||
entry_point = rz_bin_get_first_entrypoint(core->bin->cur->o);
|
||||
rz_set_u_add(entry_points, entry_point);
|
||||
} else {
|
||||
// Add all entry points given as arguments.
|
||||
for (size_t i = (run_fcn_detection ? 2 : 1); i < argc; i++) {
|
||||
ut64 entry_point = rz_num_get(core->num, argv[i]);
|
||||
rz_set_u_add(entry_points, entry_point);
|
||||
}
|
||||
}
|
||||
RzAbsIntDriverConfig config = {
|
||||
.analysis = core->analysis,
|
||||
.io = core->io,
|
||||
.entry_points = entry_points,
|
||||
.dimens = RZ_ABSINT_RESULT_DIMEN_XREFS,
|
||||
.trace_opts = RZ_ABSINT_TRACE_NONE
|
||||
};
|
||||
bool success = rz_absint_driver_run(&config);
|
||||
rz_set_u_free(entry_points);
|
||||
eprintf("Finished reference recovery: %s\n", success ? "OK" : "FAIL");
|
||||
if (!success) {
|
||||
return RZ_CMD_STATUS_ERROR;
|
||||
}
|
||||
|
||||
RzSetU *symbol_addresses = rz_set_u_new();
|
||||
if (!symbol_addresses || !rz_inquiry_get_fcn_symbol_addr(core, symbol_addresses)) {
|
||||
rz_warn_if_reached();
|
||||
return RZ_CMD_STATUS_ERROR;
|
||||
}
|
||||
const RzPVector *symbols = rz_bin_object_get_symbols(core->bin->cur->o);
|
||||
RzPVector *fcns = rz_pvector_new((RzPVectorFree)rz_inquiry_function_free);
|
||||
|
||||
if (!fcns || !symbols) {
|
||||
return RZ_CMD_STATUS_ERROR;
|
||||
}
|
||||
if (run_fcn_detection) {
|
||||
RzVector *ignored_code_regions = get_ignored_code_regions(
|
||||
rz_bin_object_get_symbols(core->bin->cur->o),
|
||||
rz_bin_object_get_sections(core->bin->cur->o),
|
||||
rz_io_maps(core->io));
|
||||
eprintf("Perform function deduction: ");
|
||||
success &= rz_inquiry_function_deduction(core->analysis, core->inquiry, symbol_addresses, symbols, ignored_code_regions, fcns);
|
||||
rz_vector_free(ignored_code_regions);
|
||||
eprintf("%s\n", success ? "OK" : "FAIL");
|
||||
}
|
||||
rz_set_u_free(symbol_addresses);
|
||||
|
||||
success &= rz_inquiry_convert_and_add_to_analysis(core->analysis, core->inquiry, fcns, symbols);
|
||||
rz_pvector_free(fcns);
|
||||
|
||||
return success ? RZ_CMD_STATUS_OK : RZ_CMD_STATUS_ERROR;
|
||||
}
|
||||
|
||||
@@ -2630,3 +2630,27 @@ commands:
|
||||
summary: analyze all functions
|
||||
cname: inquiry_analyze_all
|
||||
args: []
|
||||
- name: aIp
|
||||
summary: Abstract Interpreter Prototype
|
||||
cname: inquiry_interpreter_prototype
|
||||
args:
|
||||
- name: f
|
||||
type: RZ_CMD_ARG_TYPE_OPTION
|
||||
flags: RZ_CMD_ARG_FLAG_OPTION
|
||||
default_value: 0
|
||||
- name: entry_points
|
||||
type: RZ_CMD_ARG_TYPE_RZNUM
|
||||
flags: RZ_CMD_ARG_FLAG_ARRAY
|
||||
optional: true
|
||||
details:
|
||||
- name: Examples
|
||||
entries:
|
||||
- text: "aIp"
|
||||
arg_str: ""
|
||||
comment: "Run prototype RzIL analysis detecting cross references."
|
||||
- text: "aIp"
|
||||
arg_str: " 0x1000"
|
||||
comment: "Run prototype RzIL analysis starting at address 0x1000."
|
||||
- text: "aIp"
|
||||
arg_str: " -f"
|
||||
comment: "Run prototype RzIL analysis with function detection."
|
||||
|
||||
@@ -66,6 +66,7 @@ static const RzCmdDescDetail analysis_hint_set_optype_details[2];
|
||||
static const RzCmdDescDetail analysis_hint_set_immbase_details[3];
|
||||
static const RzCmdDescDetail analysis_hint_set_offset_details[2];
|
||||
static const RzCmdDescDetail analyze_esil_insn_access_details[4];
|
||||
static const RzCmdDescDetail inquiry_interpreter_prototype_details[2];
|
||||
static const RzCmdDescDetail basefind_compute_details[2];
|
||||
static const RzCmdDescDetail cmd_cmp_unified_details[2];
|
||||
static const RzCmdDescDetail cw_details[2];
|
||||
@@ -428,6 +429,7 @@ static const RzCmdDescArg analyze_esil_emu_fcn_find_args_args[2];
|
||||
static const RzCmdDescArg analyze_esil_int_list_load_args[2];
|
||||
static const RzCmdDescArg analyze_esil_int_remove_args[2];
|
||||
static const RzCmdDescArg analyze_esil_insn_access_args[4];
|
||||
static const RzCmdDescArg inquiry_interpreter_prototype_args[3];
|
||||
static const RzCmdDescArg block_args[2];
|
||||
static const RzCmdDescArg block_decrease_args[2];
|
||||
static const RzCmdDescArg block_increase_args[2];
|
||||
@@ -8469,6 +8471,39 @@ static const RzCmdDescHelp inquiry_analyze_all_help = {
|
||||
.args = inquiry_analyze_all_args,
|
||||
};
|
||||
|
||||
static const RzCmdDescDetailEntry inquiry_interpreter_prototype_Examples_detail_entries[] = {
|
||||
{ .text = "aIp", .arg_str = "", .comment = "Run prototype RzIL analysis detecting cross references." },
|
||||
{ .text = "aIp", .arg_str = " 0x1000", .comment = "Run prototype RzIL analysis starting at address 0x1000." },
|
||||
{ .text = "aIp", .arg_str = " -f", .comment = "Run prototype RzIL analysis with function detection." },
|
||||
{ 0 },
|
||||
};
|
||||
static const RzCmdDescDetail inquiry_interpreter_prototype_details[] = {
|
||||
{ .name = "Examples", .entries = inquiry_interpreter_prototype_Examples_detail_entries },
|
||||
{ 0 },
|
||||
};
|
||||
static const RzCmdDescArg inquiry_interpreter_prototype_args[] = {
|
||||
{
|
||||
.name = "f",
|
||||
.type = RZ_CMD_ARG_TYPE_OPTION,
|
||||
.flags = RZ_CMD_ARG_FLAG_OPTION,
|
||||
.default_value = "0",
|
||||
|
||||
},
|
||||
{
|
||||
.name = "entry_points",
|
||||
.type = RZ_CMD_ARG_TYPE_RZNUM,
|
||||
.flags = RZ_CMD_ARG_FLAG_ARRAY,
|
||||
.optional = true,
|
||||
|
||||
},
|
||||
{ 0 },
|
||||
};
|
||||
static const RzCmdDescHelp inquiry_interpreter_prototype_help = {
|
||||
.summary = "Abstract Interpreter Prototype",
|
||||
.details = inquiry_interpreter_prototype_details,
|
||||
.args = inquiry_interpreter_prototype_args,
|
||||
};
|
||||
|
||||
static const RzCmdDescHelp b_help = {
|
||||
.summary = "Display or change the block size",
|
||||
};
|
||||
@@ -23937,6 +23972,9 @@ RZ_IPI void rzshell_cmddescs_init(RzCore *core) {
|
||||
RzCmdDesc *inquiry_analyze_all_cd = rz_cmd_desc_argv_new(core->rcmd, aI_cd, "aIa", rz_inquiry_analyze_all_handler, &inquiry_analyze_all_help);
|
||||
rz_warn_if_fail(inquiry_analyze_all_cd);
|
||||
|
||||
RzCmdDesc *inquiry_interpreter_prototype_cd = rz_cmd_desc_argv_new(core->rcmd, aI_cd, "aIp", rz_inquiry_interpreter_prototype_handler, &inquiry_interpreter_prototype_help);
|
||||
rz_warn_if_fail(inquiry_interpreter_prototype_cd);
|
||||
|
||||
RzCmdDesc *b_cd = rz_cmd_desc_group_state_new(core->rcmd, root_cd, "b", RZ_OUTPUT_MODE_STANDARD | RZ_OUTPUT_MODE_JSON, rz_block_handler, &block_help, &b_help);
|
||||
rz_warn_if_fail(b_cd);
|
||||
RzCmdDesc *block_decrease_cd = rz_cmd_desc_argv_new(core->rcmd, b_cd, "b-", rz_block_decrease_handler, &block_decrease_help);
|
||||
|
||||
@@ -969,6 +969,8 @@ RZ_IPI RzCmdStatus rz_analyze_esil_insn_access_handler(RzCore *core, int argc, c
|
||||
RZ_IPI RzCmdStatus rz_inquiry_analyze_function_handler(RzCore *core, int argc, const char **argv);
|
||||
// "aIa"
|
||||
RZ_IPI RzCmdStatus rz_inquiry_analyze_all_handler(RzCore *core, int argc, const char **argv);
|
||||
// "aIp"
|
||||
RZ_IPI RzCmdStatus rz_inquiry_interpreter_prototype_handler(RzCore *core, int argc, const char **argv);
|
||||
// "b"
|
||||
RZ_IPI RzCmdStatus rz_block_handler(RzCore *core, int argc, const char **argv, RzCmdStateOutput *state);
|
||||
// "b-"
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
// SPDX-FileCopyrightText: 2009-2020 pancake <[email protected]>
|
||||
// SPDX-License-Identifier: LGPL-3.0-only
|
||||
|
||||
#include "rz_inquiry.h"
|
||||
#include <rz_mark.h>
|
||||
#include <rz_util/rz_str.h>
|
||||
#include <rz_config.h>
|
||||
@@ -1615,6 +1616,7 @@ RZ_API bool rz_core_init(RzCore *core) {
|
||||
/* XXX memory leak */
|
||||
return false;
|
||||
}
|
||||
core->inquiry = rz_inquiry_new();
|
||||
core->ev = rz_event_new(core);
|
||||
core->max_cmd_depth = RZ_CONS_CMD_DEPTH + 1;
|
||||
core->sdb = sdb_new(NULL, "rzkv.sdb", 0); // XXX: path must be in home?
|
||||
@@ -1870,6 +1872,7 @@ RZ_API void rz_core_fini(RzCore *c) {
|
||||
RZ_FREE_CUSTOM(c->hash, rz_hash_free);
|
||||
RZ_FREE_CUSTOM(c->ropchain, rz_list_free);
|
||||
RZ_FREE_CUSTOM(c->ev, rz_event_free);
|
||||
RZ_FREE_CUSTOM(c->inquiry, rz_inquiry_free);
|
||||
RZ_FREE(c->cmdlog);
|
||||
RZ_FREE(c->lastsearch);
|
||||
RZ_FREE(c->cons->pager);
|
||||
|
||||
@@ -37,6 +37,7 @@ CB(bin, bin)
|
||||
CB(demangler, bin->demangler)
|
||||
CB(egg, egg)
|
||||
CB(hash, hash)
|
||||
CB(inquiry, inquiry)
|
||||
|
||||
static bool lib_arch_cb(RzLibPlugin *pl, void *user, void *data) {
|
||||
RzArchPlugin *hand = (RzArchPlugin *)data;
|
||||
@@ -122,6 +123,7 @@ RZ_API void rz_core_loadlibs_init(RzCore *core) {
|
||||
DF(EGG, "egg plugins", egg);
|
||||
DF(HASH, "hash plugins", hash);
|
||||
DF(ARCH, "(dis)assembler & analysis plugins", arch);
|
||||
DF(INTERPRETER, "inquiry interpreter plugins", inquiry);
|
||||
core->times->loadlibs_init_time = rz_time_now_mono() - prev;
|
||||
}
|
||||
|
||||
|
||||
@@ -29,6 +29,7 @@ include_files = [
|
||||
'rz_heap_glibc.h',
|
||||
'rz_heap_jemalloc.h',
|
||||
'rz_il.h',
|
||||
'rz_inquiry.h',
|
||||
'rz_io.h',
|
||||
'rz_lang.h',
|
||||
'rz_lib.h',
|
||||
@@ -146,7 +147,8 @@ install_headers(rz_util_files, install_dir: join_paths(rizin_incdir, 'rz_util'))
|
||||
|
||||
rz_inquiry_files = [
|
||||
'rz_inquiry/rz_absint.h',
|
||||
'rz_inquiry/rz_il_cache.h'
|
||||
'rz_inquiry/rz_il_cache.h',
|
||||
'rz_inquiry/rz_bcfg.h',
|
||||
]
|
||||
install_headers(rz_inquiry_files, install_dir: join_paths(rizin_incdir, 'rz_inquiry'))
|
||||
|
||||
|
||||
@@ -358,7 +358,7 @@ typedef enum {
|
||||
RZ_ANALYSIS_OP_MASK_DISASM = (1 << 4), // It fills RzAnalysisop->mnemonic // should be RzAnalysisOp->disasm // only from rz_core_analysis_op()
|
||||
RZ_ANALYSIS_OP_MASK_IL = (1 << 5), // It fills RzAnalysisop->il_op
|
||||
RZ_ANALYSIS_OP_MASK_INSN_PKT = (1 << 6), // Set op.size to the size of the instruction packet, not the single instruction.
|
||||
RZ_ANALYSIS_OP_MASK_ALL = RZ_ANALYSIS_OP_MASK_ESIL | RZ_ANALYSIS_OP_MASK_VAL | RZ_ANALYSIS_OP_MASK_HINT | RZ_ANALYSIS_OP_MASK_OPEX | RZ_ANALYSIS_OP_MASK_DISASM | RZ_ANALYSIS_OP_MASK_IL
|
||||
RZ_ANALYSIS_OP_MASK_ALL = RZ_ANALYSIS_OP_MASK_ESIL | RZ_ANALYSIS_OP_MASK_VAL | RZ_ANALYSIS_OP_MASK_HINT | RZ_ANALYSIS_OP_MASK_OPEX | RZ_ANALYSIS_OP_MASK_DISASM | RZ_ANALYSIS_OP_MASK_IL | RZ_ANALYSIS_OP_MASK_INSN_PKT
|
||||
} RzAnalysisOpMask;
|
||||
|
||||
typedef enum {
|
||||
@@ -889,6 +889,7 @@ typedef struct rz_analysis_op_t {
|
||||
RzAnalysisSwitchOp *switch_op;
|
||||
RzAnalysisHint hint;
|
||||
RzAnalysisDataType datatype;
|
||||
ut64 hexagon_pkt_addr;
|
||||
} RzAnalysisOp;
|
||||
|
||||
#define RZ_TYPE_COND_SINGLE(x) (!x->arg[1] || x->arg[0] == x->arg[1])
|
||||
@@ -968,13 +969,33 @@ typedef enum {
|
||||
*/
|
||||
RZ_ANALYSIS_XREF_TYPE_MEM_READ = RZ_ANALYSIS_XREF_TYPE_DATA,
|
||||
RZ_ANALYSIS_XREF_TYPE_MEM_WRITE = 'w', ///< Memory write reference
|
||||
|
||||
RZ_ANALYSIS_XREF_TYPE_CALL_RET = 'r', // Call return point (next pc after a call).
|
||||
RZ_ANALYSIS_XREF_TYPE_RETURN = 'R', // A returning jump
|
||||
} RzAnalysisXRefType;
|
||||
|
||||
typedef struct rz_analysis_ref_t {
|
||||
ut64 bb_addr; ///< Temporary member to make prototype function detection work.
|
||||
ut64 from;
|
||||
ut64 to;
|
||||
RzAnalysisXRefType type;
|
||||
} RzAnalysisXRef;
|
||||
|
||||
/**
|
||||
* \brief A struct combining information about an instruction storing the
|
||||
* next instruction pointer of a basic block.
|
||||
* This indicates that the ending branch instruction in a basic block is
|
||||
* a call instruction.
|
||||
*/
|
||||
typedef struct {
|
||||
ut64 bb_addr; ///< The address of the basic block which stores the NPC, WARNING: may not actually be filled yet!
|
||||
ut64 store_addr; ///< The address of the instruction packet storing the NPC. Might be 0, if it was not added by the interpreter.
|
||||
ut64 candidate_addr; ///< Address of the call candidate instruction packet. Might be 0, if it was not added by the interpreter.
|
||||
ut64 npc; ///< The NPC stored. Should point after a basic block.
|
||||
ut64 target; ///< The address the call candidate jumps to.
|
||||
bool in_mem; ///< True if the NPC is written to memory. False if it is written to a register.
|
||||
} RzAnalysisCallCandidate;
|
||||
|
||||
RZ_API const char *rz_analysis_ref_type_tostring(RzAnalysisXRefType t);
|
||||
|
||||
/* represents a reference line from one address (from) to another (to) */
|
||||
@@ -1509,6 +1530,10 @@ RZ_API bool rz_analysis_op_fini(RzAnalysisOp *op);
|
||||
RZ_API int rz_analysis_op_reg_delta(RzAnalysis *analysis, ut64 addr, const char *name);
|
||||
RZ_API bool rz_analysis_op_is_eob(const RzAnalysisOp *op);
|
||||
RZ_API bool rz_analysis_op_is_call(RZ_NONNULL const RzAnalysisOp *op);
|
||||
RZ_API bool rz_analysis_op_changes_control_flow(RZ_NONNULL const RzAnalysisOp *op);
|
||||
RZ_API bool rz_analysis_op_is_direct_call(RZ_NONNULL const RzAnalysisOp *op);
|
||||
RZ_API bool rz_analysis_op_is_call(RZ_NONNULL const RzAnalysisOp *op);
|
||||
RZ_API bool rz_analysis_op_is_direct_jump(RZ_NONNULL const RzAnalysisOp *op);
|
||||
RZ_API RzList /*<RzAnalysisOp *>*/ *rz_analysis_op_list_new(void);
|
||||
RZ_API int rz_analysis_op(RZ_NONNULL RzAnalysis *analysis, RZ_OUT RzAnalysisOp *op, ut64 addr, const ut8 *data, ut64 len, RzAnalysisOpMask mask);
|
||||
RZ_API RzAnalysisOp *rz_analysis_op_hexstr(RzAnalysis *analysis, ut64 addr, const char *hexstr);
|
||||
@@ -1576,6 +1601,7 @@ RZ_API int rz_analysis_fcn(RzAnalysis *analysis, RzAnalysisFunction *fcn, ut64 a
|
||||
RZ_API int rz_analysis_fcn_del(RzAnalysis *analysis, ut64 addr);
|
||||
RZ_API int rz_analysis_fcn_del_locs(RzAnalysis *analysis, ut64 addr);
|
||||
RZ_API bool rz_analysis_fcn_add_bb(RzAnalysis *analysis, RzAnalysisFunction *fcn, ut64 addr, ut64 size, ut64 jump, ut64 fail);
|
||||
RZ_API bool rz_analysis_add_bb(RzAnalysis *a, ut64 addr, ut64 size);
|
||||
RZ_API bool rz_analysis_check_fcn(RzAnalysis *analysis, ut8 *buf, ut16 bufsz, ut64 addr, ut64 low, ut64 high);
|
||||
|
||||
RZ_API void rz_analysis_function_check_bp_use(RzAnalysisFunction *fcn);
|
||||
@@ -1615,6 +1641,11 @@ RZ_API bool rz_analysis_xrefs_set(RzAnalysis *analysis, ut64 from, ut64 to, RzAn
|
||||
RZ_API bool rz_analysis_xrefs_deln(RzAnalysis *analysis, ut64 from, ut64 to, RzAnalysisXRefType type);
|
||||
RZ_API bool rz_analysis_xref_del(RzAnalysis *analysis, ut64 from, ut64 to);
|
||||
|
||||
RZ_API bool rz_analysis_get_all_cf_targets(RzAnalysis *analysis,
|
||||
const RzPVector /*<RzBinSection *>*/ *sections,
|
||||
bool include_call_return_pts,
|
||||
RZ_NONNULL RZ_OUT RzSetU *branch_targets);
|
||||
|
||||
/* var.c */
|
||||
RZ_API RZ_BORROW RzAnalysisVar *rz_analysis_function_set_var(
|
||||
RzAnalysisFunction *fcn,
|
||||
|
||||
@@ -632,12 +632,18 @@ typedef struct rz_bin_map_t {
|
||||
|
||||
#define RZ_BIN_MAX_HANDLED_LAYOUT_SIZE (1024 * 1024 * 2)
|
||||
|
||||
typedef enum {
|
||||
RZ_BIN_SECTION_ROLE_UNSPECIFIED = 0,
|
||||
RZ_BIN_SECTION_ROLE_LINKING, ///< Section is used for (dynamic) linking.
|
||||
} RzBinSectionRole;
|
||||
|
||||
/**
|
||||
* \brief A repetitive data layout of a section. The type will be applied to
|
||||
* element_size * element_count.
|
||||
*/
|
||||
typedef struct rz_bin_section_format_t {
|
||||
int /* RzAnalysisMetaType */ type; ///< The meta type of the elements.
|
||||
RzBinSectionRole role; ///< The role a section has.
|
||||
ut64 element_size; ///< Size of an element in this section.
|
||||
size_t count; ///< The number of consecutive elements in this section.
|
||||
} RzBinSectionLayout;
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
#ifndef RZ_CORE_H
|
||||
#define RZ_CORE_H
|
||||
|
||||
#include <rz_inquiry.h>
|
||||
#include <rz_main.h>
|
||||
#include <rz_arch.h>
|
||||
#include <rz_types.h>
|
||||
@@ -294,6 +295,7 @@ struct rz_core_t {
|
||||
ut8 ptr_alignment_III;
|
||||
// NOTE: Do not change the order of fields above!
|
||||
// They are used in pointer passing hacks in rz_types.h.
|
||||
RzInquiry *inquiry;
|
||||
RzIO *io;
|
||||
HtSP /*<RzCorePlugin *>*/ *plugins; ///< List of registered core plugins
|
||||
HtSP /*<void *>*/ *plugin_contexts; ///< Per-core plugin state
|
||||
|
||||
@@ -0,0 +1,104 @@
|
||||
// SPDX-FileCopyrightText: 2025 RizinOrg <[email protected]>
|
||||
// SPDX-License-Identifier: LGPL-3.0-only
|
||||
|
||||
/**
|
||||
* \file The header file for the RzInquiry module provides the declarations
|
||||
* for RzInquiry plugins. As well as access to broader analysis functions.
|
||||
*/
|
||||
|
||||
#ifndef RZ_INQUIRY
|
||||
#define RZ_INQUIRY
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <rz_inquiry/rz_il_cache.h>
|
||||
#include <rz_inquiry/rz_absint.h>
|
||||
#include <rz_inquiry/rz_bcfg.h>
|
||||
|
||||
/**
|
||||
* \brief The number of iterations inquiry checks for a user given signal.
|
||||
* Checking it costs performance, so it is just checked the X iterations.
|
||||
*/
|
||||
#define RZ_INQUIRY_CHECK_USER_SIGNAL_ITC 1000
|
||||
|
||||
typedef struct rz_inquiry_plugin_t {
|
||||
const char *name;
|
||||
const char *author;
|
||||
const char *version;
|
||||
const char *desc;
|
||||
const char *license;
|
||||
RzAbsIntValueDomain *value_domain;
|
||||
} RzInquiryPlugin;
|
||||
|
||||
typedef struct {
|
||||
/**
|
||||
* \brief RzInquiry interpreter plugins. Indexed by name.
|
||||
*/
|
||||
HtSP /*<RzInquiryPlugin *>*/ *plugins;
|
||||
HtSP /*<void *>*/ *plugins_data;
|
||||
|
||||
HtUP /*<RzAnalysisCallCandidate *>*/ *call_candidates; ///< Indexed by address of basic block with the call candidate.
|
||||
RzVector /*<RzAnalysisXRef>*/ *dynamic_xrefs; ///< All xrefs the interpreter detected.
|
||||
RzInquiryBCFG *bcfg; ///< The control flow graph all the basic blocks build.
|
||||
} RzInquiry;
|
||||
|
||||
RZ_IPI bool rz_inquiry_bcfg_complement(RzInquiry *iq, RzVector /*<RzAnalysisXRef>*/ *insn_to_insn_edges);
|
||||
|
||||
RZ_IPI void rz_inquiry_add_xref(RzInquiry *iq, const RzAnalysisXRef *xref);
|
||||
|
||||
RZ_API bool rz_inquiry_plugin_add(RZ_BORROW RZ_NONNULL RzInquiry *inquiry, RZ_NONNULL RzInquiryPlugin *plugin);
|
||||
RZ_API bool rz_inquiry_plugin_del(RZ_BORROW RZ_NONNULL RzInquiry *inquiry, RZ_NONNULL RzInquiryPlugin *plugin);
|
||||
|
||||
RZ_API RZ_OWN RzInquiry *rz_inquiry_new(void);
|
||||
RZ_API void rz_inquiry_free(RZ_OWN RZ_NULLABLE RzInquiry *q);
|
||||
|
||||
RZ_API bool rz_inquiry_xref_interpreter_filter(RZ_NONNULL const RzAnalysisXRef *xref, RZ_NONNULL const RzPVector /*<RzBinSection *>*/ *allowed_segments);
|
||||
|
||||
RZ_API bool rz_inquiry_interpreter(RzCore *core, RZ_OWN RzSetU /*<ut64>*/ *entry_points);
|
||||
|
||||
RZ_API bool rz_inquiry_function_deduction(
|
||||
RZ_NONNULL RZ_BORROW RzAnalysis *analysis,
|
||||
RZ_NONNULL RZ_BORROW RzInquiry *inquiry,
|
||||
RZ_NONNULL RZ_BORROW RzSetU *symbol_addresses,
|
||||
RZ_NONNULL const RzPVector /*<RzBinSymbol *>*/ *symbols,
|
||||
RZ_NONNULL const RzVector /*<RzInterval>*/ *ignored_code,
|
||||
RZ_NONNULL RZ_OUT RzPVector /*<RzInquiryFunction *>*/ *inquiry_fcns);
|
||||
|
||||
//============
|
||||
// Algorithms
|
||||
//============
|
||||
|
||||
/**
|
||||
* \brief A simple function deduced by inquiry algorithms.
|
||||
*/
|
||||
typedef struct {
|
||||
RzVector /*<ut64>*/ *entry_points;
|
||||
RzInquiryBCFG *bcfg;
|
||||
} RzInquiryFunction;
|
||||
|
||||
RZ_IPI RZ_OWN RzInquiryFunction *rz_inquiry_function_new();
|
||||
RZ_API RZ_OWN char *rz_inquiry_function_str(const RzInquiryFunction *fcn);
|
||||
|
||||
RZ_API bool rz_inquiry_get_fcn_symbol_addr(RzCore *core, RZ_OUT RzSetU *symbol_targets);
|
||||
|
||||
RZ_API void rz_inquiry_function_free(RZ_NULLABLE RZ_OWN RzInquiryFunction *fcn);
|
||||
|
||||
RZ_API bool rz_inquiry_algo_revng_fcn_detection(
|
||||
RzSetU *symbol_addresses,
|
||||
const HtUP /*<RzAnalysisCallCandidate *>*/ *call_candidates,
|
||||
const RzInquiryBCFG *bcfg,
|
||||
RZ_OUT RzPVector /*<RzInquiryFunction *>*/ *fcns,
|
||||
RZ_NONNULL const RzVector /*<RzInterval>*/ *ignored_code);
|
||||
|
||||
RZ_IPI bool rz_inquiry_convert_and_add_to_analysis(
|
||||
RzAnalysis *analysis,
|
||||
RzInquiry *inquiry,
|
||||
const RzPVector /*<RzInquiryFunction *>*/ *fcns,
|
||||
const RzPVector /*<RzBinSymbol *>*/ *symbols);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif // RZ_INQUIRY
|
||||
@@ -0,0 +1,77 @@
|
||||
// SPDX-FileCopyrightText: 2026 Rot127 <[email protected]>
|
||||
// SPDX-License-Identifier: LGPL-3.0-only
|
||||
|
||||
#ifndef RZ_INQUIRY_BCFG_H
|
||||
#define RZ_INQUIRY_BCFG_H
|
||||
|
||||
#include <rz_types.h>
|
||||
#include <rz_util.h>
|
||||
|
||||
/**
|
||||
* \brief A block of instructions which end in a jump/call/exit.
|
||||
*/
|
||||
typedef struct {
|
||||
ut64 addr;
|
||||
ut64 size;
|
||||
} RzInquiryBlock;
|
||||
|
||||
/**
|
||||
* \brief The different kind of BB CFG edges.
|
||||
*/
|
||||
typedef enum {
|
||||
RZ_INQUIRY_BCFG_EDGE_TYPE_NONE = 0,
|
||||
/**
|
||||
* \brief An control flow change via a RzIL JMP. The "from" BB ends with a jump.
|
||||
*/
|
||||
RZ_INQUIRY_BCFG_EDGE_TYPE_JMP,
|
||||
/**
|
||||
* \brief A control flow edge between two blocks where the "from" block does not end with a JUMP.
|
||||
* It is between two blocks which were split from a single one.
|
||||
*/
|
||||
RZ_INQUIRY_BCFG_EDGE_TYPE_CF,
|
||||
/**
|
||||
* \brief An control flow change via a RzIL JMP but by a call candidate.
|
||||
* The "from" BB ends with a jump, very likely to a procedure.
|
||||
*/
|
||||
RZ_INQUIRY_BCFG_EDGE_TYPE_CALL,
|
||||
/**
|
||||
* \brief This edge does not depict a control flow edge.
|
||||
* It is an opaque edge between a call instruction and the (possible) return point of the procedure called.
|
||||
* Note that the return point is often, but not always, the instruction at the following memory address after the call.
|
||||
* There are multiple exceptions to it though, like tail calls, non-returning procedures, or delayed calls.
|
||||
*/
|
||||
RZ_INQUIRY_BCFG_EDGE_TYPE_CALL_RET,
|
||||
/**
|
||||
* \brief An edge from a return instruction to its target.
|
||||
*/
|
||||
RZ_INQUIRY_BCFG_EDGE_TYPE_RETURN,
|
||||
} RzInquiryBCFGEdgeType;
|
||||
|
||||
/**
|
||||
* \brief A control flow graph with blocks as nodes.
|
||||
* Edges can be of different jump, and call/return type.
|
||||
*/
|
||||
typedef struct {
|
||||
/**
|
||||
* \brief The CFG discovered during interpretation.
|
||||
* The node data are the addresses of basic blocks, cast to (void *).
|
||||
*/
|
||||
RzGraph /*<RzInquiryBB *, RzInquiryBCFGEdge *>*/ *graph;
|
||||
} RzInquiryBCFG;
|
||||
|
||||
RZ_IPI RZ_OWN RzInquiryBCFG *rz_inquiry_bcfg_new(RzGraphImplType impl_type);
|
||||
RZ_IPI void rz_inquiry_bcfg_free(RZ_NULLABLE RZ_OWN RzInquiryBCFG *bcfg);
|
||||
RZ_IPI bool rz_inquiry_bcfg_add_block(RzInquiryBCFG *cfg, ut64 addr, ut64 size);
|
||||
|
||||
RZ_IPI bool rz_inquiry_bcfg_get_block(const RzInquiryBCFG *cfg, ut64 bb_addr, RZ_OUT RzInquiryBlock *bb);
|
||||
RZ_IPI bool rz_inquiry_bcfg_del_out_edges(RzInquiryBCFG *cfg, ut64 bb_addr);
|
||||
RZ_IPI bool rz_inquiry_bcfg_add_edge(RzInquiryBCFG *cfg, ut64 from_bb, ut64 to_bb, RzInquiryBCFGEdgeType type);
|
||||
RZ_IPI bool rz_inquiry_bcfg_add_edge_xref(RzInquiryBCFG *cfg, const RzVector /*<RzAnalysisXRef>*/ *xrefs);
|
||||
RZ_IPI bool rz_inquiry_bcfg_del_edge(RzInquiryBCFG *cfg, ut64 from_bb, ut64 to_bb);
|
||||
RZ_API RZ_OWN RzIterator /*<RzGraphNode *>*/ *rz_inquiry_bcfg_get_outgoing_edges(const RzInquiryBCFG *cfg, ut64 bb_addr);
|
||||
RZ_API RZ_OWN RzIterator /*<RzGraphNode *>*/ *rz_inquiry_bcfg_get_incoming_edges(const RzInquiryBCFG *cfg, ut64 bb_addr);
|
||||
|
||||
RZ_IPI bool rz_inquiry_bcfg_reduce(RzInquiryBCFG *cfg);
|
||||
RZ_IPI RZ_OWN char *rz_inquiry_bcfg_as_dot(const RzInquiryBCFG *bcfg, RZ_NULLABLE const char *name);
|
||||
|
||||
#endif // RZ_INQUIRY_BCFG_H
|
||||
@@ -51,6 +51,7 @@ typedef enum {
|
||||
RZ_LIB_TYPE_EGG, ///< rz_egg plugin
|
||||
RZ_LIB_TYPE_DEMANGLER, ///< demanglers
|
||||
RZ_LIB_TYPE_ARCH, ///< demanglers
|
||||
RZ_LIB_TYPE_INTERPRETER, ///< Analysis interpreters
|
||||
RZ_LIB_TYPE_UNKNOWN
|
||||
} RzLibType;
|
||||
|
||||
|
||||
@@ -104,6 +104,7 @@ RZ_API bool rz_th_queue_is_full(RZ_NONNULL RzThreadQueue *queue);
|
||||
RZ_API size_t rz_th_queue_size(RZ_NONNULL RzThreadQueue *queue);
|
||||
RZ_API void rz_th_queue_close_when_empty(RZ_NONNULL RzThreadQueue *queue);
|
||||
RZ_API void rz_th_queue_close(RZ_NONNULL RzThreadQueue *queue);
|
||||
RZ_API void rz_th_queue_open(RZ_NONNULL RzThreadQueue *queue);
|
||||
RZ_API bool rz_th_queue_is_closed(RZ_NONNULL RzThreadQueue *queue);
|
||||
|
||||
RZ_API RZ_OWN RzAtomicBool *rz_atomic_bool_new(bool value);
|
||||
|
||||
@@ -639,6 +639,7 @@ static void report_yield_xref(
|
||||
if (!xref) {
|
||||
goto cleanup;
|
||||
}
|
||||
xref->bb_addr = 0; // TODO? ctx->astate->bb_addr;
|
||||
xref->from = from;
|
||||
xref->to = to_addr;
|
||||
xref->type = type;
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
* This is the abstract domain of either a single constant value or the universal set.
|
||||
*/
|
||||
|
||||
#include <rz_inquiry/rz_absint.h>
|
||||
#include <rz_inquiry.h>
|
||||
|
||||
typedef struct {
|
||||
/**
|
||||
@@ -251,3 +251,19 @@ RZ_IPI RzAbsIntValueDomain rz_absint_value_domain_const = {
|
||||
.eval_binop = eval_binop,
|
||||
.eval_unop = eval_unop
|
||||
};
|
||||
|
||||
RZ_API RzInquiryPlugin rz_inquiry_plugin_interpreter_prototype = {
|
||||
.name = "abstr_int_prototype",
|
||||
.author = "Rot127",
|
||||
.version = "0.1p",
|
||||
.desc = "A prototype interpreter for constant/top abstractions.",
|
||||
.license = "LGPL-3.0-only",
|
||||
.value_domain = &rz_absint_value_domain_const,
|
||||
};
|
||||
|
||||
#ifndef RZ_PLUGIN_INCORE
|
||||
RZ_API RzLibStruct rizin_plugin = {
|
||||
.type = RZ_LIB_TYPE_INTERPRETER,
|
||||
.data = &interpreter_prototype
|
||||
};
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1,260 @@
|
||||
// SPDX-FileCopyrightText: 2026 RizinOrg <[email protected]>
|
||||
// SPDX-License-Identifier: LGPL-3.0-only
|
||||
|
||||
/**
|
||||
* \file This is the function detection algorithm inspired by
|
||||
* paper: "REV.NG: A Unified Binary Analysis Framework to Recover CFGs and Function Boundaries"
|
||||
* chapter: "4.2 Function boundaries recovery"
|
||||
* doi: 10.1145/3033019.3033028
|
||||
*
|
||||
* The actually algorithm is really simple.
|
||||
*
|
||||
* TERMS:
|
||||
*
|
||||
* Basic Block (BB): A sequence of instructions having exactly one entry point and
|
||||
* one jump/call/exit at the end.
|
||||
* Call candidate: RzAnalysisCallCandidate
|
||||
* Candidate function entry points (CFEP): Addresses of possible function entry point.
|
||||
* Return Addresses: Address after a call candidate BB, with an xref to it.
|
||||
* Basic Block CFG: Control Flow Graph with basic blocks as nodes.
|
||||
*
|
||||
* IN:
|
||||
* - Call candidates.
|
||||
* - CFEPs
|
||||
* - Return Addresses
|
||||
* - Basic Block CFG (bcfg)
|
||||
*
|
||||
* ALGO:
|
||||
*
|
||||
* It simply iterates over all CFEPs.
|
||||
* For each one it follows its edges in the bcfg.
|
||||
* If an edge belongs to a call, it is NOT taken.
|
||||
*
|
||||
* Every walked edge and the basic blocks are added to the function.
|
||||
*
|
||||
* Tail calls are not modelled.
|
||||
*
|
||||
* OUT:
|
||||
* - List of functions
|
||||
* - Each functions starts with one CFEP and is a sub-graph in the bcfg.
|
||||
*/
|
||||
|
||||
#include "rz_analysis.h"
|
||||
#include "rz_inquiry/rz_bcfg.h"
|
||||
#include "rz_types_base.h"
|
||||
#include "rz_util/ht_up.h"
|
||||
#include "rz_util/rz_assert.h"
|
||||
#include "rz_util/rz_graph.h"
|
||||
#include "rz_util/rz_iterator.h"
|
||||
#include "rz_util/rz_log.h"
|
||||
#include "rz_util/rz_set.h"
|
||||
#include "rz_vector.h"
|
||||
#include <rz_inquiry.h>
|
||||
#include <rz_types.h>
|
||||
#include <rz_util.h>
|
||||
|
||||
static int cmp(const ut64 *a, const ut64 *b, void *user) {
|
||||
if (*a > *b) {
|
||||
return 1;
|
||||
} else if (*a < *b) {
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static bool jumps_to_ignored_code(const RzVector *v, ut64 jump_target) {
|
||||
void *it;
|
||||
rz_vector_foreach (v, it) {
|
||||
RzInterval *itv = it;
|
||||
if (rz_itv_contain(*itv, jump_target)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static void recurse_into_fcn_bbs(
|
||||
RzInquiryFunction *fcn,
|
||||
ut64 predecessor_bb_addr,
|
||||
ut64 this_bb_addr,
|
||||
RzInquiryBCFGEdgeType edge_type,
|
||||
RzSetU *visited_fcn_bbs,
|
||||
const RzVector /*<ut64>*/ *cfep_addresses,
|
||||
const HtUP /*<RzAnalysisCallCandidate *>*/ *call_candidates,
|
||||
const RzInquiryBCFG *binary_bcfg,
|
||||
RZ_NONNULL const RzVector /*<RzInterval>*/ *ignored_code) {
|
||||
if (rz_set_u_contains(visited_fcn_bbs, this_bb_addr)) {
|
||||
return;
|
||||
}
|
||||
rz_set_u_add(visited_fcn_bbs, this_bb_addr);
|
||||
|
||||
//
|
||||
// Add edge
|
||||
//
|
||||
RzInquiryBlock this_bb = { 0 };
|
||||
if (!rz_inquiry_bcfg_get_block(binary_bcfg, this_bb_addr, &this_bb)) {
|
||||
rz_warn_if_reached();
|
||||
goto err_return;
|
||||
}
|
||||
if (!rz_inquiry_bcfg_add_block(fcn->bcfg, this_bb.addr, this_bb.size)) {
|
||||
rz_warn_if_reached();
|
||||
goto err_return;
|
||||
}
|
||||
|
||||
if (edge_type != RZ_INQUIRY_BCFG_EDGE_TYPE_NONE) {
|
||||
RzInquiryBlock from_bb = { 0 };
|
||||
if (!rz_inquiry_bcfg_get_block(binary_bcfg, predecessor_bb_addr, &from_bb)) {
|
||||
rz_warn_if_reached();
|
||||
goto err_return;
|
||||
}
|
||||
if (!rz_inquiry_bcfg_add_block(fcn->bcfg, from_bb.addr, from_bb.size)) {
|
||||
rz_warn_if_reached();
|
||||
goto err_return;
|
||||
}
|
||||
if (!rz_inquiry_bcfg_add_edge(fcn->bcfg, predecessor_bb_addr, this_bb_addr, edge_type)) {
|
||||
rz_warn_if_reached();
|
||||
goto err_return;
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Visit neighbors
|
||||
//
|
||||
RzIterator *successors = rz_inquiry_bcfg_get_outgoing_edges(binary_bcfg, this_bb_addr);
|
||||
if (!successors) {
|
||||
// Node has no successors.
|
||||
goto err_return;
|
||||
}
|
||||
|
||||
const RzGraphEdge *e;
|
||||
rz_iterator_foreach(successors, e) {
|
||||
RzInquiryBCFGEdgeType etype = (RzInquiryBCFGEdgeType)(utptr)rz_graph_edge_get_data(e);
|
||||
ut64 succ_addr = rz_graph_node_get_id(rz_graph_edge_get_to(e));
|
||||
switch (etype) {
|
||||
case RZ_INQUIRY_BCFG_EDGE_TYPE_NONE:
|
||||
case RZ_INQUIRY_BCFG_EDGE_TYPE_CF:
|
||||
case RZ_INQUIRY_BCFG_EDGE_TYPE_JMP:
|
||||
// Just an edge between two basic blocks.
|
||||
break;
|
||||
case RZ_INQUIRY_BCFG_EDGE_TYPE_CALL_RET:
|
||||
// This is the next instruction packet after a call candidate.
|
||||
// It might be an non-existing edge which was only added as a guess.
|
||||
// In general all instructions after a call are added to the with
|
||||
// an edge, to increase coverage.
|
||||
// Even for call which never return (being a tail call or exit).
|
||||
//
|
||||
// The prototype doesn't handle tail calls. But to not loose too much
|
||||
// precission we can check here if the NPC after the call (this_bb address),
|
||||
// is a candidate function entry point.
|
||||
// If so, we can assume that the NPC is in fact not a return point of a procedure.
|
||||
// Hence, it shouldn't be added to the function CFG.
|
||||
if (rz_vector_contains(cfep_addresses, &succ_addr)) {
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
case RZ_INQUIRY_BCFG_EDGE_TYPE_CALL:
|
||||
case RZ_INQUIRY_BCFG_EDGE_TYPE_RETURN:
|
||||
continue;
|
||||
}
|
||||
if (jumps_to_ignored_code(ignored_code, succ_addr)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
recurse_into_fcn_bbs(
|
||||
fcn,
|
||||
this_bb_addr,
|
||||
succ_addr,
|
||||
etype,
|
||||
visited_fcn_bbs,
|
||||
cfep_addresses,
|
||||
call_candidates,
|
||||
binary_bcfg,
|
||||
ignored_code);
|
||||
}
|
||||
rz_iterator_free(successors);
|
||||
|
||||
err_return:
|
||||
return;
|
||||
}
|
||||
|
||||
static void fill_candidate_fcn_entry_points(
|
||||
const RzInquiryBCFG *binary_bcfg,
|
||||
const HtUP /*<RzAnalysisCallCandidate *>*/ *call_candidates,
|
||||
RzVector *cfep_addresses) {
|
||||
void **it;
|
||||
RzIterator *iter = ht_up_as_iter(call_candidates);
|
||||
rz_iterator_foreach(iter, it) {
|
||||
RzAnalysisCallCandidate *cc = *it;
|
||||
RzIterator *predecessor = rz_inquiry_bcfg_get_outgoing_edges(binary_bcfg, cc->bb_addr);
|
||||
const RzGraphEdge *e;
|
||||
rz_iterator_foreach(predecessor, e) {
|
||||
RzInquiryBCFGEdgeType type = (RzInquiryBCFGEdgeType)(utptr)rz_graph_edge_get_data(e);
|
||||
if (type == RZ_INQUIRY_BCFG_EDGE_TYPE_CALL_RET) {
|
||||
// TODO: Remove this check
|
||||
const RzGraphNode *nr = rz_graph_edge_get_to(e);
|
||||
ut64 target = rz_graph_node_get_id(nr);
|
||||
rz_warn_if_fail(target == cc->npc);
|
||||
} else if (type == RZ_INQUIRY_BCFG_EDGE_TYPE_CALL) {
|
||||
const RzGraphNode *nc = rz_graph_edge_get_to(e);
|
||||
ut64 target = rz_graph_node_get_id(nc);
|
||||
rz_vector_push(cfep_addresses, &target);
|
||||
RZ_LOG_DEBUG("Add cfep at 0x%" PFMT64x " (call: 0x%" PFMT64x ") "
|
||||
"based on BB 0x%" PFMT64x "\n",
|
||||
cc->bb_addr, cc->candidate_addr, target);
|
||||
}
|
||||
}
|
||||
rz_iterator_free(predecessor);
|
||||
}
|
||||
rz_iterator_free(iter);
|
||||
rz_vector_sort(cfep_addresses, (RzVectorComparator)cmp, false, NULL);
|
||||
}
|
||||
|
||||
RZ_API bool rz_inquiry_algo_revng_fcn_detection(
|
||||
RzSetU *symbol_addresses,
|
||||
RZ_NONNULL const HtUP /*<RzAnalysisCallCandidate *>*/ *call_candidates,
|
||||
RZ_NONNULL const RzInquiryBCFG *binary_bcfg,
|
||||
RZ_NONNULL RZ_OUT RzPVector /*<RzInquiryFunction *>*/ *fcns,
|
||||
RZ_NONNULL const RzVector /*<RzInterval>*/ *ignored_code) {
|
||||
rz_return_val_if_fail(call_candidates && binary_bcfg && fcns, false);
|
||||
|
||||
// Candidate function entry points
|
||||
RzVector *cfep_addresses = rz_vector_new(sizeof(ut64), NULL, NULL);
|
||||
RzIterator *iter = rz_set_u_as_iter(symbol_addresses);
|
||||
ut64 *addr;
|
||||
rz_iterator_foreach(iter, addr) {
|
||||
rz_vector_push(cfep_addresses, addr);
|
||||
}
|
||||
rz_iterator_free(iter);
|
||||
fill_candidate_fcn_entry_points(binary_bcfg, call_candidates, cfep_addresses);
|
||||
|
||||
// Set of handled cfep
|
||||
RzSetU *cfep_handled = rz_set_u_new();
|
||||
|
||||
ut64 *elem;
|
||||
rz_vector_foreach (cfep_addresses, elem) {
|
||||
ut64 cfep_addr = *elem;
|
||||
if (rz_set_u_contains(cfep_handled, cfep_addr)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
RzSetU *visited_bbs = rz_set_u_new();
|
||||
RzInquiryFunction *fcn = rz_inquiry_function_new();
|
||||
rz_vector_push(fcn->entry_points, &cfep_addr);
|
||||
recurse_into_fcn_bbs(fcn,
|
||||
UT64_MAX,
|
||||
cfep_addr,
|
||||
RZ_INQUIRY_BCFG_EDGE_TYPE_NONE,
|
||||
visited_bbs,
|
||||
cfep_addresses,
|
||||
call_candidates,
|
||||
binary_bcfg,
|
||||
ignored_code);
|
||||
rz_set_u_free(visited_bbs);
|
||||
rz_set_u_add(cfep_handled, cfep_addr);
|
||||
rz_pvector_push(fcns, fcn);
|
||||
}
|
||||
|
||||
rz_set_u_free(cfep_handled);
|
||||
rz_vector_free(cfep_addresses);
|
||||
return true;
|
||||
}
|
||||
@@ -0,0 +1,349 @@
|
||||
// SPDX-FileCopyrightText: 2026 RizinOrg <[email protected]>
|
||||
// SPDX-License-Identifier: LGPL-3.0-only
|
||||
|
||||
#include "rz_analysis.h"
|
||||
#include "rz_types_base.h"
|
||||
#include "rz_util/rz_assert.h"
|
||||
#include "rz_util/rz_graph.h"
|
||||
#include "rz_util/rz_iterator.h"
|
||||
#include "rz_vector.h"
|
||||
#include <rz_inquiry/rz_bcfg.h>
|
||||
|
||||
static ut64 hash_node(const void *data) {
|
||||
const RzInquiryBlock *bb = data;
|
||||
return bb->addr;
|
||||
}
|
||||
|
||||
static RZ_OWN char *node_formatter(const RzGraphNode *n) {
|
||||
const RzInquiryBlock *bb = rz_graph_node_get_data(n);
|
||||
return rz_str_newf("[label=\"0x%" PFMT64x ":%" PFMT64u "\"]",
|
||||
bb->addr, bb->size);
|
||||
}
|
||||
|
||||
static RZ_OWN char *edge_formatter(const RzGraphEdge *e) {
|
||||
RzInquiryBCFGEdgeType type = (utptr)rz_graph_edge_get_data(e);
|
||||
switch (type) {
|
||||
case RZ_INQUIRY_BCFG_EDGE_TYPE_NONE:
|
||||
return rz_str_dup("[label=Unknown]");
|
||||
case RZ_INQUIRY_BCFG_EDGE_TYPE_JMP:
|
||||
case RZ_INQUIRY_BCFG_EDGE_TYPE_CF:
|
||||
return NULL;
|
||||
case RZ_INQUIRY_BCFG_EDGE_TYPE_CALL_RET:
|
||||
return rz_str_dup("[style=dotted label=npc]");
|
||||
case RZ_INQUIRY_BCFG_EDGE_TYPE_CALL:
|
||||
return rz_str_dup("[style=dotted label=call]");
|
||||
case RZ_INQUIRY_BCFG_EDGE_TYPE_RETURN:
|
||||
return rz_str_dup("[style=dotted label=ret]");
|
||||
}
|
||||
rz_warn_if_reached();
|
||||
return NULL;
|
||||
}
|
||||
|
||||
RZ_IPI RZ_OWN char *rz_inquiry_bcfg_as_dot(const RzInquiryBCFG *bcfg, RZ_NULLABLE const char *name) {
|
||||
rz_return_val_if_fail(bcfg, NULL);
|
||||
return rz_graph_as_dot_str(bcfg->graph, name, node_formatter, edge_formatter);
|
||||
}
|
||||
|
||||
RZ_IPI RZ_OWN RzInquiryBCFG *rz_inquiry_bcfg_new(RzGraphImplType impl_type) {
|
||||
RzInquiryBCFG *bcfg = RZ_NEW0(RzInquiryBCFG);
|
||||
if (!bcfg) {
|
||||
return NULL;
|
||||
}
|
||||
bcfg->graph = rz_graph_new(impl_type, hash_node, free, NULL);
|
||||
if (!bcfg->graph) {
|
||||
rz_inquiry_bcfg_free(bcfg);
|
||||
return NULL;
|
||||
}
|
||||
return bcfg;
|
||||
}
|
||||
|
||||
RZ_IPI void rz_inquiry_bcfg_free(RZ_NULLABLE RZ_OWN RzInquiryBCFG *bcfg) {
|
||||
if (!bcfg) {
|
||||
return;
|
||||
}
|
||||
rz_graph_free(bcfg->graph);
|
||||
free(bcfg);
|
||||
}
|
||||
|
||||
static bool edge_from(const RzGraphEdge *e, void *addr) {
|
||||
ut64 from_addr = (utptr)addr;
|
||||
return rz_graph_node_get_id(rz_graph_edge_get_from(e)) == from_addr;
|
||||
}
|
||||
|
||||
RZ_IPI bool rz_inquiry_bcfg_del_out_edges(RzInquiryBCFG *cfg, ut64 bb_addr) {
|
||||
rz_return_val_if_fail(cfg, false);
|
||||
return rz_graph_del_edges(cfg->graph, edge_from, RZ_GRAPH_INT_AS_DATA(bb_addr)) != RZ_GRAPH_STATUS_ERR;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Adds an edge to the block CFG.
|
||||
*
|
||||
* \param cfg The block CFG to edit.
|
||||
* \param from_bb The address of the block with the branch.
|
||||
* Not the address of the branch instruction!
|
||||
* \param to_bb The address of the block the branch leads to.
|
||||
* \param type The type of the edge.
|
||||
*
|
||||
* \return True if edge was added. False for error or if a node doesn't exist.
|
||||
*/
|
||||
RZ_IPI bool rz_inquiry_bcfg_add_edge(RzInquiryBCFG *cfg, ut64 from_bb, ut64 to_bb, RzInquiryBCFGEdgeType type) {
|
||||
RzGraphStatus s = rz_graph_add_edge_by_id(cfg->graph, from_bb, to_bb, RZ_GRAPH_INT_AS_DATA(type));
|
||||
if (s == RZ_GRAPH_STATUS_OK || s == RZ_GRAPH_STATUS_EXISTED) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
RZ_IPI bool rz_inquiry_bcfg_del_edge(RzInquiryBCFG *cfg, ut64 from_bb, ut64 to_bb) {
|
||||
return rz_graph_del_edge_by_id(cfg->graph, from_bb, to_bb) != RZ_GRAPH_STATUS_ERR;
|
||||
}
|
||||
|
||||
static bool is_cf_edge(const RzGraphEdge *e, void *unused) {
|
||||
RzInquiryBCFGEdgeType type = (utptr)rz_graph_edge_get_data(e);
|
||||
return type == RZ_INQUIRY_BCFG_EDGE_TYPE_CF || type == RZ_INQUIRY_BCFG_EDGE_TYPE_NONE;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Updates or adds an edge to the block CFG.
|
||||
* Only edges of type RZ_INQUIRY_BCFG_EDGE_TYPE_CF are updated to \p type.
|
||||
* Otherwise the edge is not updated.
|
||||
*
|
||||
* \param cfg The block CFG to edit.
|
||||
* \param from_bb The address of the block with the branch.
|
||||
* Not the address of the branch instruction!
|
||||
* \param to_bb The address of the block the branch leads to.
|
||||
* \param type The type of the edge.
|
||||
*
|
||||
* \return True if edge was added. False in case of error.
|
||||
*/
|
||||
RZ_IPI bool rz_inquiry_bcfg_update_edge(RzInquiryBCFG *cfg, ut64 from_bb, ut64 to_bb, RzInquiryBCFGEdgeType type) {
|
||||
return rz_graph_update_edge_by_id(cfg->graph, from_bb, to_bb, RZ_GRAPH_INT_AS_DATA(type), is_cf_edge, NULL) != RZ_GRAPH_STATUS_ERR;
|
||||
}
|
||||
|
||||
RZ_IPI bool rz_inquiry_bcfg_get_block(const RzInquiryBCFG *cfg, ut64 bb_addr, RZ_OUT RZ_NULLABLE RzInquiryBlock *bb) {
|
||||
rz_return_val_if_fail(cfg, false);
|
||||
const RzGraphNode *n = rz_graph_find_node(cfg->graph, bb_addr);
|
||||
if (!n) {
|
||||
RZ_LOG_WARN("Could not find BB at 0x%" PFMT64x "\n", bb_addr);
|
||||
return false;
|
||||
}
|
||||
if (bb) {
|
||||
const RzInquiryBlock *n_data = rz_graph_node_get_data(n);
|
||||
bb->addr = n_data->addr;
|
||||
bb->size = n_data->size;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Neighbors of outgoing edges.
|
||||
*/
|
||||
RZ_API RZ_OWN RzIterator /*<RzGraphEdge *>*/ *rz_inquiry_bcfg_get_outgoing_edges(const RzInquiryBCFG *cfg, ut64 bb_addr) {
|
||||
rz_return_val_if_fail(cfg, NULL);
|
||||
return rz_graph_out_edges_by_id(cfg->graph, bb_addr);
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Neighbors of incoming edges.
|
||||
*/
|
||||
RZ_API RZ_OWN RzIterator /*<RzGraphNode *>*/ *rz_inquiry_bcfg_get_incoming_edges(const RzInquiryBCFG *cfg, ut64 bb_addr) {
|
||||
rz_return_val_if_fail(cfg, NULL);
|
||||
return rz_graph_in_edges_by_id(cfg->graph, bb_addr);
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Does not update the BB if it is already present.
|
||||
* Returns false if it already exists.
|
||||
*/
|
||||
RZ_IPI bool rz_inquiry_bcfg_add_block(RzInquiryBCFG *cfg, ut64 addr, ut64 size) {
|
||||
RzInquiryBlock *bb = RZ_NEW(RzInquiryBlock);
|
||||
if (!bb) {
|
||||
return false;
|
||||
}
|
||||
bb->addr = addr;
|
||||
bb->size = size;
|
||||
rz_graph_add_node(cfg->graph, bb, NULL);
|
||||
// const RzInquiryBB *nbb = rz_graph_node_get_data(n);
|
||||
// if (nbb->size != size) {
|
||||
// rz_warn_if_reached();
|
||||
// }
|
||||
return true;
|
||||
}
|
||||
|
||||
RZ_IPI bool rz_inquiry_bcfg_add_edge_xref(RzInquiryBCFG *cfg, const RzVector /*<RzAnalysisXRef>*/ *xrefs) {
|
||||
RzAnalysisXRef *xref;
|
||||
rz_vector_foreach (xrefs, xref) {
|
||||
switch (xref->type) {
|
||||
case RZ_ANALYSIS_XREF_TYPE_CODE:
|
||||
if (!rz_inquiry_bcfg_update_edge(cfg, xref->bb_addr, xref->to, RZ_INQUIRY_BCFG_EDGE_TYPE_JMP)) {
|
||||
RZ_LOG_DEBUG("Did not add JMP edge: 0x%" PFMT64x " -> 0x%" PFMT64x "\n", xref->bb_addr, xref->to);
|
||||
}
|
||||
break;
|
||||
case RZ_ANALYSIS_XREF_TYPE_CALL:
|
||||
if (!rz_inquiry_bcfg_update_edge(cfg, xref->bb_addr, xref->to, RZ_INQUIRY_BCFG_EDGE_TYPE_CALL)) {
|
||||
RZ_LOG_DEBUG("Did not add CALL edge: 0x%" PFMT64x " -> 0x%" PFMT64x "\n", xref->bb_addr, xref->to);
|
||||
}
|
||||
RzInquiryBlock bb = { 0 };
|
||||
if (!rz_inquiry_bcfg_get_block(cfg, xref->bb_addr, &bb)) {
|
||||
rz_warn_if_reached();
|
||||
break;
|
||||
}
|
||||
ut64 ret_addr = bb.addr + bb.size;
|
||||
if (!rz_inquiry_bcfg_update_edge(cfg, xref->bb_addr, ret_addr, RZ_INQUIRY_BCFG_EDGE_TYPE_CALL_RET)) {
|
||||
RZ_LOG_DEBUG("Did not add CALL_RET edge: 0x%" PFMT64x " -> 0x%" PFMT64x "\n", xref->bb_addr, ret_addr);
|
||||
}
|
||||
break;
|
||||
case RZ_ANALYSIS_XREF_TYPE_RETURN:
|
||||
if (!rz_inquiry_bcfg_update_edge(cfg, xref->bb_addr, xref->to, RZ_INQUIRY_BCFG_EDGE_TYPE_RETURN)) {
|
||||
RZ_LOG_DEBUG("Did not add RETURN edge: 0x%" PFMT64x " -> 0x%" PFMT64x "\n", xref->bb_addr, xref->to);
|
||||
}
|
||||
break;
|
||||
case RZ_ANALYSIS_XREF_TYPE_NULL:
|
||||
case RZ_ANALYSIS_XREF_TYPE_DATA:
|
||||
case RZ_ANALYSIS_XREF_TYPE_STRING:
|
||||
case RZ_ANALYSIS_XREF_TYPE_MEM_WRITE:
|
||||
case RZ_ANALYSIS_XREF_TYPE_CALL_RET:
|
||||
continue;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static int cmp(const RzInquiryBlock *a, const RzInquiryBlock *b, void *user) {
|
||||
if (a->addr < b->addr) {
|
||||
return -1;
|
||||
} else if (a->addr > b->addr) {
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Reduces all blocks in the cfg to their minimum size.
|
||||
* Removing duplicates and split overlapping blocks to basic blocks.
|
||||
*
|
||||
* This function makes each block just have a single entry point.
|
||||
* So each becomes a basic block (one Entry/one Exit).
|
||||
*
|
||||
* Example:
|
||||
*
|
||||
* +- 0x1000
|
||||
* |
|
||||
* |
|
||||
* | +- 0x1058
|
||||
* | |
|
||||
* | | +- 0x105c
|
||||
* | | |
|
||||
* | | |
|
||||
* | | |
|
||||
* +-+-+- 0x1080
|
||||
* |
|
||||
* | JUMP
|
||||
* v
|
||||
* +-- 0x1084
|
||||
* |
|
||||
* |
|
||||
* | +- 0x108c
|
||||
* | |
|
||||
* | |
|
||||
* +-+- 0x10a0
|
||||
*
|
||||
* Gets converted to:
|
||||
*
|
||||
* +-- 0x1000
|
||||
* |
|
||||
* +--
|
||||
* | CTRL FLOW
|
||||
* v
|
||||
* +-- 0x1058
|
||||
* |
|
||||
* +--
|
||||
* | CTRL FLOW
|
||||
* v
|
||||
* +-- 0x105c
|
||||
* |
|
||||
* |
|
||||
* |
|
||||
* +-- 0x1080
|
||||
* |
|
||||
* | JUMP
|
||||
* v
|
||||
* +-- 0x1084
|
||||
* |
|
||||
* +--
|
||||
* | CTRL FLOW
|
||||
* v
|
||||
* +-- 0x108c
|
||||
* |
|
||||
* |
|
||||
* +-- 0x10a0
|
||||
*/
|
||||
RZ_IPI bool rz_inquiry_bcfg_reduce(RzInquiryBCFG *cfg) {
|
||||
RzPVector blocks = { 0 };
|
||||
rz_pvector_init(&blocks, NULL);
|
||||
rz_pvector_reserve(&blocks, rz_graph_get_n_nodes(cfg->graph));
|
||||
|
||||
RzGraphNode *n;
|
||||
RzIterator *iter = rz_graph_get_nodes(cfg->graph);
|
||||
rz_iterator_foreach(iter, n) {
|
||||
RzInquiryBlock *b = rz_graph_node_get_data_mut(n);
|
||||
rz_pvector_push(&blocks, b); // Cast because API is not constified.
|
||||
}
|
||||
rz_iterator_free(iter);
|
||||
|
||||
// Sorting by starting address.
|
||||
// Note that this means overlapping blocks (with the same end address)
|
||||
// will lie sequentially in this vector.
|
||||
rz_pvector_sort(&blocks, (RzPVectorComparator)cmp, NULL);
|
||||
|
||||
RzVector outedges = { 0 };
|
||||
rz_vector_init(&outedges, sizeof(ut64), NULL, NULL);
|
||||
// It is unlikely any node will have more than 8 outgoing edges.
|
||||
rz_vector_reserve(&outedges, 8);
|
||||
|
||||
size_t n_blocks = rz_pvector_len(&blocks);
|
||||
for (size_t i = 0; n_blocks && i < n_blocks - 1; ++i) {
|
||||
RzInquiryBlock *a = rz_pvector_at(&blocks, i);
|
||||
|
||||
// Split of all blocks a overlaps with.
|
||||
for (; i < n_blocks - 1; ++i) {
|
||||
RzInquiryBlock *b = rz_pvector_at(&blocks, i + 1);
|
||||
if ((a->addr + a->size) != (b->addr + b->size)) {
|
||||
// End addresses don't match => b lies not within a.
|
||||
break;
|
||||
}
|
||||
// b and a have the same end address => b lies within a.
|
||||
// Shrink a.
|
||||
a->size = b->addr - a->addr;
|
||||
RzIterator *out_iter = rz_graph_out_edges_by_id(cfg->graph, a->addr);
|
||||
if (!out_iter) {
|
||||
// No edges to update.
|
||||
// Check for blocks b overlaps with.
|
||||
a = b;
|
||||
continue;
|
||||
}
|
||||
|
||||
// Replace a's outgoing edges with a single edge to b,
|
||||
RzGraphEdge *e;
|
||||
rz_iterator_foreach(out_iter, e) {
|
||||
const RzGraphNode *to_node = rz_graph_edge_get_to(e);
|
||||
ut64 to = rz_graph_node_get_id(to_node);
|
||||
rz_vector_push(&outedges, &to);
|
||||
}
|
||||
rz_iterator_free(out_iter);
|
||||
|
||||
ut64 *to;
|
||||
rz_vector_foreach (&outedges, to) {
|
||||
rz_graph_del_edge_by_id(cfg->graph, a->addr, *to);
|
||||
}
|
||||
rz_vector_purge(&outedges);
|
||||
rz_graph_add_edge_by_id(cfg->graph, a->addr, b->addr, RZ_GRAPH_INT_AS_DATA(RZ_INQUIRY_BCFG_EDGE_TYPE_CF));
|
||||
// Check for blocks b overlaps with.
|
||||
a = b;
|
||||
}
|
||||
}
|
||||
rz_vector_fini(&outedges);
|
||||
rz_pvector_fini(&blocks);
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -0,0 +1,341 @@
|
||||
// SPDX-FileCopyrightText: 2025 RizinOrg <[email protected]>
|
||||
// SPDX-License-Identifier: LGPL-3.0-only
|
||||
|
||||
#include <rz_core.h>
|
||||
#include <rz_lib.h>
|
||||
#include <rz_inquiry.h>
|
||||
|
||||
#include "rz_analysis.h"
|
||||
#include "rz_bin.h"
|
||||
#include "rz_inquiry/rz_bcfg.h"
|
||||
#include "rz_types.h"
|
||||
#include "rz_util/ht_pp.h"
|
||||
#include "rz_util/ht_sp.h"
|
||||
#include "rz_util/ht_up.h"
|
||||
#include "rz_util/rz_graph.h"
|
||||
#include "rz_util/rz_iterator.h"
|
||||
#include "rz_util/rz_log.h"
|
||||
#include "rz_util/rz_set.h"
|
||||
#include "rz_util/rz_str.h"
|
||||
#include "rz_vector.h"
|
||||
#include <rz_il.h>
|
||||
#include <rz_list.h>
|
||||
#include <rz_types_base.h>
|
||||
#include <rz_util/rz_assert.h>
|
||||
|
||||
#if 0
|
||||
RZ_LIB_VERSION(rz_inquiry);
|
||||
|
||||
static RzInquiryPlugin *inquiry_static_plugins[] = { RZ_INQUIRY_STATIC_PLUGINS };
|
||||
|
||||
RZ_API const size_t rz_inquiry_get_n_plugins() {
|
||||
return RZ_ARRAY_SIZE(inquiry_static_plugins);
|
||||
}
|
||||
|
||||
RZ_API RZ_BORROW RzInquiryPlugin *rz_inquiry_get_plugin(size_t index) {
|
||||
if (index >= RZ_ARRAY_SIZE(inquiry_static_plugins)) {
|
||||
return NULL;
|
||||
}
|
||||
return inquiry_static_plugins[index];
|
||||
}
|
||||
#endif
|
||||
|
||||
RZ_API bool rz_inquiry_plugin_add(RZ_BORROW RZ_NONNULL RzInquiry *inquiry, RZ_OWN RZ_NONNULL RzInquiryPlugin *plugin) {
|
||||
rz_return_val_if_fail(inquiry && plugin, false);
|
||||
if (!plugin->value_domain) {
|
||||
rz_warn_if_reached();
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!ht_sp_insert(inquiry->plugins, plugin->name, plugin)) {
|
||||
RZ_LOG_WARN("Plugin '%s' was already added.\n", plugin->name);
|
||||
return true;
|
||||
}
|
||||
|
||||
void **p_data = RZ_NEW0(void *);
|
||||
if (!ht_sp_insert(inquiry->plugins_data, plugin->name, p_data)) {
|
||||
rz_warn_if_reached();
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
RZ_API bool rz_inquiry_plugin_del(RZ_BORROW RZ_NONNULL RzInquiry *inquiry, RZ_OWN RZ_NONNULL RzInquiryPlugin *plugin) {
|
||||
rz_return_val_if_fail(inquiry && plugin, false);
|
||||
|
||||
void **p_data = ht_sp_find(inquiry->plugins_data, plugin->name, NULL);
|
||||
#if 0
|
||||
if (plugin->p_interpreter->fini) {
|
||||
plugin->p_interpreter->fini(p_data ? *p_data : NULL);
|
||||
}
|
||||
#endif
|
||||
free(p_data);
|
||||
if (plugin->value_domain) {
|
||||
return ht_sp_delete(inquiry->plugins, plugin->name);
|
||||
}
|
||||
rz_warn_if_reached();
|
||||
return false;
|
||||
}
|
||||
|
||||
RZ_API void rz_inquiry_function_free(RZ_NULLABLE RZ_OWN RzInquiryFunction *fcn) {
|
||||
if (!fcn) {
|
||||
return;
|
||||
}
|
||||
rz_inquiry_bcfg_free(fcn->bcfg);
|
||||
rz_vector_free(fcn->entry_points);
|
||||
free(fcn);
|
||||
}
|
||||
|
||||
RZ_IPI RZ_OWN RzInquiryFunction *rz_inquiry_function_new() {
|
||||
RzInquiryFunction *fcn = RZ_NEW0(RzInquiryFunction);
|
||||
if (!fcn) {
|
||||
return NULL;
|
||||
}
|
||||
fcn->bcfg = rz_inquiry_bcfg_new(RZ_GRAPH_IMPL_LIST);
|
||||
fcn->entry_points = rz_vector_new(sizeof(ut64), NULL, NULL);
|
||||
if (!fcn->bcfg || !fcn->entry_points) {
|
||||
rz_inquiry_function_free(fcn);
|
||||
return NULL;
|
||||
}
|
||||
return fcn;
|
||||
}
|
||||
|
||||
RZ_API RZ_OWN char *rz_inquiry_function_str(const RzInquiryFunction *fcn) {
|
||||
RzStrBuf *buf = rz_strbuf_new("");
|
||||
rz_strbuf_append(buf, "ifcn: [");
|
||||
ut64 *it;
|
||||
size_t i = 0;
|
||||
rz_vector_foreach (fcn->entry_points, it) {
|
||||
rz_strbuf_appendf(buf, "%s0x%" PFMT64x, (i++ > 0 ? ", " : " "), *it);
|
||||
}
|
||||
rz_strbuf_append(buf, " ]\n");
|
||||
RzIterator *iter = rz_graph_get_nodes(fcn->bcfg->graph);
|
||||
RzGraphNode *n;
|
||||
rz_iterator_foreach(iter, n) {
|
||||
const RzInquiryBlock *bb = rz_graph_node_get_data(n);
|
||||
rz_strbuf_appendf(buf, "\t0x%" PFMT64x ":0x%" PFMT64x "\n", bb->addr, bb->size);
|
||||
}
|
||||
rz_iterator_free(iter);
|
||||
return rz_strbuf_drain(buf);
|
||||
}
|
||||
|
||||
RZ_API RZ_OWN RzInquiry *rz_inquiry_new(void) {
|
||||
RzInquiry *iq = RZ_NEW0(RzInquiry);
|
||||
if (!iq) {
|
||||
return NULL;
|
||||
}
|
||||
iq->plugins = ht_sp_new(HT_STR_CONST, NULL, NULL);
|
||||
iq->plugins_data = ht_sp_new(HT_STR_CONST, NULL, NULL);
|
||||
iq->call_candidates = ht_up_new(NULL, free);
|
||||
iq->dynamic_xrefs = rz_vector_new(sizeof(RzAnalysisXRef), NULL, NULL);
|
||||
iq->bcfg = rz_inquiry_bcfg_new(RZ_GRAPH_IMPL_LIST);
|
||||
if (!iq->plugins || !iq->plugins_data || !iq->bcfg) {
|
||||
ht_sp_free(iq->plugins);
|
||||
ht_sp_free(iq->plugins_data);
|
||||
rz_inquiry_bcfg_free(iq->bcfg);
|
||||
free(iq);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#if 0
|
||||
for (size_t i = 0; i < RZ_ARRAY_SIZE(inquiry_static_plugins); ++i) {
|
||||
rz_inquiry_plugin_add(iq, inquiry_static_plugins[i]);
|
||||
}
|
||||
#endif
|
||||
return iq;
|
||||
}
|
||||
|
||||
RZ_API void rz_inquiry_free(RZ_OWN RZ_NULLABLE RzInquiry *iq) {
|
||||
if (!iq) {
|
||||
return;
|
||||
}
|
||||
#if 0
|
||||
for (size_t i = 0; i < RZ_ARRAY_SIZE(inquiry_static_plugins); ++i) {
|
||||
rz_inquiry_plugin_del(iq, inquiry_static_plugins[i]);
|
||||
}
|
||||
#endif
|
||||
ht_sp_free(iq->plugins);
|
||||
ht_sp_free(iq->plugins_data);
|
||||
ht_up_free(iq->call_candidates);
|
||||
rz_inquiry_bcfg_free(iq->bcfg);
|
||||
rz_vector_free(iq->dynamic_xrefs);
|
||||
free(iq);
|
||||
}
|
||||
|
||||
RZ_IPI void rz_inquiry_add_xref(RzInquiry *iq, const RzAnalysisXRef *xref) {
|
||||
rz_vector_push(iq->dynamic_xrefs, (void *)xref);
|
||||
}
|
||||
|
||||
RZ_API bool rz_inquiry_xref_interpreter_filter(RZ_NONNULL const RzAnalysisXRef *xref, RZ_NONNULL const RzPVector /*<RzBinSection *>*/ *allowed_segments) {
|
||||
rz_return_val_if_fail(xref && allowed_segments, false);
|
||||
void **it;
|
||||
rz_pvector_foreach (allowed_segments, it) {
|
||||
const RzBinSection *sec = *it;
|
||||
|
||||
ut64 start = sec->vaddr;
|
||||
ut64 end = start + sec->vsize;
|
||||
if (RZ_BETWEEN_EXCL(start, xref->to, end)) {
|
||||
switch (xref->type) {
|
||||
case RZ_ANALYSIS_XREF_TYPE_CALL_RET:
|
||||
case RZ_ANALYSIS_XREF_TYPE_CALL:
|
||||
case RZ_ANALYSIS_XREF_TYPE_CODE:
|
||||
case RZ_ANALYSIS_XREF_TYPE_RETURN:
|
||||
return sec->perm & RZ_PERM_X;
|
||||
case RZ_ANALYSIS_XREF_TYPE_MEM_WRITE:
|
||||
return sec->perm & RZ_PERM_W;
|
||||
case RZ_ANALYSIS_XREF_TYPE_MEM_READ:
|
||||
case RZ_ANALYSIS_XREF_TYPE_STRING:
|
||||
return sec->perm & RZ_PERM_R;
|
||||
case RZ_ANALYSIS_XREF_TYPE_NULL:
|
||||
rz_warn_if_reached();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
RZ_API bool rz_inquiry_get_fcn_symbol_addr(RzCore *core, RZ_OUT RzSetU *symbol_targets) {
|
||||
rz_return_val_if_fail(core && symbol_targets, false);
|
||||
RzPVector /*<RzBinSection *>*/ *sections = rz_bin_object_get_sections(core->bin->cur->o);
|
||||
if (!sections) {
|
||||
rz_warn_if_reached();
|
||||
return false;
|
||||
}
|
||||
// Add function addresses of function symbols in the executable region.
|
||||
void **it;
|
||||
const RzPVector *symbols = rz_bin_object_get_symbols(core->bin->cur->o);
|
||||
if (!symbols) {
|
||||
rz_pvector_free(sections);
|
||||
rz_warn_if_reached();
|
||||
return false;
|
||||
}
|
||||
rz_pvector_foreach (symbols, it) {
|
||||
RzBinSymbol *sym = *it;
|
||||
if (!RZ_STR_EQ(sym->type, RZ_BIN_TYPE_FUNC_STR)) {
|
||||
continue;
|
||||
}
|
||||
void **it2;
|
||||
rz_pvector_foreach (sections, it2) {
|
||||
RzBinSection *sec = *it2;
|
||||
if (sec->perm & RZ_PERM_X &&
|
||||
RZ_BETWEEN_EXCL(sec->vaddr, sym->vaddr, sec->vaddr + sec->vsize)) {
|
||||
rz_set_u_add(symbol_targets, sym->vaddr);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
rz_pvector_free(sections);
|
||||
return true;
|
||||
}
|
||||
|
||||
RZ_API bool rz_inquiry_convert_and_add_to_analysis(
|
||||
RzAnalysis *analysis,
|
||||
RzInquiry *inquiry,
|
||||
const RzPVector /*<RzInquiryFunction *>*/ *fcns,
|
||||
const RzPVector /*<RzBinSymbol *>*/ *symbols) {
|
||||
rz_return_val_if_fail(analysis && inquiry && fcns && symbols, false);
|
||||
// Add all discovered binary blocks to analysis
|
||||
|
||||
RzIterator *iter = rz_graph_get_nodes(inquiry->bcfg->graph);
|
||||
RzGraphNode *n;
|
||||
rz_iterator_foreach(iter, n) {
|
||||
const RzInquiryBlock *bb = rz_graph_node_get_data(n);
|
||||
rz_analysis_add_bb(analysis, bb->addr, bb->size);
|
||||
RzAnalysisBlock *abb = rz_analysis_get_block_at(analysis, bb->addr);
|
||||
RzIterator *out_edges = rz_inquiry_bcfg_get_outgoing_edges(inquiry->bcfg, bb->addr);
|
||||
if (!out_edges) {
|
||||
continue;
|
||||
}
|
||||
RzGraphEdge *e;
|
||||
rz_iterator_foreach(out_edges, e) {
|
||||
ut64 target = rz_graph_node_get_id(rz_graph_edge_get_to(e));
|
||||
RzInquiryBCFGEdgeType type = (RzInquiryBCFGEdgeType)(utptr)rz_graph_edge_get_data(e);
|
||||
switch (type) {
|
||||
default:
|
||||
continue;
|
||||
case RZ_INQUIRY_BCFG_EDGE_TYPE_CALL_RET:
|
||||
case RZ_INQUIRY_BCFG_EDGE_TYPE_CF:
|
||||
case RZ_INQUIRY_BCFG_EDGE_TYPE_JMP: {
|
||||
if (abb->jump == UT64_MAX && abb->fail != target) {
|
||||
abb->jump = target;
|
||||
} else if (abb->fail == UT64_MAX && abb->jump != target) {
|
||||
abb->fail = target;
|
||||
} else if (abb->fail != target && abb->jump != target) {
|
||||
RZ_LOG_WARN("The basic block at 0x%" PFMT64x " has more than two outgoing edges.\n"
|
||||
"\t\tHas jump = 0x%" PFMT64x " fail = 0x%" PFMT64x ". Will miss = 0x%" PFMT64x " (%d)\n",
|
||||
bb->addr, abb->jump, abb->fail,
|
||||
target, type);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
rz_iterator_free(out_edges);
|
||||
}
|
||||
rz_iterator_free(iter);
|
||||
|
||||
RzAnalysisXRef *xref;
|
||||
rz_vector_foreach (inquiry->dynamic_xrefs, xref) {
|
||||
rz_analysis_xrefs_set(analysis, xref->from, xref->to, xref->type);
|
||||
}
|
||||
|
||||
// Convert the Inquiry functions to analysis function.
|
||||
void **it;
|
||||
rz_pvector_foreach (fcns, it) {
|
||||
RzInquiryFunction *fcn = *it;
|
||||
|
||||
ut64 fcn_addr = *(ut64 *)rz_vector_head(fcn->entry_points);
|
||||
char new_fcn_name[64] = { 0 };
|
||||
void **it;
|
||||
rz_pvector_foreach (symbols, it) {
|
||||
RzBinSymbol *s = *it;
|
||||
if (s->vaddr == fcn_addr && RZ_STR_EQ(s->type, RZ_BIN_TYPE_FUNC_STR)) {
|
||||
rz_strf(new_fcn_name, "sym.%s", s->name);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (new_fcn_name[0] == '\0') {
|
||||
rz_strf(new_fcn_name, "fcn_0x%" PFMT64x, fcn_addr);
|
||||
}
|
||||
RzAnalysisFunction *afcn = rz_analysis_create_function(analysis, new_fcn_name, fcn_addr, RZ_ANALYSIS_FCN_TYPE_FCN);
|
||||
if (!afcn) {
|
||||
rz_warn_if_reached();
|
||||
continue;
|
||||
}
|
||||
|
||||
RzIterator *iter = rz_graph_get_nodes(fcn->bcfg->graph);
|
||||
RzGraphNode *n;
|
||||
rz_iterator_foreach(iter, n) {
|
||||
const RzInquiryBlock *bb = rz_graph_node_get_data(n);
|
||||
RzAnalysisBlock *abb = rz_analysis_get_block_at(analysis, bb->addr);
|
||||
if (!abb && !(abb = rz_analysis_create_block(analysis, bb->addr, bb->size))) {
|
||||
rz_warn_if_reached();
|
||||
continue;
|
||||
}
|
||||
rz_analysis_function_add_block(afcn, abb);
|
||||
}
|
||||
rz_iterator_free(iter);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
RZ_API bool rz_inquiry_function_deduction(
|
||||
RZ_NONNULL RZ_BORROW RzAnalysis *analysis,
|
||||
RZ_NONNULL RZ_BORROW RzInquiry *inquiry,
|
||||
RZ_NONNULL RZ_BORROW RzSetU *symbol_addresses,
|
||||
RZ_NONNULL const RzPVector /*<RzBinSymbol *>*/ *symbols,
|
||||
RZ_NONNULL const RzVector /*<RzInterval>*/ *ignored_code,
|
||||
RZ_NONNULL RZ_OUT RzPVector /*<RzInquiryFunction *>*/ *inquiry_fcns) {
|
||||
rz_return_val_if_fail(analysis && inquiry && symbol_addresses && symbols && ignored_code && inquiry_fcns, false);
|
||||
if (!rz_inquiry_algo_revng_fcn_detection(
|
||||
symbol_addresses,
|
||||
inquiry->call_candidates,
|
||||
inquiry->bcfg,
|
||||
inquiry_fcns,
|
||||
ignored_code)) {
|
||||
rz_warn_if_reached();
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@@ -2,6 +2,9 @@
|
||||
# SPDX-License-Identifier: LGPL-3.0-only
|
||||
|
||||
rz_inquiry_sources = [
|
||||
'algorithms/revng_fcn_detection.c',
|
||||
'bcfg.c',
|
||||
'inquiry.c',
|
||||
'il_cache.c',
|
||||
'absint/interpreter.c',
|
||||
'absint/driver.c',
|
||||
|
||||
@@ -143,6 +143,19 @@ RZ_API void rz_th_queue_close_when_empty(RZ_NONNULL RzThreadQueue *queue) {
|
||||
rz_th_lock_leave(queue->data_lock);
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Opens a RzThreadQueue (allows to read/write data).
|
||||
*
|
||||
* \param queue The RzThreadQueue to close
|
||||
*/
|
||||
RZ_API void rz_th_queue_open(RZ_NONNULL RzThreadQueue *queue) {
|
||||
rz_return_if_fail(queue);
|
||||
|
||||
rz_th_lock_enter(queue->data_lock);
|
||||
queue->closed = false;
|
||||
rz_th_lock_leave(queue->data_lock);
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Closes a RzThreadQueue (once closed you cannot read/write data).
|
||||
*
|
||||
|
||||
@@ -0,0 +1,155 @@
|
||||
NAME=Indirect call x86
|
||||
FILE=bins/inquiry/interpreter/prototype/x86_unmapped_fcn_in_loop
|
||||
CMDS=<<EOF
|
||||
aIp -f sym.run
|
||||
agf @ sym.run
|
||||
agf @ sym.recurse
|
||||
agf @ sym.function_0
|
||||
axl
|
||||
ablt
|
||||
EOF
|
||||
EXPECT=<<EOF
|
||||
.--------------------------------------------.
|
||||
| 0x8000050 |
|
||||
| ; CALL XREF from sym.recurse @ 0x8000044 |
|
||||
| ;-- run: |
|
||||
| sym.run(); |
|
||||
| push rbp |
|
||||
| mov rbp, rsp |
|
||||
| sub rsp, 0x10 |
|
||||
| mov dword [rbp-0x04], 0x00 |
|
||||
| mov dword [rbp-0x08], 0x00 |
|
||||
`--------------------------------------------'
|
||||
v
|
||||
|
|
||||
'----.
|
||||
| .--------------------------------------------------------.
|
||||
| | |
|
||||
.--------------------------------------. |
|
||||
| 0x8000066 | |
|
||||
| ; CODE XREF from sym.run @ 0x800009d | |
|
||||
| cmp dword [rbp-0x08], 0x02 | |
|
||||
| jnl 0x800009f | |
|
||||
`--------------------------------------' |
|
||||
t f |
|
||||
| | |
|
||||
.---------------------' | |
|
||||
| '-------------------. |
|
||||
| | |
|
||||
.--------------------------------------. .--------------------------------. |
|
||||
| 0x800009f | | 0x800006c | |
|
||||
| ; CODE XREF from sym.run @ 0x800006a | | movsxd rcx, dword [rbp-0x08] | |
|
||||
| mov eax, dword [rbp-0x04] | | mov al, 0x00 | |
|
||||
| add rsp, 0x10 | | ; 0x80000d0 | |
|
||||
| pop rbp | | call qword [rcx*8+obj.fcn_arr] | |
|
||||
| ret | `--------------------------------' |
|
||||
`--------------------------------------' v |
|
||||
| |
|
||||
| |
|
||||
'-. |
|
||||
| |
|
||||
.----------------------------. |
|
||||
| 0x8000079 | |
|
||||
| mov qword [rbp-0x10], rax | |
|
||||
| cmp dword [rbp-0x08], 0x03 | |
|
||||
| jnz 0x8000088 | |
|
||||
`----------------------------' |
|
||||
f t |
|
||||
| | |
|
||||
| '---------------------. |
|
||||
'. | |
|
||||
| | |
|
||||
.------------------. | |
|
||||
| 0x8000083 | | |
|
||||
| call sym.recurse | | |
|
||||
`------------------' | |
|
||||
v | |
|
||||
| | |
|
||||
'-----. | |
|
||||
| .--------------' |
|
||||
| | |
|
||||
.---------------------------. |
|
||||
| 0x8000088 | |
|
||||
| mov rax, qword [rbp-0x10] | |
|
||||
| mov eax, dword [rax] | |
|
||||
| add eax, dword [rbp-0x04] | |
|
||||
| mov dword [rbp-0x04], eax | |
|
||||
| mov eax, dword [rbp-0x08] | |
|
||||
| add eax, 0x01 | |
|
||||
| mov dword [rbp-0x08], eax | |
|
||||
| jmp 0x8000066 | |
|
||||
`---------------------------' |
|
||||
v |
|
||||
| |
|
||||
`-------------------------'
|
||||
.------------------------------------------.
|
||||
| 0x8000040 |
|
||||
| ; [02] -r-x section size 144 named .text |
|
||||
| ; CALL XREF from sym.run @ 0x8000083 |
|
||||
| ;-- section..text: |
|
||||
| ;-- recurse: |
|
||||
| ;-- .text: |
|
||||
| sym.recurse(); |
|
||||
| push rbp |
|
||||
| mov rbp, rsp |
|
||||
| call sym.run |
|
||||
`------------------------------------------'
|
||||
v
|
||||
|
|
||||
'--------------.
|
||||
|
|
||||
.-------------.
|
||||
| 0x8000049 |
|
||||
| pop rbp |
|
||||
| ret |
|
||||
`-------------'
|
||||
.----------------------------------------.
|
||||
| 0x80000b0 |
|
||||
| ; CALL XREF from sym.run @ 0x8000072 |
|
||||
| sym.function_0(); |
|
||||
| push rbp |
|
||||
| mov rbp, rsp |
|
||||
| ; 0xc |
|
||||
| ; 12 |
|
||||
| mov edi, 0x0c |
|
||||
| call fcn_0x8000440 |
|
||||
`----------------------------------------'
|
||||
v
|
||||
|
|
||||
'-------------.
|
||||
|
|
||||
.-------------.
|
||||
| 0x80000be |
|
||||
| pop rbp |
|
||||
| ret |
|
||||
`-------------'
|
||||
section..text+4 0x8000044 -> CALL -> 0x8000050 reloc.target.run
|
||||
reloc.target.run+26 0x800006a -> CODE -> 0x800009f reloc.recurse+27
|
||||
reloc.target.run+34 0x8000072 -> CALL -> 0x80000b0 sym.function_0
|
||||
reloc.target.run+34 0x8000072 -> DATA -> 0x80000d0 section..data
|
||||
reloc.fcn_arr+14 0x8000083 -> CALL -> 0x8000040 section..text
|
||||
reloc.recurse+25 0x800009d -> CODE -> 0x8000066 reloc.target.run+22
|
||||
addr size traced ninstr jump fail fcns calls xrefs
|
||||
---------------------------------------------------------------------------------------
|
||||
0x8000040 9 0 3 0x08000049 0x08000040 0x08000050 0x08000083
|
||||
0x8000049 2 0 2 0x08000040
|
||||
0x800004b 5 0 1 0x08000050
|
||||
0x8000050 22 0 5 0x08000066 0x08000050 0x08000044
|
||||
0x8000066 6 0 2 0x0800009f 0x0800006c 0x08000050 0x0800009d
|
||||
0x800006c 13 0 3 0x08000079 0x08000050 0x080000b0
|
||||
0x8000079 10 0 3 0x08000088 0x08000083 0x08000050
|
||||
0x8000083 5 0 1 0x08000088 0x08000050 0x08000040
|
||||
0x8000088 23 0 8 0x08000066 0x08000050
|
||||
0x800009f 9 0 4 0x08000050 0x0800006a
|
||||
0x80000a8 8 0 1 0x080000b0
|
||||
0x80000b0 14 0 4 0x080000be 0x080000b0 0x08000440 0x08000072
|
||||
0x80000be 2 0 2 0x080000b0
|
||||
0x80000c0 14 0 4 0x080000ce 0x080000c0 0x08000440
|
||||
0x80000ce 2 0 2 0x080000c0
|
||||
0x8000440 1 0 0 0x08000440
|
||||
EOF
|
||||
EXPECT_ERR=<<EOF
|
||||
Finished reference recovery: OK
|
||||
Perform function deduction: OK
|
||||
EOF
|
||||
RUN
|
||||
@@ -0,0 +1,685 @@
|
||||
NAME=Indirect call x86
|
||||
FILE=bins/inquiry/interpreter/prototype/x86_icall_malloc
|
||||
CMDS=<<EOF
|
||||
aIp -f sym.main
|
||||
pd 48 @ sym.main
|
||||
axl
|
||||
ablt
|
||||
EOF
|
||||
EXPECT=<<EOF
|
||||
;-- section..text:
|
||||
;-- .text:
|
||||
/ int sym.main(int argc, char **argv, char **envp);
|
||||
| 0x08000040 push rbp ; RELOC TARGET 32 .text @ 0x08000040 - 0x8000138 ; [02] -r-x section size 155 named .text
|
||||
| 0x08000041 mov rbp, rsp
|
||||
| 0x08000044 sub rsp, 0x20
|
||||
| 0x08000048 mov dword [rbp-0x04], 0x00
|
||||
| 0x0800004f mov dword [rbp-0x08], 0x00
|
||||
| 0x08000056 mov dword [rbp-0x0c], 0x00
|
||||
| ; CODE XREF from sym.main @ 0x800008b
|
||||
| .-> 0x0800005d cmp dword [rbp-0x0c], 0x03
|
||||
| ,==< 0x08000061 jnb 0x800008d
|
||||
| |: 0x08000063 mov eax, dword [rbp-0x0c]
|
||||
| |: 0x08000066 mov ecx, eax
|
||||
| |: 0x08000068 mov al, 0x00
|
||||
| |: 0x0800006a call qword [rcx*8+obj.fcn_arr] ; sym..data
|
||||
| |: ; 0x80000e0; RELOC 32 .data @ 0x080000e0
|
||||
| |: ; RETURN XREF from sym.function_0 @ 0x80000aa
|
||||
| |: 0x08000071 mov qword [rbp-0x18], rax
|
||||
| |: 0x08000075 mov rax, qword [rbp-0x18]
|
||||
| |: 0x08000079 movzx eax, byte [rax]
|
||||
| |: 0x0800007c add eax, dword [rbp-0x08]
|
||||
| |: 0x0800007f mov dword [rbp-0x08], eax
|
||||
| |: 0x08000082 mov eax, dword [rbp-0x0c]
|
||||
| |: 0x08000085 add eax, 0x01
|
||||
| |: 0x08000088 mov dword [rbp-0x0c], eax
|
||||
| |`=< 0x0800008b jmp 0x800005d
|
||||
| `--> 0x0800008d mov eax, dword [rbp-0x08]
|
||||
| 0x08000090 add rsp, 0x20
|
||||
| 0x08000094 pop rbp
|
||||
\ 0x08000095 ret
|
||||
0x08000096 nop word [rax+rax*1], ax
|
||||
; CALL XREF from sym.main @ 0x800006a
|
||||
/ sym.function_0();
|
||||
| 0x080000a0 push rbp
|
||||
| 0x080000a1 mov rbp, rsp
|
||||
| 0x080000a4 call sym.some_ptr
|
||||
| ; RETURN XREF from sym.some_ptr @ 0x80000bf
|
||||
| 0x080000a9 pop rbp
|
||||
\ 0x080000aa ret
|
||||
0x080000ab nop dword [rax+rax*1], eax
|
||||
; CALL XREF from sym.function_0 @ 0x80000a4
|
||||
; CALL XREF from sym.function_1 @ 0x80000c4
|
||||
; CALL XREF from sym.function_2 @ 0x80000d4
|
||||
/ sym.some_ptr();
|
||||
| 0x080000b0 push rbp
|
||||
| 0x080000b1 mov rbp, rsp
|
||||
| 0x080000b4 mov rax, obj.z ; sym..bss
|
||||
| ; 0x80000f8; RELOC 64 .bss @ 0x080000f8
|
||||
| 0x080000be pop rbp
|
||||
\ 0x080000bf ret
|
||||
/ sym.function_1();
|
||||
| 0x080000c0 push rbp
|
||||
| 0x080000c1 mov rbp, rsp
|
||||
| 0x080000c4 call sym.some_ptr
|
||||
| ; RETURN XREF from sym.some_ptr @ 0x80000bf
|
||||
| 0x080000c9 pop rbp
|
||||
\ 0x080000ca ret
|
||||
0x080000cb nop dword [rax+rax*1], eax
|
||||
/ sym.function_2();
|
||||
| 0x080000d0 push rbp
|
||||
| 0x080000d1 mov rbp, rsp
|
||||
| 0x080000d4 call sym.some_ptr
|
||||
| ; RETURN XREF from sym.some_ptr @ 0x80000bf
|
||||
| 0x080000d9 pop rbp
|
||||
\ 0x080000da ret
|
||||
section..text+42 0x800006a -> CALL -> 0x80000a0 sym.function_0
|
||||
section..text+42 0x800006a -> DATA -> 0x80000e0 section..data
|
||||
reloc..data+30 0x800008b -> CODE -> 0x800005d section..text+29
|
||||
sym.function_0+4 0x80000a4 -> CALL -> 0x80000b0 sym.some_ptr
|
||||
sym.function_0+10 0x80000aa -> RETURN -> 0x8000071 reloc..data+4
|
||||
reloc..bss+9 0x80000bf -> RETURN -> 0x80000a9 sym.function_0+9
|
||||
reloc..bss+9 0x80000bf -> RETURN -> 0x80000c9 sym.function_1+9
|
||||
reloc..bss+9 0x80000bf -> RETURN -> 0x80000d9 sym.function_2+9
|
||||
sym.function_1+4 0x80000c4 -> CALL -> 0x80000b0 sym.some_ptr
|
||||
sym.function_2+4 0x80000d4 -> CALL -> 0x80000b0 sym.some_ptr
|
||||
addr size traced ninstr jump fail fcns calls xrefs
|
||||
-------------------------------------------------------------------------------------------------------------
|
||||
0x8000040 29 0 6 0x0800005d 0x08000040
|
||||
0x800005d 6 0 2 0x0800008d 0x08000063 0x08000040 0x0800008b
|
||||
0x8000063 14 0 4 0x08000071 0x08000040 0x080000a0
|
||||
0x8000071 28 0 9 0x0800005d 0x08000040 0x080000aa
|
||||
0x800008d 9 0 4 0x08000040
|
||||
0x8000096 10 0 1 0x080000a0
|
||||
0x80000a0 9 0 3 0x080000a9 0x080000a0 0x080000b0 0x0800006a
|
||||
0x80000a9 2 0 2 0x080000a0 0x080000bf
|
||||
0x80000ab 5 0 1
|
||||
0x80000b0 16 0 5 0x080000b0 0x080000a4 0x080000d4 0x080000c4
|
||||
0x80000c0 9 0 3 0x080000c9 0x080000c0 0x080000b0
|
||||
0x80000c9 2 0 2 0x080000c0 0x080000bf
|
||||
0x80000cb 5 0 1 0x080000d0
|
||||
0x80000d0 9 0 3 0x080000d9 0x080000d0 0x080000b0
|
||||
0x80000d9 2 0 2 0x080000d0 0x080000bf
|
||||
EOF
|
||||
RUN
|
||||
|
||||
NAME=Indirect call hexagon
|
||||
FILE=bins/inquiry/interpreter/prototype/hexagon_icall_malloc
|
||||
CMDS=<<EOF
|
||||
aIp -f
|
||||
pd 47
|
||||
axl
|
||||
ablt
|
||||
EOF
|
||||
EXPECT=<<EOF
|
||||
;-- section..text:
|
||||
;-- .text:
|
||||
/ int sym.main(int argc, char **argv, char **envp);
|
||||
| 0x08000040 [ allocframe(SP,#0x10):raw ; RELOC TARGET 32 .text @ 0x08000040 + 0x9c ; [02] -r-x section size 168 named .text
|
||||
| 0x08000044 [ R2 = add(FP,##-0x4)
|
||||
| 0x08000048 [ memw(R2+#0x0) = ##0x0
|
||||
| 0x0800004c [ R2 = add(FP,##-0x8)
|
||||
| 0x08000050 [ memw(R2+#0x0) = ##0x0
|
||||
| 0x08000054 [ R2 = add(FP,##-0xc)
|
||||
| 0x08000058 [ memw(R2+#0x0) = ##0x0
|
||||
| ,=< 0x0800005c [ jump 0x8000060
|
||||
| | ; CODE XREF from sym.main @ 0x80000a8
|
||||
| .`-> 0x08000060 [ R2 = memw(FP+##-0xc)
|
||||
| : 0x08000064 [ P0 = cmp.gtu(R2,##0x2)
|
||||
| :,=< 0x08000068 [ if (P0) jump:nt 0x80000ac
|
||||
| ,===< 0x0800006c [ jump 0x8000070
|
||||
| `---> 0x08000070 [ R2 = memw(FP+##-0xc)
|
||||
| :| ;-- .data:
|
||||
| :| 0x08000074 / immext(##sym.some_ptr) ; 0x80000e8
|
||||
| :| ; sym..data; RELOC 32 .data @ 0x080000e8
|
||||
| :| ;-- .data:
|
||||
| :| 0x08000078 \ R2 = memw(R2<<#0x2) ; RELOC 32 .data @ 0x080000e8
|
||||
| :| 0x0800007c [ callr R2
|
||||
| :| ; RETURN XREF from sym.function_0 @ 0x80000bc
|
||||
| :| ; RETURN XREF from sym.function_1 @ 0x80000d8
|
||||
| :| ; RETURN XREF from sym.function_2 @ 0x80000e4
|
||||
| :| 0x08000080 [ memw(FP+##-0x10) = R0
|
||||
| :| 0x08000084 [ R2 = memw(FP+##-0x10)
|
||||
| :| 0x08000088 [ R3 = memub(R2+##0x0)
|
||||
| :| 0x0800008c [ R2 = memw(FP+##-0x8)
|
||||
| :| 0x08000090 [ R2 = add(R2,R3)
|
||||
| :| 0x08000094 [ memw(FP+##-0x8) = R2
|
||||
| ,===< 0x08000098 [ jump 0x800009c
|
||||
| `---> 0x0800009c [ R2 = memw(FP+##-0xc)
|
||||
| :| 0x080000a0 [ R2 = add(R2,##0x1)
|
||||
| :| 0x080000a4 [ memw(FP+##-0xc) = R2
|
||||
| `==< 0x080000a8 [ jump 0x8000060
|
||||
| | ; CODE XREF from sym.main @ 0x8000068
|
||||
| `-> 0x080000ac [ R0 = memw(FP+##-0x8)
|
||||
\ 0x080000b0 [ LR:FP = dealloc_return(FP):raw
|
||||
; CALL XREF from sym.main @ 0x800007c
|
||||
/ sym.function_0();
|
||||
| 0x080000b4 [ allocframe(SP,#0x0):raw
|
||||
| 0x080000b8 [ call sym.some_ptr
|
||||
| ; RETURN XREF from sym.some_ptr @ 0x80000cc
|
||||
\ 0x080000bc [ LR:FP = dealloc_return(FP):raw
|
||||
; CALL XREF from sym.function_0 @ 0x80000b8
|
||||
; CALL XREF from sym.function_1 @ 0x80000d4
|
||||
; CALL XREF from sym.function_2 @ 0x80000e0
|
||||
/ sym.some_ptr();
|
||||
| 0x080000c0 [ allocframe(SP,#0x0):raw
|
||||
| ;-- .bss:
|
||||
| 0x080000c4 / immext(##sym.some_ptr) ; RELOC 32 .bss @ 0x080000f8
|
||||
| ;-- .bss:
|
||||
| 0x080000c8 \ R0 = ##obj.z ; RELOC 32 .bss @ 0x080000f8
|
||||
\ 0x080000cc [ LR:FP = dealloc_return(FP):raw
|
||||
; CALL XREF from sym.main @ 0x800007c
|
||||
/ sym.function_1();
|
||||
| 0x080000d0 [ allocframe(SP,#0x0):raw
|
||||
| 0x080000d4 [ call sym.some_ptr
|
||||
| ; RETURN XREF from sym.some_ptr @ 0x80000cc
|
||||
\ 0x080000d8 [ LR:FP = dealloc_return(FP):raw
|
||||
; CALL XREF from sym.main @ 0x800007c
|
||||
/ sym.function_2();
|
||||
| 0x080000dc [ allocframe(SP,#0x0):raw
|
||||
| 0x080000e0 [ call sym.some_ptr
|
||||
| ; RETURN XREF from sym.some_ptr @ 0x80000cc
|
||||
\ 0x080000e4 [ LR:FP = dealloc_return(FP):raw
|
||||
; DATA XREF from sym.main @ 0x8000074
|
||||
;-- section..data:
|
||||
;-- .data:
|
||||
;-- .text:
|
||||
;-- fcn_arr:
|
||||
0x080000e8 .dword 0x080000b4 ; sym.function_0 ; RELOC 32 .text @ 0x08000040 + 0x74 ; [04] -rw- section size 12 named .data
|
||||
; DATA XREF from sym.main @ 0x8000074
|
||||
;-- .text:
|
||||
0x080000ec .dword 0x080000d0 ; sym.function_1 ; RELOC 32 .text @ 0x08000040 + 0x90
|
||||
; DATA XREF from sym.main @ 0x8000074
|
||||
;-- .text:
|
||||
0x080000f0 .dword 0x080000dc ; sym.function_2 ; RELOC 32 .text @ 0x08000040 + 0x9c
|
||||
0x080000f4
|
||||
;-- section..bss:
|
||||
;-- section..comment:
|
||||
;-- .bss:
|
||||
;-- z:
|
||||
0x080000f8 .dword 0xffffffff ; RELOC TARGET 32 .bss @ 0x080000f8 ; [07] ---- section size 41 named .comment
|
||||
section..text+40 0x8000068 -> CODE -> 0x80000ac reloc..data.8000078+52
|
||||
reloc..data 0x8000074 -> DATA -> 0x80000e8 section..data
|
||||
reloc..data 0x8000074 -> DATA -> 0x80000ec reloc..text.80000ec
|
||||
reloc..data 0x8000074 -> DATA -> 0x80000f0 reloc..text.80000f0
|
||||
reloc..data.8000078+4 0x800007c -> CALL -> 0x80000b4 sym.function_0
|
||||
reloc..data.8000078+4 0x800007c -> CALL -> 0x80000d0 sym.function_1
|
||||
reloc..data.8000078+4 0x800007c -> CALL -> 0x80000dc sym.function_2
|
||||
reloc..data.8000078+48 0x80000a8 -> CODE -> 0x8000060 section..text+32
|
||||
sym.function_0+4 0x80000b8 -> CALL -> 0x80000c0 sym.some_ptr
|
||||
sym.function_0+8 0x80000bc -> RETURN -> 0x8000080 reloc..data.8000078+8
|
||||
reloc..bss.80000c8+4 0x80000cc -> RETURN -> 0x80000bc sym.function_0+8
|
||||
reloc..bss.80000c8+4 0x80000cc -> RETURN -> 0x80000d8 sym.function_1+8
|
||||
reloc..bss.80000c8+4 0x80000cc -> RETURN -> 0x80000e4 sym.function_2+8
|
||||
sym.function_1+4 0x80000d4 -> CALL -> 0x80000c0 sym.some_ptr
|
||||
sym.function_1+8 0x80000d8 -> RETURN -> 0x8000080 reloc..data.8000078+8
|
||||
sym.function_2+4 0x80000e0 -> CALL -> 0x80000c0 sym.some_ptr
|
||||
sym.function_2+8 0x80000e4 -> RETURN -> 0x8000080 reloc..data.8000078+8
|
||||
addr size traced ninstr jump fail fcns calls xrefs
|
||||
-----------------------------------------------------------------------------------------------------------------------------------
|
||||
0x8000040 32 0 8 0x08000060 0x08000040
|
||||
0x8000060 12 0 3 0x0800006c 0x080000ac 0x08000040 0x080000a8
|
||||
0x800006c 4 0 1 0x08000070 0x08000040
|
||||
0x8000070 16 0 4 0x08000080 0x08000040 0x080000b4 0x080000d0 0x080000dc
|
||||
0x8000080 28 0 7 0x0800009c 0x08000040 0x080000e4 0x080000d8 0x080000bc
|
||||
0x800009c 16 0 4 0x08000060 0x08000040
|
||||
0x80000ac 8 0 2 0x08000040 0x08000068
|
||||
0x80000b4 8 0 2 0x080000bc 0x080000b4 0x080000c0 0x0800007c
|
||||
0x80000bc 4 0 1 0x080000b4 0x080000cc
|
||||
0x80000c0 16 0 4 0x080000c0 0x080000b8 0x080000e0 0x080000d4
|
||||
0x80000d0 8 0 2 0x080000d8 0x080000d0 0x080000c0 0x0800007c
|
||||
0x80000d8 4 0 1 0x080000d0 0x080000cc
|
||||
0x80000dc 8 0 2 0x080000e4 0x080000dc 0x080000c0 0x0800007c
|
||||
0x80000e4 4 0 1 0x080000dc 0x080000cc
|
||||
EOF
|
||||
EXPECT_ERR=<<EOF
|
||||
Finished reference recovery: OK
|
||||
Perform function deduction: OK
|
||||
WARNING: Failed to read chunk of size 0x101 at 0x8000040 from io.
|
||||
EOF
|
||||
RUN
|
||||
|
||||
NAME=Indirect call sparc
|
||||
FILE=bins/inquiry/interpreter/prototype/sparc_icall_malloc
|
||||
CMDS=<<EOF
|
||||
aIp -f sym.main
|
||||
pd 60 @ sym.some_ptr
|
||||
axl
|
||||
ablt
|
||||
EOF
|
||||
EXPECT=<<EOF
|
||||
; CALL XREF from sym.function_0 @ 0x8000060
|
||||
; CALL XREF from sym.function_1 @ 0x800007c
|
||||
; CALL XREF from sym.function_2 @ 0x8000098
|
||||
;-- section..text:
|
||||
;-- .text:
|
||||
/ sym.some_ptr();
|
||||
| 0x08000040 save sp, -0xb0, sp ; RELOC TARGET 64 .text @ 0x08000040 + 0x50 ; [01] -r-x section size 236 named .text
|
||||
| ;-- .bss:
|
||||
| 0x08000044 sethi 0x20000, g1 ; RELOC 0 .bss @ 0x08000148
|
||||
| ;-- .bss:
|
||||
| 0x08000048 or g1, 0x148, g1 ; RELOC 0 .bss @ 0x08000148
|
||||
| 0x0800004c mov g1, i0
|
||||
| 0x08000050 rett i7+8
|
||||
\ 0x08000054 nop
|
||||
; CALL XREF from sym.main @ 0x80000dc
|
||||
/ sym.function_0();
|
||||
| 0x08000058 save sp, -0xb0, sp
|
||||
| 0x0800005c call sym.some_ptr
|
||||
| 0x08000060 nop
|
||||
| ; RETURN XREF from sym.some_ptr @ 0x8000054
|
||||
| 0x08000064 mov o0, g1
|
||||
| 0x08000068 mov g1, i0
|
||||
| 0x0800006c rett i7+8
|
||||
\ 0x08000070 nop
|
||||
; CALL XREF from sym.main @ 0x80000dc
|
||||
/ sym.function_1();
|
||||
| 0x08000074 save sp, -0xb0, sp
|
||||
| 0x08000078 call sym.some_ptr
|
||||
| 0x0800007c nop
|
||||
| ; RETURN XREF from sym.some_ptr @ 0x8000054
|
||||
| 0x08000080 mov o0, g1
|
||||
| 0x08000084 mov g1, i0
|
||||
| 0x08000088 rett i7+8
|
||||
\ 0x0800008c nop
|
||||
; CALL XREF from sym.main @ 0x80000dc
|
||||
/ sym.function_2();
|
||||
| 0x08000090 save sp, -0xb0, sp
|
||||
| 0x08000094 call sym.some_ptr
|
||||
| 0x08000098 nop
|
||||
| ; RETURN XREF from sym.some_ptr @ 0x8000054
|
||||
| 0x0800009c mov o0, g1
|
||||
| 0x080000a0 mov g1, i0
|
||||
| 0x080000a4 rett i7+8
|
||||
\ 0x080000a8 nop
|
||||
/ int sym.main(int argc, char **argv, char **envp);
|
||||
| 0x080000ac save sp, -0xc0, sp
|
||||
| 0x080000b0 st g0, [fp+0x7fb]
|
||||
| 0x080000b4 st g0, [fp+0x7f7]
|
||||
| ,=< 0x080000b8 ba xcc, 0x8000108
|
||||
| | 0x080000bc nop
|
||||
| | ; CODE XREF from sym.main @ 0x8000114
|
||||
| | ;-- .data:
|
||||
| .--> 0x080000c0 sethi 0x20000, g1 ; RELOC 0 .data @ 0x08000130
|
||||
| :| ;-- .data:
|
||||
| :| 0x080000c4 or g1, 0x130, g2 ; RELOC 0 .data @ 0x08000130
|
||||
| :| 0x080000c8 ld [fp+0x7f7], g1
|
||||
| :| 0x080000cc srl g1, 0, g1
|
||||
| :| 0x080000d0 sllx g1, 3, g1
|
||||
| :| 0x080000d4 ldx [g2+g1], g1 ; 0x8000130
|
||||
| :| ; obj.fcn_arr
|
||||
| :| 0x080000d8 call g1
|
||||
| :| 0x080000dc nop
|
||||
| :| ; RETURN XREF from sym.function_0 @ 0x8000070
|
||||
| :| ; RETURN XREF from sym.function_1 @ 0x800008c
|
||||
| :| ; RETURN XREF from sym.function_2 @ 0x80000a8
|
||||
| :| 0x080000e0 stx o0, [fp+0x7ef]
|
||||
| :| 0x080000e4 ldx [fp+0x7ef], g1
|
||||
| :| 0x080000e8 ldub [g1], g1
|
||||
| :| 0x080000ec and g1, 0xff, g1
|
||||
| :| 0x080000f0 ld [fp+0x7fb], g2
|
||||
| :| 0x080000f4 add g2, g1, g1
|
||||
| :| 0x080000f8 st g1, [fp+0x7fb]
|
||||
| :| 0x080000fc ld [fp+0x7f7], g1
|
||||
| :| 0x08000100 add g1, 1, g1
|
||||
| :| 0x08000104 st g1, [fp+0x7f7]
|
||||
| :| ; CODE XREF from sym.main @ 0x80000bc
|
||||
| :`-> 0x08000108 ld [fp+0x7f7], g1
|
||||
| : 0x0800010c cmp g1, 2
|
||||
| `==< 0x08000110 bleu icc, reloc..data
|
||||
| ; CODE XREF from sym.main @ 0x80000e0
|
||||
| 0x08000114 nop
|
||||
| 0x08000118 ld [fp+0x7fb], g1
|
||||
| 0x0800011c sra g1, 0, g1
|
||||
| 0x08000120 mov g1, i0
|
||||
| 0x08000124 rett i7+8
|
||||
\ 0x08000128 nop
|
||||
0x0800012c invalid
|
||||
reloc..bss.8000048+12 0x8000054 -> RETURN -> 0x8000064 sym.function_0+12
|
||||
reloc..bss.8000048+12 0x8000054 -> RETURN -> 0x8000080 sym.function_1+12
|
||||
reloc..bss.8000048+12 0x8000054 -> RETURN -> 0x800009c sym.function_2+12
|
||||
sym.function_0+8 0x8000060 -> CALL -> 0x8000040 section..text
|
||||
sym.function_0+24 0x8000070 -> RETURN -> 0x80000e0 reloc..data.80000c4+28
|
||||
sym.function_1+8 0x800007c -> CALL -> 0x8000040 section..text
|
||||
sym.function_1+24 0x800008c -> RETURN -> 0x80000e0 reloc..data.80000c4+28
|
||||
sym.function_2+8 0x8000098 -> CALL -> 0x8000040 section..text
|
||||
sym.function_2+24 0x80000a8 -> RETURN -> 0x80000e0 reloc..data.80000c4+28
|
||||
sym.main+16 0x80000bc -> CODE -> 0x8000108 reloc..data.80000c4+68
|
||||
reloc..data.80000c4+16 0x80000d4 -> DATA -> 0x8000130 section..data
|
||||
reloc..data.80000c4+16 0x80000d4 -> DATA -> 0x8000138 reloc..text.8000138
|
||||
reloc..data.80000c4+16 0x80000d4 -> DATA -> 0x8000140 reloc..text.8000140
|
||||
reloc..data.80000c4+24 0x80000dc -> CALL -> 0x8000058 sym.function_0
|
||||
reloc..data.80000c4+24 0x80000dc -> CALL -> 0x8000074 sym.function_1
|
||||
reloc..data.80000c4+24 0x80000dc -> CALL -> 0x8000090 sym.function_2
|
||||
reloc..data.80000c4+28 0x80000e0 -> CODE -> 0x8000114 reloc..data.80000c4+80
|
||||
reloc..data.80000c4+80 0x8000114 -> CODE -> 0x80000c0 reloc..data
|
||||
addr size traced ninstr jump fail fcns calls xrefs
|
||||
-------------------------------------------------------------------------------------------------------------
|
||||
0x8000040 24 0 6 0x08000040 0x08000098 0x08000060 0x0800007c
|
||||
0x8000058 12 0 3 0x08000064 0x08000058 0x08000040 0x080000dc
|
||||
0x8000060 4 0 1
|
||||
0x8000064 16 0 4 0x08000058 0x08000054
|
||||
0x8000074 12 0 3 0x08000080 0x08000074 0x08000040 0x080000dc
|
||||
0x800007c 4 0 1
|
||||
0x8000080 16 0 4 0x08000074 0x08000054
|
||||
0x8000090 12 0 3 0x0800009c 0x08000090 0x08000040 0x080000dc
|
||||
0x8000098 4 0 1
|
||||
0x800009c 16 0 4 0x08000090 0x08000054
|
||||
0x80000ac 20 0 5 0x08000108 0x080000ac
|
||||
0x80000c0 32 0 8 0x080000e0 0x080000ac 0x08000114
|
||||
0x80000dc 4 0 1 0x080000e0
|
||||
0x80000e0 40 0 10 0x08000108 0x080000ac 0x0800008c 0x080000a8 0x08000070
|
||||
0x8000108 16 0 4 0x080000c0 0x08000118 0x080000ac 0x080000e0 0x080000bc
|
||||
0x8000114 4 0 1 0x080000e0
|
||||
0x8000118 20 0 5 0x080000ac
|
||||
EOF
|
||||
EXPECT_ERR=<<EOF
|
||||
WARNING: Unhandled conversion of ELF reloc 9 (R_SPARC_HI22)
|
||||
WARNING: Unhandled conversion of ELF reloc 12 (R_SPARC_LO10)
|
||||
WARNING: Unhandled conversion of ELF reloc 9 (R_SPARC_HI22)
|
||||
WARNING: Unhandled conversion of ELF reloc 12 (R_SPARC_LO10)
|
||||
Finished reference recovery: OK
|
||||
Perform function deduction: OK
|
||||
EOF
|
||||
RUN
|
||||
|
||||
NAME=Indirect call arm
|
||||
FILE=bins/inquiry/interpreter/prototype/arm_icall_malloc
|
||||
CMDS=<<EOF
|
||||
aIp -f sym.main
|
||||
pd 69
|
||||
axl
|
||||
ablt
|
||||
EOF
|
||||
EXPECT=<<EOF
|
||||
; CALL XREF from sym.function_0 @ 0x800005c
|
||||
; CALL XREF from sym.function_1 @ 0x800007c
|
||||
; CALL XREF from sym.function_2 @ 0x800009c
|
||||
;-- section..text:
|
||||
;-- .text:
|
||||
/ sym.some_ptr();
|
||||
| 0x08000034 str fp, [sp, -4]! ; [01] -r-x section size 256 named .text
|
||||
| 0x08000038 add fp, sp, 0
|
||||
| 0x0800003c ldr r3, loc.z ; [reloc..bss:4]=0x8000140 sym..comment ; "@\U00000001"
|
||||
| 0x08000040 mov r0, r3
|
||||
| 0x08000044 add sp, fp, 0
|
||||
| 0x08000048 pop {fp}
|
||||
\ 0x0800004c bx lr ; RELOC 0
|
||||
; DATA XREF from sym.some_ptr @ 0x800003c
|
||||
;-- .bss:
|
||||
0x08000050 stmdaeq r0, {r6, r8} ; RELOC 32 .bss @ 0x08000140
|
||||
; CALL XREF from sym.main @ 0x80000e4
|
||||
;-- function_0:
|
||||
/ sym.function_0();
|
||||
| 0x08000054 push {fp, lr} ; RELOC TARGET 32 function_0 @ 0x08000054
|
||||
| 0x08000058 add fp, sp, 4
|
||||
| 0x0800005c bl sym.some_ptr
|
||||
| ; RETURN XREF from sym.some_ptr @ 0x800004c
|
||||
| 0x08000060 mov r3, r0
|
||||
| 0x08000064 mov r0, r3
|
||||
| 0x08000068 sub sp, fp, 4
|
||||
| 0x0800006c pop {fp, lr}
|
||||
\ 0x08000070 bx lr ; RELOC 0
|
||||
; CALL XREF from sym.main @ 0x80000e4
|
||||
;-- function_1:
|
||||
/ sym.function_1();
|
||||
| 0x08000074 push {fp, lr} ; RELOC TARGET 32 function_1 @ 0x08000074
|
||||
| 0x08000078 add fp, sp, 4
|
||||
| 0x0800007c bl sym.some_ptr
|
||||
| ; RETURN XREF from sym.some_ptr @ 0x800004c
|
||||
| 0x08000080 mov r3, r0
|
||||
| 0x08000084 mov r0, r3
|
||||
| 0x08000088 sub sp, fp, 4
|
||||
| 0x0800008c pop {fp, lr}
|
||||
\ 0x08000090 bx lr ; RELOC 0
|
||||
;-- function_2:
|
||||
/ sym.function_2();
|
||||
| 0x08000094 push {fp, lr} ; RELOC TARGET 32 function_2 @ 0x08000094
|
||||
| 0x08000098 add fp, sp, 4
|
||||
| 0x0800009c bl sym.some_ptr
|
||||
| ; RETURN XREF from sym.some_ptr @ 0x800004c
|
||||
| 0x080000a0 mov r3, r0
|
||||
| 0x080000a4 mov r0, r3
|
||||
| 0x080000a8 sub sp, fp, 4
|
||||
| 0x080000ac pop {fp, lr}
|
||||
\ 0x080000b0 bx lr ; RELOC 0
|
||||
/ int sym.main(int argc, char **argv, char **envp);
|
||||
| 0x080000b4 push {fp, lr}
|
||||
| 0x080000b8 add fp, sp, 4
|
||||
| 0x080000bc sub sp, sp, 0x10
|
||||
| 0x080000c0 mov r3, 0
|
||||
| 0x080000c4 str r3, [fp, -8] ; 8
|
||||
| 0x080000c8 mov r3, 0
|
||||
| 0x080000cc str r3, [fp, -0xc] ; 12
|
||||
| ,=< 0x080000d0 b 0x8000110
|
||||
| | ; CODE XREF from sym.main @ 0x8000118
|
||||
| .--> 0x080000d4 ldr r2, obj.fcn_arr ; [reloc..data:4]=0x8000134 obj.fcn_arr ; "4\U00000001"
|
||||
| :| 0x080000d8 ldr r3, [fp, -0xc] ; 12
|
||||
| :| 0x080000dc ldr r3, [r2, r3, lsl 2] ; 0x8000130 ; "4\U00000001"
|
||||
| :| 0x080000e0 mov lr, pc
|
||||
| :| 0x080000e4 bx r3 ; RELOC 0
|
||||
| :| ; RETURN XREF from sym.function_0 @ 0x8000070
|
||||
| :| ; RETURN XREF from sym.function_1 @ 0x8000090
|
||||
| :| 0x080000e8 str r0, [fp, -0x10] ; 16
|
||||
| :| 0x080000ec ldr r3, [fp, -0x10] ; 16
|
||||
| :| 0x080000f0 ldrb r3, [r3]
|
||||
| :| 0x080000f4 mov r2, r3
|
||||
| :| 0x080000f8 ldr r3, [fp, -8] ; 8
|
||||
| :| 0x080000fc add r3, r3, r2
|
||||
| :| 0x08000100 str r3, [fp, -8] ; 8
|
||||
| :| 0x08000104 ldr r3, [fp, -0xc] ; 12
|
||||
| :| 0x08000108 add r3, r3, 1
|
||||
| :| 0x0800010c str r3, [fp, -0xc] ; 12
|
||||
| :| ; CODE XREF from sym.main @ 0x80000d0
|
||||
| :`-> 0x08000110 ldr r3, [fp, -0xc] ; 12
|
||||
| : 0x08000114 cmp r3, 2 ; 2
|
||||
| `==< 0x08000118 bls 0x80000d4
|
||||
| 0x0800011c ldr r3, [fp, -8] ; 8
|
||||
| 0x08000120 mov r0, r3
|
||||
| 0x08000124 sub sp, fp, 4
|
||||
| 0x08000128 pop {fp, lr}
|
||||
\ 0x0800012c bx lr ; RELOC 0
|
||||
; DATA XREFS from sym.main @ 0x80000d4, 0x80000dc
|
||||
;-- .data:
|
||||
0x08000130 stmdaeq r0, {r2, r4, r5, r8} ; RELOC 32 .data @ 0x08000134
|
||||
; DATA XREF from sym.main @ 0x80000dc
|
||||
;-- section..data:
|
||||
;-- .data:
|
||||
;-- function_0:
|
||||
;-- fcn_arr:
|
||||
0x08000134 .dword 0x08000054 ; reloc.target.function_0 ; sym.function_0; RELOC 32 function_0 @ 0x08000054 ; [03] -rw- section size 12 named .data
|
||||
; DATA XREF from sym.main @ 0x80000dc
|
||||
;-- function_1:
|
||||
0x08000138 .dword 0x08000074 ; reloc.target.function_1 ; sym.function_1; RELOC 32 function_1 @ 0x08000074
|
||||
;-- function_2:
|
||||
0x0800013c .dword 0x08000094 ; reloc.target.function_2 ; sym.function_2; RELOC 32 function_2 @ 0x08000094
|
||||
;-- section..bss:
|
||||
;-- section..comment:
|
||||
;-- .bss:
|
||||
;-- z:
|
||||
;-- .comment:
|
||||
0x08000140 .dword 0xffffffff ; RELOC TARGET 32 .bss @ 0x08000140 ; [06] ---- section size 36 named .comment
|
||||
0x08000144 invalid
|
||||
section..text+8 0x800003c -> DATA -> 0x8000050 reloc..bss
|
||||
section..text+24 0x800004c -> RETURN -> 0x8000060 reloc.target.function_0+12
|
||||
section..text+24 0x800004c -> RETURN -> 0x8000080 reloc.target.function_1+12
|
||||
section..text+24 0x800004c -> RETURN -> 0x80000a0 reloc.target.function_2+12
|
||||
reloc.target.function_0+8 0x800005c -> CALL -> 0x8000034 section..text
|
||||
reloc.target.function_0+28 0x8000070 -> RETURN -> 0x80000e8 sym.main+52
|
||||
reloc.target.function_1+8 0x800007c -> CALL -> 0x8000034 section..text
|
||||
reloc.target.function_1+28 0x8000090 -> RETURN -> 0x80000e8 sym.main+52
|
||||
reloc.target.function_2+8 0x800009c -> CALL -> 0x8000034 section..text
|
||||
sym.main+28 0x80000d0 -> CODE -> 0x8000110 sym.main+92
|
||||
sym.main+32 0x80000d4 -> DATA -> 0x8000130 reloc..data
|
||||
sym.main+40 0x80000dc -> DATA -> 0x8000130 reloc..data
|
||||
sym.main+40 0x80000dc -> DATA -> 0x8000134 section..data
|
||||
sym.main+40 0x80000dc -> DATA -> 0x8000138 reloc.function_1
|
||||
sym.main+48 0x80000e4 -> CALL -> 0x8000054 reloc.target.function_0
|
||||
sym.main+48 0x80000e4 -> CALL -> 0x8000074 reloc.target.function_1
|
||||
sym.main+100 0x8000118 -> CODE -> 0x80000d4 sym.main+32
|
||||
addr size traced ninstr jump fail fcns calls xrefs
|
||||
-------------------------------------------------------------------------------------------------------------
|
||||
0x8000034 28 0 7 0x08000034 0x0800005c 0x0800009c 0x0800007c
|
||||
0x8000050 4 0 1 0x08000054 0x0800003c
|
||||
0x8000054 12 0 3 0x08000060 0x08000054 0x08000034 0x080000e4
|
||||
0x8000060 20 0 5 0x08000054 0x0800004c
|
||||
0x8000074 12 0 3 0x08000080 0x08000074 0x08000034 0x080000e4
|
||||
0x8000080 20 0 5 0x08000074 0x0800004c
|
||||
0x8000094 12 0 3 0x080000a0 0x08000094 0x08000034
|
||||
0x80000a0 20 0 5 0x08000094 0x0800004c
|
||||
0x80000b4 32 0 8 0x08000110 0x080000b4
|
||||
0x80000d4 20 0 5 0x080000e8 0x080000b4 0x08000118
|
||||
0x80000e8 40 0 10 0x08000110 0x080000b4 0x08000090 0x08000070
|
||||
0x8000110 12 0 3 0x080000d4 0x0800011c 0x080000b4 0x080000d0
|
||||
0x800011c 20 0 5 0x080000b4
|
||||
0x8000134 1 0 1 0x080000dc
|
||||
EOF
|
||||
EXPECT_ERR=<<EOF
|
||||
WARNING: Unhandled conversion of ELF reloc 40 (R_ARM_V4BX)
|
||||
WARNING: Unhandled conversion of ELF reloc 40 (R_ARM_V4BX)
|
||||
WARNING: Unhandled conversion of ELF reloc 40 (R_ARM_V4BX)
|
||||
WARNING: Unhandled conversion of ELF reloc 40 (R_ARM_V4BX)
|
||||
WARNING: Unhandled conversion of ELF reloc 40 (R_ARM_V4BX)
|
||||
WARNING: Unhandled conversion of ELF reloc 40 (R_ARM_V4BX)
|
||||
Finished reference recovery: OK
|
||||
Perform function deduction: OK
|
||||
EOF
|
||||
RUN
|
||||
|
||||
NAME=Indirect call mips64
|
||||
FILE=bins/inquiry/interpreter/prototype/mips64_icall_malloc
|
||||
CMDS=<<EOF
|
||||
# Mips misses many relocations.
|
||||
# So the interpreter doesn't come far before a jump to 0x0 happens.
|
||||
aIp -f 0x08000164
|
||||
pd 41 @ 0x08000164
|
||||
axl
|
||||
ablt
|
||||
EOF
|
||||
EXPECT=<<EOF
|
||||
;-- main:
|
||||
/ int sym.main(int argc, char **argv, char **envp);
|
||||
| 0x08000164 daddiu sp, sp, -0x30 ; RELOC TARGET 32 main @ 0x08000164
|
||||
| 0x08000168 sd ra, 0x28(sp)
|
||||
| 0x0800016c sd fp, 0x20(sp)
|
||||
| 0x08000170 sd gp, 0x18(sp)
|
||||
| 0x08000174 move fp, sp
|
||||
| ;-- main:
|
||||
| 0x08000178 lui gp, 0 ; RELOC 0 main @ 0x08000164
|
||||
| 0x0800017c daddu gp, gp, t9
|
||||
| ;-- main:
|
||||
| 0x08000180 daddiu gp, gp, 0 ; RELOC 0 main @ 0x08000164
|
||||
| 0x08000184 sw zero, 0(fp)
|
||||
| 0x08000188 sw zero, 4(fp)
|
||||
| ,=< 0x0800018c b 0x80001dc
|
||||
| 0x08000190 nop
|
||||
| | ; CODE XREF from sym.main @ 0x80001e4
|
||||
| | ;-- .data.rel.local:
|
||||
| .--> 0x08000194 ld v0, 0(gp) ; RELOC 0 .data.rel.local @ 0x080002f0
|
||||
| :| 0x08000198 lwu v1, 4(fp)
|
||||
| :| 0x0800019c dsll v1, v1, 3
|
||||
| :| ;-- .data.rel.local:
|
||||
| :| 0x080001a0 daddiu v0, v0, 0 ; RELOC 0 .data.rel.local @ 0x080002f0
|
||||
| :| 0x080001a4 daddu v0, v1, v0
|
||||
| :| 0x080001a8 ld v0, 0(v0)
|
||||
| :| 0x080001ac move t9, v0
|
||||
| :| 0x080001b0 jalr t9
|
||||
:| 0x080001b4 nop
|
||||
:| 0x080001b8 sd v0, 8(fp)
|
||||
:| 0x080001bc ld v0, 8(fp)
|
||||
:| 0x080001c0 lbu v0, 0(v0)
|
||||
:| 0x080001c4 lw v1, 0(fp)
|
||||
:| 0x080001c8 addu v0, v1, v0
|
||||
:| 0x080001cc sw v0, 0(fp)
|
||||
:| 0x080001d0 lw v0, 4(fp)
|
||||
:| 0x080001d4 addiu v0, v0, 1
|
||||
:| 0x080001d8 sw v0, 4(fp)
|
||||
| :| ; CODE XREF from sym.main @ 0x800018c
|
||||
| :`-> 0x080001dc lw v0, 4(fp)
|
||||
| : 0x080001e0 sltiu v0, v0, 3
|
||||
| `==< 0x080001e4 bnez v0, reloc..data.rel.local
|
||||
| 0x080001e8 nop
|
||||
| 0x080001ec lw v0, 0(fp)
|
||||
| 0x080001f0 move sp, fp
|
||||
| 0x080001f4 ld ra, 0x28(sp)
|
||||
| 0x080001f8 ld fp, 0x20(sp)
|
||||
| 0x080001fc ld gp, 0x18(sp)
|
||||
| 0x08000200 daddiu sp, sp, 0x30
|
||||
\ 0x08000204 jr ra
|
||||
reloc.main.8000180+12 0x800018c -> CODE -> 0x80001dc reloc..data.rel.local.80001a0+60
|
||||
reloc..data.rel.local.80001a0+68 0x80001e4 -> CODE -> 0x8000194 reloc..data.rel.local
|
||||
addr size traced ninstr jump fail fcns calls xrefs
|
||||
---------------------------------------------------------------------------------
|
||||
0x8000040 48 0 12 0x08000040
|
||||
0x8000070 4 0 1
|
||||
0x8000074 48 0 12 0x08000074
|
||||
0x80000a4 28 0 7
|
||||
0x80000c0 4 0 1
|
||||
0x80000c4 48 0 12 0x080000c4
|
||||
0x80000f4 28 0 7
|
||||
0x8000110 4 0 1
|
||||
0x8000114 48 0 12 0x08000114
|
||||
0x8000144 28 0 7
|
||||
0x8000160 4 0 1 0x08000164
|
||||
0x8000164 44 0 11 0x080001dc 0x08000164
|
||||
0x8000190 4 0 1
|
||||
0x8000194 32 0 8 0x08000164 0x080001e4
|
||||
0x80001b4 40 0 10 0x080001dc
|
||||
0x80001dc 12 0 3 0x08000194 0x080001e8 0x08000164 0x0800018c
|
||||
0x80001e8 32 0 8 0x08000164
|
||||
EOF
|
||||
EXPECT_ERR=<<EOF
|
||||
WARNING: MIPS: Unhandled patching case for relocation 333831.
|
||||
WARNING: MIPS: Unhandled patching case for relocation 399367.
|
||||
WARNING: Unhandled R_MIPS_GOT_PAGE reloc
|
||||
WARNING: Unhandled R_MIPS_GOT_OFST reloc
|
||||
WARNING: MIPS: Unhandled patching case for relocation 333831.
|
||||
WARNING: MIPS: Unhandled patching case for relocation 399367.
|
||||
WARNING: Unhandled R_MIPS_GOT_PAGE reloc
|
||||
WARNING: Unhandled R_MIPS_GOT_OFST reloc
|
||||
WARNING: Unhandled R_MIPS_JALR reloc
|
||||
WARNING: MIPS: Unhandled patching case for relocation 333831.
|
||||
WARNING: MIPS: Unhandled patching case for relocation 399367.
|
||||
WARNING: Unhandled R_MIPS_GOT_PAGE reloc
|
||||
WARNING: Unhandled R_MIPS_GOT_OFST reloc
|
||||
WARNING: Unhandled R_MIPS_JALR reloc
|
||||
WARNING: MIPS: Unhandled patching case for relocation 333831.
|
||||
WARNING: MIPS: Unhandled patching case for relocation 399367.
|
||||
WARNING: Unhandled R_MIPS_GOT_PAGE reloc
|
||||
WARNING: Unhandled R_MIPS_GOT_OFST reloc
|
||||
WARNING: Unhandled R_MIPS_JALR reloc
|
||||
WARNING: MIPS: Unhandled patching case for relocation 333831.
|
||||
WARNING: MIPS: Unhandled patching case for relocation 399367.
|
||||
WARNING: Unhandled R_MIPS_GOT_PAGE reloc
|
||||
WARNING: Unhandled R_MIPS_GOT_OFST reloc
|
||||
WARNING: Unhandled R_MIPS_64 reloc
|
||||
WARNING: Unhandled R_MIPS_64 reloc
|
||||
WARNING: Unhandled R_MIPS_64 reloc
|
||||
WARNING: Unhandled conversion of ELF reloc 333831 (R_MIPS_GPREL16)
|
||||
WARNING: Unhandled conversion of ELF reloc 399367 (R_MIPS_GPREL16)
|
||||
WARNING: Unhandled conversion of ELF reloc 20 (R_MIPS_GOT_PAGE)
|
||||
WARNING: Unhandled conversion of ELF reloc 21 (R_MIPS_GOT_OFST)
|
||||
WARNING: Unhandled conversion of ELF reloc 333831 (R_MIPS_GPREL16)
|
||||
WARNING: Unhandled conversion of ELF reloc 399367 (R_MIPS_GPREL16)
|
||||
WARNING: Unhandled conversion of ELF reloc 20 (R_MIPS_GOT_PAGE)
|
||||
WARNING: Unhandled conversion of ELF reloc 21 (R_MIPS_GOT_OFST)
|
||||
WARNING: Unhandled conversion of ELF reloc 37 (R_MIPS_JALR)
|
||||
WARNING: Unhandled conversion of ELF reloc 333831 (R_MIPS_GPREL16)
|
||||
WARNING: Unhandled conversion of ELF reloc 399367 (R_MIPS_GPREL16)
|
||||
WARNING: Unhandled conversion of ELF reloc 20 (R_MIPS_GOT_PAGE)
|
||||
WARNING: Unhandled conversion of ELF reloc 21 (R_MIPS_GOT_OFST)
|
||||
WARNING: Unhandled conversion of ELF reloc 37 (R_MIPS_JALR)
|
||||
WARNING: Unhandled conversion of ELF reloc 333831 (R_MIPS_GPREL16)
|
||||
WARNING: Unhandled conversion of ELF reloc 399367 (R_MIPS_GPREL16)
|
||||
WARNING: Unhandled conversion of ELF reloc 20 (R_MIPS_GOT_PAGE)
|
||||
WARNING: Unhandled conversion of ELF reloc 21 (R_MIPS_GOT_OFST)
|
||||
WARNING: Unhandled conversion of ELF reloc 37 (R_MIPS_JALR)
|
||||
WARNING: Unhandled conversion of ELF reloc 333831 (R_MIPS_GPREL16)
|
||||
WARNING: Unhandled conversion of ELF reloc 399367 (R_MIPS_GPREL16)
|
||||
WARNING: Unhandled conversion of ELF reloc 20 (R_MIPS_GOT_PAGE)
|
||||
WARNING: Unhandled conversion of ELF reloc 21 (R_MIPS_GOT_OFST)
|
||||
Finished reference recovery: OK
|
||||
Perform function deduction: OK
|
||||
WARNING: Failed to read chunk of size 0x101 at 0x8000164 from io.
|
||||
EOF
|
||||
RUN
|
||||
Reference in New Issue
Block a user