Fix for mixed version loclists, tests (#521)
[pyelftools.git] / elftools / dwarf / structs.py
1 #-------------------------------------------------------------------------------
2 # elftools: dwarf/structs.py
3 #
4 # Encapsulation of Construct structs for parsing DWARF, adjusted for correct
5 # endianness and word-size.
6 #
7 # Eli Bendersky (eliben@gmail.com)
8 # This code is in the public domain
9 #-------------------------------------------------------------------------------
10 from logging.config import valid_ident
11 from ..construct import (
12 UBInt8, UBInt16, UBInt32, UBInt64, ULInt8, ULInt16, ULInt32, ULInt64,
13 SBInt8, SBInt16, SBInt32, SBInt64, SLInt8, SLInt16, SLInt32, SLInt64,
14 Adapter, Struct, ConstructError, If, Enum, Array, PrefixedArray,
15 CString, Embed, StaticField, IfThenElse, Construct, Rename, Sequence,
16 String, Switch, Value
17 )
18 from ..common.construct_utils import (RepeatUntilExcluding, ULEB128, SLEB128,
19 StreamOffset)
20 from .enums import *
21
22
23 class DWARFStructs(object):
24 """ Exposes Construct structs suitable for parsing information from DWARF
25 sections. Each compile unit in DWARF info can have its own structs
26 object. Keep in mind that these structs have to be given a name (by
27 calling them with a name) before being used for parsing (like other
28 Construct structs). Those that should be used without a name are marked
29 by (+).
30
31 Accessible attributes (mostly as described in chapter 7 of the DWARF
32 spec v3):
33
34 Dwarf_[u]int{8,16,32,64):
35 Data chunks of the common sizes
36
37 Dwarf_offset:
38 32-bit or 64-bit word, depending on dwarf_format
39
40 Dwarf_length:
41 32-bit or 64-bit word, depending on dwarf_format
42
43 Dwarf_target_addr:
44 32-bit or 64-bit word, depending on address size
45
46 Dwarf_initial_length:
47 "Initial length field" encoding
48 section 7.4
49
50 Dwarf_{u,s}leb128:
51 ULEB128 and SLEB128 variable-length encoding
52
53 Dwarf_CU_header (+):
54 Compilation unit header
55
56 Dwarf_abbrev_declaration (+):
57 Abbreviation table declaration - doesn't include the initial
58 code, only the contents.
59
60 Dwarf_dw_form (+):
61 A dictionary mapping 'DW_FORM_*' keys into construct Structs
62 that parse such forms. These Structs have already been given
63 dummy names.
64
65 Dwarf_lineprog_header (+):
66 Line program header
67
68 Dwarf_lineprog_file_entry (+):
69 A single file entry in a line program header or instruction
70
71 Dwarf_CIE_header (+):
72 A call-frame CIE
73
74 Dwarf_FDE_header (+):
75 A call-frame FDE
76
77 See also the documentation of public methods.
78 """
79
80 # Cache for structs instances based on creation parameters. Structs
81 # initialization is expensive and we don't won't to repeat it
82 # unnecessarily.
83 _structs_cache = {}
84
85 def __new__(cls, little_endian, dwarf_format, address_size, dwarf_version=2):
86 """ dwarf_version:
87 Numeric DWARF version
88
89 little_endian:
90 True if the file is little endian, False if big
91
92 dwarf_format:
93 DWARF Format: 32 or 64-bit (see spec section 7.4)
94
95 address_size:
96 Target machine address size, in bytes (4 or 8). (See spec
97 section 7.5.1)
98 """
99 key = (little_endian, dwarf_format, address_size, dwarf_version)
100
101 if key in cls._structs_cache:
102 return cls._structs_cache[key]
103
104 self = super().__new__(cls)
105 assert dwarf_format == 32 or dwarf_format == 64
106 assert address_size == 8 or address_size == 4, str(address_size)
107 self.little_endian = little_endian
108 self.dwarf_format = dwarf_format
109 self.address_size = address_size
110 self.dwarf_version = dwarf_version
111 self._create_structs()
112 cls._structs_cache[key] = self
113 return self
114
115 def initial_length_field_size(self):
116 """ Size of an initial length field.
117 """
118 return 4 if self.dwarf_format == 32 else 12
119
120 def _create_structs(self):
121 if self.little_endian:
122 self.Dwarf_uint8 = ULInt8
123 self.Dwarf_uint16 = ULInt16
124 self.Dwarf_uint32 = ULInt32
125 self.Dwarf_uint64 = ULInt64
126 self.Dwarf_offset = ULInt32 if self.dwarf_format == 32 else ULInt64
127 self.Dwarf_length = ULInt32 if self.dwarf_format == 32 else ULInt64
128 self.Dwarf_target_addr = (
129 ULInt32 if self.address_size == 4 else ULInt64)
130 self.Dwarf_int8 = SLInt8
131 self.Dwarf_int16 = SLInt16
132 self.Dwarf_int32 = SLInt32
133 self.Dwarf_int64 = SLInt64
134 else:
135 self.Dwarf_uint8 = UBInt8
136 self.Dwarf_uint16 = UBInt16
137 self.Dwarf_uint32 = UBInt32
138 self.Dwarf_uint64 = UBInt64
139 self.Dwarf_offset = UBInt32 if self.dwarf_format == 32 else UBInt64
140 self.Dwarf_length = UBInt32 if self.dwarf_format == 32 else UBInt64
141 self.Dwarf_target_addr = (
142 UBInt32 if self.address_size == 4 else UBInt64)
143 self.Dwarf_int8 = SBInt8
144 self.Dwarf_int16 = SBInt16
145 self.Dwarf_int32 = SBInt32
146 self.Dwarf_int64 = SBInt64
147
148 self._create_initial_length()
149 self._create_leb128()
150 self._create_cu_header()
151 self._create_abbrev_declaration()
152 self._create_dw_form()
153 self._create_lineprog_header()
154 self._create_callframe_entry_headers()
155 self._create_aranges_header()
156 self._create_nameLUT_header()
157 self._create_string_offsets_table_header()
158 self._create_address_table_header()
159 self._create_loclists_parsers()
160 self._create_rnglists_parsers()
161
162 self._create_debugsup()
163 self._create_gnu_debugaltlink()
164
165 def _create_initial_length(self):
166 def _InitialLength(name):
167 # Adapts a Struct that parses forward a full initial length field.
168 # Only if the first word is the continuation value, the second
169 # word is parsed from the stream.
170 return _InitialLengthAdapter(
171 Struct(name,
172 self.Dwarf_uint32('first'),
173 If(lambda ctx: ctx.first == 0xFFFFFFFF,
174 self.Dwarf_uint64('second'),
175 elsevalue=None)))
176 self.Dwarf_initial_length = _InitialLength
177
178 def _create_leb128(self):
179 self.Dwarf_uleb128 = ULEB128
180 self.Dwarf_sleb128 = SLEB128
181
182 def _create_cu_header(self):
183 dwarfv4_CU_header = Struct('',
184 self.Dwarf_offset('debug_abbrev_offset'),
185 self.Dwarf_uint8('address_size')
186 )
187 # DWARFv5 reverses the order of address_size and debug_abbrev_offset.
188 # DWARFv5 7.5.1.1
189 dwarfv5_CP_CU_header = Struct('',
190 self.Dwarf_uint8('address_size'),
191 self.Dwarf_offset('debug_abbrev_offset')
192 )
193 # DWARFv5 7.5.1.2
194 dwarfv5_SS_CU_header = Struct('',
195 self.Dwarf_uint8('address_size'),
196 self.Dwarf_offset('debug_abbrev_offset'),
197 self.Dwarf_uint64('dwo_id')
198 )
199 # DWARFv5 7.5.1.3
200 dwarfv5_TS_CU_header = Struct('',
201 self.Dwarf_uint8('address_size'),
202 self.Dwarf_offset('debug_abbrev_offset'),
203 self.Dwarf_uint64('type_signature'),
204 self.Dwarf_offset('type_offset')
205 )
206 dwarfv5_CU_header = Struct('',
207 Enum(self.Dwarf_uint8('unit_type'), **ENUM_DW_UT),
208 Embed(Switch('', lambda ctx: ctx.unit_type,
209 {
210 'DW_UT_compile' : dwarfv5_CP_CU_header,
211 'DW_UT_partial' : dwarfv5_CP_CU_header,
212 'DW_UT_skeleton' : dwarfv5_SS_CU_header,
213 'DW_UT_split_compile' : dwarfv5_SS_CU_header,
214 'DW_UT_type' : dwarfv5_TS_CU_header,
215 'DW_UT_split_type' : dwarfv5_TS_CU_header,
216 })))
217 self.Dwarf_CU_header = Struct('Dwarf_CU_header',
218 self.Dwarf_initial_length('unit_length'),
219 self.Dwarf_uint16('version'),
220 IfThenElse('', lambda ctx: ctx['version'] >= 5,
221 Embed(dwarfv5_CU_header),
222 Embed(dwarfv4_CU_header),
223 ))
224
225 def _create_abbrev_declaration(self):
226 self.Dwarf_abbrev_declaration = Struct('Dwarf_abbrev_entry',
227 Enum(self.Dwarf_uleb128('tag'), **ENUM_DW_TAG),
228 Enum(self.Dwarf_uint8('children_flag'), **ENUM_DW_CHILDREN),
229 RepeatUntilExcluding(
230 lambda obj, ctx:
231 obj.name == 'DW_AT_null' and obj.form == 'DW_FORM_null',
232 Struct('attr_spec',
233 Enum(self.Dwarf_uleb128('name'), **ENUM_DW_AT),
234 Enum(self.Dwarf_uleb128('form'), **ENUM_DW_FORM),
235 If(lambda ctx: ctx['form'] == 'DW_FORM_implicit_const',
236 self.Dwarf_sleb128('value')))))
237
238 def _create_debugsup(self):
239 # We don't care about checksums, for now.
240 self.Dwarf_debugsup = Struct('Elf_debugsup',
241 self.Dwarf_int16('version'),
242 self.Dwarf_uint8('is_supplementary'),
243 CString('sup_filename'))
244
245 def _create_gnu_debugaltlink(self):
246 self.Dwarf_debugaltlink = Struct('Elf_debugaltlink',
247 CString("sup_filename"),
248 String("sup_checksum", length=20))
249
250 def _create_dw_form(self):
251 self.Dwarf_dw_form = dict(
252 DW_FORM_addr=self.Dwarf_target_addr(''),
253 DW_FORM_addrx=self.Dwarf_uleb128(''),
254 DW_FORM_addrx1=self.Dwarf_uint8(''),
255 DW_FORM_addrx2=self.Dwarf_uint16(''),
256 # DW_FORM_addrx3=self.Dwarf_uint24(''), # TODO
257 DW_FORM_addrx4=self.Dwarf_uint32(''),
258
259 DW_FORM_block1=self._make_block_struct(self.Dwarf_uint8),
260 DW_FORM_block2=self._make_block_struct(self.Dwarf_uint16),
261 DW_FORM_block4=self._make_block_struct(self.Dwarf_uint32),
262 DW_FORM_block=self._make_block_struct(self.Dwarf_uleb128),
263
264 # All DW_FORM_data<n> forms are assumed to be unsigned
265 DW_FORM_data1=self.Dwarf_uint8(''),
266 DW_FORM_data2=self.Dwarf_uint16(''),
267 DW_FORM_data4=self.Dwarf_uint32(''),
268 DW_FORM_data8=self.Dwarf_uint64(''),
269 DW_FORM_data16=Array(16, self.Dwarf_uint8('')), # Used for hashes and such, not for integers
270 DW_FORM_sdata=self.Dwarf_sleb128(''),
271 DW_FORM_udata=self.Dwarf_uleb128(''),
272
273 DW_FORM_string=CString(''),
274 DW_FORM_strp=self.Dwarf_offset(''),
275 DW_FORM_strp_sup=self.Dwarf_offset(''),
276 DW_FORM_line_strp=self.Dwarf_offset(''),
277 DW_FORM_strx1=self.Dwarf_uint8(''),
278 DW_FORM_strx2=self.Dwarf_uint16(''),
279 # DW_FORM_strx3=self.Dwarf_uint24(''), # TODO
280 DW_FORM_strx4=self.Dwarf_uint64(''),
281 DW_FORM_flag=self.Dwarf_uint8(''),
282
283 DW_FORM_ref=self.Dwarf_uint32(''),
284 DW_FORM_ref1=self.Dwarf_uint8(''),
285 DW_FORM_ref2=self.Dwarf_uint16(''),
286 DW_FORM_ref4=self.Dwarf_uint32(''),
287 DW_FORM_ref_sup4=self.Dwarf_uint32(''),
288 DW_FORM_ref8=self.Dwarf_uint64(''),
289 DW_FORM_ref_sup8=self.Dwarf_uint64(''),
290 DW_FORM_ref_udata=self.Dwarf_uleb128(''),
291 DW_FORM_ref_addr=self.Dwarf_target_addr('') if self.dwarf_version == 2 else self.Dwarf_offset(''),
292
293 DW_FORM_indirect=self.Dwarf_uleb128(''),
294
295 # New forms in DWARFv4
296 DW_FORM_flag_present = StaticField('', 0),
297 DW_FORM_sec_offset = self.Dwarf_offset(''),
298 DW_FORM_exprloc = self._make_block_struct(self.Dwarf_uleb128),
299 DW_FORM_ref_sig8 = self.Dwarf_uint64(''),
300
301 DW_FORM_GNU_strp_alt=self.Dwarf_offset(''),
302 DW_FORM_GNU_ref_alt=self.Dwarf_offset(''),
303 DW_AT_GNU_all_call_sites=self.Dwarf_uleb128(''),
304
305 # New forms in DWARFv5
306 DW_FORM_loclistx=self.Dwarf_uleb128(''),
307 DW_FORM_rnglistx=self.Dwarf_uleb128('')
308 )
309
310 def _create_aranges_header(self):
311 self.Dwarf_aranges_header = Struct("Dwarf_aranges_header",
312 self.Dwarf_initial_length('unit_length'),
313 self.Dwarf_uint16('version'),
314 self.Dwarf_offset('debug_info_offset'), # a little tbd
315 self.Dwarf_uint8('address_size'),
316 self.Dwarf_uint8('segment_size')
317 )
318
319 def _create_nameLUT_header(self):
320 self.Dwarf_nameLUT_header = Struct("Dwarf_nameLUT_header",
321 self.Dwarf_initial_length('unit_length'),
322 self.Dwarf_uint16('version'),
323 self.Dwarf_offset('debug_info_offset'),
324 self.Dwarf_length('debug_info_length')
325 )
326
327 def _create_string_offsets_table_header(self):
328 self.Dwarf_string_offsets_table_header = Struct(
329 "Dwarf_string_offets_table_header",
330 self.Dwarf_initial_length('unit_length'),
331 self.Dwarf_uint16('version'),
332 self.Dwarf_uint16('padding'),
333 )
334
335 def _create_address_table_header(self):
336 self.Dwarf_address_table_header = Struct("Dwarf_address_table_header",
337 self.Dwarf_initial_length('unit_length'),
338 self.Dwarf_uint16('version'),
339 self.Dwarf_uint8('address_size'),
340 self.Dwarf_uint8('segment_selector_size'),
341 )
342
343 def _create_lineprog_header(self):
344 # A file entry is terminated by a NULL byte, so we don't want to parse
345 # past it. Therefore an If is used.
346 self.Dwarf_lineprog_file_entry = Struct('file_entry',
347 CString('name'),
348 If(lambda ctx: len(ctx.name) != 0,
349 Embed(Struct('',
350 self.Dwarf_uleb128('dir_index'),
351 self.Dwarf_uleb128('mtime'),
352 self.Dwarf_uleb128('length')))))
353
354 class FormattedEntry(Construct):
355 # Generates a parser based on a previously parsed piece,
356 # similar to deprecared Dynamic.
357 # Strings are resolved later, since it potentially requires
358 # looking at another section.
359 def __init__(self, name, structs, format_field):
360 Construct.__init__(self, name)
361 self.structs = structs
362 self.format_field = format_field
363
364 def _parse(self, stream, context):
365 # Somewhat tricky technique here, explicitly writing back to the context
366 if self.format_field + "_parser" in context:
367 parser = context[self.format_field + "_parser"]
368 else:
369 fields = tuple(
370 Rename(f.content_type, self.structs.Dwarf_dw_form[f.form])
371 for f in context[self.format_field])
372 parser = Struct('formatted_entry', *fields)
373 context[self.format_field + "_parser"] = parser
374 return parser._parse(stream, context)
375
376 ver5 = lambda ctx: ctx.version >= 5
377
378 self.Dwarf_lineprog_header = Struct('Dwarf_lineprog_header',
379 self.Dwarf_initial_length('unit_length'),
380 self.Dwarf_uint16('version'),
381 If(ver5,
382 self.Dwarf_uint8("address_size"),
383 None),
384 If(ver5,
385 self.Dwarf_uint8("segment_selector_size"),
386 None),
387 self.Dwarf_offset('header_length'),
388 self.Dwarf_uint8('minimum_instruction_length'),
389 If(lambda ctx: ctx.version >= 4,
390 self.Dwarf_uint8("maximum_operations_per_instruction"),
391 1),
392 self.Dwarf_uint8('default_is_stmt'),
393 self.Dwarf_int8('line_base'),
394 self.Dwarf_uint8('line_range'),
395 self.Dwarf_uint8('opcode_base'),
396 Array(lambda ctx: ctx.opcode_base - 1,
397 self.Dwarf_uint8('standard_opcode_lengths')),
398 If(ver5,
399 PrefixedArray(
400 Struct('directory_entry_format',
401 Enum(self.Dwarf_uleb128('content_type'), **ENUM_DW_LNCT),
402 Enum(self.Dwarf_uleb128('form'), **ENUM_DW_FORM)),
403 self.Dwarf_uint8("directory_entry_format_count"))),
404 If(ver5, # Name deliberately doesn't match the legacy object, since the format can't be made compatible
405 PrefixedArray(
406 FormattedEntry('directories', self, "directory_entry_format"),
407 self.Dwarf_uleb128('directories_count'))),
408 If(ver5,
409 PrefixedArray(
410 Struct('file_name_entry_format',
411 Enum(self.Dwarf_uleb128('content_type'), **ENUM_DW_LNCT),
412 Enum(self.Dwarf_uleb128('form'), **ENUM_DW_FORM)),
413 self.Dwarf_uint8("file_name_entry_format_count"))),
414 If(ver5,
415 PrefixedArray(
416 FormattedEntry('file_names', self, "file_name_entry_format"),
417 self.Dwarf_uleb128('file_names_count'))),
418 # Legacy directories/files - DWARF < 5 only
419 If(lambda ctx: ctx.version < 5,
420 RepeatUntilExcluding(
421 lambda obj, ctx: obj == b'',
422 CString('include_directory'))),
423 If(lambda ctx: ctx.version < 5,
424 RepeatUntilExcluding(
425 lambda obj, ctx: len(obj.name) == 0,
426 self.Dwarf_lineprog_file_entry)) # array name is file_entry
427 )
428
429 def _create_callframe_entry_headers(self):
430 self.Dwarf_CIE_header = Struct('Dwarf_CIE_header',
431 self.Dwarf_initial_length('length'),
432 self.Dwarf_offset('CIE_id'),
433 self.Dwarf_uint8('version'),
434 CString('augmentation'),
435 self.Dwarf_uleb128('code_alignment_factor'),
436 self.Dwarf_sleb128('data_alignment_factor'),
437 self.Dwarf_uleb128('return_address_register'))
438 self.EH_CIE_header = self.Dwarf_CIE_header
439
440 # The CIE header was modified in DWARFv4.
441 if self.dwarf_version == 4:
442 self.Dwarf_CIE_header = Struct('Dwarf_CIE_header',
443 self.Dwarf_initial_length('length'),
444 self.Dwarf_offset('CIE_id'),
445 self.Dwarf_uint8('version'),
446 CString('augmentation'),
447 self.Dwarf_uint8('address_size'),
448 self.Dwarf_uint8('segment_size'),
449 self.Dwarf_uleb128('code_alignment_factor'),
450 self.Dwarf_sleb128('data_alignment_factor'),
451 self.Dwarf_uleb128('return_address_register'))
452
453 self.Dwarf_FDE_header = Struct('Dwarf_FDE_header',
454 self.Dwarf_initial_length('length'),
455 self.Dwarf_offset('CIE_pointer'),
456 self.Dwarf_target_addr('initial_location'),
457 self.Dwarf_target_addr('address_range'))
458
459 def _make_block_struct(self, length_field):
460 """ Create a struct for DW_FORM_block<size>
461 """
462 return PrefixedArray(
463 subcon=self.Dwarf_uint8('elem'),
464 length_field=length_field(''))
465
466 def _create_loclists_parsers(self):
467 """ Create a struct for debug_loclists CU header, DWARFv5, 7,29
468 """
469 self.Dwarf_loclists_CU_header = Struct('Dwarf_loclists_CU_header',
470 StreamOffset('cu_offset'),
471 self.Dwarf_initial_length('unit_length'),
472 Value('is64', lambda ctx: ctx.is64),
473 StreamOffset('offset_after_length'),
474 self.Dwarf_uint16('version'),
475 self.Dwarf_uint8('address_size'),
476 self.Dwarf_uint8('segment_selector_size'),
477 self.Dwarf_uint32('offset_count'),
478 StreamOffset('offset_table_offset'))
479
480 cld = self.Dwarf_loclists_counted_location_description = PrefixedArray(self.Dwarf_uint8('loc_expr'), self.Dwarf_uleb128(''))
481
482 self.Dwarf_loclists_entries = RepeatUntilExcluding(
483 lambda obj, ctx: obj.entry_type == 'DW_LLE_end_of_list',
484 Struct('entry',
485 StreamOffset('entry_offset'),
486 Enum(self.Dwarf_uint8('entry_type'), **ENUM_DW_LLE),
487 Embed(Switch('', lambda ctx: ctx.entry_type,
488 {
489 'DW_LLE_end_of_list' : Struct('end_of_list'),
490 'DW_LLE_base_addressx' : Struct('base_addressx', self.Dwarf_uleb128('index')),
491 'DW_LLE_startx_endx' : Struct('startx_endx', self.Dwarf_uleb128('start_index'), self.Dwarf_uleb128('end_index'), cld),
492 'DW_LLE_startx_length' : Struct('startx_endx', self.Dwarf_uleb128('start_index'), self.Dwarf_uleb128('length'), cld),
493 'DW_LLE_offset_pair' : Struct('startx_endx', self.Dwarf_uleb128('start_offset'), self.Dwarf_uleb128('end_offset'), cld),
494 'DW_LLE_default_location' : Struct('default_location', cld),
495 'DW_LLE_base_address' : Struct('base_address', self.Dwarf_target_addr('address')),
496 'DW_LLE_start_end' : Struct('start_end', self.Dwarf_target_addr('start_address'), self.Dwarf_target_addr('end_address'), cld),
497 'DW_LLE_start_length' : Struct('start_length', self.Dwarf_target_addr('start_address'), self.Dwarf_uleb128('length'), cld),
498 })),
499 StreamOffset('entry_end_offset'),
500 Value('entry_length', lambda ctx: ctx.entry_end_offset - ctx.entry_offset)))
501
502 self.Dwarf_locview_pair = Struct('locview_pair',
503 StreamOffset('entry_offset'), self.Dwarf_uleb128('begin'), self.Dwarf_uleb128('end'))
504
505 def _create_rnglists_parsers(self):
506 self.Dwarf_rnglists_CU_header = Struct('Dwarf_rnglists_CU_header',
507 StreamOffset('cu_offset'),
508 self.Dwarf_initial_length('unit_length'),
509 Value('is64', lambda ctx: ctx.is64),
510 StreamOffset('offset_after_length'),
511 self.Dwarf_uint16('version'),
512 self.Dwarf_uint8('address_size'),
513 self.Dwarf_uint8('segment_selector_size'),
514 self.Dwarf_uint32('offset_count'),
515 StreamOffset('offset_table_offset'))
516
517 self.Dwarf_rnglists_entries = RepeatUntilExcluding(
518 lambda obj, ctx: obj.entry_type == 'DW_RLE_end_of_list',
519 Struct('entry',
520 StreamOffset('entry_offset'),
521 Enum(self.Dwarf_uint8('entry_type'), **ENUM_DW_RLE),
522 Embed(Switch('', lambda ctx: ctx.entry_type,
523 {
524 'DW_RLE_end_of_list' : Struct('end_of_list'),
525 'DW_RLE_base_addressx' : Struct('base_addressx', self.Dwarf_uleb128('index')),
526 'DW_RLE_startx_endx' : Struct('startx_endx', self.Dwarf_uleb128('start_index'), self.Dwarf_uleb128('end_index')),
527 'DW_RLE_startx_length' : Struct('startx_endx', self.Dwarf_uleb128('start_index'), self.Dwarf_uleb128('length')),
528 'DW_RLE_offset_pair' : Struct('startx_endx', self.Dwarf_uleb128('start_offset'), self.Dwarf_uleb128('end_offset')),
529 'DW_RLE_base_address' : Struct('base_address', self.Dwarf_target_addr('address')),
530 'DW_RLE_start_end' : Struct('start_end', self.Dwarf_target_addr('start_address'), self.Dwarf_target_addr('end_address')),
531 'DW_RLE_start_length' : Struct('start_length', self.Dwarf_target_addr('start_address'), self.Dwarf_uleb128('length'))
532 })),
533 StreamOffset('entry_end_offset'),
534 Value('entry_length', lambda ctx: ctx.entry_end_offset - ctx.entry_offset)))
535
536
537 class _InitialLengthAdapter(Adapter):
538 """ A standard Construct adapter that expects a sub-construct
539 as a struct with one or two values (first, second).
540 """
541 def _decode(self, obj, context):
542 if obj.first < 0xFFFFFF00:
543 context['is64'] = False
544 return obj.first
545 else:
546 if obj.first == 0xFFFFFFFF:
547 context['is64'] = True
548 return obj.second
549 else:
550 raise ConstructError("Failed decoding initial length for %X" % (
551 obj.first))