1 #-------------------------------------------------------------------------------
2 # elftools: dwarf/descriptions.py
4 # Textual descriptions of the various values and enums of DWARF
6 # Eli Bendersky (eliben@gmail.com)
7 # This code is in the public domain
8 #-------------------------------------------------------------------------------
9 from collections
import defaultdict
11 from .constants
import *
12 from .dwarf_expr
import DWARFExprParser
14 from ..common
.utils
import preserve_stream_pos
, dwarf_assert
15 from ..common
.py3compat
import bytes2str
16 from .callframe
import instruction_name
, CIE
, FDE
19 def set_global_machine_arch(machine_arch
):
21 _MACHINE_ARCH
= machine_arch
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.
28 To cover all cases, this function needs some extra arguments:
30 die: the DIE this attribute was extracted from
31 section_offset: offset in the stream of the section the DIE belongs to
33 descr_func
= _ATTR_DESCRIPTION_MAP
[attr
.form
]
34 val_description
= descr_func(attr
, die
, section_offset
)
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
42 def describe_CFI_instructions(entry
):
43 """ Given a CFI entry (CIE or FDE), return the textual description of its
46 def _assert_FDE_instruction(instr
):
48 isinstance(entry
, FDE
),
49 'Unexpected instruction "%s" for a CIE' % instr
)
51 def _full_reg_name(regnum
):
52 regname
= describe_reg_name(regnum
, _MACHINE_ARCH
, False)
54 return 'r%s (%s)' % (regnum
, regname
)
58 if isinstance(entry
, CIE
):
62 pc
= entry
['initial_location']
65 for instr
in entry
.instructions
:
66 name
= instruction_name(instr
.opcode
)
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':
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
)
92 elif name
in ( 'DW_CFA_remember_state', 'DW_CFA_restore_state',
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]))
114 s
+= ' %s: <??>\n' % name
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
)
128 def describe_CFI_CFA_rule(rule
):
132 return '%s%+d' % (describe_reg_name(rule
.reg
), rule
.offset
)
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.
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
] = \
147 dwarf_expr_dumper
= _DWARF_EXPR_DUMPER_CACHE
[cache_key
]
148 return '(' + dwarf_expr_dumper
.dump_expr(expr
, cu_offset
) + ')'
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.
155 if machine_arch
is None:
156 machine_arch
= _MACHINE_ARCH
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
]
165 return 'r%s' % regnum
169 def describe_form_class(form
):
170 """For a given form name, determine its value class.
172 For example, given 'DW_FORM_data1' returns 'constant'.
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
178 return _FORM_CLASS
[form
]
181 #-------------------------------------------------------------------------------
183 # The machine architecture. Set globally via set_global_machine_arch
188 def _describe_attr_ref(attr
, die
, section_offset
):
189 return '<0x%x>' % (attr
.value
+ die
.cu
.cu_offset
)
191 def _describe_attr_value_passthrough(attr
, die
, section_offset
):
194 def _describe_attr_hex(attr
, die
, section_offset
):
195 return '0x%x' % (attr
.value
)
197 def _describe_attr_hex_addr(attr
, die
, section_offset
):
198 return '<0x%x>' % (attr
.value
)
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
)
205 def _describe_attr_strp(attr
, die
, section_offset
):
206 return '(indirect string, offset: 0x%x): %s' % (
207 attr
.raw_value
, bytes2str(attr
.value
))
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
))
213 def _describe_attr_string(attr
, die
, section_offset
):
214 return bytes2str(attr
.value
)
216 def _describe_attr_debool(attr
, die
, section_offset
):
217 """ To be consistent with readelf, generate 1 for True flags, 0 for False
220 return '1' if attr
.value
else '0'
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.
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
) + ' '
234 _ATTR_DESCRIPTION_MAP
= defaultdict(
235 lambda: _describe_attr_value_passthrough
, # default_factory
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
,
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',
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',
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)',
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)',
319 DW_LANG_Python
: '(Python)',
320 DW_LANG_OpenCL
: '(OpenCL)',
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)'
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)',
373 DW_ACCESS_public
: '(public)',
374 DW_ACCESS_protected
: '(protected)',
375 DW_ACCESS_private
: '(private)',
379 DW_VIS_local
: '(local)',
380 DW_VIS_exported
: '(exported)',
381 DW_VIS_qualified
: '(qualified)',
384 _DESCR_DW_VIRTUALITY
= {
385 DW_VIRTUALITY_none
: '(none)',
386 DW_VIRTUALITY_virtual
: '(virtual)',
387 DW_VIRTUALITY_pure_virtual
: '(pure virtual)',
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)',
398 DW_CC_normal
: '(normal)',
399 DW_CC_program
: '(program)',
400 DW_CC_nocall
: '(nocall)',
404 DW_ORD_row_major
: '(row major)',
405 DW_ORD_col_major
: '(column major)',
408 _DESCR_CFI_REGISTER_RULE_TYPE
= dict(
415 VAL_EXPRESSION
='vexp',
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.
423 def mapper(attr
, die
, section_offset
):
424 if default_interpolate_value
:
425 d
= default
% attr
.value
428 return mapping
.get(attr
.value
, d
)
432 def _make_extra_string(s
=''):
433 """ Create an extra function that just returns a constant string.
435 def extra(attr
, die
, section_offset
):
440 _DWARF_EXPR_DUMPER_CACHE
= {}
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)'
449 return describe_DWARF_expr(attr
.value
, die
.cu
.structs
, die
.cu
.cu_offset
)
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.
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
)
462 return describe_DWARF_expr(attr
.value
, die
.cu
.structs
, die
.cu
.cu_offset
)
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
473 # Relative offset to the current DIE's CU
474 ref_die_offset
= attr
.value
+ die
.cu
.cu_offset
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
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
)
492 _EXTRA_INFO_DESCRIPTION_MAP
= defaultdict(
493 lambda: _make_extra_string(''), # default_factory
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
,
533 # 8 in a line, for easier counting
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'
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'
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'
576 class ExprDumper(object):
577 """ A dumper for DWARF expressions that dumps a textual
578 representation of the complete expression.
580 Usage: after creation, call dump_expr repeatedly - it's stateless.
582 def __init__(self
, structs
):
583 self
.structs
= structs
584 self
.expr_parser
= DWARFExprParser(self
.structs
)
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.
595 Returns a string representing the expression.
597 parsed
= self
.expr_parser
.parse_expr(expr
)
600 s
.append(self
._dump
_to
_string
(deo
.op
, deo
.op_name
, deo
.args
, cu_offset
))
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',])
611 for n
in range(0, 32):
612 self
._ops
_with
_decimal
_arg
.add('DW_OP_breg%s' % n
)
614 self
._ops
_with
_two
_decimal
_args
= set(['DW_OP_bregx', 'DW_OP_bit_piece'])
616 self
._ops
_with
_hex
_arg
= set(
617 ['DW_OP_addr', 'DW_OP_call2', 'DW_OP_call4', 'DW_OP_call_ref'])
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:
628 if opcode_name
.startswith('DW_OP_reg'):
629 regnum
= int(opcode_name
[9:])
632 describe_reg_name(regnum
, _MACHINE_ARCH
))
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' % (
640 describe_reg_name(regnum
, _MACHINE_ARCH
),
642 elif opcode_name
.endswith('regx'):
643 # applies to both regx and bregx
644 return '%s: %s (%s)' % (
647 describe_reg_name(args
[0], _MACHINE_ARCH
))
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
)
671 return '<unknown %s>' % opcode_name