e6aa81c4688601cc7661b0deb8473c94453e7a2c
1 #-------------------------------------------------------------------------------
2 # elftools: dwarf/structs.py
4 # Encapsulation of Construct structs for parsing DWARF, adjusted for correct
5 # endianness and word-size.
7 # Eli Bendersky (eliben@gmail.com)
8 # This code is in the public domain
9 #-------------------------------------------------------------------------------
10 from ..construct
import (
11 UBInt8
, UBInt16
, UBInt32
, UBInt64
,
12 ULInt8
, ULInt16
, ULInt32
, ULInt64
,
13 Adapter
, Struct
, ConstructError
, If
, RepeatUntil
, Field
, Rename
,
17 class DWARFStructs(object):
18 """ Accessible attributes:
20 Dwarf_uint{8,16,32,64):
21 Data chunks of the common sizes
24 32-bit or 64-bit word, depending on dwarfclass
27 "Initial length field" encoding, as described in DWARFv3 spec
31 ULEB128 and SLEB128 variable-length encoding, as described in
32 DWARFv3 spec section 7.6
34 def __init__(self
, little_endian
=True, dwarfclass
=32):
35 assert dwarfclass
== 32 or dwarfclass
== 64
36 self
.little_endian
= little_endian
37 self
.dwarfclass
= dwarfclass
38 self
._create
_structs
()
41 def _create_structs(self
):
42 if self
.little_endian
:
43 self
.Dwarf_uint8
= ULInt8
44 self
.Dwarf_uint16
= ULInt16
45 self
.Dwarf_uint32
= ULInt32
46 self
.Dwarf_uint64
= ULInt64
47 self
.Dwarf_xword
= ULInt32
if self
.dwarfclass
== 32 else ULInt64
49 self
.Dwarf_uint8
= UBInt8
50 self
.Dwarf_uint16
= UBInt16
51 self
.Dwarf_uint32
= UBInt32
52 self
.Dwarf_uint64
= UBInt64
53 self
.Dwarf_xword
= UBInt32
if self
.dwarfclass
== 32 else UBInt64
55 self
._create
_initial
_length
()
57 def _create_initial_length(self
):
58 def _InitialLength(name
):
59 # Adapts a Struct that parses forward a full initial length field.
60 # Only if the first word is the continuation value, the second
61 # word is parsed from the stream.
63 return _InitialLengthAdapter(
65 self
.Dwarf_uint32('first'),
66 If(lambda ctx
: ctx
.first
== 0xFFFFFFFF,
67 self
.Dwarf_uint64('second'),
69 self
.Dwarf_initial_length
= _InitialLength
71 def _create_leb128(self
):
72 self
.Dwarf_uleb128
= _ULEB128
73 self
.Dwarf_sleb128
= _SLEB128
76 class _InitialLengthAdapter(Adapter
):
77 """ A standard Construct adapter that expects a sub-construct
78 as a struct with one or two values (first, second).
80 def _decode(self
, obj
, context
):
81 if obj
.first
< 0xFFFFFF00:
84 if obj
.first
== 0xFFFFFFFF:
87 raise ConstructError("Failed decoding initial length for %X" % (
92 """ Read LEB128 variable-length data from the stream. The data is terminated
93 by a byte with 0 in its highest bit.
96 lambda obj
, ctx
: ord(obj
) < 0x80,
100 class _ULEB128Adapter(Adapter
):
101 """ An adapter for ULEB128, given a sequence of bytes in a sub-construct.
103 def _decode(self
, obj
, context
):
105 for b
in reversed(obj
):
106 value
= (value
<< 7) + (ord(b
) & 0x7F)
110 class _SLEB128Adapter(Adapter
):
111 """ An adapter for SLEB128, given a sequence of bytes in a sub-construct.
113 def _decode(self
, obj
, context
):
115 for b
in reversed(obj
):
116 value
= (value
<< 7) + (ord(b
) & 0x7F)
117 if ord(obj
[-1]) & 0x40:
118 # negative -> sign extend
120 value |
= - (1 << (7 * len(obj
)))
125 """ A construct creator for ULEB128 encoding.
127 return Rename(name
, _ULEB128Adapter(_LEB128_reader()))
131 """ A construct creator for SLEB128 encoding.
133 return Rename(name
, _SLEB128Adapter(_LEB128_reader()))