Skip to content

Commit

Permalink
Create global variable from DWARF (#3985)
Browse files Browse the repository at this point in the history
* Create global variable from DWARF
* Update test
* Add test "Static variables inside function"
* Clean typedb when apply_dwarf
  • Loading branch information
imbillow authored Nov 19, 2023
1 parent b9851b7 commit 947e9b5
Show file tree
Hide file tree
Showing 13 changed files with 745 additions and 74 deletions.
70 changes: 61 additions & 9 deletions librz/analysis/dwarf_process.c
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
#include "analysis_private.h"

typedef struct dwarf_parse_context_t {
const RzAnalysis *analysis;
RzAnalysis *analysis;
RzBinDwarfCompUnit *unit;
RzBinDWARF *dw;
} Context;
Expand Down Expand Up @@ -1390,7 +1390,12 @@ static bool function_var_parse(
v->kind = RZ_ANALYSIS_VAR_KIND_VARIABLE;
break;
case DW_TAG_unspecified_parameters:
*has_unspecified_parameters = f->has_unspecified_parameters = true;
if (f) {
f->has_unspecified_parameters = true;
}
if (has_unspecified_parameters) {
*has_unspecified_parameters = true;
}
return true;
default:
return false;
Expand Down Expand Up @@ -1444,7 +1449,8 @@ static bool function_var_parse(
return true;
}

static bool function_children_parse(Context *ctx, const RzBinDwarfDie *die, RzCallable *callable, RzAnalysisDwarfFunction *fn) {
static bool function_children_parse(
Context *ctx, const RzBinDwarfDie *die, RzCallable *callable, RzAnalysisDwarfFunction *fn) {
if (!die->has_children) {
return false;
}
Expand All @@ -1462,16 +1468,16 @@ static bool function_children_parse(Context *ctx, const RzBinDwarfDie *die, RzCa
RzAnalysisDwarfVariable v = { 0 };
bool has_unspecified_parameters = false;
if (!function_var_parse(ctx, fn, die, &v, child_die, &has_unspecified_parameters)) {
goto err;
goto loop_end;
}
if (has_unspecified_parameters) {
callable->has_unspecified_parameters = true;
goto err;
goto loop_end;
}
if (!v.type) {
RZ_LOG_ERROR("DWARF function %s variable %s failed\n",
fn->prefer_name, v.prefer_name);
goto err;
goto loop_end;
}
if (v.kind == RZ_ANALYSIS_VAR_KIND_FORMAL_PARAMETER) {
RzCallableArg *arg = rz_type_callable_arg_new(
Expand All @@ -1481,7 +1487,7 @@ static bool function_children_parse(Context *ctx, const RzBinDwarfDie *die, RzCa
rz_vector_push(&fn->variables, &v);
ht_up_insert(ctx->analysis->debug_info->variable_by_offset, v.offset, &v);
continue;
err:
loop_end:
variable_fini(&v);
}
rz_pvector_free(children);
Expand Down Expand Up @@ -1622,7 +1628,45 @@ static bool function_from_die(
return false;
}

static bool variable_exist_global(RzAnalysis *a, RzAnalysisDwarfVariable *v) {
RzAnalysisVarGlobal *existing_glob = NULL;
if ((existing_glob = rz_analysis_var_global_get_byaddr_in(a, v->location->address))) {
return true;
}
if ((existing_glob = rz_analysis_var_global_get_byname(a, v->prefer_name))) {
return true;
}
return false;
}

static bool variable_from_die(
RZ_BORROW RZ_IN RZ_NONNULL Context *ctx,
RZ_BORROW RZ_IN RZ_NONNULL const RzBinDwarfDie *die) {
RzAnalysisDwarfVariable v = { 0 };
if (!function_var_parse(ctx, NULL, NULL, &v, die, NULL)) {
return false;
}
if (!(v.type && v.location->kind == RzBinDwarfLocationKind_ADDRESS)) {
return false;
}

if (variable_exist_global(ctx->analysis, &v)) {
return false;
}

bool result = rz_analysis_var_global_create(
ctx->analysis, v.prefer_name, v.type, v.location->address);

v.type = NULL;
variable_fini(&v);
return result;
}

static void parse_die(Context *ctx, RzBinDwarfDie *die) {
if (set_u_contains(ctx->analysis->debug_info->visited, die->offset)) {
return;
}
set_u_add(ctx->analysis->debug_info->visited, die->offset);
switch (die->tag) {
case DW_TAG_structure_type:
case DW_TAG_union_type:
Expand All @@ -1638,6 +1682,9 @@ static void parse_die(Context *ctx, RzBinDwarfDie *die) {
case DW_TAG_subprogram:
function_from_die(ctx, die);
break;
case DW_TAG_variable:
variable_from_die(ctx, die);
break;
default:
break;
}
Expand All @@ -1650,7 +1697,7 @@ static void parse_die(Context *ctx, RzBinDwarfDie *die) {
* \param dw RzBinDwarf pointer
*/
RZ_API void rz_analysis_dwarf_preprocess_info(
RZ_NONNULL RZ_BORROW const RzAnalysis *analysis,
RZ_NONNULL RZ_BORROW RzAnalysis *analysis,
RZ_NONNULL RZ_BORROW RzBinDWARF *dw) {
rz_return_if_fail(analysis && dw);
if (!dw->info) {
Expand Down Expand Up @@ -1767,7 +1814,7 @@ static bool store_callable(void *u, ut64 k, const void *v) {
* \param analysis RzAnalysis pointer
* \param dw RzBinDwarf pointer
*/
RZ_API void rz_analysis_dwarf_process_info(const RzAnalysis *analysis, RzBinDWARF *dw) {
RZ_API void rz_analysis_dwarf_process_info(RzAnalysis *analysis, RzBinDWARF *dw) {
rz_return_if_fail(analysis && dw);
rz_analysis_dwarf_preprocess_info(analysis, dw);
ht_pp_foreach(analysis->debug_info->base_type_by_name, store_base_type, (void *)analysis);
Expand Down Expand Up @@ -1866,6 +1913,9 @@ static bool RzBinDwarfLocation_as_RzAnalysisVarStorage(
break;
}
case RzBinDwarfLocationKind_ADDRESS: {
if (variable_exist_global(a, dw_var)) {
return false;
}
rz_analysis_var_global_create(a, dw_var->prefer_name,
rz_type_clone(dw_var->type), loc->address);
rz_analysis_var_fini(var);
Expand Down Expand Up @@ -2007,6 +2057,7 @@ RZ_API RzAnalysisDebugInfo *rz_analysis_debug_info_new() {
debug_info->callable_by_offset = ht_up_new(NULL, HtUP_RzCallable_free, NULL);
debug_info->base_type_by_offset = ht_up_new(NULL, HtUP_RzBaseType_free, NULL);
debug_info->base_type_by_name = ht_pp_new(NULL, HtPP_RzPVector_free, NULL);
debug_info->visited = set_u_new();
return debug_info;
}

Expand All @@ -2026,5 +2077,6 @@ RZ_API void rz_analysis_debug_info_free(RzAnalysisDebugInfo *debuginfo) {
ht_up_free(debuginfo->base_type_by_offset);
ht_pp_free(debuginfo->base_type_by_name);
rz_bin_dwarf_free(debuginfo->dw);
set_u_free(debuginfo->visited);
free(debuginfo);
}
38 changes: 26 additions & 12 deletions librz/bin/dwarf/op.c
Original file line number Diff line number Diff line change
Expand Up @@ -692,7 +692,7 @@ RZ_API RZ_OWN RzBinDwarfEvaluation *rz_bin_dwarf_evaluation_new(
RZ_OWN RZ_NONNULL RzBinEndianReader *byte_code,
RZ_BORROW RZ_NONNULL const RzBinDWARF *dw,
RZ_BORROW RZ_NULLABLE const RzBinDwarfCompUnit *unit,
RZ_BORROW RZ_NULLABLE const RzBinDwarfDie *die) {
RZ_BORROW RZ_NULLABLE const RzBinDwarfDie *fn_die) {
rz_return_val_if_fail(byte_code && dw && unit, NULL);
RzBinDwarfEvaluation *self = RZ_NEW0(RzBinDwarfEvaluation);
RET_NULL_IF_FAIL(self);
Expand All @@ -704,7 +704,7 @@ RZ_API RZ_OWN RzBinDwarfEvaluation *rz_bin_dwarf_evaluation_new(
self->pc = RzBinEndianReader_clone(byte_code);
self->dw = dw;
self->unit = unit;
self->die = die;
self->fn_die = fn_die;
rz_vector_init(&self->stack, sizeof(RzBinDwarfValue), vec_Value_fini, NULL);
rz_vector_init(&self->expression_stack, sizeof(RzBinDwarfExprStackItem), vec_RzBinDwarfExprStackItem_fini, NULL);
rz_vector_init(&self->result, sizeof(RzBinDwarfPiece), (RzVectorFree)RzBinDwarfPiece_fini, NULL);
Expand Down Expand Up @@ -802,7 +802,8 @@ RZ_API void RzBinDwarfEvaluationResult_free(RZ_OWN RzBinDwarfEvaluationResult *s
break; \
}

static bool Evaluation_evaluate_one_operation(RzBinDwarfEvaluation *self, OperationEvaluationResult *out) {
static bool Evaluation_evaluate_one_operation(
RzBinDwarfEvaluation *self, OperationEvaluationResult *out) {
RzBinEndianReader *reader = self->pc;
Operation operation = { 0 };
bool ret = false;
Expand Down Expand Up @@ -968,7 +969,13 @@ static bool Evaluation_evaluate_one_operation(RzBinDwarfEvaluation *self, Operat
break;
}
case OPERATION_KIND_FRAME_OFFSET: {
RzBinDwarfAttr *fb_attr = rz_bin_dwarf_die_get_attr(self->die, DW_AT_frame_base);
if (!self->fn_die) {
out->kind = OperationEvaluationResult_WAITING;
out->waiting._1 = EvaluationStateWaiting_FbReg;
goto ok;
}

RzBinDwarfAttr *fb_attr = rz_bin_dwarf_die_get_attr(self->fn_die, DW_AT_frame_base);
ERR_IF_FAIL(fb_attr);
if (fb_attr->value.kind == RzBinDwarfAttr_UConstant) {
RzBinDwarfValue v = {
Expand All @@ -982,7 +989,7 @@ static bool Evaluation_evaluate_one_operation(RzBinDwarfEvaluation *self, Operat
rz_bin_dwarf_location_free(v.location));
break;
} else if (fb_attr->value.kind == RzBinDwarfAttr_Block) {
RzBinDwarfLocation *loc = rz_bin_dwarf_location_from_block(rz_bin_dwarf_attr_block(fb_attr), self->dw, self->unit, self->die);
RzBinDwarfLocation *loc = rz_bin_dwarf_location_from_block(rz_bin_dwarf_attr_block(fb_attr), self->dw, self->unit, self->fn_die);
if (!loc) {
RzBinDWARFDumpOption opt = {
.loclist_indent = "",
Expand Down Expand Up @@ -1107,16 +1114,23 @@ static bool Evaluation_evaluate_one_operation(RzBinDwarfEvaluation *self, Operat
goto ok;
}
case OPERATION_KIND_ADDRESS: {
out->kind = OperationEvaluationResult_WAITING;
out->waiting._1 = EvaluationStateWaiting_RelocatedAddress;
out->waiting._2.requires_relocated_address = operation.address.address;
out->kind = OperationEvaluationResult_COMPLETE;
out->complete.kind = RzBinDwarfLocationKind_ADDRESS;
out->complete.address = operation.address.address;
goto ok;
}
case OPERATION_KIND_ADDRESS_INDEX: {
out->kind = OperationEvaluationResult_WAITING;
out->waiting._1 = EvaluationStateWaiting_IndexedAddress;
out->waiting._2.requires_indexed_address.index = operation.address_index.index;
out->waiting._2.requires_indexed_address.relocate = true;
ut64 addr = 0;
if (self->dw && self->unit && rz_bin_dwarf_addr_get(self->dw->addr, &addr, self->unit->hdr.encoding.address_size, self->unit->addr_base, operation.address_index.index)) {
out->kind = OperationEvaluationResult_COMPLETE;
out->complete.kind = RzBinDwarfLocationKind_ADDRESS;
out->complete.address = addr;
} else {
out->kind = OperationEvaluationResult_WAITING;
out->waiting._1 = EvaluationStateWaiting_IndexedAddress;
out->waiting._2.requires_indexed_address.index = operation.address_index.index;
out->waiting._2.requires_indexed_address.relocate = true;
}
goto ok;
}
case OPERATION_KIND_CONSTANT_INDEX: {
Expand Down
5 changes: 5 additions & 0 deletions librz/core/cbin.c
Original file line number Diff line number Diff line change
Expand Up @@ -684,6 +684,11 @@ RZ_API bool rz_core_bin_apply_dwarf(RzCore *core, RzBinFile *binfile) {
return false;
}

rz_type_db_purge(core->analysis->typedb);
char *types_dir = rz_path_system(RZ_SDB_TYPES);
rz_type_db_reload(core->analysis->typedb, types_dir);
free(types_dir);

rz_analysis_debug_info_free(core->analysis->debug_info);
core->analysis->debug_info = rz_analysis_debug_info_new();
core->analysis->debug_info->dw = dw;
Expand Down
1 change: 1 addition & 0 deletions librz/core/cdwarf.c
Original file line number Diff line number Diff line change
Expand Up @@ -249,6 +249,7 @@ static bool htup_loclists_cb(void *u, ut64 k, const void *v) {
RzBinDWARFDumpOption dump_opt = {
.loclist_sep = ",\t",
.loclist_indent = "",
.expr_sep = ", "
};
rz_bin_dwarf_expression_dump(
&ctx->cu->hdr.encoding, entry->expression, ctx->sb, &dump_opt);
Expand Down
5 changes: 3 additions & 2 deletions librz/include/rz_analysis.h
Original file line number Diff line number Diff line change
Expand Up @@ -456,6 +456,7 @@ typedef struct {
HtPP /*<const char*, RzPVector<const RzBaseType *>>*/ *base_type_by_name; ///< Store all RzBaseType parsed from DWARF by DIE offset
DWARF_RegisterMapping dwarf_register_mapping; ///< Store the mapping function between DWARF registers number and register name in current architecture
RzBinDWARF *dw; ///< Holds ownership of RzBinDwarf, avoid releasing it prematurely
SetU *visited;
} RzAnalysisDebugInfo;

typedef struct rz_analysis_t {
Expand Down Expand Up @@ -2284,9 +2285,9 @@ RZ_API void rz_parse_pdb_types(const RzTypeDB *typedb, const RzPdb *pdb);

/* DWARF */
RZ_API void rz_analysis_dwarf_preprocess_info(
RZ_NONNULL RZ_BORROW const RzAnalysis *analysis,
RZ_NONNULL RZ_BORROW RzAnalysis *analysis,
RZ_NONNULL RZ_BORROW RzBinDWARF *dw);
RZ_API void rz_analysis_dwarf_process_info(const RzAnalysis *analysis, RzBinDWARF *dw);
RZ_API void rz_analysis_dwarf_process_info(RzAnalysis *analysis, RzBinDWARF *dw);
RZ_API void rz_analysis_dwarf_integrate_functions(RzAnalysis *analysis, RzFlag *flags);
RZ_API RzAnalysisDebugInfo *rz_analysis_debug_info_new();
RZ_API void rz_analysis_debug_info_free(RzAnalysisDebugInfo *debuginfo);
Expand Down
4 changes: 2 additions & 2 deletions librz/include/rz_bin_dwarf.h
Original file line number Diff line number Diff line change
Expand Up @@ -1608,7 +1608,7 @@ typedef struct {
typedef struct {
const RzBinDWARF *dw;
const RzBinDwarfCompUnit *unit;
const RzBinDwarfDie *die;
const RzBinDwarfDie *fn_die;
RzBinEndianReader *bytecode;
const RzBinDwarfEncoding *encoding;
ut64 *object_address;
Expand Down Expand Up @@ -1709,7 +1709,7 @@ RZ_API RZ_OWN RzBinDwarfEvaluation *rz_bin_dwarf_evaluation_new(
RZ_OWN RZ_NONNULL RzBinEndianReader *byte_code,
RZ_BORROW RZ_NONNULL const RzBinDWARF *dw,
RZ_BORROW RZ_NULLABLE const RzBinDwarfCompUnit *unit,
RZ_BORROW RZ_NULLABLE const RzBinDwarfDie *die);
RZ_BORROW RZ_NULLABLE const RzBinDwarfDie *fn_die);
RZ_API RZ_OWN RzBinDwarfEvaluation *rz_bin_dwarf_evaluation_new_from_block(
RZ_BORROW RZ_NONNULL const RzBinDwarfBlock *block,
RZ_BORROW RZ_NONNULL const RzBinDWARF *dw,
Expand Down
2 changes: 1 addition & 1 deletion test/db/abi/compilers/clang
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ CMDS=<<EOF
id~?
EOF
EXPECT=<<EOF
22327
22330
EOF
RUN

Expand Down
2 changes: 1 addition & 1 deletion test/db/abi/compilers/clang_64
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ CMDS=<<EOF
id~?
EOF
EXPECT=<<EOF
22442
22445
EOF
RUN

Expand Down
2 changes: 1 addition & 1 deletion test/db/abi/compilers/gcc
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ CMDS=<<EOF
id~?
EOF
EXPECT=<<EOF
25788
25791
EOF
RUN

Expand Down
2 changes: 1 addition & 1 deletion test/db/abi/compilers/gcc_64
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ CMDS=<<EOF
id~?
EOF
EXPECT=<<EOF
25945
25948
EOF
RUN

Expand Down
2 changes: 1 addition & 1 deletion test/db/cmd/cmd_flags
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ fs *
fsl~?*
EOF
EXPECT=<<EOF
8
9
EOF
RUN

Expand Down
Loading

0 comments on commit 947e9b5

Please sign in to comment.