readelf 2.41 with Ranges test excluded on 2 files (#489)
[pyelftools.git] / elftools / dwarf / descriptions.py
1 #-------------------------------------------------------------------------------
2 # elftools: dwarf/descriptions.py
3 #
4 # Textual descriptions of the various values and enums of DWARF
5 #
6 # Eli Bendersky (eliben@gmail.com)
7 # This code is in the public domain
8 #-------------------------------------------------------------------------------
9 from collections import defaultdict
10
11 from .constants import *
12 from .dwarf_expr import DWARFExprParser
13 from .die import DIE
14 from ..common.utils import preserve_stream_pos, dwarf_assert, bytes2str
15 from .callframe import instruction_name, CIE, FDE
16
17
18 def set_global_machine_arch(machine_arch):
19 global _MACHINE_ARCH
20 _MACHINE_ARCH = machine_arch
21
22
23 def describe_attr_value(attr, die, section_offset):
24 """ Given an attribute attr, return the textual representation of its
25 value, suitable for tools like readelf.
26
27 To cover all cases, this function needs some extra arguments:
28
29 die: the DIE this attribute was extracted from
30 section_offset: offset in the stream of the section the DIE belongs to
31 """
32 descr_func = _ATTR_DESCRIPTION_MAP[attr.form]
33 val_description = descr_func(attr, die, section_offset)
34
35 # For some attributes we can display further information
36 extra_info_func = _EXTRA_INFO_DESCRIPTION_MAP[attr.name]
37 extra_info = extra_info_func(attr, die, section_offset)
38 return str(val_description) + '\t' + extra_info
39
40
41 def describe_CFI_instructions(entry):
42 """ Given a CFI entry (CIE or FDE), return the textual description of its
43 instructions.
44 """
45 def _assert_FDE_instruction(instr):
46 dwarf_assert(
47 isinstance(entry, FDE),
48 'Unexpected instruction "%s" for a CIE' % instr)
49
50 def _full_reg_name(regnum):
51 regname = describe_reg_name(regnum, _MACHINE_ARCH, False)
52 if regname:
53 return 'r%s (%s)' % (regnum, regname)
54 else:
55 return 'r%s' % regnum
56
57 if isinstance(entry, CIE):
58 cie = entry
59 else: # FDE
60 cie = entry.cie
61 pc = entry['initial_location']
62
63 s = ''
64 for instr in entry.instructions:
65 name = instruction_name(instr.opcode)
66
67 if name in ('DW_CFA_offset',
68 'DW_CFA_offset_extended', 'DW_CFA_offset_extended_sf',
69 'DW_CFA_val_offset', 'DW_CFA_val_offset_sf'):
70 s += ' %s: %s at cfa%+d\n' % (
71 name, _full_reg_name(instr.args[0]),
72 instr.args[1] * cie['data_alignment_factor'])
73 elif name in ( 'DW_CFA_restore', 'DW_CFA_restore_extended',
74 'DW_CFA_undefined', 'DW_CFA_same_value',
75 'DW_CFA_def_cfa_register'):
76 s += ' %s: %s\n' % (name, _full_reg_name(instr.args[0]))
77 elif name == 'DW_CFA_register':
78 s += ' %s: %s in %s' % (
79 name, _full_reg_name(instr.args[0]),
80 _full_reg_name(instr.args[1]))
81 elif name == 'DW_CFA_set_loc':
82 pc = instr.args[0]
83 s += ' %s: %08x\n' % (name, pc)
84 elif name in ( 'DW_CFA_advance_loc1', 'DW_CFA_advance_loc2',
85 'DW_CFA_advance_loc4', 'DW_CFA_advance_loc'):
86 _assert_FDE_instruction(instr)
87 factored_offset = instr.args[0] * cie['code_alignment_factor']
88 s += ' %s: %s to %08x\n' % (
89 name, factored_offset, factored_offset + pc)
90 pc += factored_offset
91 elif name in ( 'DW_CFA_remember_state', 'DW_CFA_restore_state',
92 'DW_CFA_nop'):
93 s += ' %s\n' % name
94 elif name == 'DW_CFA_def_cfa':
95 s += ' %s: %s ofs %s\n' % (
96 name, _full_reg_name(instr.args[0]), instr.args[1])
97 elif name == 'DW_CFA_def_cfa_sf':
98 s += ' %s: %s ofs %s\n' % (
99 name, _full_reg_name(instr.args[0]),
100 instr.args[1] * cie['data_alignment_factor'])
101 elif name in ('DW_CFA_def_cfa_offset', 'DW_CFA_GNU_args_size'):
102 s += ' %s: %s\n' % (name, instr.args[0])
103 elif name == 'DW_CFA_def_cfa_expression':
104 expr_dumper = ExprDumper(entry.structs)
105 # readelf output is missing a colon for DW_CFA_def_cfa_expression
106 s += ' %s (%s)\n' % (name, expr_dumper.dump_expr(instr.args[0]))
107 elif name == 'DW_CFA_expression':
108 expr_dumper = ExprDumper(entry.structs)
109 s += ' %s: %s (%s)\n' % (
110 name, _full_reg_name(instr.args[0]),
111 expr_dumper.dump_expr(instr.args[1]))
112 else:
113 s += ' %s: <??>\n' % name
114
115 return s
116
117
118 def describe_CFI_register_rule(rule):
119 s = _DESCR_CFI_REGISTER_RULE_TYPE[rule.type]
120 if rule.type in ('OFFSET', 'VAL_OFFSET'):
121 s += '%+d' % rule.arg
122 elif rule.type == 'REGISTER':
123 s += describe_reg_name(rule.arg)
124 return s
125
126
127 def describe_CFI_CFA_rule(rule):
128 if rule.expr:
129 return 'exp'
130 else:
131 return '%s%+d' % (describe_reg_name(rule.reg), rule.offset)
132
133
134 def describe_DWARF_expr(expr, structs, cu_offset=None):
135 """ Textual description of a DWARF expression encoded in 'expr'.
136 structs should come from the entity encompassing the expression - it's
137 needed to be able to parse it correctly.
138 """
139 # Since this function can be called a lot, initializing a fresh new
140 # ExprDumper per call is expensive. So a rudimentary caching scheme is in
141 # place to create only one such dumper per instance of structs.
142 cache_key = id(structs)
143 if cache_key not in _DWARF_EXPR_DUMPER_CACHE:
144 _DWARF_EXPR_DUMPER_CACHE[cache_key] = \
145 ExprDumper(structs)
146 dwarf_expr_dumper = _DWARF_EXPR_DUMPER_CACHE[cache_key]
147 return '(' + dwarf_expr_dumper.dump_expr(expr, cu_offset) + ')'
148
149
150 def describe_reg_name(regnum, machine_arch=None, default=True):
151 """ Provide a textual description for a register name, given its serial
152 number. The number is expected to be valid.
153 """
154 if machine_arch is None:
155 machine_arch = _MACHINE_ARCH
156
157 if machine_arch == 'x86':
158 return _REG_NAMES_x86[regnum]
159 elif machine_arch == 'x64':
160 return _REG_NAMES_x64[regnum]
161 elif machine_arch == 'AArch64':
162 return _REG_NAMES_AArch64[regnum]
163 elif default:
164 return 'r%s' % regnum
165 else:
166 return None
167
168 def describe_form_class(form):
169 """For a given form name, determine its value class.
170
171 For example, given 'DW_FORM_data1' returns 'constant'.
172
173 For some forms, like DW_FORM_indirect and DW_FORM_sec_offset, the class is
174 not hard-coded and extra information is required. For these, None is
175 returned.
176 """
177 return _FORM_CLASS[form]
178
179
180 #-------------------------------------------------------------------------------
181
182 # The machine architecture. Set globally via set_global_machine_arch
183 #
184 _MACHINE_ARCH = None
185
186 # Implements the alternative format of readelf: lowercase hex, prefixed with 0x unless 0
187 def _format_hex(n):
188 return '0x%x' % n if n != 0 else '0'
189
190 def _describe_attr_ref(attr, die, section_offset):
191 return '<%s>' % _format_hex(attr.value + die.cu.cu_offset)
192
193 def _describe_attr_ref_sig8(attr, die, section_offset):
194 return 'signature: %s' % _format_hex(attr.value)
195
196 def _describe_attr_value_passthrough(attr, die, section_offset):
197 return attr.value
198
199 def _describe_attr_hex(attr, die, section_offset):
200 return '%s' % _format_hex(attr.value)
201
202 def _describe_attr_hex_addr(attr, die, section_offset):
203 return '<%s>' % _format_hex(attr.value)
204
205 def _describe_attr_split_64bit(attr, die, section_offset):
206 low_word = attr.value & 0xFFFFFFFF
207 high_word = (attr.value >> 32) & 0xFFFFFFFF
208 return '%s %s' % (_format_hex(low_word), _format_hex(high_word))
209
210 def _describe_attr_strp(attr, die, section_offset):
211 return '(indirect string, offset: %s): %s' % (
212 _format_hex(attr.raw_value), bytes2str(attr.value))
213
214 def _describe_attr_line_strp(attr, die, section_offset):
215 return '(indirect line string, offset: %s): %s' % (
216 _format_hex(attr.raw_value), bytes2str(attr.value))
217
218 def _describe_attr_string(attr, die, section_offset):
219 return bytes2str(attr.value)
220
221 def _describe_attr_debool(attr, die, section_offset):
222 """ To be consistent with readelf, generate 1 for True flags, 0 for False
223 flags.
224 """
225 return '1' if attr.value else '0'
226
227 def _describe_attr_present(attr, die, section_offset):
228 """ Some forms may simply mean that an attribute is present,
229 without providing any value.
230 """
231 return '1'
232
233 def _describe_attr_block(attr, die, section_offset):
234 s = '%s byte block: ' % len(attr.value)
235 s += ' '.join('%x' % item for item in attr.value) + ' '
236 return s
237
238
239 _ATTR_DESCRIPTION_MAP = defaultdict(
240 lambda: _describe_attr_value_passthrough, # default_factory
241
242 DW_FORM_ref1=_describe_attr_ref,
243 DW_FORM_ref2=_describe_attr_ref,
244 DW_FORM_ref4=_describe_attr_ref,
245 DW_FORM_ref8=_describe_attr_split_64bit,
246 DW_FORM_ref_udata=_describe_attr_ref,
247 DW_FORM_ref_addr=_describe_attr_hex_addr,
248 DW_FORM_data4=_describe_attr_hex,
249 DW_FORM_data8=_describe_attr_hex,
250 DW_FORM_addr=_describe_attr_hex,
251 DW_FORM_sec_offset=_describe_attr_hex,
252 DW_FORM_flag=_describe_attr_debool,
253 DW_FORM_data1=_describe_attr_value_passthrough,
254 DW_FORM_data2=_describe_attr_value_passthrough,
255 DW_FORM_sdata=_describe_attr_value_passthrough,
256 DW_FORM_udata=_describe_attr_value_passthrough,
257 DW_FORM_string=_describe_attr_string,
258 DW_FORM_strp=_describe_attr_strp,
259 DW_FORM_line_strp=_describe_attr_line_strp,
260 DW_FORM_block1=_describe_attr_block,
261 DW_FORM_block2=_describe_attr_block,
262 DW_FORM_block4=_describe_attr_block,
263 DW_FORM_block=_describe_attr_block,
264 DW_FORM_flag_present=_describe_attr_present,
265 DW_FORM_exprloc=_describe_attr_block,
266 DW_FORM_ref_sig8=_describe_attr_ref_sig8,
267 )
268
269 _FORM_CLASS = dict(
270 DW_FORM_addr='address',
271 DW_FORM_block2='block',
272 DW_FORM_block4='block',
273 DW_FORM_data2='constant',
274 DW_FORM_data4='constant',
275 DW_FORM_data8='constant',
276 DW_FORM_string='string',
277 DW_FORM_block='block',
278 DW_FORM_block1='block',
279 DW_FORM_data1='constant',
280 DW_FORM_flag='flag',
281 DW_FORM_sdata='constant',
282 DW_FORM_strp='string',
283 DW_FORM_udata='constant',
284 DW_FORM_ref_addr='reference',
285 DW_FORM_ref1='reference',
286 DW_FORM_ref2='reference',
287 DW_FORM_ref4='reference',
288 DW_FORM_ref8='reference',
289 DW_FORM_ref_udata='reference',
290 DW_FORM_indirect=None,
291 DW_FORM_sec_offset=None,
292 DW_FORM_exprloc='exprloc',
293 DW_FORM_flag_present='flag',
294 DW_FORM_ref_sig8='reference',
295 )
296
297 _DESCR_DW_INL = {
298 DW_INL_not_inlined: '(not inlined)',
299 DW_INL_inlined: '(inlined)',
300 DW_INL_declared_not_inlined: '(declared as inline but ignored)',
301 DW_INL_declared_inlined: '(declared as inline and inlined)',
302 }
303
304 _DESCR_DW_LANG = {
305 DW_LANG_C89: '(ANSI C)',
306 DW_LANG_C: '(non-ANSI C)',
307 DW_LANG_Ada83: '(Ada)',
308 DW_LANG_C_plus_plus: '(C++)',
309 DW_LANG_Cobol74: '(Cobol 74)',
310 DW_LANG_Cobol85: '(Cobol 85)',
311 DW_LANG_Fortran77: '(FORTRAN 77)',
312 DW_LANG_Fortran90: '(Fortran 90)',
313 DW_LANG_Pascal83: '(ANSI Pascal)',
314 DW_LANG_Modula2: '(Modula 2)',
315 DW_LANG_Java: '(Java)',
316 DW_LANG_C99: '(ANSI C99)',
317 DW_LANG_Ada95: '(ADA 95)',
318 DW_LANG_Fortran95: '(Fortran 95)',
319 DW_LANG_PLI: '(PLI)',
320 DW_LANG_ObjC: '(Objective C)',
321 DW_LANG_ObjC_plus_plus: '(Objective C++)',
322 DW_LANG_UPC: '(Unified Parallel C)',
323 DW_LANG_D: '(D)',
324 DW_LANG_Python: '(Python)',
325 DW_LANG_OpenCL: '(OpenCL)',
326 DW_LANG_Go: '(Go)',
327 DW_LANG_Modula3: '(Modula 3)',
328 DW_LANG_Haskell: '(Haskell)',
329 DW_LANG_C_plus_plus_03: '(C++03)',
330 DW_LANG_C_plus_plus_11: '(C++11)',
331 DW_LANG_OCaml: '(OCaml)',
332 DW_LANG_Rust: '(Rust)',
333 DW_LANG_C11: '(C11)',
334 DW_LANG_Swift: '(Swift)',
335 DW_LANG_Julia: '(Julia)',
336 DW_LANG_Dylan: '(Dylan)',
337 DW_LANG_C_plus_plus_14: '(C++14)',
338 DW_LANG_Fortran03: '(Fortran 03)',
339 DW_LANG_Fortran08: '(Fortran 08)',
340 DW_LANG_RenderScript: '(RenderScript)',
341 DW_LANG_BLISS: '(Bliss)', # Not in binutils
342 DW_LANG_Mips_Assembler: '(MIPS assembler)',
343 DW_LANG_HP_Bliss: '(HP Bliss)',
344 DW_LANG_HP_Basic91: '(HP Basic 91)',
345 DW_LANG_HP_Pascal91: '(HP Pascal 91)',
346 DW_LANG_HP_IMacro: '(HP IMacro)',
347 DW_LANG_HP_Assembler: '(HP assembler)'
348 }
349
350 _DESCR_DW_ATE = {
351 DW_ATE_void: '(void)',
352 DW_ATE_address: '(machine address)',
353 DW_ATE_boolean: '(boolean)',
354 DW_ATE_complex_float: '(complex float)',
355 DW_ATE_float: '(float)',
356 DW_ATE_signed: '(signed)',
357 DW_ATE_signed_char: '(signed char)',
358 DW_ATE_unsigned: '(unsigned)',
359 DW_ATE_unsigned_char: '(unsigned char)',
360 DW_ATE_imaginary_float: '(imaginary float)',
361 DW_ATE_decimal_float: '(decimal float)',
362 DW_ATE_packed_decimal: '(packed_decimal)',
363 DW_ATE_numeric_string: '(numeric_string)',
364 DW_ATE_edited: '(edited)',
365 DW_ATE_signed_fixed: '(signed_fixed)',
366 DW_ATE_unsigned_fixed: '(unsigned_fixed)',
367 DW_ATE_UTF: '(unicode string)',
368 DW_ATE_HP_float80: '(HP_float80)',
369 DW_ATE_HP_complex_float80: '(HP_complex_float80)',
370 DW_ATE_HP_float128: '(HP_float128)',
371 DW_ATE_HP_complex_float128: '(HP_complex_float128)',
372 DW_ATE_HP_floathpintel: '(HP_floathpintel)',
373 DW_ATE_HP_imaginary_float80: '(HP_imaginary_float80)',
374 DW_ATE_HP_imaginary_float128: '(HP_imaginary_float128)',
375 }
376
377 _DESCR_DW_ACCESS = {
378 DW_ACCESS_public: '(public)',
379 DW_ACCESS_protected: '(protected)',
380 DW_ACCESS_private: '(private)',
381 }
382
383 _DESCR_DW_VIS = {
384 DW_VIS_local: '(local)',
385 DW_VIS_exported: '(exported)',
386 DW_VIS_qualified: '(qualified)',
387 }
388
389 _DESCR_DW_VIRTUALITY = {
390 DW_VIRTUALITY_none: '(none)',
391 DW_VIRTUALITY_virtual: '(virtual)',
392 DW_VIRTUALITY_pure_virtual: '(pure virtual)',
393 }
394
395 _DESCR_DW_ID_CASE = {
396 DW_ID_case_sensitive: '(case_sensitive)',
397 DW_ID_up_case: '(up_case)',
398 DW_ID_down_case: '(down_case)',
399 DW_ID_case_insensitive: '(case_insensitive)',
400 }
401
402 _DESCR_DW_CC = {
403 DW_CC_normal: '(normal)',
404 DW_CC_program: '(program)',
405 DW_CC_nocall: '(nocall)',
406 }
407
408 _DESCR_DW_ORD = {
409 DW_ORD_row_major: '(row major)',
410 DW_ORD_col_major: '(column major)',
411 }
412
413 _DESCR_CFI_REGISTER_RULE_TYPE = dict(
414 UNDEFINED='u',
415 SAME_VALUE='s',
416 OFFSET='c',
417 VAL_OFFSET='v',
418 REGISTER='',
419 EXPRESSION='exp',
420 VAL_EXPRESSION='vexp',
421 ARCHITECTURAL='a',
422 )
423
424 def _make_extra_mapper(mapping, default, default_interpolate_value=False):
425 """ Create a mapping function from attribute parameters to an extra
426 value that should be displayed.
427 """
428 def mapper(attr, die, section_offset):
429 if default_interpolate_value:
430 d = default % attr.value
431 else:
432 d = default
433 return mapping.get(attr.value, d)
434 return mapper
435
436
437 def _make_extra_string(s=''):
438 """ Create an extra function that just returns a constant string.
439 """
440 def extra(attr, die, section_offset):
441 return s
442 return extra
443
444
445 _DWARF_EXPR_DUMPER_CACHE = {}
446
447 def _location_list_extra(attr, die, section_offset):
448 # According to section 2.6 of the DWARF spec v3, class loclistptr means
449 # a location list, and class block means a location expression.
450 # DW_FORM_sec_offset is new in DWARFv4 as a section offset.
451 if attr.form in ('DW_FORM_data4', 'DW_FORM_data8', 'DW_FORM_sec_offset'):
452 return '(location list)'
453 else:
454 return describe_DWARF_expr(attr.value, die.cu.structs, die.cu.cu_offset)
455
456
457 def _data_member_location_extra(attr, die, section_offset):
458 # According to section 5.5.6 of the DWARF spec v4, a data member location
459 # can be an integer offset, or a location description.
460 #
461 if attr.form in ('DW_FORM_data1', 'DW_FORM_data2',
462 'DW_FORM_data4', 'DW_FORM_data8',
463 'DW_FORM_sdata'):
464 return '' # No extra description needed
465 else:
466 return describe_DWARF_expr(attr.value, die.cu.structs, die.cu.cu_offset)
467
468
469 def _import_extra(attr, die, section_offset):
470 # For DW_AT_import the value points to a DIE (that can be either in the
471 # current DIE's CU or in another CU, depending on the FORM). The extra
472 # information for it is the abbreviation number in this DIE and its tag.
473 if attr.form == 'DW_FORM_ref_addr':
474 # Absolute offset value
475 ref_die_offset = section_offset + attr.value
476 else:
477 # Relative offset to the current DIE's CU
478 ref_die_offset = attr.value + die.cu.cu_offset
479
480 # Now find the CU this DIE belongs to (since we have to find its abbrev
481 # table). This is done by linearly scanning through all CUs, looking for
482 # one spanning an address space containing the referred DIE's offset.
483 for cu in die.dwarfinfo.iter_CUs():
484 if cu['unit_length'] + cu.cu_offset > ref_die_offset >= cu.cu_offset:
485 # Once we have the CU, we can actually parse this DIE from the
486 # stream.
487 with preserve_stream_pos(die.stream):
488 ref_die = DIE(cu, die.stream, ref_die_offset)
489 #print '&&& ref_die', ref_die
490 return '[Abbrev Number: %s (%s)]' % (
491 ref_die.abbrev_code, ref_die.tag)
492
493 return '[unknown]'
494
495
496 _EXTRA_INFO_DESCRIPTION_MAP = defaultdict(
497 lambda: _make_extra_string(''), # default_factory
498
499 DW_AT_inline=_make_extra_mapper(
500 _DESCR_DW_INL, '(Unknown inline attribute value: %x',
501 default_interpolate_value=True),
502 DW_AT_language=_make_extra_mapper(
503 _DESCR_DW_LANG, '(Unknown: %x)', default_interpolate_value=True),
504 DW_AT_encoding=_make_extra_mapper(_DESCR_DW_ATE, '(unknown type)'),
505 DW_AT_accessibility=_make_extra_mapper(
506 _DESCR_DW_ACCESS, '(unknown accessibility)'),
507 DW_AT_visibility=_make_extra_mapper(
508 _DESCR_DW_VIS, '(unknown visibility)'),
509 DW_AT_virtuality=_make_extra_mapper(
510 _DESCR_DW_VIRTUALITY, '(unknown virtuality)'),
511 DW_AT_identifier_case=_make_extra_mapper(
512 _DESCR_DW_ID_CASE, '(unknown case)'),
513 DW_AT_calling_convention=_make_extra_mapper(
514 _DESCR_DW_CC, '(unknown convention)'),
515 DW_AT_ordering=_make_extra_mapper(
516 _DESCR_DW_ORD, '(undefined)'),
517 DW_AT_frame_base=_location_list_extra,
518 DW_AT_location=_location_list_extra,
519 DW_AT_string_length=_location_list_extra,
520 DW_AT_return_addr=_location_list_extra,
521 DW_AT_data_member_location=_data_member_location_extra,
522 DW_AT_vtable_elem_location=_location_list_extra,
523 DW_AT_segment=_location_list_extra,
524 DW_AT_static_link=_location_list_extra,
525 DW_AT_use_location=_location_list_extra,
526 DW_AT_allocated=_location_list_extra,
527 DW_AT_associated=_location_list_extra,
528 DW_AT_data_location=_location_list_extra,
529 DW_AT_stride=_location_list_extra,
530 DW_AT_call_value=_location_list_extra,
531 DW_AT_import=_import_extra,
532 DW_AT_GNU_call_site_value=_location_list_extra,
533 DW_AT_GNU_call_site_data_value=_location_list_extra,
534 DW_AT_GNU_call_site_target=_location_list_extra,
535 DW_AT_GNU_call_site_target_clobbered=_location_list_extra,
536 )
537
538 # 8 in a line, for easier counting
539 _REG_NAMES_x86 = [
540 'eax', 'ecx', 'edx', 'ebx', 'esp', 'ebp', 'esi', 'edi',
541 'eip', 'eflags', '<none>', 'st0', 'st1', 'st2', 'st3', 'st4',
542 'st5', 'st6', 'st7', '<none>', '<none>', 'xmm0', 'xmm1', 'xmm2',
543 'xmm3', 'xmm4', 'xmm5', 'xmm6', 'xmm7', 'mm0', 'mm1', 'mm2',
544 'mm3', 'mm4', 'mm5', 'mm6', 'mm7', 'fcw', 'fsw', 'mxcsr',
545 'es', 'cs', 'ss', 'ds', 'fs', 'gs', '<none>', '<none>', 'tr', 'ldtr'
546 ]
547
548 _REG_NAMES_x64 = [
549 'rax', 'rdx', 'rcx', 'rbx', 'rsi', 'rdi', 'rbp', 'rsp',
550 'r8', 'r9', 'r10', 'r11', 'r12', 'r13', 'r14', 'r15',
551 'rip', 'xmm0', 'xmm1', 'xmm2', 'xmm3', 'xmm4', 'xmm5', 'xmm6',
552 'xmm7', 'xmm8', 'xmm9', 'xmm10', 'xmm11', 'xmm12', 'xmm13', 'xmm14',
553 'xmm15', 'st0', 'st1', 'st2', 'st3', 'st4', 'st5', 'st6',
554 'st7', 'mm0', 'mm1', 'mm2', 'mm3', 'mm4', 'mm5', 'mm6',
555 'mm7', 'rflags', 'es', 'cs', 'ss', 'ds', 'fs', 'gs',
556 '<none>', '<none>', 'fs.base', 'gs.base', '<none>', '<none>', 'tr', 'ldtr',
557 'mxcsr', 'fcw', 'fsw'
558 ]
559
560 # https://developer.arm.com/documentation/ihi0057/e/?lang=en#dwarf-register-names
561 _REG_NAMES_AArch64 = [
562 'x0', 'x1', 'x2', 'x3', 'x4', 'x5', 'x6', 'x7',
563 'x8', 'x9', 'x10', 'x11', 'x12', 'x13', 'x14', 'x15',
564 'x16', 'x17', 'x18', 'x19', 'x20', 'x21', 'x22', 'x23',
565 'x24', 'x25', 'x26', 'x27', 'x28', 'x29', 'x30', 'sp',
566 '<none>', 'ELR_mode', 'RA_SIGN_STATE', '<none>', '<none>', '<none>', '<none>', '<none>',
567 '<none>', '<none>', '<none>', '<none>', '<none>', '<none>', 'VG', 'FFR',
568 'p0', 'p1', 'p2', 'p3', 'p4', 'p5', 'p6', 'p7',
569 'p8', 'p9', 'p10', 'p11', 'p12', 'p13', 'p14', 'p15',
570 'v0', 'v1', 'v2', 'v3', 'v4', 'v5', 'v6', 'v7',
571 'v8', 'v9', 'v10', 'v11', 'v12', 'v13', 'v14', 'v15',
572 'v16', 'v17', 'v18', 'v19', 'v20', 'v21', 'v22', 'v23',
573 'v24', 'v25', 'v26', 'v27', 'v28', 'v29', 'v30', 'v31',
574 'z0', 'z1', 'z2', 'z3', 'z4', 'z5', 'z6', 'z7',
575 'z8', 'z9', 'z10', 'z11', 'z12', 'z13', 'z14', 'z15',
576 'z16', 'z17', 'z18', 'z19', 'z20', 'z21', 'z22', 'z23',
577 'z24', 'z25', 'z26', 'z27', 'z28', 'z29', 'z30', 'z31'
578 ]
579
580
581 class ExprDumper(object):
582 """ A dumper for DWARF expressions that dumps a textual
583 representation of the complete expression.
584
585 Usage: after creation, call dump_expr repeatedly - it's stateless.
586 """
587 def __init__(self, structs):
588 self.structs = structs
589 self.expr_parser = DWARFExprParser(self.structs)
590 self._init_lookups()
591
592 def dump_expr(self, expr, cu_offset=None):
593 """ Parse and dump a DWARF expression. expr should be a list of
594 (integer) byte values. cu_offset is the cu_offset
595 value from the CU object where the expression resides.
596 Only affects a handful of GNU opcodes, if None is provided,
597 that's not a crash condition, only the expression dump will
598 not be consistent of that of readelf.
599
600 Returns a string representing the expression.
601 """
602 parsed = self.expr_parser.parse_expr(expr)
603 s = []
604 for deo in parsed:
605 s.append(self._dump_to_string(deo.op, deo.op_name, deo.args, cu_offset))
606 return '; '.join(s)
607
608 def _init_lookups(self):
609 self._ops_with_decimal_arg = set([
610 'DW_OP_const1u', 'DW_OP_const1s', 'DW_OP_const2u', 'DW_OP_const2s',
611 'DW_OP_const4u', 'DW_OP_const4s', 'DW_OP_const8u', 'DW_OP_const8s',
612 'DW_OP_constu', 'DW_OP_consts', 'DW_OP_pick', 'DW_OP_plus_uconst',
613 'DW_OP_bra', 'DW_OP_skip', 'DW_OP_fbreg', 'DW_OP_piece',
614 'DW_OP_deref_size', 'DW_OP_xderef_size', 'DW_OP_regx',])
615
616 for n in range(0, 32):
617 self._ops_with_decimal_arg.add('DW_OP_breg%s' % n)
618
619 self._ops_with_two_decimal_args = set(['DW_OP_bregx', 'DW_OP_bit_piece'])
620
621 self._ops_with_hex_arg = set(
622 ['DW_OP_addr', 'DW_OP_call2', 'DW_OP_call4', 'DW_OP_call_ref'])
623
624 def _dump_to_string(self, opcode, opcode_name, args, cu_offset=None):
625 # Some GNU ops contain an offset from the current CU as an argument,
626 # but readelf emits those ops with offset from the info section
627 # so we need the base offset of the parent CU.
628 # If omitted, arguments on some GNU opcodes will be off.
629 if cu_offset is None:
630 cu_offset = 0
631
632 if len(args) == 0:
633 if opcode_name.startswith('DW_OP_reg'):
634 regnum = int(opcode_name[9:])
635 return '%s (%s)' % (
636 opcode_name,
637 describe_reg_name(regnum, _MACHINE_ARCH))
638 else:
639 return opcode_name
640 elif opcode_name in self._ops_with_decimal_arg:
641 if opcode_name.startswith('DW_OP_breg'):
642 regnum = int(opcode_name[10:])
643 return '%s (%s): %s' % (
644 opcode_name,
645 describe_reg_name(regnum, _MACHINE_ARCH),
646 args[0])
647 elif opcode_name.endswith('regx'):
648 # applies to both regx and bregx
649 return '%s: %s (%s)' % (
650 opcode_name,
651 args[0],
652 describe_reg_name(args[0], _MACHINE_ARCH))
653 else:
654 return '%s: %s' % (opcode_name, args[0])
655 elif opcode_name in self._ops_with_hex_arg:
656 return '%s: %x' % (opcode_name, args[0])
657 elif opcode_name in self._ops_with_two_decimal_args:
658 return '%s: %s %s' % (opcode_name, args[0], args[1])
659 elif opcode_name in ('DW_OP_GNU_entry_value', 'DW_OP_entry_value'):
660 return '%s: (%s)' % (opcode_name, ','.join([self._dump_to_string(deo.op, deo.op_name, deo.args, cu_offset) for deo in args[0]]))
661 elif opcode_name == 'DW_OP_implicit_value':
662 return "%s %s byte block: %s" % (opcode_name, len(args[0]), ''.join(["%x " % b for b in args[0]]))
663 elif opcode_name == 'DW_OP_GNU_parameter_ref':
664 return "%s: <0x%x>" % (opcode_name, args[0] + cu_offset)
665 elif opcode_name in ('DW_OP_GNU_implicit_pointer', 'DW_OP_implicit_pointer'):
666 return "%s: <0x%x> %d" % (opcode_name, args[0], args[1])
667 elif opcode_name in ('DW_OP_GNU_convert', 'DW_OP_convert'):
668 return "%s <0x%x>" % (opcode_name, args[0] + cu_offset)
669 elif opcode_name in ('DW_OP_GNU_deref_type', 'DW_OP_deref_type'):
670 return "%s: %d <0x%x>" % (opcode_name, args[0], args[1] + cu_offset)
671 elif opcode_name in ('DW_OP_GNU_const_type', 'DW_OP_const_type'):
672 return "%s: <0x%x> %d byte block: %s " % (opcode_name, args[0] + cu_offset, len(args[1]), ' '.join("%x" % b for b in args[1]))
673 elif opcode_name in ('DW_OP_GNU_regval_type', 'DW_OP_regval_type'):
674 return "%s: %d (%s) <0x%x>" % (opcode_name, args[0], describe_reg_name(args[0], _MACHINE_ARCH), args[1] + cu_offset)
675 else:
676 return '<unknown %s>' % opcode_name