From 26e41c4b59ed72ac7bb74006bf077b2438a6acfb Mon Sep 17 00:00:00 2001 From: Eli Bendersky Date: Wed, 28 Dec 2011 09:21:14 +0200 Subject: [PATCH] a bit of refactoring in the test/ dir + completed dwarf_location_lists example --- examples/dwarf_location_lists.py | 43 ++++++++++++++++++-- test/__init__.py | 0 test/{utils => external_tools}/Makefile | 0 test/{utils => external_tools}/README.txt | 0 test/{utils => external_tools}/elf_creator.c | 0 test/run_readelf_tests.py | 30 ++------------ test/utils.py | 22 ++++++++++ z.py | 8 ++-- 8 files changed, 69 insertions(+), 34 deletions(-) create mode 100644 test/__init__.py rename test/{utils => external_tools}/Makefile (100%) rename test/{utils => external_tools}/README.txt (100%) rename test/{utils => external_tools}/elf_creator.c (100%) create mode 100644 test/utils.py diff --git a/examples/dwarf_location_lists.py b/examples/dwarf_location_lists.py index 266bceb..a9f22bb 100644 --- a/examples/dwarf_location_lists.py +++ b/examples/dwarf_location_lists.py @@ -18,6 +18,9 @@ except ImportError: sys.path.extend(['.', '..']) from elftools.elf.elffile import ELFFile +from elftools.dwarf.descriptions import ( + describe_DWARF_expr, set_global_machine_arch) +from elftools.dwarf.locationlists import LocationEntry def process_file(filename): @@ -37,6 +40,10 @@ def process_file(filename): # section, and returned here as a LocationLists object. location_lists = dwarfinfo.location_lists() + # This is required for the descriptions module to correctly decode + # register names contained in DWARF expressions. + set_global_machine_arch(elffile.get_machine_arch()) + for CU in dwarfinfo.iter_CUs(): # DWARFInfo allows to iterate over the compile units contained in # the .debug_info section. CU is a CompileUnit object, with some @@ -52,17 +59,45 @@ def process_file(filename): # AttributeValue object (from elftools.dwarf.die), which we # can examine. for attr in DIE.attributes.itervalues(): - if ( attr.name == 'DW_AT_location' and - attr.form in ('DW_FORM_data4', 'DW_FORM_data8')): + if attribute_has_location_list(attr): # This is a location list. Its value is an offset into # the .debug_loc section, so we can use the location # lists object to decode it. loclist = location_lists.get_location_list_at_offset( attr.value) - print(' DIE %s. attr %s.\n %s' % ( + + print(' DIE %s. attr %s.\n%s' % ( DIE.tag, attr.name, - loclist)) + show_loclist(loclist, dwarfinfo, indent=' '))) + +def show_loclist(loclist, dwarfinfo, indent): + """ Display a location list nicely, decoding the DWARF expressions + contained within. + """ + d = [] + for loc_entity in loclist: + if isinstance(loc_entity, LocationEntry): + d.append('%s <<%s>>' % ( + loc_entity, + describe_DWARF_expr(loc_entity.loc_expr, dwarfinfo.structs))) + else: + d.append(str(loc_entity)) + return '\n'.join(indent + s for s in d) + + +def attribute_has_location_list(attr): + """ Only some attributes can have location list values, if they have the + required DW_FORM (loclistptr "class" in DWARF spec v3) + """ + if (attr.name in ( 'DW_AT_location', 'DW_AT_string_length', + 'DW_AT_const_value', 'DW_AT_return_addr', + 'DW_AT_data_member_location', 'DW_AT_frame_base', + 'DW_AT_segment', 'DW_AT_static_link', + 'DW_AT_use_location', 'DW_AT_vtable_elem_location')): + if attr.form in ('DW_FORM_data4', 'DW_FORM_data8'): + return True + return False if __name__ == '__main__': diff --git a/test/__init__.py b/test/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/test/utils/Makefile b/test/external_tools/Makefile similarity index 100% rename from test/utils/Makefile rename to test/external_tools/Makefile diff --git a/test/utils/README.txt b/test/external_tools/README.txt similarity index 100% rename from test/utils/README.txt rename to test/external_tools/README.txt diff --git a/test/utils/elf_creator.c b/test/external_tools/elf_creator.c similarity index 100% rename from test/utils/elf_creator.c rename to test/external_tools/elf_creator.c diff --git a/test/run_readelf_tests.py b/test/run_readelf_tests.py index 5effd5f..9ffa519 100755 --- a/test/run_readelf_tests.py +++ b/test/run_readelf_tests.py @@ -12,9 +12,9 @@ import re from difflib import SequenceMatcher from optparse import OptionParser import logging -import subprocess import tempfile import platform +from test.utils import run_exe, is_in_rootdir # Create a global logger object @@ -33,19 +33,6 @@ def discover_testfiles(rootdir): yield os.path.join(rootdir, filename) -def run_exe(exe_path, args): - """ Runs the given executable as a subprocess, given the - list of arguments. Captures its return code (rc) and stdout and - returns a pair: rc, stdout_str - """ - popen_cmd = [exe_path] + args - if os.path.splitext(exe_path)[1] == '.py': - popen_cmd.insert(0, 'python') - proc = subprocess.Popen(popen_cmd, stdout=subprocess.PIPE) - proc_stdout = proc.communicate()[0] - return proc.returncode, proc_stdout - - def run_test_on_file(filename, verbose=False): """ Runs a test on the given input filename. Return True if all test runs succeeded. @@ -173,21 +160,10 @@ def dump_output_to_temp_files(*args): testlog.info('@@ Output #%s dumped to file: %s' % (i + 1, path)) -def die(msg): - testlog.error('Error: %s' % msg) - sys.exit(1) - - -def is_in_rootdir(): - """ Check whether the current dir is the root dir of pyelftools - """ - dirstuff = os.listdir('.') - return 'test' in dirstuff and 'elftools' in dirstuff - - def main(): if not is_in_rootdir(): - die('Please run me from the root dir of pyelftools!') + testlog.error('Error: Please run me from the root dir of pyelftools!') + return 1 optparser = OptionParser( usage='usage: %prog [options] [file] [file] ...', diff --git a/test/utils.py b/test/utils.py new file mode 100644 index 0000000..e09521c --- /dev/null +++ b/test/utils.py @@ -0,0 +1,22 @@ +import os, subprocess + + +def run_exe(exe_path, args): + """ Runs the given executable as a subprocess, given the + list of arguments. Captures its return code (rc) and stdout and + returns a pair: rc, stdout_str + """ + popen_cmd = [exe_path] + args + if os.path.splitext(exe_path)[1] == '.py': + popen_cmd.insert(0, 'python') + proc = subprocess.Popen(popen_cmd, stdout=subprocess.PIPE) + proc_stdout = proc.communicate()[0] + return proc.returncode, proc_stdout + + +def is_in_rootdir(): + """ Check whether the current dir is the root dir of pyelftools + """ + dirstuff = os.listdir('.') + return 'test' in dirstuff and 'elftools' in dirstuff + diff --git a/z.py b/z.py index f04c4cd..02d4f3f 100644 --- a/z.py +++ b/z.py @@ -21,8 +21,10 @@ dinfo = efile.get_dwarf_info() from elftools.dwarf.locationlists import LocationLists from elftools.dwarf.descriptions import describe_DWARF_expr llists = LocationLists(dinfo.debug_loc_sec.stream, dinfo.structs) -for li in llists.get_location_list_at_offset(0): - print li - print describe_DWARF_expr(li.loc_expr, dinfo.structs) +for loclist in llists.iter_location_lists(): + print '----> loclist!' + for li in loclist: + print li + print describe_DWARF_expr(li.loc_expr, dinfo.structs) -- 2.30.2