I made pale analog of world famous pdbdump to dump types and functions from DWARF. Before introducing my tool I have several words about DWARF - it is excess, compiler-specific, inconsistent and dangerous
Redudancy
ls -l llvm-dwarfdump
llvm-dwarfdump.stripped
-rwxrwxr-x 1 redp redp 471241104 mar 29 00:52 llvm-dwarfdump
-rwxrwxr-x 1 redp redp 22170696 mar 29 17:49 llvm-
dwarfdump
.stripped
grep console_printk vm.g | wc -l
2883
compiler-specific
<0><b>: Abbrev Number: 1 (DW_TAG_compile_unit)
<c> DW_AT_name : internal/cpu
<19> DW_AT_language : 22 (Go)
<1a> DW_AT_stmt_list : 0x0
<1e> DW_AT_low_pc : 0x401000
<26> DW_AT_ranges : 0x0
<2a> DW_AT_comp_dir : .
<2c> DW_AT_producer : Go cmd/compile go1.13.8
<44> Unknown AT value: 2905: cpu
Inconsistency
- order of tags, so you can have mix of formal parameters with types at the same nesting level
- which attributes are mandatory for tags - I saw lots of missed DW_AT_sibling for example
- encoding of addresses. You have DW_AT_low_pc for functions address. But also there is DW_AT_abstract_origin (and DW_AT_specification). The same function can have different addresses even in plain C via this attributes:
<1><191cde>: Abbrev Number: 194 (DW_TAG_subprogram)
<191ce0> DW_AT_external : 1
<191ce0> DW_AT_name : (indirect string, offset: 0x24d2f): perf_events_lapic_init
<191ce4> DW_AT_decl_file : 1
<191ce5> DW_AT_decl_line : 1719
<191ce7> DW_AT_decl_column : 6
<191ce8> DW_AT_prototyped : 1
<191ce8> DW_AT_inline : 1 (inlined)
<1><19a945>: Abbrev Number: 96 (DW_TAG_subprogram)
<19a946> DW_AT_abstract_origin: <0x191cde>
<19a94a> DW_AT_low_pc : 0xffffffff81004dc0
<1><19b3c7>: Abbrev Number: 96 (DW_TAG_subprogram)
<19b3c8> DW_AT_abstract_origin: <0x191cde>
<19b3cc> DW_AT_low_pc : 0xffffffff81007930
Dangerous
Features of dwarfdump
- JSON
- plain C and some subset of C++. This output my looks strange for other languages like Go. I am too lazy to develop renderers for other languages
What is not supported
command-line options
performance
ls -l libLTO.so.17git
-rwxrwxr-x 1 redp redp 3519267480 mar 28 23:47 libLTO.so.17git
time objdump -g -Wi ./libLTO.so.17git | tail
real 10m50,079s
user 10m29,327s
sys 0m52,881s
time llvm-dwarfdump --debug-info libLTO.so.17git | tail
real 8m13,707s
user 8m10,424s
sys 0m36,764s
time ../dumper -v -V -f -k -L libLTO.so.17git
| tail
real 1m11,879s
user 0m48,765s
sys 0m5,249s
example of output
struct restart_block {
// Offset 0x0
long unsigned int arch_data;
// Offset 0x8
long int (*fn)(struct restart_block*);
// Offset 0x10
union {
// Offset 0x0
struct {
// Offset 0x0
u32* uaddr;
// Offset 0x8
u32 val;
// Offset 0xC
u32 flags;
// Offset 0x10
u32 bitset;
// Offset 0x18
u64 time;
// Offset 0x20
u32* uaddr2;
} futex;
// Offset 0x0
struct {
// Offset 0x0
clockid_t clockid;
// Offset 0x4
enum timespec_type type;
// Offset 0x8
union {
// Offset 0x0
struct __kernel_timespec* rmtp;
// Offset 0x0
struct old_timespec32* compat_rmtp;
};
// Offset 0x10
u64 expires;
} nanosleep;
// Offset 0x0
struct {
// Offset 0x0
struct pollfd* ufds;
// Offset 0x8
int nfds;
// Offset 0xC
int has_timeout;
// Offset 0x10
long unsigned int tv_sec;
// Offset 0x18
long unsigned int tv_nsec;
} poll;
};
};
Function with strange calling convention from linux kernel:// Addr 0xFFFFFFFF810082F0
// TypeId 1A408F
// kobj id 1A40B1: OP_reg rdi
// attr id 1A40BF: OP_reg rsi
// i id 1A40CD: OP_reg rdx
umode_t not_visible(struct kobject* kobj,struct attribute* attr,int i);
// Size 0x18
struct tableRegNames {
// Offset 0x8
const const char** tab_;
// Offset 0x10
size_t tab_size;
// --- methods
tableRegNames(struct tableRegNames* this,struct tableRegNames&&);
tableRegNames(struct tableRegNames* this,const struct tableRegNames&);
// specification
// addr AC42 type_id 39AE5 _ZN13tableRegNamesC2EPKPKcm
tableRegNames(struct tableRegNames* this,const const char**,size_t);
// Vtbl index 2
// specification
// addr AC90 type_id 39A78
virtual const char* reg_name(struct tableRegNames* this,unsigned int);
// specifications: 2
// addr AD2A type_id 3998E _ZN13tableRegNamesD0Ev
// addr ACFC type_id 399BA _ZN13tableRegNamesD2Ev
virtual ~tableRegNames(struct tableRegNames* this,int);
};