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