Version 5 lineprogram header (#411)
[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_import=_import_extra,
527 DW_AT_GNU_call_site_value=_location_list_extra,
528 DW_AT_GNU_call_site_data_value=_location_list_extra,
529 DW_AT_GNU_call_site_target=_location_list_extra,
530 DW_AT_GNU_call_site_target_clobbered=_location_list_extra,
531 )
532
533 # 8 in a line, for easier counting
534 _REG_NAMES_x86 = [
535 'eax', 'ecx', 'edx', 'ebx', 'esp', 'ebp', 'esi', 'edi',
536 'eip', 'eflags', '<none>', 'st0', 'st1', 'st2', 'st3', 'st4',
537 'st5', 'st6', 'st7', '<none>', '<none>', 'xmm0', 'xmm1', 'xmm2',
538 'xmm3', 'xmm4', 'xmm5', 'xmm6', 'xmm7', 'mm0', 'mm1', 'mm2',
539 'mm3', 'mm4', 'mm5', 'mm6', 'mm7', 'fcw', 'fsw', 'mxcsr',
540 'es', 'cs', 'ss', 'ds', 'fs', 'gs', '<none>', '<none>', 'tr', 'ldtr'
541 ]
542
543 _REG_NAMES_x64 = [
544 'rax', 'rdx', 'rcx', 'rbx', 'rsi', 'rdi', 'rbp', 'rsp',
545 'r8', 'r9', 'r10', 'r11', 'r12', 'r13', 'r14', 'r15',
546 'rip', 'xmm0', 'xmm1', 'xmm2', 'xmm3', 'xmm4', 'xmm5', 'xmm6',
547 'xmm7', 'xmm8', 'xmm9', 'xmm10', 'xmm11', 'xmm12', 'xmm13', 'xmm14',
548 'xmm15', 'st0', 'st1', 'st2', 'st3', 'st4', 'st5', 'st6',
549 'st7', 'mm0', 'mm1', 'mm2', 'mm3', 'mm4', 'mm5', 'mm6',
550 'mm7', 'rflags', 'es', 'cs', 'ss', 'ds', 'fs', 'gs',
551 '<none>', '<none>', 'fs.base', 'gs.base', '<none>', '<none>', 'tr', 'ldtr',
552 'mxcsr', 'fcw', 'fsw'
553 ]
554
555 # https://developer.arm.com/documentation/ihi0057/e/?lang=en#dwarf-register-names
556 _REG_NAMES_AArch64 = [
557 'x0', 'x1', 'x2', 'x3', 'x4', 'x5', 'x6', 'x7',
558 'x8', 'x9', 'x10', 'x11', 'x12', 'x13', 'x14', 'x15',
559 'x16', 'x17', 'x18', 'x19', 'x20', 'x21', 'x22', 'x23',
560 'x24', 'x25', 'x26', 'x27', 'x28', 'x29', 'x30', 'sp',
561 '<none>', 'ELR_mode', 'RA_SIGN_STATE', '<none>', '<none>', '<none>', '<none>', '<none>',
562 '<none>', '<none>', '<none>', '<none>', '<none>', '<none>', 'VG', 'FFR',
563 'p0', 'p1', 'p2', 'p3', 'p4', 'p5', 'p6', 'p7',
564 'p8', 'p9', 'p10', 'p11', 'p12', 'p13', 'p14', 'p15',
565 'v0', 'v1', 'v2', 'v3', 'v4', 'v5', 'v6', 'v7',
566 'v8', 'v9', 'v10', 'v11', 'v12', 'v13', 'v14', 'v15',
567 'v16', 'v17', 'v18', 'v19', 'v20', 'v21', 'v22', 'v23',
568 'v24', 'v25', 'v26', 'v27', 'v28', 'v29', 'v30', 'v31',
569 'z0', 'z1', 'z2', 'z3', 'z4', 'z5', 'z6', 'z7',
570 'z8', 'z9', 'z10', 'z11', 'z12', 'z13', 'z14', 'z15',
571 'z16', 'z17', 'z18', 'z19', 'z20', 'z21', 'z22', 'z23',
572 'z24', 'z25', 'z26', 'z27', 'z28', 'z29', 'z30', 'z31'
573 ]
574
575
576 class ExprDumper(object):
577 """ A dumper for DWARF expressions that dumps a textual
578 representation of the complete expression.
579
580 Usage: after creation, call dump_expr repeatedly - it's stateless.
581 """
582 def __init__(self, structs):
583 self.structs = structs
584 self.expr_parser = DWARFExprParser(self.structs)
585 self._init_lookups()
586
587 def dump_expr(self, expr, cu_offset=None):
588 """ Parse and dump a DWARF expression. expr should be a list of
589 (integer) byte values. cu_offset is the cu_offset
590 value from the CU object where the expression resides.
591 Only affects a handful of GNU opcodes, if None is provided,
592 that's not a crash condition, only the expression dump will
593 not be consistent of that of readelf.
594
595 Returns a string representing the expression.
596 """
597 parsed = self.expr_parser.parse_expr(expr)
598 s = []
599 for deo in parsed:
600 s.append(self._dump_to_string(deo.op, deo.op_name, deo.args, cu_offset))
601 return '; '.join(s)
602
603 def _init_lookups(self):
604 self._ops_with_decimal_arg = set([
605 'DW_OP_const1u', 'DW_OP_const1s', 'DW_OP_const2u', 'DW_OP_const2s',
606 'DW_OP_const4u', 'DW_OP_const4s', 'DW_OP_const8u', 'DW_OP_const8s',
607 'DW_OP_constu', 'DW_OP_consts', 'DW_OP_pick', 'DW_OP_plus_uconst',
608 'DW_OP_bra', 'DW_OP_skip', 'DW_OP_fbreg', 'DW_OP_piece',
609 'DW_OP_deref_size', 'DW_OP_xderef_size', 'DW_OP_regx',])
610
611 for n in range(0, 32):
612 self._ops_with_decimal_arg.add('DW_OP_breg%s' % n)
613
614 self._ops_with_two_decimal_args = set(['DW_OP_bregx', 'DW_OP_bit_piece'])
615
616 self._ops_with_hex_arg = set(
617 ['DW_OP_addr', 'DW_OP_call2', 'DW_OP_call4', 'DW_OP_call_ref'])
618
619 def _dump_to_string(self, opcode, opcode_name, args, cu_offset=None):
620 # Some GNU ops contain an offset from the current CU as an argument,
621 # but readelf emits those ops with offset from the info section
622 # so we need the base offset of the parent CU.
623 # If omitted, arguments on some GNU opcodes will be off.
624 if cu_offset is None:
625 cu_offset = 0
626
627 if len(args) == 0:
628 if opcode_name.startswith('DW_OP_reg'):
629 regnum = int(opcode_name[9:])
630 return '%s (%s)' % (
631 opcode_name,
632 describe_reg_name(regnum, _MACHINE_ARCH))
633 else:
634 return opcode_name
635 elif opcode_name in self._ops_with_decimal_arg:
636 if opcode_name.startswith('DW_OP_breg'):
637 regnum = int(opcode_name[10:])
638 return '%s (%s): %s' % (
639 opcode_name,
640 describe_reg_name(regnum, _MACHINE_ARCH),
641 args[0])
642 elif opcode_name.endswith('regx'):
643 # applies to both regx and bregx
644 return '%s: %s (%s)' % (
645 opcode_name,
646 args[0],
647 describe_reg_name(args[0], _MACHINE_ARCH))
648 else:
649 return '%s: %s' % (opcode_name, args[0])
650 elif opcode_name in self._ops_with_hex_arg:
651 return '%s: %x' % (opcode_name, args[0])
652 elif opcode_name in self._ops_with_two_decimal_args:
653 return '%s: %s %s' % (opcode_name, args[0], args[1])
654 elif opcode_name == 'DW_OP_GNU_entry_value':
655 return '%s: (%s)' % (opcode_name, ','.join([self._dump_to_string(deo.op, deo.op_name, deo.args) for deo in args[0]]))
656 elif opcode_name == 'DW_OP_implicit_value':
657 return "%s %s byte block: %s" % (opcode_name, len(args[0]), ''.join(["%x " % b for b in args[0]]))
658 elif opcode_name == 'DW_OP_GNU_parameter_ref':
659 return "%s: <0x%x>" % (opcode_name, args[0] + cu_offset)
660 elif opcode_name == 'DW_OP_GNU_implicit_pointer':
661 return "%s: <0x%x> %d" % (opcode_name, args[0], args[1])
662 elif opcode_name == 'DW_OP_GNU_convert':
663 return "%s <0x%x>" % (opcode_name, args[0] + cu_offset)
664 elif opcode_name == 'DW_OP_GNU_deref_type':
665 return "%s: %d <0x%x>" % (opcode_name, args[0], args[1] + cu_offset)
666 elif opcode_name == 'DW_OP_GNU_const_type':
667 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]))
668 elif opcode_name == 'DW_OP_GNU_regval_type':
669 return "%s: %d (%s) <0x%x>" % (opcode_name, args[0], describe_reg_name(args[0], _MACHINE_ARCH), args[1] + cu_offset)
670 else:
671 return '<unknown %s>' % opcode_name