Skip to content

Commit

Permalink
dwarf: support non-native byte order
Browse files Browse the repository at this point in the history
This implements sniffing of the DWARF byte order from the header
(which isn't actually specified; thanks DWARF) and fixes the one
cursor operation that depends on byte order to use the detected byte
order instead of assuming the system's native byte order.

Fixes #19.
  • Loading branch information
Austin Clements committed Dec 2, 2016
1 parent 666596b commit d5ad1b9
Show file tree
Hide file tree
Showing 14 changed files with 314 additions and 15 deletions.
2 changes: 1 addition & 1 deletion dwarf/cursor.cc
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ cursor::subsection()
throw format_error("initial length has reserved value");
}
pos = begin + length;
return make_shared<section>(sec->type, begin, length, fmt);
return make_shared<section>(sec->type, begin, length, sec->ord, fmt);
}

void
Expand Down
2 changes: 0 additions & 2 deletions dwarf/dwarf++.hh
Original file line number Diff line number Diff line change
Expand Up @@ -53,8 +53,6 @@ struct cursor;

// XXX operator==/!= and hash functions

// XXX Support non-native byte order

// XXX Indicate DWARF4 in all spec references

// XXX Big missing support: .debug_aranges, .debug_frame, loclists,
Expand Down
20 changes: 17 additions & 3 deletions dwarf/dwarf.cc
Original file line number Diff line number Diff line change
Expand Up @@ -40,12 +40,26 @@ dwarf::dwarf(const std::shared_ptr<loader> &l)
data = l->load(section_type::info, &size);
if (!data)
throw format_error("required .debug_info section missing");
m->sec_info = make_shared<section>(section_type::info, data, size);
m->sec_info = make_shared<section>(section_type::info, data, size, byte_order::lsb);

// Sniff the endianness from the version field of the first
// CU. This is always a small but non-zero integer.
cursor endcur(m->sec_info);
// Skip length.
section_length length = endcur.fixed<uword>();
if (length == 0xffffffff)
endcur.fixed<uint64_t>();
// Get version in both little and big endian.
uhalf version = endcur.fixed<uhalf>();
uhalf versionbe = (version >> 8) | ((version & 0xFF) << 8);
if (versionbe < version) {
m->sec_info = make_shared<section>(section_type::info, data, size, byte_order::msb);
}

data = l->load(section_type::abbrev, &size);
if (!data)
throw format_error("required .debug_abbrev section missing");
m->sec_abbrev = make_shared<section>(section_type::abbrev, data, size);
m->sec_abbrev = make_shared<section>(section_type::abbrev, data, size, m->sec_info->ord);

// Get compilation units. Everything derives from these, so
// there's no point in doing it lazily.
Expand Down Expand Up @@ -108,7 +122,7 @@ dwarf::get_section(section_type type) const
if (!data)
throw format_error(std::string(elf::section_type_to_name(type))
+ " section missing");
m->sections[type] = std::make_shared<section>(section_type::str, data, size);
m->sections[type] = std::make_shared<section>(section_type::str, data, size, m->sec_info->ord);
return m->sections[type];
}

Expand Down
3 changes: 2 additions & 1 deletion dwarf/expr.cc
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,8 @@ expr::evaluate(expr_context *ctx, const std::initializer_list<taddr> &arguments)
shared_ptr<section> subsec
(make_shared<section>(cusec->type,
cusec->begin + offset, len,
cusec->fmt, cusec->addr_size));
cusec->ord, cusec->fmt,
cusec->addr_size));
cursor cur(subsec);

// Prepare the expression result. Some location descriptions
Expand Down
42 changes: 37 additions & 5 deletions dwarf/internal.hh
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,27 @@ enum class format
dwarf64
};

enum class byte_order
{
lsb,
msb
};

/**
* Return this system's native byte order.
*/
static inline byte_order
native_order()
{
static const union
{
int i;
char c[sizeof(int)];
} test = {1};

return test.c[0] == 1 ? byte_order::lsb : byte_order::msb;
}

