Skip to content

Commit

Permalink
analysis/dwarf: load sourceline information for global variables (#4635)
Browse files Browse the repository at this point in the history
* refactor `rz_analysis_var_global_list_show`
* Adding source line information to global variables (DWARF only)
* Add test `global variables list`
  • Loading branch information
imbillow authored Sep 15, 2024
1 parent db1e499 commit a13438b
Show file tree
Hide file tree
Showing 10 changed files with 237 additions and 112 deletions.
64 changes: 46 additions & 18 deletions librz/arch/dwarf_process.c
Original file line number Diff line number Diff line change
Expand Up @@ -1399,6 +1399,7 @@ static bool function_var_parse(
const RzBinDwarfDie *var_die,
bool *has_unspecified_parameters) {
v->offset = var_die->offset;
v->cu_index = ctx->unit->index;
switch (var_die->tag) {
case DW_TAG_formal_parameter:
v->kind = RZ_ANALYSIS_VAR_KIND_FORMAL_PARAMETER;
Expand Down Expand Up @@ -1656,6 +1657,41 @@ static bool variable_exist_global(RzAnalysis *a, RzAnalysisDwarfVariable *v) {
return false;
}

static bool try_create_var_global(
RZ_BORROW RZ_IN RZ_NONNULL DwContext *ctx,
RZ_BORROW RZ_IN RZ_NONNULL const RzBinDwarfDie *die,
RzAnalysisDwarfVariable *v) {

bool result = false;
if (!(v->type && v->location->kind == RzBinDwarfLocationKind_ADDRESS)) {
goto beach;
}
if (variable_exist_global(ctx->analysis, v)) {
goto beach;
}

RzBinDwarfAttr *attr = NULL;
attr = rz_bin_dwarf_die_get_attr(die, DW_AT_decl_file);
RzBinDwarfLineUnit *lu = ctx->unit ? rz_pvector_at(ctx->dw->line->units, ctx->unit->index) : NULL;
ut64 file_index = attr ? rz_bin_dwarf_attr_udata(attr) : UT64_MAX;
const char *file = file_index != 0 && lu ? rz_bin_dwarf_file_path(ctx->dw, lu, file_index) : NULL;

attr = rz_bin_dwarf_die_get_attr(die, DW_AT_decl_line);
ut32 line = attr ? rz_bin_dwarf_attr_udata(attr) : UT32_MAX;

attr = rz_bin_dwarf_die_get_attr(die, DW_AT_decl_column);
ut32 column = attr ? rz_bin_dwarf_attr_udata(attr) : UT32_MAX;

result = rz_analysis_var_global_create_with_sourceline(
ctx->analysis, v->prefer_name, v->type, v->location->address,
file, line, column);

v->type = NULL;
beach:
variable_fini(v);
return result;
}

static bool variable_from_die(
RZ_BORROW RZ_IN RZ_NONNULL DwContext *ctx,
RZ_BORROW RZ_IN RZ_NONNULL const RzBinDwarfDie *die) {
Expand All @@ -1664,22 +1700,8 @@ static bool variable_from_die(
variable_fini(&v);
return false;
}
if (!(v.type && v.location->kind == RzBinDwarfLocationKind_ADDRESS)) {
variable_fini(&v);
return false;
}

if (variable_exist_global(ctx->analysis, &v)) {
variable_fini(&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;
return try_create_var_global(ctx, die, &v);
}

static void die_parse(DwContext *ctx, RzBinDwarfDie *die) {
Expand Down Expand Up @@ -1943,11 +1965,17 @@ static bool RzBinDwarfLocation_as_RzAnalysisVarStorage(
break;
}
case RzBinDwarfLocationKind_ADDRESS: {
if (variable_exist_global(a, dw_var)) {
RzBinDwarfDie *die = ht_up_find(a->debug_info->dw->info->die_by_offset, dw_var->offset, NULL);
if (!die) {
return false;
}
rz_analysis_var_global_create(a, dw_var->prefer_name,
rz_type_clone(dw_var->type), loc->address);
DwContext context = {
.analysis = a,
.dw = a->debug_info->dw,
.unit = rz_vector_index_ptr(&a->debug_info->dw->info->units, dw_var->cu_index),
.str_escaped = NULL
};
try_create_var_global(&context, die, dw_var);
rz_analysis_var_fini(var);
return false;
}
Expand Down
30 changes: 29 additions & 1 deletion librz/arch/var_global.c
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,9 @@ RZ_API RZ_OWN RzAnalysisVarGlobal *rz_analysis_var_global_new(RZ_NONNULL const c
glob->name = rz_str_dup(name);
glob->addr = addr;
glob->analysis = NULL;
glob->coord.decl_file = NULL;
glob->coord.decl_line = UT32_MAX;
glob->coord.decl_col = UT32_MAX;

return glob;
}
Expand Down Expand Up @@ -85,9 +88,14 @@ RZ_API bool rz_analysis_var_global_add(RzAnalysis *analysis, RZ_NONNULL RzAnalys
* \param name Global variable name
* \param type Global variable type
* \param addr Global variable address
* \param file File containing source declaration
* \param line Line number of source declaration
* \param colum Column position of source declaration
* \return true if succeed
*/
RZ_API bool rz_analysis_var_global_create(RzAnalysis *analysis, RZ_NONNULL const char *name, RZ_NONNULL RZ_BORROW RzType *type, ut64 addr) {
RZ_API bool rz_analysis_var_global_create_with_sourceline(RzAnalysis *analysis,
RZ_NONNULL const char *name, RZ_NONNULL RZ_BORROW RzType *type, ut64 addr,
RZ_NULLABLE const char *file, ut32 line, ut32 colum) {
rz_return_val_if_fail(analysis && name && type, false);

RzAnalysisVarGlobal *glob = rz_analysis_var_global_new(name, addr);
Expand All @@ -102,9 +110,29 @@ RZ_API bool rz_analysis_var_global_create(RzAnalysis *analysis, RZ_NONNULL const
return false;
}

glob->coord.decl_file = rz_str_constpool_get(&analysis->constpool, file);
glob->coord.decl_line = line;
glob->coord.decl_col = colum;

return true;
}

/**
* \brief Create the global variable and add into hashtable
*
* \param analysis RzAnalysis
* \param name Global variable name
* \param type Global variable type
* \param addr Global variable address
* \return true if succeed
*/
RZ_API bool rz_analysis_var_global_create(RzAnalysis *analysis,
RZ_NONNULL const char *name, RZ_NONNULL RZ_BORROW RzType *type, ut64 addr) {
rz_return_val_if_fail(analysis && name && type, false);
return rz_analysis_var_global_create_with_sourceline(
analysis, name, type, addr, NULL, UT32_MAX, UT32_MAX);
}

/**
* \brief Free the global variable instance
*
Expand Down
52 changes: 34 additions & 18 deletions librz/bin/dwarf/line.c
Original file line number Diff line number Diff line change
Expand Up @@ -205,18 +205,20 @@ static bool LineHdr_parse_v4(DWLineContext *ctx) {

/**
* \brief Get the full path from a file index, it will join the directory find in \p info with the filename
* \param ctx the context
* \param dw the DWARF instance
* \param hdr the RzBinDwarfLineUnitHdr instance
* \param index the index of the file
* \return the full path or NULL if the file index is invalid
*/
static char *full_file_path(
DWLineContext *ctx,
RzBinDWARF *dw,
RzBinDwarfLineUnitHdr *hdr,
ut64 index) {
rz_return_val_if_fail(ctx && ctx->hdr, NULL);
if (index >= rz_vector_len(&ctx->hdr->file_names)) {
rz_return_val_if_fail(hdr, NULL);
if (index >= rz_vector_len(&hdr->file_names)) {
return NULL;
}
RzBinDwarfFileEntry *file = rz_vector_index_ptr(&ctx->hdr->file_names, index);
RzBinDwarfFileEntry *file = rz_vector_index_ptr(&hdr->file_names, index);
if (!file->path_name) {
return NULL;
}
Expand All @@ -230,12 +232,12 @@ static char *full_file_path(
* or backslashes anyway, we will simply use slashes always here.
*/

const char *comp_dir = ctx->dw && ctx->dw->info
? ht_up_find(ctx->dw->info->offset_comp_dir, ctx->hdr->offset, NULL)
const char *comp_dir = dw && dw->info
? ht_up_find(dw->info->comp_dir_by_offset, hdr->offset, NULL)
: NULL;
const ut64 dir_index = ctx->hdr->encoding.version < 5 ? file->directory_index - 1 : file->directory_index;
const char *dir = (dir_index >= 0 && dir_index < rz_pvector_len(&ctx->hdr->directories))
? rz_pvector_at(&ctx->hdr->directories, dir_index)
const ut64 dir_index = hdr->encoding.version < 5 ? file->directory_index - 1 : file->directory_index;
const char *dir = (dir_index >= 0 && dir_index < rz_pvector_len(&hdr->directories))
? rz_pvector_at(&hdr->directories, dir_index)
: NULL;
char *file_path_abs = NULL;
if (comp_dir && dir) {
Expand All @@ -254,6 +256,19 @@ static char *full_file_path(
return file_path_abs;
}

/**
* \brief Get the full path from a file index, it will join the directory find in \p info with the filename
* \param dw the DWARF instance
* \param lu the RzBinDwarfLineUnit instance
* \param index the index of the file
* \return the full path or NULL if the file index is invalid
*/
RZ_API char *rz_bin_dwarf_file_path(RZ_NONNULL RZ_BORROW RzBinDWARF *dw,
RZ_NONNULL RZ_BORROW RzBinDwarfLineUnit *lu, ut64 index) {
rz_return_val_if_fail(dw && lu, NULL);
return full_file_path(dw, &lu->hdr, index);
}

static const char *full_file_path_cached(DWLineContext *ctx, ut64 file_index) {
if (ctx->hdr->encoding.version <= 4) {
file_index -= 1;
Expand All @@ -267,7 +282,7 @@ static const char *full_file_path_cached(DWLineContext *ctx, ut64 file_index) {
}
char *path = rz_pvector_at(ctx->file_path_cache, file_index);
if (!path) {
path = full_file_path(ctx, file_index);
path = full_file_path(ctx->dw, ctx->hdr, file_index);
rz_pvector_set(ctx->file_path_cache, file_index, path);
}
return path;
Expand Down Expand Up @@ -636,7 +651,7 @@ static RzBinDwarfLine *Line_parse(
return NULL;
}
li->R = R;
li->units = rz_list_newf((RzListFree)LineUnit_free);
li->units = rz_pvector_new((RzPVectorFree)LineUnit_free);
if (!li->units) {
free(li);
return NULL;
Expand Down Expand Up @@ -678,7 +693,7 @@ static RzBinDwarfLine *Line_parse(
}

rz_pvector_free(ctx.file_path_cache);
rz_list_push(li->units, unit);
rz_pvector_push(li->units, unit);
}
li->lines = rz_bin_source_line_info_builder_build_and_fini(&source_line_info_builder);
return li;
Expand All @@ -689,7 +704,7 @@ RZ_API void rz_bin_dwarf_line_free(RZ_OWN RZ_NULLABLE RzBinDwarfLine *li) {
return;
}
R_free(li->R);
rz_list_free(li->units);
rz_pvector_free(li->units);
rz_bin_source_line_info_free(li->lines);
free(li);
}
Expand Down Expand Up @@ -854,16 +869,17 @@ RZ_API void rz_bin_dwarf_line_units_dump(
RZ_NONNULL RZ_BORROW RzBinDwarfLine *line,
RZ_NONNULL RZ_BORROW RzStrBuf *sb) {
rz_return_if_fail(line && line->R && sb);
if (!(rz_list_empty(line->units))) {
if (!(rz_pvector_empty(line->units))) {
rz_strbuf_append(sb, ".debug_line content:\n");
}
RzListIter *it;
void **it;
RzBinDwarfLineUnit *unit;
bool first = true;
rz_list_foreach (line->units, it, unit) {
if (!unit) {
rz_pvector_foreach (line->units, it) {
if (!it) {
continue;
}
unit = *it;
if (first) {
first = false;
} else {
Expand Down
10 changes: 6 additions & 4 deletions librz/bin/dwarf/unit.c
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ static void CU_attr_apply(DebugInfoContext *ctx, RzBinDwarfCompUnit *cu, RzBinDw
return;
offset_comp_dir:
if (cu->stmt_list < UT64_MAX && cu->comp_dir) {
ht_up_insert(ctx->info->offset_comp_dir, cu->stmt_list, (void *)cu->comp_dir);
ht_up_insert(ctx->info->comp_dir_by_offset, cu->stmt_list, (void *)cu->comp_dir);
}
}

Expand Down Expand Up @@ -264,6 +264,7 @@ static bool CU_Hdr_parse(DebugInfoContext *ctx, RzBinDwarfCompUnitHdr *hdr) {
*/
static bool CU_parse_all(DebugInfoContext *ctx) {
RzBinEndianReader *buffer = ctx->info->R;
ut64 index = 0;
while (true) {
ut64 offset = R_tell(buffer);
if (offset >= R_size(buffer)) {
Expand Down Expand Up @@ -293,6 +294,7 @@ static bool CU_parse_all(DebugInfoContext *ctx) {
unit.offset, unit.hdr.length, unit.hdr.abbrev_offset);
CU_dies_parse(ctx, &unit, tbl);
ctx->info->die_count += rz_vector_len(&unit.dies);
unit.index = index++;
rz_vector_push(&ctx->info->units, &unit);
}
return true;
Expand All @@ -314,9 +316,9 @@ RZ_API RZ_BORROW RzBinDwarfAttr *rz_bin_dwarf_die_get_attr(

static bool info_init(RzBinDwarfInfo *info) {
rz_vector_init(&info->units, sizeof(RzBinDwarfCompUnit), (RzVectorFree)CU_fini, NULL);
info->offset_comp_dir = ht_up_new(NULL, NULL);
info->comp_dir_by_offset = ht_up_new(NULL, NULL);
info->location_encoding = ht_up_new(NULL, NULL);
if (!info->offset_comp_dir) {
if (!info->comp_dir_by_offset) {
goto beach;
}
return true;
Expand All @@ -331,7 +333,7 @@ static inline void info_free(RzBinDwarfInfo *info) {
}
R_free(info->R);
rz_vector_fini(&info->units);
ht_up_free(info->offset_comp_dir);
ht_up_free(info->comp_dir_by_offset);
ht_up_free(info->die_by_offset);
ht_up_free(info->unit_by_offset);
ht_up_free(info->location_encoding);
Expand Down
Loading

0 comments on commit a13438b

Please sign in to comment.