Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add cache for source line #4129

Merged
merged 5 commits into from
Jan 20, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
145 changes: 105 additions & 40 deletions librz/bin/dbginfo.c
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@
// SPDX-License-Identifier: LGPL-3.0-only

#include <rz_types.h>
#include <rz_bin.h>
#include <rz_bin_source_line.h>
#include <ctype.h>

RZ_API void rz_bin_source_line_info_builder_init(RzBinSourceLineInfoBuilder *builder) {
rz_vector_init(&builder->samples, sizeof(RzBinSourceLineSample), NULL, NULL);
Expand Down Expand Up @@ -216,12 +217,14 @@ RZ_API const RzBinSourceLineSample *rz_bin_source_line_info_get_next(const RzBin
return next;
}

RZ_DEPRECATE RZ_API bool rz_bin_addr2line(RzBin *bin, ut64 addr, char *file, int len, int *line) {
rz_return_val_if_fail(bin, false);
if (!bin->cur || !bin->cur->o || !bin->cur->o->lines) {
return false;
}
const RzBinSourceLineSample *s = rz_bin_source_line_info_get_first_at(bin->cur->o->lines, addr);
RZ_API bool rz_bin_source_line_addr2line(
RZ_BORROW RZ_IN RZ_NONNULL const RzBinSourceLineInfo *sl,
ut64 addr,
RZ_BORROW RZ_OUT RZ_NULLABLE char *file,
int len,
RZ_BORROW RZ_OUT RZ_NULLABLE int *line) {
rz_return_val_if_fail(sl, false);
const RzBinSourceLineSample *s = rz_bin_source_line_info_get_first_at(sl, addr);
if (!s || s->address != addr) {
// consider only exact matches, not inside of samples
return false;
Expand All @@ -236,50 +239,112 @@ RZ_DEPRECATE RZ_API bool rz_bin_addr2line(RzBin *bin, ut64 addr, char *file, int
*file = 0;
}
}
return false;
return true;
}

RZ_DEPRECATE RZ_API char *rz_bin_addr2text(RzBin *bin, ut64 addr, int origin) {
rz_return_val_if_fail(bin, NULL);
if (!bin->cur || !bin->cur->o || !bin->cur->o->lines) {
return NULL;
static char *str_trim_left_right(char *l, char *r) {
l = (char *)rz_str_trim_head_ro(l);
for (; r > l && isspace(*r); --r) {
*r = '\0';
}
return l;
}

static void cache_lines(RzBinSourceLineCacheItem *x) {
if (!x->file_content) {
return;
}

char *p = x->file_content;
char *q = NULL;
do {
q = strchr(p, '\n');
if (!q) {
break;
}
*q = '\0';
p = str_trim_left_right(p, q);
rz_pvector_push(x->line_by_ln, p);
p = q + 1;
} while ((p && p - x->file_content < x->file_size));
}

static const char *read_line(const char *file, int line, RzBinSourceLineCache *cache) {
rz_return_val_if_fail(file && line >= 1, NULL);
if (!(cache && cache->items)) {
return rz_file_slurp_line(file, line, 0);
}
bool found = false;
char *content = NULL;
size_t sz = 0;
RzBinSourceLineCacheItem *item = ht_pp_find(cache->items, file, &found);
if (found) {
if (!(item && item->file_content)) {
return NULL;
} else {
return rz_pvector_at(item->line_by_ln, line - 1);
}
} else {
content = rz_file_slurp(file, &sz);
if (!content) {
ht_pp_insert(cache->items, file, NULL);
return NULL;
}
item = RZ_NEW0(RzBinSourceLineCacheItem);
if (!item) {
goto err;
}
item->file_content = content;
item->file_size = sz;
item->line_by_ln = rz_pvector_new(NULL);
if (!item->line_by_ln) {
goto err;
}
ht_pp_update(cache->items, file, item);

rz_pvector_reserve(item->line_by_ln, line);
cache_lines(item);
return rz_pvector_at(item->line_by_ln, line - 1);
}
err:
if (item) {
rz_pvector_free(item->line_by_ln);
}
const RzBinSourceLineSample *s = rz_bin_source_line_info_get_first_at(bin->cur->o->lines, addr);
if (s && s->address != addr) {
free(content);
free(item);
return NULL;
}

RZ_API RZ_OWN char *rz_bin_source_line_addr2text(
RZ_BORROW RZ_IN RZ_NONNULL const RzBinSourceLineInfo *sl, ut64 addr, RzDebugInfoOption opt) {
rz_return_val_if_fail(sl, NULL);
const RzBinSourceLineSample *s = rz_bin_source_line_info_get_first_at(sl, addr);
if (!(s && s->address == addr)) {
// consider only exact matches, not inside of samples
return NULL;
}
while (s && !s->file) {
s = rz_bin_source_line_info_get_next(bin->cur->o->lines, s);
s = rz_bin_source_line_info_get_next(sl, s);
}
if (!s) {
return NULL;
}
const char *file_nopath;
if (origin > 1) {
file_nopath = s->file;
} else {
file_nopath = strrchr(s->file, '/');
if (file_nopath) {
file_nopath++;
} else {
file_nopath = s->file;
}
}
const char *filepath = opt.abspath ? s->file : rz_file_basename(s->file);
if (!s->line) {
return strdup(file_nopath);
}
char *out = rz_file_slurp_line(s->file, s->line, 0);
if (out) {
rz_str_trim(out);
if (origin) {
char *res = rz_str_newf("%s:%d %s",
file_nopath, s->line,
out ? out : "");
free(out);
out = res;
}
return out;
return strdup(filepath);
}
return rz_str_newf("%s:%" PFMT32u, file_nopath, s->line);

RzStrBuf sb = { 0 };
rz_strbuf_initf(&sb, "%s:%" PFMT32u, filepath, s->line);
if (!opt.file) {
return rz_strbuf_drain_nofree(&sb);
}

const char *out = read_line(s->file, s->line, &opt.cache);
if (!out) {
return rz_strbuf_drain_nofree(&sb);
}

rz_strbuf_appendf(&sb, " %s", out);
return rz_strbuf_drain_nofree(&sb);
}
37 changes: 20 additions & 17 deletions librz/bin/dwarf/line.c
Original file line number Diff line number Diff line change
Expand Up @@ -222,17 +222,17 @@ 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 file_index the index of the file
* \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,
ut64 file_index) {
ut64 index) {
rz_return_val_if_fail(ctx && ctx->hdr, NULL);
if (file_index >= rz_vector_len(&ctx->hdr->file_names)) {
if (index >= rz_vector_len(&ctx->hdr->file_names)) {
return NULL;
}
RzBinDwarfFileEntry *file = rz_vector_index_ptr(&ctx->hdr->file_names, file_index);
RzBinDwarfFileEntry *file = rz_vector_index_ptr(&ctx->hdr->file_names, index);
if (!file->path_name) {
return NULL;
}
Expand All @@ -249,22 +249,25 @@ static char *full_file_path(
const char *comp_dir = ctx->dw && ctx->dw->info
? ht_up_find(ctx->dw->info->offset_comp_dir, ctx->hdr->offset, NULL)
: NULL;
const char *include_dir = NULL;
char *own_str = NULL;
if (file->directory_index > 0 && file->directory_index - 1 < rz_pvector_len(&ctx->hdr->directories)) {
include_dir = rz_pvector_at(&ctx->hdr->directories, file->directory_index - 1);
if (include_dir && include_dir[0] != '/' && comp_dir) {
include_dir = own_str = rz_str_newf("%s/%s/", comp_dir, include_dir);
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)
: NULL;
char *file_path_abs = NULL;
if (comp_dir && dir) {
if (dir[0] == '/') {
file_path_abs = rz_str_newf("%s/%s", dir, file->path_name);
} else {
file_path_abs = rz_str_newf("%s/%s/%s", comp_dir, dir, file->path_name);
}
} else if (comp_dir) {
file_path_abs = rz_str_newf("%s/%s", comp_dir, file->path_name);
} else if (dir) {
file_path_abs = rz_str_newf("%s/%s", dir, file->path_name);
} else {
include_dir = comp_dir;
}
if (!include_dir) {
include_dir = "./";
file_path_abs = rz_str_new(file->path_name);
}
char *r = rz_str_newf("%s/%s", include_dir, file->path_name);
free(own_str);
return r;
return file_path_abs;
}

static const char *full_file_path_cached(DWLineContext *ctx, ut64 file_index) {
Expand Down
6 changes: 5 additions & 1 deletion librz/core/cgraph.c
Original file line number Diff line number Diff line change
Expand Up @@ -416,8 +416,12 @@ static char *block_line(RzCore *core, ut64 addr, RzAnalysisBlock *bb) {
int line = 0, oline = 0, idx = 0;
int is_html = rz_cons_singleton()->is_html;
ut64 end = bb->addr + bb->size - 2;
RzBinObject *o = rz_bin_cur_object(core->bin);
RzBinSourceLineInfo *sl = o ? o->lines : NULL;
for (ut64 at = bb->addr; at < end; at += 2) {
rz_bin_addr2line(core->bin, at, file, sizeof(file) - 1, &line);
if (sl) {
rz_bin_source_line_addr2line(sl, at, file, sizeof(file) - 1, &line);
}
if (line != 0 && line != oline && strcmp(file, "??") != 0) {
file_str = rz_file_slurp_line(file, line, 0);
if (file_str) {
Expand Down
6 changes: 4 additions & 2 deletions librz/core/cmd/cmd_debug.c
Original file line number Diff line number Diff line change
Expand Up @@ -454,7 +454,9 @@ static bool step_line(RzCore *core, int times) {
}
file[0] = 0;
file2[0] = 0;
if (rz_bin_addr2line(core->bin, off, file, sizeof(file), &line)) {
RzBinObject *o = rz_bin_cur_object(core->bin);
RzBinSourceLineInfo *sl = o ? o->lines : NULL;
if (sl && rz_bin_source_line_addr2line(sl, off, file, sizeof(file), &line)) {
char *ptr = rz_file_slurp_line(file, line, 0);
RZ_LOG_INFO("--> 0x%08" PFMT64x " %s : %d\n", off, file, line);
RZ_LOG_INFO("--> %s\n", ptr);
Expand All @@ -467,7 +469,7 @@ static bool step_line(RzCore *core, int times) {
do {
rz_debug_step(core->dbg, 1);
off = rz_debug_reg_get(core->dbg, "PC");
if (!rz_bin_addr2line(core->bin, off, file2, sizeof(file2), &line2)) {
if (!(sl && rz_bin_source_line_addr2line(sl, off, file2, sizeof(file2), &line2))) {
if (find_meta) {
continue;
}
Expand Down
72 changes: 30 additions & 42 deletions librz/core/disasm.c
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,8 @@ typedef struct {
int tracespace;
int cyclespace;
int show_indent;
ut32 debuginfo;
RzDebugInfoOption debuginfo;

bool show_size;
bool show_trace;
bool show_family;
Expand Down Expand Up @@ -270,24 +271,6 @@ typedef struct {
RzPVector /*<RzAnalysisDisasmText *>*/ *vec;
} RzDisasmState;

// Function to set or clear a flag based on a boolean value
static inline void set_flag(uint32_t *flags, uint32_t flag, bool value) {
if (value) {
// Set the flag
*flags |= flag;
} else {
// Clear the flag
*flags &= ~flag;
}
}

enum debuginfo_flag_enum_t {
DEBUGINFO = 1 << 0,
DEBUGINFO_ABSPATH = 1 << 1,
DEBUGINFO_FILE = 1 << 2,
DEBUGINFO_LINES = 1 << 3,
};

static void ds_setup_print_pre(RzDisasmState *ds, bool tail, bool middle);
static void ds_setup_pre(RzDisasmState *ds, bool tail, bool middle);
static void ds_print_pre(RzDisasmState *ds, bool fcnline);
Expand Down Expand Up @@ -566,6 +549,22 @@ static void ds_print_esil_analysis_fini(RzDisasmState *ds) {
}
}

static void RzBinSourceLineCacheItem_free(RzBinSourceLineCacheItem *x) {
if (!x) {
return;
}
free(x->file_content);
rz_pvector_free(x->line_by_ln);
free(x);
}

static void RzBinSourceLineCacheItem_HtPPKv_free(HtPPKv *x) {
if (!x) {
return;
}
RzBinSourceLineCacheItem_free(x->value);
}

static RzDisasmState *ds_init(RzCore *core) {
RzDisasmState *ds = RZ_NEW0(RzDisasmState);
if (!ds) {
Expand Down Expand Up @@ -631,10 +630,11 @@ static RzDisasmState *ds_init(RzCore *core) {
ds->tracespace = rz_config_get_i(core->config, "asm.tracespace");
ds->cyclespace = rz_config_get_i(core->config, "asm.cyclespace");

set_flag(&ds->debuginfo, DEBUGINFO, rz_config_get_b(core->config, "asm.debuginfo"));
set_flag(&ds->debuginfo, DEBUGINFO_FILE, rz_config_get_b(core->config, "asm.debuginfo.file"));
set_flag(&ds->debuginfo, DEBUGINFO_ABSPATH, rz_config_get_b(core->config, "asm.debuginfo.abspath"));
set_flag(&ds->debuginfo, DEBUGINFO_LINES, rz_config_get_b(core->config, "asm.debuginfo.lines"));
ds->debuginfo.enable = rz_config_get_b(core->config, "asm.debuginfo");
ds->debuginfo.file = rz_config_get_b(core->config, "asm.debuginfo.file");
ds->debuginfo.abspath = rz_config_get_b(core->config, "asm.debuginfo.abspath");
ds->debuginfo.lines = rz_config_get_b(core->config, "asm.debuginfo.lines");
ds->debuginfo.cache.items = ht_pp_new(NULL, RzBinSourceLineCacheItem_HtPPKv_free, NULL);

ds->show_lines_call = ds->show_lines ? rz_config_get_b(core->config, "asm.lines.call") : false;
ds->show_lines_ret = ds->show_lines ? rz_config_get_b(core->config, "asm.lines.ret") : false;
Expand Down Expand Up @@ -838,6 +838,7 @@ static void ds_free(RzDisasmState *ds) {
ds_reflines_fini(ds);
ds_print_esil_analysis_fini(ds);
sdb_free(ds->ssa);
ht_pp_free(ds->debuginfo.cache.items);
free(ds->comment);
free(ds->line);
free(ds->line_col);
Expand Down Expand Up @@ -3699,36 +3700,23 @@ static void ds_align_comment(RzDisasmState *ds) {
}

static void ds_print_debuginfo(RzDisasmState *ds) {
if (!(ds->debuginfo & DEBUGINFO)) {
if (!ds->debuginfo.enable)
return;
}

if (ds->debuginfo & DEBUGINFO_LINES) {
// TODO: cache value in ds
int file_and_abspath = (ds->debuginfo & DEBUGINFO_FILE) ? 1 : 0;
file_and_abspath += (ds->debuginfo & DEBUGINFO_ABSPATH) ? 1 : 0;
RzBinObject *o = rz_bin_cur_object(ds->core->bin);
RzBinSourceLineInfo *sl = o ? o->lines : NULL;
if (ds->debuginfo.lines && sl) {
free(ds->sl);
ds->sl = rz_bin_addr2text(ds->core->bin, ds->at, file_and_abspath);
ds->sl = rz_bin_source_line_addr2text(sl, ds->at, ds->debuginfo);
if (RZ_STR_ISEMPTY(ds->sl))
return;
if (ds->osl && !(ds->osl && strcmp(ds->sl, ds->osl)))
return;
char *line = strdup(ds->sl);
rz_str_replace_char(line, '\t', ' ');
rz_str_replace_char(line, '\x1b', ' ');
rz_str_replace_char(line, '\r', ' ');
rz_str_replace_char(line, '\n', '\x00');
rz_str_trim(line);
if (RZ_STR_ISEMPTY(line)) {
free(line);
return;
}
ds_align_comment(ds);
theme_printf(comment, "; %s", line);
theme_printf(comment, "; %s", ds->sl);
free(ds->osl);
ds->osl = ds->sl;
ds->sl = NULL;
free(line);
}
}

Expand Down
Loading
Loading