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
, bytes2str
15 from .callframe
import instruction_name
, CIE
, FDE
18 def set_global_machine_arch(machine_arch
):
20 _MACHINE_ARCH
= machine_arch
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.
27 To cover all cases, this function needs some extra arguments:
29 die: the DIE this attribute was extracted from
30 section_offset: offset in the stream of the section the DIE belongs to
32 descr_func
= _ATTR_DESCRIPTION_MAP
[attr
.form
]
33 val_description
= descr_func(attr
, die
, section_offset
)
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
41 def describe_CFI_instructions(entry
):
42 """ Given a CFI entry (CIE or FDE), return the textual description of its
45 def _assert_FDE_instruction(instr
):
47 isinstance(entry
, FDE
),
48 'Unexpected instruction "%s" for a CIE' % instr
)
50 def _full_reg_name(regnum
):
51 regname
= describe_reg_name(regnum
, _MACHINE_ARCH
, False)
53 return 'r%s (%s)' % (regnum
, regname
)
57 if isinstance(entry
, CIE
):
61 pc
= entry
['initial_location']
64 for instr
in entry
.instructions
:
65 name
= instruction_name(instr
.opcode
)
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':
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
)
91 elif name
in ( 'DW_CFA_remember_state', 'DW_CFA_restore_state',
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]))
113 s
+= ' %s: <??>\n' % name
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
)
127 def describe_CFI_CFA_rule(rule
):
131 return '%s%+d' % (describe_reg_name(rule
.reg
), rule
.offset
)
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.
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
] = \
146 dwarf_expr_dumper
= _DWARF_EXPR_DUMPER_CACHE
[cache_key
]
147 return '(' + dwarf_expr_dumper
.dump_expr(expr
, cu_offset
) + ')'
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.
154 if machine_arch
is None:
155 machine_arch
= _MACHINE_ARCH
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
]
164 return 'r%s' % regnum
168 def describe_form_class(form
):
169 """For a given form name, determine its value class.
171 For example, given 'DW_FORM_data1' returns 'constant'.
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
177 return _FORM_CLASS
[form
]
180 #-------------------------------------------------------------------------------
182 # The machine architecture. Set globally via set_global_machine_arch
187 def _describe_attr_ref(attr
, die
, section_offset
):
188 return '<0x%x>' % (attr
.value
+ die
.cu
.cu_offset
)
190 def _describe_attr_value_passthrough(attr
, die
, section_offset
):
193 def _describe_attr_hex(attr
, die
, section_offset
):
194 return '0x%x' % (attr
.value
)
196 def _describe_attr_hex_addr(attr
, die
, section_offset
):
197 return '<0x%x>' % (attr
.value
)
199 def _describe_attr_split_64bit(attr
, die
, section_offset
):
200 low_word
= attr
.value
& 0xFFFFFFFF
201 high_word
= (attr
.value
>> 32) & 0xFFFFFFFF
202 return '0x%x 0x%x' % (low_word
, high_word
)
204 def _describe_attr_strp(attr
, die
, section_offset
):
205 return '(indirect string, offset: 0x%x): %s' % (
206 attr
.raw_value
, bytes2str(attr
.value
))
208 def _describe_attr_line_strp(attr
, die
, section_offset
):
209 return '(indirect line string, offset: 0x%x): %s' % (
210 attr
.raw_value
, bytes2str(attr
.value
))
212 def _describe_attr_string(attr
, die
, section_offset
):
213 return bytes2str(attr
.value
)
215 def _describe_attr_debool(attr
, die
, section_offset
):
216 """ To be consistent with readelf, generate 1 for True flags, 0 for False
219 return '1' if attr
.value
else '0'
221 def _describe_attr_present(attr
, die
, section_offset
):
222 """ Some forms may simply mean that an attribute is present,
223 without providing any value.
227 def _describe_attr_block(attr
, die
, section_offset
):
228 s
= '%s byte block: ' % len(attr
.value
)
229 s
+= ' '.join('%x' % item
for item
in attr
.value
) + ' '
233 _ATTR_DESCRIPTION_MAP
= defaultdict(
234 lambda: _describe_attr_value_passthrough
, # default_factory
236 DW_FORM_ref1
=_describe_attr_ref
,
237 DW_FORM_ref2
=_describe_attr_ref
,
238 DW_FORM_ref4
=_describe_attr_ref
,
239 DW_FORM_ref8
=_describe_attr_split_64bit
,
240 DW_FORM_ref_udata
=_describe_attr_ref
,
241 DW_FORM_ref_addr
=_describe_attr_hex_addr
,
242 DW_FORM_data4
=_describe_attr_hex
,
243 DW_FORM_data8
=_describe_attr_hex
,
244 DW_FORM_addr
=_describe_attr_hex
,
245 DW_FORM_sec_offset
=_describe_attr_hex
,
246 DW_FORM_flag
=_describe_attr_debool
,
247 DW_FORM_data1
=_describe_attr_value_passthrough
,
248 DW_FORM_data2
=_describe_attr_value_passthrough
,
249 DW_FORM_sdata
=_describe_attr_value_passthrough
,
250 DW_FORM_udata
=_describe_attr_value_passthrough
,
251 DW_FORM_string
=_describe_attr_string
,
252 DW_FORM_strp
=_describe_attr_strp
,
253 DW_FORM_line_strp
=_describe_attr_line_strp
,
254 DW_FORM_block1
=_describe_attr_block
,
255 DW_FORM_block2
=_describe_attr_block
,
256 DW_FORM_block4
=_describe_attr_block
,
257 DW_FORM_block
=_describe_attr_block
,
258 DW_FORM_flag_present
=_describe_attr_present
,
259 DW_FORM_exprloc
=_describe_attr_block
,
260 DW_FORM_ref_sig8
=_describe_attr_ref
,
264 DW_FORM_addr
='address',
265 DW_FORM_block2
='block',
266 DW_FORM_block4
='block',
267 DW_FORM_data2
='constant',
268 DW_FORM_data4
='constant',
269 DW_FORM_data8
='constant',
270 DW_FORM_string
='string',
271 DW_FORM_block
='block',
272 DW_FORM_block1
='block',
273 DW_FORM_data1
='constant',
275 DW_FORM_sdata
='constant',
276 DW_FORM_strp
='string',
277 DW_FORM_udata
='constant',
278 DW_FORM_ref_addr
='reference',
279 DW_FORM_ref1
='reference',
280 DW_FORM_ref2
='reference',
281 DW_FORM_ref4
='reference',
282 DW_FORM_ref8
='reference',
283 DW_FORM_ref_udata
='reference',
284 DW_FORM_indirect
=None,
285 DW_FORM_sec_offset
=None,
286 DW_FORM_exprloc
='exprloc',
287 DW_FORM_flag_present
='flag',
288 DW_FORM_ref_sig8
='reference',
292 DW_INL_not_inlined
: '(not inlined)',
293 DW_INL_inlined
: '(inlined)',
294 DW_INL_declared_not_inlined
: '(declared as inline but ignored)',
295 DW_INL_declared_inlined
: '(declared as inline and inlined)',
299 DW_LANG_C89
: '(ANSI C)',
300 DW_LANG_C
: '(non-ANSI C)',
301 DW_LANG_Ada83
: '(Ada)',
302 DW_LANG_C_plus_plus
: '(C++)',
303 DW_LANG_Cobol74
: '(Cobol 74)',
304 DW_LANG_Cobol85
: '(Cobol 85)',
305 DW_LANG_Fortran77
: '(FORTRAN 77)',
306 DW_LANG_Fortran90
: '(Fortran 90)',
307 DW_LANG_Pascal83
: '(ANSI Pascal)',
308 DW_LANG_Modula2
: '(Modula 2)',
309 DW_LANG_Java
: '(Java)',
310 DW_LANG_C99
: '(ANSI C99)',
311 DW_LANG_Ada95
: '(ADA 95)',
312 DW_LANG_Fortran95
: '(Fortran 95)',
313 DW_LANG_PLI
: '(PLI)',
314 DW_LANG_ObjC
: '(Objective C)',
315 DW_LANG_ObjC_plus_plus
: '(Objective C++)',
316 DW_LANG_UPC
: '(Unified Parallel C)',
318 DW_LANG_Python
: '(Python)',
319 DW_LANG_OpenCL
: '(OpenCL)',
321 DW_LANG_Modula3
: '(Modula 3)',
322 DW_LANG_Haskell
: '(Haskell)',
323 DW_LANG_C_plus_plus_03
: '(C++03)',
324 DW_LANG_C_plus_plus_11
: '(C++11)',
325 DW_LANG_OCaml
: '(OCaml)',
326 DW_LANG_Rust
: '(Rust)',
327 DW_LANG_C11
: '(C11)',
328 DW_LANG_Swift
: '(Swift)',
329 DW_LANG_Julia
: '(Julia)',
330 DW_LANG_Dylan
: '(Dylan)',
331 DW_LANG_C_plus_plus_14
: '(C++14)',
332 DW_LANG_Fortran03
: '(Fortran 03)',
333 DW_LANG_Fortran08
: '(Fortran 08)',
334 DW_LANG_RenderScript
: '(RenderScript)',
335 DW_LANG_BLISS
: '(Bliss)', # Not in binutils
336 DW_LANG_Mips_Assembler
: '(MIPS assembler)',
337 DW_LANG_HP_Bliss
: '(HP Bliss)',
338 DW_LANG_HP_Basic91
: '(HP Basic 91)',
339 DW_LANG_HP_Pascal91
: '(HP Pascal 91)',
340 DW_LANG_HP_IMacro
: '(HP IMacro)',
341 DW_LANG_HP_Assembler
: '(HP assembler)'
345 DW_ATE_void
: '(void)',
346 DW_ATE_address
: '(machine address)',
347 DW_ATE_boolean
: '(boolean)',
348 DW_ATE_complex_float
: '(complex float)',
349 DW_ATE_float
: '(float)',
350 DW_ATE_signed
: '(signed)',
351 DW_ATE_signed_char
: '(signed char)',
352 DW_ATE_unsigned
: '(unsigned)',
353 DW_ATE_unsigned_char
: '(unsigned char)',
354 DW_ATE_imaginary_float
: '(imaginary float)',
355 DW_ATE_decimal_float
: '(decimal float)',
356 DW_ATE_packed_decimal
: '(packed_decimal)',
357 DW_ATE_numeric_string
: '(numeric_string)',
358 DW_ATE_edited
: '(edited)',
359 DW_ATE_signed_fixed
: '(signed_fixed)',
360 DW_ATE_unsigned_fixed
: '(unsigned_fixed)',
361 DW_ATE_UTF
: '(unicode string)',
362 DW_ATE_HP_float80
: '(HP_float80)',
363 DW_ATE_HP_complex_float80
: '(HP_complex_float80)',
364 DW_ATE_HP_float128
: '(HP_float128)',
365 DW_ATE_HP_complex_float128
: '(HP_complex_float128)',
366 DW_ATE_HP_floathpintel
: '(HP_floathpintel)',
367 DW_ATE_HP_imaginary_float80
: '(HP_imaginary_float80)',
368 DW_ATE_HP_imaginary_float128
: '(HP_imaginary_float128)',
372 DW_ACCESS_public
: '(public)',
373 DW_ACCESS_protected
: '(protected)',
374 DW_ACCESS_private
: '(private)',
378 DW_VIS_local
: '(local)',
379 DW_VIS_exported
: '(exported)',
380 DW_VIS_qualified
: '(qualified)',
383 _DESCR_DW_VIRTUALITY
= {
384 DW_VIRTUALITY_none
: '(none)',
385 DW_VIRTUALITY_virtual
: '(virtual)',
386 DW_VIRTUALITY_pure_virtual
: '(pure virtual)',
389 _DESCR_DW_ID_CASE
= {
390 DW_ID_case_sensitive
: '(case_sensitive)',
391 DW_ID_up_case
: '(up_case)',
392 DW_ID_down_case
: '(down_case)',
393 DW_ID_case_insensitive
: '(case_insensitive)',
397 DW_CC_normal
: '(normal)',
398 DW_CC_program
: '(program)',
399 DW_CC_nocall
: '(nocall)',
403 DW_ORD_row_major
: '(row major)',
404 DW_ORD_col_major
: '(column major)',
407 _DESCR_CFI_REGISTER_RULE_TYPE
= dict(
414 VAL_EXPRESSION
='vexp',
418 def _make_extra_mapper(mapping
, default
, default_interpolate_value
=False):
419 """ Create a mapping function from attribute parameters to an extra
420 value that should be displayed.
422 def mapper(attr
, die
, section_offset
):
423 if default_interpolate_value
:
424 d
= default
% attr
.value
427 return mapping
.get(attr
.value
, d
)
431 def _make_extra_string(s
=''):
432 """ Create an extra function that just returns a constant string.
434 def extra(attr
, die
, section_offset
):
439 _DWARF_EXPR_DUMPER_CACHE
= {}
441 def _location_list_extra(attr
, die
, section_offset
):
442 # According to section 2.6 of the DWARF spec v3, class loclistptr means
443 # a location list, and class block means a location expression.
444 # DW_FORM_sec_offset is new in DWARFv4 as a section offset.
445 if attr
.form
in ('DW_FORM_data4', 'DW_FORM_data8', 'DW_FORM_sec_offset'):
446 return '(location list)'
448 return describe_DWARF_expr(attr
.value
, die
.cu
.structs
, die
.cu
.cu_offset
)
451 def _data_member_location_extra(attr
, die
, section_offset
):
452 # According to section 5.5.6 of the DWARF spec v4, a data member location
453 # can be an integer offset, or a location description.
455 if attr
.form
in ('DW_FORM_data1', 'DW_FORM_data2',
456 'DW_FORM_data4', 'DW_FORM_data8',
458 return '' # No extra description needed
460 return describe_DWARF_expr(attr
.value
, die
.cu
.structs
, die
.cu
.cu_offset
)
463 def _import_extra(attr
, die
, section_offset
):
464 # For DW_AT_import the value points to a DIE (that can be either in the
465 # current DIE's CU or in another CU, depending on the FORM). The extra
466 # information for it is the abbreviation number in this DIE and its tag.
467 if attr
.form
== 'DW_FORM_ref_addr':
468 # Absolute offset value
469 ref_die_offset
= section_offset
+ attr
.value
471 # Relative offset to the current DIE's CU
472 ref_die_offset
= attr
.value
+ die
.cu
.cu_offset
474 # Now find the CU this DIE belongs to (since we have to find its abbrev
475 # table). This is done by linearly scanning through all CUs, looking for
476 # one spanning an address space containing the referred DIE's offset.
477 for cu
in die
.dwarfinfo
.iter_CUs():
478 if cu
['unit_length'] + cu
.cu_offset
> ref_die_offset
>= cu
.cu_offset
:
479 # Once we have the CU, we can actually parse this DIE from the
481 with
preserve_stream_pos(die
.stream
):
482 ref_die
= DIE(cu
, die
.stream
, ref_die_offset
)
483 #print '&&& ref_die', ref_die
484 return '[Abbrev Number: %s (%s)]' % (
485 ref_die
.abbrev_code
, ref_die
.tag
)
490 _EXTRA_INFO_DESCRIPTION_MAP
= defaultdict(
491 lambda: _make_extra_string(''), # default_factory
493 DW_AT_inline
=_make_extra_mapper(
494 _DESCR_DW_INL
, '(Unknown inline attribute value: %x',
495 default_interpolate_value
=True),
496 DW_AT_language
=_make_extra_mapper(
497 _DESCR_DW_LANG
, '(Unknown: %x)', default_interpolate_value
=True),
498 DW_AT_encoding
=_make_extra_mapper(_DESCR_DW_ATE
, '(unknown type)'),
499 DW_AT_accessibility
=_make_extra_mapper(
500 _DESCR_DW_ACCESS
, '(unknown accessibility)'),
501 DW_AT_visibility
=_make_extra_mapper(
502 _DESCR_DW_VIS
, '(unknown visibility)'),
503 DW_AT_virtuality
=_make_extra_mapper(
504 _DESCR_DW_VIRTUALITY
, '(unknown virtuality)'),
505 DW_AT_identifier_case
=_make_extra_mapper(
506 _DESCR_DW_ID_CASE
, '(unknown case)'),
507 DW_AT_calling_convention
=_make_extra_mapper(
508 _DESCR_DW_CC
, '(unknown convention)'),
509 DW_AT_ordering
=_make_extra_mapper(
510 _DESCR_DW_ORD
, '(undefined)'),
511 DW_AT_frame_base
=_location_list_extra
,
512 DW_AT_location
=_location_list_extra
,
513 DW_AT_string_length
=_location_list_extra
,
514 DW_AT_return_addr
=_location_list_extra
,
515 DW_AT_data_member_location
=_data_member_location_extra
,
516 DW_AT_vtable_elem_location
=_location_list_extra
,
517 DW_AT_segment
=_location_list_extra
,
518 DW_AT_static_link
=_location_list_extra
,
519 DW_AT_use_location
=_location_list_extra
,
520 DW_AT_allocated
=_location_list_extra
,
521 DW_AT_associated
=_location_list_extra
,
522 DW_AT_data_location
=_location_list_extra
,
523 DW_AT_stride
=_location_list_extra
,
524 DW_AT_call_value
=_location_list_extra
,
525 DW_AT_import
=_import_extra
,
526 DW_AT_GNU_call_site_value
=_location_list_extra
,
527 DW_AT_GNU_call_site_data_value
=_location_list_extra
,
528 DW_AT_GNU_call_site_target
=_location_list_extra
,
529 DW_AT_GNU_call_site_target_clobbered
=_location_list_extra
,
532 # 8 in a line, for easier counting
534 'eax', 'ecx', 'edx', 'ebx', 'esp', 'ebp', 'esi', 'edi',
535 'eip', 'eflags', '<none>', 'st0', 'st1', 'st2', 'st3', 'st4',
536 'st5', 'st6', 'st7', '<none>', '<none>', 'xmm0', 'xmm1', 'xmm2',
537 'xmm3', 'xmm4', 'xmm5', 'xmm6', 'xmm7', 'mm0', 'mm1', 'mm2',
538 'mm3', 'mm4', 'mm5', 'mm6', 'mm7', 'fcw', 'fsw', 'mxcsr',
539 'es', 'cs', 'ss', 'ds', 'fs', 'gs', '<none>', '<none>', 'tr', 'ldtr'
543 'rax', 'rdx', 'rcx', 'rbx', 'rsi', 'rdi', 'rbp', 'rsp',
544 'r8', 'r9', 'r10', 'r11', 'r12', 'r13', 'r14', 'r15',
545 'rip', 'xmm0', 'xmm1', 'xmm2', 'xmm3', 'xmm4', 'xmm5', 'xmm6',
546 'xmm7', 'xmm8', 'xmm9', 'xmm10', 'xmm11', 'xmm12', 'xmm13', 'xmm14',
547 'xmm15', 'st0', 'st1', 'st2', 'st3', 'st4', 'st5', 'st6',
548 'st7', 'mm0', 'mm1', 'mm2', 'mm3', 'mm4', 'mm5', 'mm6',
549 'mm7', 'rflags', 'es', 'cs', 'ss', 'ds', 'fs', 'gs',
550 '<none>', '<none>', 'fs.base', 'gs.base', '<none>', '<none>', 'tr', 'ldtr',
551 'mxcsr', 'fcw', 'fsw'
554 # https://developer.arm.com/documentation/ihi0057/e/?lang=en#dwarf-register-names
555 _REG_NAMES_AArch64
= [
556 'x0', 'x1', 'x2', 'x3', 'x4', 'x5', 'x6', 'x7',
557 'x8', 'x9', 'x10', 'x11', 'x12', 'x13', 'x14', 'x15',
558 'x16', 'x17', 'x18', 'x19', 'x20', 'x21', 'x22', 'x23',
559 'x24', 'x25', 'x26', 'x27', 'x28', 'x29', 'x30', 'sp',
560 '<none>', 'ELR_mode', 'RA_SIGN_STATE', '<none>', '<none>', '<none>', '<none>', '<none>',
561 '<none>', '<none>', '<none>', '<none>', '<none>', '<none>', 'VG', 'FFR',
562 'p0', 'p1', 'p2', 'p3', 'p4', 'p5', 'p6', 'p7',
563 'p8', 'p9', 'p10', 'p11', 'p12', 'p13', 'p14', 'p15',
564 'v0', 'v1', 'v2', 'v3', 'v4', 'v5', 'v6', 'v7',
565 'v8', 'v9', 'v10', 'v11', 'v12', 'v13', 'v14', 'v15',
566 'v16', 'v17', 'v18', 'v19', 'v20', 'v21', 'v22', 'v23',
567 'v24', 'v25', 'v26', 'v27', 'v28', 'v29', 'v30', 'v31',
568 'z0', 'z1', 'z2', 'z3', 'z4', 'z5', 'z6', 'z7',
569 'z8', 'z9', 'z10', 'z11', 'z12', 'z13', 'z14', 'z15',
570 'z16', 'z17', 'z18', 'z19', 'z20', 'z21', 'z22', 'z23',
571 'z24', 'z25', 'z26', 'z27', 'z28', 'z29', 'z30', 'z31'
575 class ExprDumper(object):
576 """ A dumper for DWARF expressions that dumps a textual
577 representation of the complete expression.
579 Usage: after creation, call dump_expr repeatedly - it's stateless.
581 def __init__(self
, structs
):
582 self
.structs
= structs
583 self
.expr_parser
= DWARFExprParser(self
.structs
)
586 def dump_expr(self
, expr
, cu_offset
=None):
587 """ Parse and dump a DWARF expression. expr should be a list of
588 (integer) byte values. cu_offset is the cu_offset
589 value from the CU object where the expression resides.
590 Only affects a handful of GNU opcodes, if None is provided,
591 that's not a crash condition, only the expression dump will
592 not be consistent of that of readelf.
594 Returns a string representing the expression.
596 parsed
= self
.expr_parser
.parse_expr(expr
)
599 s
.append(self
._dump
_to
_string
(deo
.op
, deo
.op_name
, deo
.args
, cu_offset
))
602 def _init_lookups(self
):
603 self
._ops
_with
_decimal
_arg
= set([
604 'DW_OP_const1u', 'DW_OP_const1s', 'DW_OP_const2u', 'DW_OP_const2s',
605 'DW_OP_const4u', 'DW_OP_const4s', 'DW_OP_const8u', 'DW_OP_const8s',
606 'DW_OP_constu', 'DW_OP_consts', 'DW_OP_pick', 'DW_OP_plus_uconst',
607 'DW_OP_bra', 'DW_OP_skip', 'DW_OP_fbreg', 'DW_OP_piece',
608 'DW_OP_deref_size', 'DW_OP_xderef_size', 'DW_OP_regx',])
610 for n
in range(0, 32):
611 self
._ops
_with
_decimal
_arg
.add('DW_OP_breg%s' % n
)
613 self
._ops
_with
_two
_decimal
_args
= set(['DW_OP_bregx', 'DW_OP_bit_piece'])
615 self
._ops
_with
_hex
_arg
= set(
616 ['DW_OP_addr', 'DW_OP_call2', 'DW_OP_call4', 'DW_OP_call_ref'])
618 def _dump_to_string(self
, opcode
, opcode_name
, args
, cu_offset
=None):
619 # Some GNU ops contain an offset from the current CU as an argument,
620 # but readelf emits those ops with offset from the info section
621 # so we need the base offset of the parent CU.
622 # If omitted, arguments on some GNU opcodes will be off.
623 if cu_offset
is None:
627 if opcode_name
.startswith('DW_OP_reg'):
628 regnum
= int(opcode_name
[9:])
631 describe_reg_name(regnum
, _MACHINE_ARCH
))
634 elif opcode_name
in self
._ops
_with
_decimal
_arg
:
635 if opcode_name
.startswith('DW_OP_breg'):
636 regnum
= int(opcode_name
[10:])
637 return '%s (%s): %s' % (
639 describe_reg_name(regnum
, _MACHINE_ARCH
),
641 elif opcode_name
.endswith('regx'):
642 # applies to both regx and bregx
643 return '%s: %s (%s)' % (
646 describe_reg_name(args
[0], _MACHINE_ARCH
))
648 return '%s: %s' % (opcode_name
, args
[0])
649 elif opcode_name
in self
._ops
_with
_hex
_arg
:
650 return '%s: %x' % (opcode_name
, args
[0])
651 elif opcode_name
in self
._ops
_with
_two
_decimal
_args
:
652 return '%s: %s %s' % (opcode_name
, args
[0], args
[1])
653 elif opcode_name
in ('DW_OP_GNU_entry_value', 'DW_OP_entry_value'):
654 return '%s: (%s)' % (opcode_name
, ','.join([self
._dump
_to
_string
(deo
.op
, deo
.op_name
, deo
.args
, cu_offset
) for deo
in args
[0]]))
655 elif opcode_name
== 'DW_OP_implicit_value':
656 return "%s %s byte block: %s" % (opcode_name
, len(args
[0]), ''.join(["%x " % b
for b
in args
[0]]))
657 elif opcode_name
== 'DW_OP_GNU_parameter_ref':
658 return "%s: <0x%x>" % (opcode_name
, args
[0] + cu_offset
)
659 elif opcode_name
in ('DW_OP_GNU_implicit_pointer', 'DW_OP_implicit_pointer'):
660 return "%s: <0x%x> %d" % (opcode_name
, args
[0], args
[1])
661 elif opcode_name
in ('DW_OP_GNU_convert', 'DW_OP_convert'):
662 return "%s <0x%x>" % (opcode_name
, args
[0] + cu_offset
)
663 elif opcode_name
in ('DW_OP_GNU_deref_type', 'DW_OP_deref_type'):
664 return "%s: %d <0x%x>" % (opcode_name
, args
[0], args
[1] + cu_offset
)
665 elif opcode_name
in ('DW_OP_GNU_const_type', 'DW_OP_const_type'):
666 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]))
667 elif opcode_name
in ('DW_OP_GNU_regval_type', 'DW_OP_regval_type'):
668 return "%s: %d (%s) <0x%x>" % (opcode_name
, args
[0], describe_reg_name(args
[0], _MACHINE_ARCH
), args
[1] + cu_offset
)
670 return '<unknown %s>' % opcode_name