4050fe5409fca28b4d0b510126960f7da57675bd
[pyelftools.git] / scripts / dwarfdump.py
1 #!/usr/bin/env python
2 #-------------------------------------------------------------------------------
3 # scripts/dwarfdump.py
4 #
5 # A clone of 'llvm-dwarfdump' in Python, based on the pyelftools library
6 # Roughly corresponding to v15
7 #
8 # Sources under https://github.com/llvm/llvm-project/tree/main/llvm/tools/llvm-dwarfdump
9 #
10 # Utterly incompatible with 64-bit DWARF or DWARFv2 targeting a 64-bit machine.
11 # Also incompatible with machines that have a selector/segment in the address.
12 #
13 # Eli Bendersky (eliben@gmail.com)
14 # This code is in the public domain
15 #-------------------------------------------------------------------------------
16 import argparse
17 import os, sys, posixpath
18 import traceback
19
20 # For running from development directory. It should take precedence over the
21 # installed pyelftools.
22 sys.path.insert(0, '.')
23
24 from elftools import __version__
25 from elftools.common.exceptions import DWARFError, ELFError
26 from elftools.common.utils import bytes2str
27 from elftools.elf.elffile import ELFFile
28 from elftools.dwarf.locationlists import LocationParser, LocationEntry, LocationExpr, LocationViewPair, BaseAddressEntry as LocBaseAddressEntry
29 from elftools.dwarf.ranges import RangeEntry # ranges.BaseAddressEntry collides with the one above
30 import elftools.dwarf.ranges
31 from elftools.dwarf.enums import *
32 from elftools.dwarf.dwarf_expr import DWARFExprParser, DWARFExprOp
33 from elftools.dwarf.datatype_cpp import DIE_name, describe_cpp_datatype
34 from elftools.dwarf.descriptions import describe_reg_name
35
36 # ------------------------------
37 # ------------------------------
38
39 def _get_cu_base(cu):
40 top_die = cu.get_top_DIE()
41 attr = top_die.attributes
42 if 'DW_AT_low_pc' in attr:
43 return attr['DW_AT_low_pc'].value
44 elif 'DW_AT_entry_pc' in attr:
45 return attr['DW_AT_entry_pc'].value
46 else:
47 raise ValueError("Can't find the base IP (low_pc) for a CU")
48
49 def _addr_str_length(die):
50 return die.cu.header.address_size*2
51
52 def _DIE_name(die):
53 if 'DW_AT_name' in die.attributes:
54 return bytes2str(die.attributes['DW_AT_name'].value)
55 elif 'DW_AT_linkage_name' in die.attributes:
56 return bytes2str(die.attributes['DW_AT_linkage_name'].value)
57 else:
58 raise DWARFError()
59
60 def _DIE_linkage_name(die):
61 if 'DW_AT_linkage_name' in die.attributes:
62 return bytes2str(die.attributes['DW_AT_linkage_name'].value)
63 elif 'DW_AT_name' in die.attributes:
64 return bytes2str(die.attributes['DW_AT_name'].value)
65 else:
66 raise DWARFError()
67
68 def _safe_DIE_name(die, default=None):
69 if 'DW_AT_name' in die.attributes:
70 return bytes2str(die.attributes['DW_AT_name'].value)
71 elif 'DW_AT_linkage_name' in die.attributes:
72 return bytes2str(die.attributes['DW_AT_linkage_name'].value)
73 else:
74 return default
75
76 def _safe_DIE_linkage_name(die, default=None):
77 if 'DW_AT_linkage_name' in die.attributes:
78 return bytes2str(die.attributes['DW_AT_linkage_name'].value)
79 elif 'DW_AT_name' in die.attributes:
80 return bytes2str(die.attributes['DW_AT_name'].value)
81 else:
82 return default
83
84 def _desc_ref(attr, die, extra=''):
85 if extra:
86 extra = " \"%s\"" % extra
87 return "cu + 0x%04x => {0x%08x}%s" % (
88 attr.raw_value,
89 die.cu.cu_offset + attr.raw_value,
90 extra)
91
92 def _desc_data(attr, die):
93 """ Hex with length driven by form
94 """
95 len = int(attr.form[12:]) * 2
96 return "0x%0*x" % (len, attr.value,)
97
98 def _desc_strx(attr, die):
99 return "indexed (%08x) string = \"%s\"" % (attr.raw_value, bytes2str(attr.value).replace("\\", "\\\\"))
100
101 FORM_DESCRIPTIONS = dict(
102 DW_FORM_string=lambda attr, die: "\"%s\"" % (bytes2str(attr.value),),
103 DW_FORM_strp=lambda attr, die: " .debug_str[0x%08x] = \"%s\"" % (attr.raw_value, bytes2str(attr.value).replace("\\", "\\\\")),
104 DW_FORM_strx1=_desc_strx,
105 DW_FORM_strx2=_desc_strx,
106 DW_FORM_strx3=_desc_strx,
107 DW_FORM_strx4=_desc_strx,
108 DW_FORM_line_strp=lambda attr, die: ".debug_line_str[0x%08x] = \"%s\"" % (attr.raw_value, bytes2str(attr.value).replace("\\", "\\\\")),
109 DW_FORM_flag_present=lambda attr, die: "true",
110 DW_FORM_flag=lambda attr, die: "0x%02x" % int(attr.value),
111 DW_FORM_addr=lambda attr, die: "0x%0*x" % (_addr_str_length(die), attr.value),
112 DW_FORM_addrx=lambda attr, die: "indexed (%08x) address = 0x%0*x" % (attr.raw_value, _addr_str_length(die), attr.value),
113 DW_FORM_data1=_desc_data,
114 DW_FORM_data2=_desc_data,
115 DW_FORM_data4=_desc_data,
116 DW_FORM_data8=_desc_data,
117 DW_FORM_block1=lambda attr, die: "<0x%02x> %s " % (len(attr.value), " ".join("%02x" %b for b in attr.value)),
118 DW_FORM_block2=lambda attr, die: "<0x%04x> %s " % (len(attr.value), " ".join("%02x" %b for b in attr.value)),
119 DW_FORM_block4=lambda attr, die: "<0x%08x> %s " % (len(attr.value), " ".join("%02x" %b for b in attr.value)),
120 DW_FORM_ref=_desc_ref,
121 DW_FORM_ref1=_desc_ref, DW_FORM_ref2=_desc_ref,
122 DW_FORM_ref4=_desc_ref, DW_FORM_ref8=_desc_ref,
123 DW_FORM_sec_offset=lambda attr,die: "0x%08x" % (attr.value,),
124 DW_FORM_exprloc=lambda attr, die: _desc_expression(attr.value, die)
125 )
126
127 def _desc_enum(attr, enum):
128 """For attributes like DW_AT_language, physically
129 int, logically an enum
130 """
131 return next((k for (k, v) in enum.items() if v == attr.value), str(attr.value))
132
133 def _cu_comp_dir(cu):
134 return bytes2str(cu.get_top_DIE().attributes['DW_AT_comp_dir'].value)
135
136 def _desc_decl_file(attr, die):
137 # Filename/dirname arrays are 0 based in DWARFv5
138 cu = die.cu
139 if not hasattr(cu, "_lineprogram"):
140 cu._lineprogram = die.dwarfinfo.line_program_for_CU(cu)
141 ver5 = cu._lineprogram.header.version >= 5
142 file_index = attr.value if ver5 else attr.value-1
143 if cu._lineprogram and file_index >= 0 and file_index < len(cu._lineprogram.header.file_entry):
144 file_entry = cu._lineprogram.header.file_entry[file_index]
145 dir_index = file_entry.dir_index if ver5 else file_entry.dir_index - 1
146 includes = cu._lineprogram.header.include_directory
147 if dir_index >= 0:
148 dir = bytes2str(includes[dir_index])
149 if dir.startswith('.'):
150 dir = posixpath.join(_cu_comp_dir(cu), dir)
151 else:
152 dir = _cu_comp_dir(cu)
153 file_name = bytes2str(file_entry.name)
154 else:
155 raise DWARFError("Invalid source filename entry index in a decl_file attribute")
156 return "\"%s\"" % (posixpath.join(dir, file_name),)
157
158
159 def _desc_ranges(attr, die):
160 di = die.cu.dwarfinfo
161 if not hasattr(di, '_rnglists'):
162 di._rangelists = di.range_lists()
163 rangelist = di._rangelists.get_range_list_at_offset(attr.value, die.cu)
164 base_ip = _get_cu_base(die.cu)
165 lines = []
166 addr_str_len = die.cu.header.address_size*2
167 for entry in rangelist:
168 if isinstance(entry, RangeEntry):
169 lines.append(" [0x%0*x, 0x%0*x)" % (
170 addr_str_len,
171 (0 if entry.is_absolute else base_ip) + entry.begin_offset,
172 addr_str_len,
173 (0 if entry.is_absolute else base_ip) + entry.end_offset))
174 elif isinstance(entry, elftools.dwarf.ranges.BaseAddressEntry):
175 base_ip = entry.base_address
176 else:
177 raise NotImplementedError("Unknown object in a range list")
178 prefix = "indexed (0x%x) rangelist = " % attr.raw_value if attr.form == 'DW_FORM_rnglistx' else ''
179 return ("%s0x%08x\n" % (prefix, attr.value)) + "\n".join(lines)
180
181 def _desc_locations(attr, die):
182 cu = die.cu
183 di = cu.dwarfinfo
184 if not hasattr(di, '_loclists'):
185 di._loclists = di.location_lists()
186 if not hasattr(di, '_locparser'):
187 di._locparser = LocationParser(di._loclists)
188 loclist = di._locparser.parse_from_attribute(attr, cu.header.version, die)
189 if isinstance(loclist, LocationExpr):
190 return _desc_expression(loclist.loc_expr, die)
191 else:
192 base_ip = _get_cu_base(cu)
193 lines = []
194 addr_str_len = die.cu.header.address_size*2
195 for entry in loclist:
196 if isinstance(entry, LocationEntry):
197 lines.append(" [0x%0*x, 0x%0*x): %s" % (
198 addr_str_len,
199 (0 if entry.is_absolute else base_ip) + entry.begin_offset,
200 addr_str_len,
201 (0 if entry.is_absolute else base_ip) + entry.end_offset,
202 _desc_expression(entry.loc_expr, die)))
203 elif isinstance(entry, LocBaseAddressEntry):
204 base_ip = entry.base_address
205 else:
206 raise NotImplementedError("Unknown object in a location list")
207 prefix = "indexed (0x%x) loclist = " % attr.raw_value if attr.form == 'DW_FORM_loclistx' else ''
208 return ("%s0x%08x:\n" % (prefix, attr.value)) + "\n".join(lines)
209
210 # By default, numeric arguments are spelled in hex with a leading 0x
211 def _desc_operationarg(s, cu):
212 if isinstance(s, str):
213 return s
214 elif isinstance(s, int):
215 return hex(s)
216 elif isinstance(s, list): # Could be a blob (list of ints), could be a subexpression
217 if len(s) > 0 and isinstance(s[0], DWARFExprOp): # Subexpression
218 return '(' + '; '.join(_desc_operation(op.op, op.op_name, op.args, cu) for op in s) + ')'
219 else:
220 return " ".join((hex(len(s)),) + tuple("0x%02x" % b for b in s))
221
222 def _arch(cu):
223 return cu.dwarfinfo.config.machine_arch
224
225 def _desc_reg(reg_no, cu):
226 return describe_reg_name(reg_no, _arch(cu), True).upper()
227
228 def _desc_operation(op, op_name, args, cu):
229 # Not sure about regx(regno) and bregx(regno, offset)
230 if 0x50 <= op <= 0x6f: # reg0...reg31 - decode reg name
231 return op_name + " " + _desc_reg(op - 0x50, cu)
232 elif 0x70 <= op <= 0x8f: # breg0...breg31(offset) - also decode reg name
233 return '%s %s%+d' % (
234 op_name,
235 _desc_reg(op - 0x70, cu),
236 args[0])
237 elif op_name in ('DW_OP_fbreg', 'DW_OP_bra', 'DW_OP_skip', 'DW_OP_consts', ): # Argument is decimal with a leading sign
238 return op_name + ' ' + "%+d" % (args[0])
239 elif op_name in ('DW_OP_const1s', 'DW_OP_const2s'): # Argument is decimal without a leading sign
240 return op_name + ' ' + "%d" % (args[0])
241 elif op_name in ('DW_OP_entry_value', 'DW_OP_GNU_entry_value'): # No space between opcode and args
242 return op_name + _desc_operationarg(args[0], cu)
243 elif op_name == 'DW_OP_regval_type': # Arg is a DIE pointer
244 return "%s %s (0x%08x -> 0x%08x) \"%s\"" % (
245 op_name,
246 _desc_reg(args[0], cu),
247 args[1],
248 args[1] + cu.cu_offset,
249 _DIE_name(cu._get_cached_DIE(args[1] + cu.cu_offset)))
250 elif op_name == 'DW_OP_convert': # Arg is a DIE pointer
251 return "%s (0x%08x -> 0x%08x) \"%s\"" % (
252 op_name,
253 args[0],
254 args[0] + cu.cu_offset,
255 _DIE_name(cu._get_cached_DIE(args[0] + cu.cu_offset)))
256 elif args:
257 return op_name + ' ' + ', '.join(_desc_operationarg(s, cu) for s in args)
258 else:
259 return op_name
260
261 # TODO: remove this once dwarfdump catches up
262 UNSUPPORTED_OPS = (
263 'DW_OP_implicit_pointer',
264 'DW_OP_deref_type',
265 'DW_OP_GNU_parameter_ref',
266 'DW_OP_GNU_deref_type',
267 'DW_OP_GNU_implicit_pointer',
268 'DW_OP_GNU_convert',
269 'DW_OP_GNU_regval_type')
270
271 def _desc_expression(expr, die):
272 cu = die.cu
273 if not hasattr(cu, '_exprparser'):
274 cu._exprparser = DWARFExprParser(cu.structs)
275
276 parsed = cu._exprparser.parse_expr(expr)
277 # TODO: remove this once dwarfdump catches up
278 first_unsupported = next((i for (i, op) in enumerate(parsed) if op.op_name in UNSUPPORTED_OPS), None)
279 if first_unsupported is None:
280 lines = [_desc_operation(op.op, op.op_name, op.args, cu) for op in parsed]
281 else:
282 lines = [_desc_operation(op.op, op.op_name, op.args, cu) for op in parsed[0:first_unsupported]]
283 start_of_unparsed = parsed[first_unsupported].offset
284 lines.append("<decoding error> " + " ".join("%02x" % b for b in expr[start_of_unparsed:]))
285 return ", ".join(lines)
286
287 def _desc_datatype(attr, die):
288 """Oy vey
289 """
290 return _desc_ref(attr, die, describe_cpp_datatype(die))
291
292 def _get_origin_name(die):
293 func_die = die.get_DIE_from_attribute('DW_AT_abstract_origin')
294 name = _safe_DIE_linkage_name(func_die, '')
295 if not name:
296 if 'DW_AT_specification' in func_die.attributes:
297 name = _DIE_linkage_name(func_die.get_DIE_from_attribute('DW_AT_specification'))
298 elif 'DW_AT_abstract_origin' in func_die.attributes:
299 return _get_origin_name(func_die)
300 return name
301
302 def _desc_origin(attr, die):
303 return _desc_ref(attr, die, _get_origin_name(die))
304
305 def _desc_spec(attr, die):
306 return _desc_ref(attr, die,
307 _DIE_linkage_name(die.get_DIE_from_attribute('DW_AT_specification')))
308
309 def _desc_value(attr, die):
310 return str(attr.value)
311
312 ATTR_DESCRIPTIONS = dict(
313 DW_AT_language=lambda attr, die: _desc_enum(attr, ENUM_DW_LANG),
314 DW_AT_encoding=lambda attr, die: _desc_enum(attr, ENUM_DW_ATE),
315 DW_AT_accessibility=lambda attr, die: _desc_enum(attr, ENUM_DW_ACCESS),
316 DW_AT_inline=lambda attr, die: _desc_enum(attr, ENUM_DW_INL),
317 DW_AT_calling_convention=lambda attr, die: _desc_enum(attr, ENUM_DW_CC),
318 DW_AT_decl_file=_desc_decl_file,
319 DW_AT_decl_line=_desc_value,
320 DW_AT_ranges=_desc_ranges,
321 DW_AT_location=_desc_locations,
322 DW_AT_data_member_location=lambda attr, die: _desc_data(attr, die) if attr.form.startswith('DW_FORM_data') else _desc_locations(attr, die),
323 DW_AT_frame_base=_desc_locations,
324 DW_AT_type=_desc_datatype,
325 DW_AT_call_line=_desc_value,
326 DW_AT_call_file=_desc_decl_file,
327 DW_AT_abstract_origin=_desc_origin,
328 DW_AT_specification=_desc_spec
329 )
330
331 class ReadElf(object):
332 """ dump_xxx is used to dump the respective section.
333 Mimics the output of dwarfdump with --verbose
334 """
335 def __init__(self, filename, file, output):
336 """ file:
337 stream object with the ELF file to read
338
339 output:
340 output stream to write to
341 """
342 self.elffile = ELFFile(file)
343 self.output = output
344 self._dwarfinfo = self.elffile.get_dwarf_info()
345 arches = {"EM_386": "i386", "EM_X86_64": "x86-64", "EM_AARCH64": "littleaarch64"}
346 arch = arches[self.elffile['e_machine']]
347 bits = self.elffile.elfclass
348 self._emitline("%s: file format elf%d-%s" % (filename, bits, arch))
349
350 def _emit(self, s=''):
351 """ Emit an object to output
352 """
353 self.output.write(str(s))
354
355 def _emitline(self, s=''):
356 """ Emit an object to output, followed by a newline
357 """
358 self.output.write(str(s).rstrip() + '\n')
359
360 def dump_info(self):
361 # TODO: DWARF64 will cause discrepancies in hex offset sizes
362 self._emitline(".debug_info contents:")
363 for cu in self._dwarfinfo.iter_CUs():
364 if cu.header.version >= 5:
365 unit_type_str = " unit_type = %s," % cu.header.unit_type
366 else:
367 unit_type_str = ''
368
369 self._emitline("0x%08x: Compile Unit: length = 0x%08x, format = DWARF%d, version = 0x%04x,%s abbr_offset = 0x%04x, addr_size = 0x%02x (next unit at 0x%08x)" %(
370 cu.cu_offset,
371 cu.header.unit_length,
372 cu.structs.dwarf_format,
373 cu.header.version,
374 unit_type_str,
375 cu.header.debug_abbrev_offset,
376 cu.header.address_size,
377 cu.cu_offset + (4 if cu.structs.dwarf_format == 32 else 12) + cu.header.unit_length))
378 self._emitline()
379 parent = cu.get_top_DIE()
380 for die in cu.iter_DIEs():
381 if die.get_parent() == parent:
382 parent = die
383 if not die.is_null():
384 self._emitline("0x%08x: %s [%d] %s %s" % (
385 die.offset,
386 die.tag,
387 die.abbrev_code,
388 '*' if die.has_children else '',
389 '(0x%08x)' % die.get_parent().offset if die.get_parent() is not None else ''))
390 for attr_name in die.attributes:
391 attr = die.attributes[attr_name]
392 self._emitline(" %s [%s] (%s)" % (attr_name, attr.form, self.describe_attr_value(die, attr)))
393 else:
394 self._emitline("0x%08x: NULL" % (die.offset,))
395 parent = die.get_parent()
396 self._emitline()
397
398 def describe_attr_value(self, die, attr):
399 """This describes the attribute value in the way that's compatible
400 with llvm_dwarfdump. Somewhat duplicates the work of describe_attr_value() in descriptions
401 """
402 if attr.name in ATTR_DESCRIPTIONS:
403 return ATTR_DESCRIPTIONS[attr.name](attr, die)
404 elif attr.form in FORM_DESCRIPTIONS:
405 return FORM_DESCRIPTIONS[attr.form](attr, die)
406 else:
407 return str(attr.value)
408
409 def dump_loc(self):
410 pass
411
412 def dump_loclists(self):
413 pass
414
415 def dump_ranges(self):
416 pass
417
418 def dump_v4_rangelist(self, rangelist, cu_map):
419 cu = cu_map[rangelist[0].entry_offset]
420 addr_str_len = cu.header.address_size*2
421 base_ip = _get_cu_base(cu)
422 for entry in rangelist:
423 if isinstance(entry, RangeEntry):
424 self._emitline("[0x%0*x, 0x%0*x)" % (
425 addr_str_len,
426 (0 if entry.is_absolute else base_ip) + entry.begin_offset,
427 addr_str_len,
428 (0 if entry.is_absolute else base_ip) + entry.end_offset))
429 elif isinstance(entry, elftools.dwarf.ranges.BaseAddressEntry):
430 base_ip = entry.base_address
431 else:
432 raise NotImplementedError("Unknown object in a range list")
433
434 def dump_rnglists(self):
435 self._emitline(".debug_rnglists contents:")
436 ranges_sec = self._dwarfinfo.range_lists()
437 if ranges_sec.version < 5:
438 return
439
440 cu_map = {die.attributes['DW_AT_ranges'].value : cu # Dict from range offset to home CU
441 for cu in self._dwarfinfo.iter_CUs()
442 for die in cu.iter_DIEs()
443 if 'DW_AT_ranges' in die.attributes}
444
445 for cu in ranges_sec.iter_CUs():
446 self._emitline("0x%08x: range list header: length = 0x%08x, format = DWARF%d, version = 0x%04x, addr_size = 0x%02x, seg_size = 0x%02x, offset_entry_count = 0x%08x" % (
447 cu.cu_offset,
448 cu.unit_length,
449 64 if cu.is64 else 32,
450 cu.version,
451 cu.address_size,
452 cu.segment_selector_size,
453 cu.offset_count))
454 self._emitline("ranges:")
455 if cu.offset_count > 0:
456 rangelists = [ranges_sec.get_range_list_at_offset_ex(offset) for offset in cu.offsets]
457 else:
458 rangelists = list(ranges_sec.iter_CU_range_lists_ex(cu))
459 # We have to parse it completely before dumping, because dwarfdump aligns columns,
460 # no way to do that without some lookahead
461 max_type_len = max(len(entry.entry_type) for rangelist in rangelists for entry in rangelist)
462 for rangelist in rangelists:
463 self.dump_v5_rangelist(rangelist, cu_map, max_type_len)
464
465 def dump_v5_rangelist(self, rangelist, cu_map, max_type_len):
466 cu = cu_map[rangelist[0].entry_offset]
467 addr_str_len = cu.header.address_size*2
468 base_ip = _get_cu_base(cu)
469 for entry in rangelist:
470 type = entry.entry_type
471 self._emit("0x%08x: [%s]: " % (entry.entry_offset, type.ljust(max_type_len)))
472 if type == 'DW_RLE_base_address':
473 base_ip = entry.address
474 self._emitline("0x%0*x" % (addr_str_len, base_ip))
475 elif type == 'DW_RLE_offset_pair':
476 self._emitline("0x%0*x, 0x%0*x => [0x%0*x, 0x%0*x)" % (
477 addr_str_len, entry.start_offset,
478 addr_str_len, entry.end_offset,
479 addr_str_len, entry.start_offset + base_ip,
480 addr_str_len, entry.end_offset + base_ip))
481 elif type == 'DW_RLE_start_length':
482 self._emitline("0x%0*x, 0x%0*x => [0x%0*x, 0x%0*x)" % (
483 addr_str_len, entry.start_address,
484 addr_str_len, entry.length,
485 addr_str_len, entry.start_address,
486 addr_str_len, entry.start_address + entry.length))
487 elif type == 'DW_RLE_start_end':
488 self._emitline("0x%0*x, 0x%0*x => [0x%0*x, 0x%0*x)" % (
489 addr_str_len, entry.start_address,
490 addr_str_len, entry.end_address,
491 addr_str_len, entry.start_address,
492 addr_str_len, entry.end_address))
493 else:
494 raise NotImplementedError()
495 last = rangelist[-1]
496 self._emitline("0x%08x: [DW_RLE_end_of_list ]" % (last.entry_offset + last.entry_length,))
497
498 SCRIPT_DESCRIPTION = 'Display information about the contents of ELF format files'
499 VERSION_STRING = '%%(prog)s: based on pyelftools %s' % __version__
500
501 def main(stream=None):
502 # parse the command-line arguments and invoke ReadElf
503 argparser = argparse.ArgumentParser(
504 usage='usage: %(prog)s [options] <elf-file>',
505 description=SCRIPT_DESCRIPTION,
506 add_help=False,
507 prog='readelf.py')
508 argparser.add_argument('file',
509 nargs='?', default=None,
510 help='ELF file to parse')
511 argparser.add_argument('-H', '--help',
512 action='store_true', dest='help',
513 help='Display this information')
514 argparser.add_argument('--verbose',
515 action='store_true', dest='verbose',
516 help=('For compatibility with dwarfdump. Non-verbose mode is not implemented.'))
517
518 # Section dumpers
519 sections = ('info', 'loclists', 'rnglists') # 'loc', 'ranges' not implemented yet
520 for section in sections:
521 argparser.add_argument('--debug-%s' % section,
522 action='store_true', dest=section,
523 help=('Display the contents of DWARF debug_%s section.' % section))
524
525 args = argparser.parse_args()
526
527 if args.help or not args.file:
528 argparser.print_help()
529 sys.exit(0)
530
531 # A compatibility hack on top of a compatibility hack :(
532 del ENUM_DW_TAG["DW_TAG_template_type_param"]
533 del ENUM_DW_TAG["DW_TAG_template_value_param"]
534 ENUM_DW_TAG['DW_TAG_template_type_parameter'] = 0x2f
535 ENUM_DW_TAG['DW_TAG_template_value_parameter'] = 0x30
536
537 with open(args.file, 'rb') as file:
538 try:
539 readelf = ReadElf(args.file, file, stream or sys.stdout)
540 if args.info:
541 readelf.dump_info()
542 if args.loclists:
543 readelf.dump_loclists()
544 if args.rnglists:
545 readelf.dump_rnglists()
546 #if args.loc:
547 # readelf.dump_loc()
548 #if args.ranges:
549 # readelf.dump_ranges()
550 except ELFError as ex:
551 sys.stdout.flush()
552 sys.stderr.write('ELF error: %s\n' % ex)
553 if args.show_traceback:
554 traceback.print_exc()
555 sys.exit(1)
556
557 #-------------------------------------------------------------------------------
558 if __name__ == '__main__':
559 main()
560 #profile_main()