/**
* A single DWARF section or a slice of a section. This also tracks
* dynamic information necessary to decode values in this section.
Expand All @@ -31,13 +52,15 @@ struct section
section_type type;
const char *begin, *end;
const format fmt;
const byte_order ord;
unsigned addr_size;

section(section_type type, const void *begin,
section_length length, format fmt = format::unknown,
section_length length,
byte_order ord, format fmt = format::unknown,
unsigned addr_size = 0)
: type(type), begin((char*)begin), end((char*)begin + length),
fmt(fmt), addr_size(addr_size) { }
fmt(fmt), ord(ord), addr_size(addr_size) { }

section(const section &o) = default;

Expand All @@ -53,7 +76,7 @@ struct section
return std::make_shared<section>(
type, begin+start,
std::min(len, (section_length)(end-begin)),
fmt, addr_size);
ord, fmt, addr_size);
}

size_t size() const
Expand Down Expand Up @@ -107,9 +130,18 @@ struct cursor
T fixed()
{
ensure(sizeof(T));
T val = *(T*)pos;
static_assert(sizeof(T) <= 8, "T too big");
uint64_t val = 0;
const unsigned char *p = (const unsigned char*)pos;
if (sec->ord == byte_order::lsb) {
for (unsigned i = 0; i < sizeof(T); i++)
val |= ((uint64_t)p[i]) << (i * 8);
} else {
for (unsigned i = 0; i < sizeof(T); i++)
val = (val << 8) | (uint64_t)p[i];
}
pos += sizeof(T);
return val;
return (T)val;
}

std::uint64_t uleb128()
Expand Down
4 changes: 2 additions & 2 deletions dwarf/rangelist.cc
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,8 @@ rangelist::rangelist(const initializer_list<pair<taddr, taddr> > &ranges)

sec = make_shared<section>(
section_type::ranges, (const char*)synthetic.data(),
synthetic.size() * sizeof(taddr), format::unknown,
sizeof(taddr));
synthetic.size() * sizeof(taddr),
native_order(), format::unknown, sizeof(taddr));

base_addr = 0;
}
Expand Down
6 changes: 6 additions & 0 deletions test/golden-gcc-6.2.1-s390x/NOTES
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
Built with

$ gcc -o golden-gcc-6.2.1-s390x/example -g -fdebug-prefix-map=$PWD=x example.c

using gcc 6.2.1 from Debian on s390x. This binary uses big-endian ELF
and DWARF.
Binary file added test/golden-gcc-6.2.1-s390x/example
Binary file not shown.
10 changes: 10 additions & 0 deletions test/golden-gcc-6.2.1-s390x/lines
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
--- <0>
x/example.c 2 0x768
x/example.c 3 0x77e
x/example.c 4 0x78a
x/example.c 5 0x792
x/example.c 6 0x7ce
x/example.c 9 0x7e0
x/example.c 10 0x7fc
x/example.c 11 0x80e

70 changes: 70 additions & 0 deletions test/golden-gcc-6.2.1-s390x/sections
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
[Nr] Name Type Address Offset
Size EntSize Flags Link Info Align
[ 0] null 0000000000000000 00000000
0000000000000000 0000000000000000 (shf)0x0 undef 0 0
[ 1] .interp progbits 0000000000000238 00000238
000000000000000f 0000000000000000 alloc undef 0 1
[ 2] .note.ABI-tag note 0000000000000248 00000248
0000000000000020 0000000000000000 alloc undef 0 4
[ 3] .note.gnu.build-id note 0000000000000268 00000268
0000000000000024 0000000000000000 alloc undef 0 4
[ 4] .gnu.hash (sht)0x6ffffff6 0000000000000290 00000290
0000000000000024 0000000000000000 alloc 5 0 8
[ 5] .dynsym dynsym 00000000000002b8 000002b8
00000000000000d8 0000000000000018 alloc 6 2 8
[ 6] .dynstr strtab 0000000000000390 00000390
000000000000008f 0000000000000000 alloc undef 0 1
[ 7] .gnu.version (sht)0x6fffffff 0000000000000420 00000420
0000000000000012 0000000000000002 alloc 5 0 2
[ 8] .gnu.version_r (sht)0x6ffffffe 0000000000000438 00000438
0000000000000020 0000000000000000 alloc 6 1 8
[ 9] .rela.dyn rela 0000000000000458 00000458
00000000000000d8 0000000000000018 alloc 5 0 8
[10] .rela.plt rela 0000000000000530 00000530
0000000000000030 0000000000000018 alloc|(shf)0x40 5 22 8
[11] .init progbits 0000000000000560 00000560
0000000000000040 0000000000000000 alloc|execinstr undef 0 4
[12] .plt progbits 00000000000005a0 000005a0
0000000000000060 0000000000000020 alloc|execinstr undef 0 4
[13] .text progbits 0000000000000600 00000600
0000000000000290 0000000000000000 alloc|execinstr undef 0 8
[14] .fini progbits 0000000000000890 00000890
000000000000002c 0000000000000000 alloc|execinstr undef 0 4
[15] .rodata progbits 00000000000008c0 000008c0
0000000000000020 0000000000000000 alloc undef 0 8
[16] .eh_frame_hdr progbits 00000000000008e0 000008e0
000000000000002c 0000000000000000 alloc undef 0 4
[17] .eh_frame progbits 0000000000000910 00000910
00000000000000d4 0000000000000000 alloc undef 0 8
[18] .init_array (sht)0xe 0000000000001e08 00000e08
0000000000000008 0000000000000008 write|alloc undef 0 8
[19] .fini_array (sht)0xf 0000000000001e10 00000e10
0000000000000008 0000000000000008 write|alloc undef 0 8
[20] .jcr progbits 0000000000001e18 00000e18
0000000000000008 0000000000000000 write|alloc undef 0 8
[21] .dynamic dynamic 0000000000001e20 00000e20
00000000000001e0 0000000000000010 write|alloc 6 0 8
[22] .got progbits 0000000000002000 00001000
0000000000000058 0000000000000008 write|alloc undef 0 8
[23] .data progbits 0000000000002058 00001058
0000000000000010 0000000000000000 write|alloc undef 0 8
[24] .bss nobits 0000000000002068 00001068
0000000000000008 0000000000000000 write|alloc undef 0 4
[25] .comment progbits 0000000000000000 00001068
0000000000000025 0000000000000001 (shf)0x30 undef 0 1
[26] .debug_aranges progbits 0000000000000000 0000108d
0000000000000030 0000000000000000 (shf)0x0 undef 0 1
[27] .debug_info progbits 0000000000000000 000010bd
00000000000000b1 0000000000000000 (shf)0x0 undef 0 1
[28] .debug_abbrev progbits 0000000000000000 0000116e
0000000000000087 0000000000000000 (shf)0x0 undef 0 1
[29] .debug_line progbits 0000000000000000 000011f5
0000000000000048 0000000000000000 (shf)0x0 undef 0 1
[30] .debug_str progbits 0000000000000000 0000123d
0000000000000051 0000000000000001 (shf)0x30 undef 0 1
[31] .symtab symtab 0000000000000000 00001290
00000000000006a8 0000000000000018 (shf)0x0 32 50 8
[32] .strtab strtab 0000000000000000 00001938
0000000000000220 0000000000000000 (shf)0x0 undef 0 1
[33] .shstrtab strtab 0000000000000000 00001b58
000000000000013f 0000000000000000 (shf)0x0 undef 0 1
20 changes: 20 additions & 0 deletions test/golden-gcc-6.2.1-s390x/segments
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
Type Offset VirtAddr PhysAddr
FileSiz MemSiz Flags Align
phdr 0x0000000000000040 0x0000000000000040 0x0000000000000040
0x00000000000001f8 0x00000000000001f8 x|r 8
interp 0x0000000000000238 0x0000000000000238 0x0000000000000238
0x000000000000000f 0x000000000000000f r 1
load 0x0000000000000000 0x0000000000000000 0x0000000000000000
0x00000000000009e4 0x00000000000009e4 x|r 1000
load 0x0000000000000e08 0x0000000000001e08 0x0000000000001e08
0x0000000000000260 0x0000000000000268 w|r 1000
dynamic 0x0000000000000e20 0x0000000000001e20 0x0000000000001e20
0x00000000000001e0 0x00000000000001e0 w|r 8
note 0x0000000000000248 0x0000000000000248 0x0000000000000248
0x0000000000000044 0x0000000000000044 r 4
(pt)0x6474e550 0x00000000000008e0 0x00000000000008e0 0x00000000000008e0
0x000000000000002c 0x000000000000002c r 4
(pt)0x6474e551 0x0000000000000000 0x0000000000000000 0x0000000000000000
0x0000000000000000 0x0000000000000000 w|r 10
(pt)0x6474e552 0x0000000000000e08 0x0000000000001e08 0x0000000000001e08
0x00000000000001f8 0x00000000000001f8 r 1
84 changes: 84 additions & 0 deletions test/golden-gcc-6.2.1-s390x/syms
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
Symbol table '.dynsym':
Num: Value Size Type Binding Index Name
0: 0000000000000000 0 notype local undef
1: 0000000000000560 0 section local 11
2: 0000000000000000 0 func weak undef __cxa_finalize
3: 0000000000000000 0 notype weak undef _ITM_deregisterTMCloneTable
4: 0000000000000000 0 notype weak undef __gmon_start__
5: 0000000000000000 0 func global undef __libc_start_main
6: 0000000000000000 0 notype weak undef _Jv_RegisterClasses
7: 0000000000000000 0 notype weak undef _ITM_registerTMCloneTable
8: 00000000000007e0 64 func global 13 main
Symbol table '.symtab':
Num: Value Size Type Binding Index Name
0: 0000000000000000 0 notype local undef
1: 0000000000000238 0 section local 1
2: 0000000000000248 0 section local 2
3: 0000000000000268 0 section local 3
4: 0000000000000290 0 section local 4
5: 00000000000002b8 0 section local 5
6: 0000000000000390 0 section local 6
7: 0000000000000420 0 section local 7
8: 0000000000000438 0 section local 8
9: 0000000000000458 0 section local 9
10: 0000000000000530 0 section local 10
11: 0000000000000560 0 section local 11
12: 00000000000005a0 0 section local 12
13: 0000000000000600 0 section local 13
14: 0000000000000890 0 section local 14
15: 00000000000008c0 0 section local 15
16: 00000000000008e0 0 section local 16
17: 0000000000000910 0 section local 17
18: 0000000000001e08 0 section local 18
19: 0000000000001e10 0 section local 19
20: 0000000000001e18 0 section local 20
21: 0000000000001e20 0 section local 21
22: 0000000000002000 0 section local 22
23: 0000000000002058 0 section local 23
24: 0000000000002068 0 section local 24
25: 0000000000000000 0 section local 25
26: 0000000000000000 0 section local 26
27: 0000000000000000 0 section local 27
28: 0000000000000000 0 section local 28
29: 0000000000000000 0 section local 29
30: 0000000000000000 0 section local 30
31: 0000000000000000 0 file local abs crtstuff.c
32: 0000000000001e18 0 object local 20 __JCR_LIST__
33: 0000000000000648 0 func local 13 deregister_tm_clones
34: 0000000000000680 0 func local 13 register_tm_clones
35: 00000000000006c8 0 func local 13 __do_global_dtors_aux
36: 0000000000002068 1 object local 24 completed.6615
37: 0000000000001e10 0 object local 19 __do_global_dtors_aux_fini_array_entry
38: 0000000000000720 0 func local 13 frame_dummy
39: 0000000000001e08 0 object local 18 __frame_dummy_init_array_entry
40: 0000000000000000 0 file local abs example.c
41: 0000000000000000 0 file local abs crtstuff.c
42: 00000000000009e0 0 object local 17 __FRAME_END__
43: 0000000000001e18 0 object local 20 __JCR_END__
44: 0000000000000000 0 file local abs
45: 0000000000001e10 0 notype local 18 __init_array_end
46: 0000000000001e20 0 object local abs _DYNAMIC
47: 0000000000001e08 0 notype local 18 __init_array_start
48: 00000000000008e0 0 notype local 16 __GNU_EH_FRAME_HDR
49: 0000000000002000 0 object local abs _GLOBAL_OFFSET_TABLE_
50: 0000000000000888 2 func global 13 __libc_csu_fini
51: 0000000000000000 0 func weak undef __cxa_finalize@@GLIBC_2.2
52: 0000000000000000 0 notype weak undef _ITM_deregisterTMCloneTable
53: 0000000000002058 0 notype weak 23 data_start
54: 0000000000002068 0 notype global 23 _edata
55: 0000000000000890 0 func global 14 _fini
56: 0000000000002058 0 notype global 23 __data_start
57: 0000000000000000 0 notype weak undef __gmon_start__
58: 0000000000002060 0 object global 23 __dso_handle
59: 00000000000008c0 4 object global 15 _IO_stdin_used
60: 0000000000000000 0 func global undef __libc_start_main@@GLIBC_2.2
61: 0000000000000820 100 func global 13 __libc_csu_init
62: 0000000000002070 0 notype global 24 _end
63: 0000000000000600 0 func global 13 _start
64: 0000000000002068 0 notype global 24 __bss_start
65: 00000000000007e0 64 func global 13 main
66: 0000000000000768 120 func global 13 fib
67: 0000000000000000 0 notype weak undef _Jv_RegisterClasses
68: 0000000000002068 0 object global 23 __TMC_END__
69: 0000000000000000 0 notype weak undef _ITM_registerTMCloneTable
70: 0000000000000560 0 func global 11 _init
Loading

0 comments on commit d5ad1b9

Please sign in to comment.