From 459fc39f5b1af08805e7e114abf1f00e76cfbff9 Mon Sep 17 00:00:00 2001 From: Marc Date: Tue, 24 Jan 2017 18:51:27 +0100 Subject: [PATCH] Add debug info support for Dalvik (#6570) --- libr/bin/dbginfo.c | 2 +- libr/bin/dwarf.c | 14 +++----- libr/bin/format/dex/dex.h | 1 + libr/bin/p/bin_dbginfo_dex.c | 26 +++++++++++++++ libr/bin/p/bin_dbginfo_elf.c | 12 +++---- libr/bin/p/bin_dex.c | 62 ++++++++++++++++++++++++------------ libr/bin/p/dex.mk | 2 +- 7 files changed, 81 insertions(+), 38 deletions(-) create mode 100644 libr/bin/p/bin_dbginfo_dex.c diff --git a/libr/bin/dbginfo.c b/libr/bin/dbginfo.c index 76694805a5..53f3669ee8 100644 --- a/libr/bin/dbginfo.c +++ b/libr/bin/dbginfo.c @@ -72,7 +72,7 @@ R_API char *r_bin_addr2text(RBin *bin, ut64 addr, int origin) { // TODO: this is slow. must use a cached pool of mmaped files and line:off entries out = r_file_slurp_line (file, line, 0); if (!out) { - return 0; + return r_str_newf ("%s:%d", file, line); } out2 = malloc ((strlen (file) + 64 + strlen (out)) * sizeof (char)); if (origin > 1) { diff --git a/libr/bin/dwarf.c b/libr/bin/dwarf.c index 0e0f826bdb..9455c4169c 100644 --- a/libr/bin/dwarf.c +++ b/libr/bin/dwarf.c @@ -367,7 +367,7 @@ beach: static inline void add_sdb_addrline(Sdb *s, ut64 addr, const char *file, ut64 line, FILE *f, int mode) { const char *p; - char fileline[128]; + char *fileline; char offset[64]; char *offset_ptr; @@ -398,16 +398,10 @@ static inline void add_sdb_addrline(Sdb *s, ut64 addr, const char *file, ut64 li #else p = file; #endif - snprintf (fileline, sizeof (fileline) - 1, "%s|%"PFMT64d, p, line); + fileline = r_str_newf ("%s|%"PFMT64d, p, line); offset_ptr = sdb_itoa (addr, offset, 16); - - if (!sdb_add (s, offset_ptr, fileline, 0)) { - sdb_set (s, offset_ptr, fileline, 0); - } - - if (!sdb_add (s, fileline, offset_ptr, 0)) { - sdb_set (s, fileline, offset_ptr, 0); - } + sdb_add (s, offset_ptr, fileline, 0); + sdb_add (s, fileline, offset_ptr, 0); } static const ut8* r_bin_dwarf_parse_ext_opcode(const RBin *a, const ut8 *obuf, diff --git a/libr/bin/format/dex/dex.h b/libr/bin/format/dex/dex.h index 6b4c3b1bd9..9208824a58 100644 --- a/libr/bin/format/dex/dex.h +++ b/libr/bin/format/dex/dex.h @@ -118,6 +118,7 @@ struct dex_encoded_catch_handler_t { }; struct dex_debug_position_t { + ut32 source_file_idx; ut64 address; ut64 line; }; diff --git a/libr/bin/p/bin_dbginfo_dex.c b/libr/bin/p/bin_dbginfo_dex.c new file mode 100644 index 0000000000..5d6a3d56fe --- /dev/null +++ b/libr/bin/p/bin_dbginfo_dex.c @@ -0,0 +1,26 @@ +/* radare - LGPL - Copyright 2009-2016 - nibble, montekki, pancake */ + +#include +#include + +static int get_line(RBinFile *arch, ut64 addr, char *file, int len, int *line) { + if (arch->sdb_addrinfo) { + char offset[64]; + char *offset_ptr = sdb_itoa (addr, offset, 16); + char *ret = sdb_get (arch->sdb_addrinfo, offset_ptr, 0); + if (ret) { + char *p = strchr (ret, '|'); + if (p) { + *p = '\0'; + strncpy (file, ret, len); + *line = atoi (p + 1); + return true; + } + } + } + return false; +} + +struct r_bin_dbginfo_t r_bin_dbginfo_dex = { + .get_line = &get_line, +}; \ No newline at end of file diff --git a/libr/bin/p/bin_dbginfo_elf.c b/libr/bin/p/bin_dbginfo_elf.c index af1bec3946..0b226f0461 100644 --- a/libr/bin/p/bin_dbginfo_elf.c +++ b/libr/bin/p/bin_dbginfo_elf.c @@ -5,16 +5,16 @@ // TODO: use proper dwarf api here.. or deprecate static int get_line(RBinFile *arch, ut64 addr, char *file, int len, int *line) { - char *ret, *p, *offset_ptr, offset[64]; if (arch->sdb_addrinfo) { - offset_ptr = sdb_itoa (addr, offset, 16); - ret = sdb_get (arch->sdb_addrinfo, offset_ptr, 0); + char offset[64]; + char *offset_ptr = sdb_itoa (addr, offset, 16); + char *ret = sdb_get (arch->sdb_addrinfo, offset_ptr, 0); if (ret) { - p = strchr (ret, '|'); + char *p = strchr (ret, '|'); if (p) { *p = '\0'; - strncpy(file, ret, len); - *line = atoi(p + 1); + strncpy (file, ret, len); + *line = atoi (p + 1); return true; } } diff --git a/libr/bin/p/bin_dex.c b/libr/bin/p/bin_dex.c index c9a4239435..aa7b4b5d81 100644 --- a/libr/bin/p/bin_dex.c +++ b/libr/bin/p/bin_dex.c @@ -9,6 +9,8 @@ #define r_hash_adler32 __adler32 #include "../../hash/adler32.c" +extern struct r_bin_dbginfo_t r_bin_dbginfo_dex; + #define DEBUG_PRINTF 0 #if DEBUG_PRINTF @@ -26,7 +28,7 @@ static char *getstr(RBinDexObj *bin, int idx) { ut64 len; int uleblen; if (!bin || idx < 0 || idx >= bin->header.strings_size || - !bin->strings) { + !bin->strings) { return NULL; } if (bin->strings[idx] >= bin->size) { @@ -57,7 +59,7 @@ static char *getstr(RBinDexObj *bin, int idx) { char *str = calloc (1, len + 1); if (str) { r_buf_read_at (bin->b, (bin->strings[idx]) + uleblen, - (ut8 *)str, len); + (ut8 *)str, len); str[len] = 0; return str; } @@ -294,7 +296,7 @@ out_error: // https://github.com/android/platform_dalvik/blob/0641c2b4836fae3ee8daf6c0af45c316c84d5aeb/libdex/DexDebugInfo.cpp#L312 // https://github.com/android/platform_dalvik/blob/0641c2b4836fae3ee8daf6c0af45c316c84d5aeb/libdex/DexDebugInfo.cpp#L141 static void dex_parse_debug_item(RBinFile *binfile, RBinDexObj *bin, - RBinDexClass *c, int MI, int MA, int ins_size, + RBinDexClass *c, int MI, int MA, int paddr, int ins_size, int insns_size, char *class_name, int regsz, int debug_info_off) { struct r_bin_t *rbin = binfile->rbin; @@ -304,6 +306,7 @@ static void dex_parse_debug_item(RBinFile *binfile, RBinDexObj *bin, ut64 parameters_size; ut64 param_type_idx; ut16 argReg = regsz - ins_size; + ut32 source_file_idx = c->source_file; RList *params, *debug_positions, *emitted_debug_locals = NULL; bool keep = true; if (argReg >= regsz) { @@ -519,9 +522,8 @@ static void dex_parse_debug_item(RBinFile *binfile, RBinDexObj *bin, break; case 0x9: { - ut64 name_idx; - p4 = r_uleb128 (p4, p4_end - p4, &name_idx); - name_idx -= 1; + p4 = r_uleb128 (p4, p4_end - p4, &source_file_idx); + --source_file_idx; } break; default: @@ -535,6 +537,7 @@ static void dex_parse_debug_item(RBinFile *binfile, RBinDexObj *bin, keep = false; break; } + position->source_file_idx = source_file_idx; position->address = address; position->line = line; r_list_append (debug_positions, position); @@ -543,6 +546,24 @@ static void dex_parse_debug_item(RBinFile *binfile, RBinDexObj *bin, } opcode = *(p4++) & 0xff; } + + if (!binfile->sdb_addrinfo) { + binfile->sdb_addrinfo = sdb_new0 (); + } + + char *fileline; + char offset[64]; + char *offset_ptr; + + RListIter *iter1; + struct dex_debug_position_t *pos; + r_list_foreach (debug_positions, iter1, pos) { + fileline = r_str_newf ("%s|%"PFMT64d, getstr (bin, pos->source_file_idx), pos->line); + offset_ptr = sdb_itoa (pos->address + paddr, offset, 16); + sdb_set (binfile->sdb_addrinfo, offset_ptr, fileline, 0); + sdb_set (binfile->sdb_addrinfo, fileline, offset_ptr, 0); + } + if (!dexdump) { r_list_free (debug_positions); r_list_free (emitted_debug_locals); @@ -907,7 +928,7 @@ static const ut8 *parse_dex_class_fields(RBinFile *binfile, RBinDexObj *bin, break; } if (r_buf_read_at (binfile->buf, total, ff, - sizeof (DexField)) != sizeof (DexField)) { + sizeof (DexField)) != sizeof (DexField)) { break; } field.class_id = r_read_le16 (ff); @@ -1157,17 +1178,6 @@ static const ut8 *parse_dex_class_method(RBinFile *binfile, RBinDexObj *bin, } } - if (MC > 0 && debug_info_off > 0 && bin->header.data_offset < debug_info_off && - debug_info_off < bin->header.data_offset + bin->header.data_size) { - dex_parse_debug_item (binfile, bin, c, MI, MA, ins_size, - insns_size, cls->name, regsz, debug_info_off); - } else if (MC > 0) { - if (dexdump) { - rbin->cb_printf (" positions :\n"); - rbin->cb_printf (" locals :\n"); - } - } - if (*flag_name) { RBinSymbol *sym = R_NEW0 (RBinSymbol); sym->name = flag_name; @@ -1181,7 +1191,7 @@ static const ut8 *parse_dex_class_method(RBinFile *binfile, RBinDexObj *bin, sym->vaddr = MC;// + 0x10; sym->ordinal = (*sym_count)++; if (MC > 0) { - // TODO: parse debug info + if (r_buf_read_at (binfile->buf, binfile->buf->base + MC, ff2, 16) < 1) { R_FREE (sym); R_FREE (signature); @@ -1236,6 +1246,17 @@ static const ut8 *parse_dex_class_method(RBinFile *binfile, RBinDexObj *bin, // XXX memleak sym R_FREE (sym); } + + if (MC > 0 && debug_info_off > 0 && bin->header.data_offset < debug_info_off && + debug_info_off < bin->header.data_offset + bin->header.data_size) { + dex_parse_debug_item (binfile, bin, c, MI, MA, sym->paddr, ins_size, + insns_size, cls->name, regsz, debug_info_off); + } else if (MC > 0) { + if (dexdump) { + rbin->cb_printf (" positions :\n"); + rbin->cb_printf (" locals :\n"); + } + } } else { R_FREE (flag_name); } @@ -1791,7 +1812,8 @@ RBinPlugin r_bin_plugin_dex = { .header = &header, .size = &size, .get_offset = &getoffset, - .get_name = &getname + .get_name = &getname, + .dbginfo = &r_bin_dbginfo_dex, }; #ifndef CORELIB diff --git a/libr/bin/p/dex.mk b/libr/bin/p/dex.mk index 30348fe6ec..c54e5e2611 100644 --- a/libr/bin/p/dex.mk +++ b/libr/bin/p/dex.mk @@ -1,4 +1,4 @@ -OBJ_DEX=bin_dex.o ../format/dex/dex.o +OBJ_DEX=bin_dex.o bin_dbginfo_dex.o ../format/dex/dex.o STATIC_OBJ+=${OBJ_DEX} TARGET_DEX=bin_dex.${EXT_SO}