├── menus.xml ├── .gitignore ├── README.md ├── dwarfmodeltest.py ├── test.c ├── dwarftree.py └── dwarfmodel.py /menus.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.py[cod] 2 | 3 | # C extensions 4 | *.so 5 | 6 | # Packages 7 | *.egg 8 | *.egg-info 9 | dist 10 | build 11 | eggs 12 | parts 13 | bin 14 | var 15 | sdist 16 | develop-eggs 17 | .installed.cfg 18 | lib 19 | lib64 20 | __pycache__ 21 | 22 | # Installer logs 23 | pip-log.txt 24 | 25 | # Unit test / coverage reports 26 | .coverage 27 | .tox 28 | nosetests.xml 29 | 30 | # Translations 31 | *.mo 32 | 33 | # Mr Developer 34 | .mr.developer.cfg 35 | .project 36 | .pydevproject 37 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # dwarftree 2 | 3 | A visual, tree-based, DWARF explorer. It uses [pyelftools](https://github.com/eliben/pyelftools). 4 | 5 | ## What do I do ? 6 | 7 | If you have a recent compiler, it might user DWARF 4. At least, this is the case with gcc 4.8.2-10ubuntu2. pyelftools doesn't seem to support it yet, so make sure to compile with DWARF 3. 8 | 9 | gcc -gdwarf-3 test.c 10 | 11 | Then, open dwarftree. 12 | 13 | python3 dwarftree.py 14 | 15 | Finally, you can use the superior input device (AKA the mouse ;) to open up `a.out`. 16 | 17 | ## Dependencies 18 | 19 | * Python 3 20 | * pyelftools 21 | * `sudo pip3 install pyelftools` 22 | * PyGObject / PyGI 23 | * Debian/Ubuntu: `python3-gi` package 24 | * Fedora: `pygobject3` package 25 | 26 | ## Screenshot 27 | ![Screenshot](http://nova.polymtl.ca/~simark/ss/tmp.EwQc8kcem0.png) 28 | -------------------------------------------------------------------------------- /dwarfmodeltest.py: -------------------------------------------------------------------------------- 1 | from dwarfmodel import ChildrenGroup, DwarfModelBuilder 2 | import sys 3 | from elftools.elf.elffile import ELFFile 4 | 5 | def print_rec(elem, tabs = ""): 6 | print("%s%s" % (tabs, elem.name)) 7 | 8 | tabs += " " 9 | 10 | for group in elem.children_groups: 11 | children_list = elem.children_groups[group] 12 | if group is not None: 13 | print("%s%s:" % (tabs, ChildrenGroup.name(group))) 14 | else: 15 | print("%s%s:" % (tabs, "Others")) 16 | for child in children_list: 17 | print_rec(child, tabs) 18 | 19 | 20 | if __name__ == "__main__": 21 | filename = sys.argv[1] 22 | 23 | with open(filename, 'rb') as f: 24 | elf = ELFFile(f) 25 | 26 | if not elf.has_dwarf_info(): 27 | print("%s has no dwarf info." % filename) 28 | sys.exit(1) 29 | 30 | 31 | di = elf.get_dwarf_info() 32 | 33 | builder = DwarfModelBuilder(di) 34 | root_elem = builder.build() 35 | print_rec(root_elem) 36 | -------------------------------------------------------------------------------- /test.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | int (*ptr_to_func_taking_char_and_float_and_returning_int)(char, float); 5 | int (**ptr_to_ptr_to_func_taking_char_and_float_and_returning_int)(char, float); 6 | 7 | volatile int c; 8 | 9 | int func1(char a, float b) { 10 | printf("ALLO %c %f!\n", a, b); 11 | 12 | return 0; 13 | } 14 | 15 | struct bobby { 16 | char tables; 17 | int roflmao; 18 | }; 19 | 20 | const float xxx() { 21 | return 1.2f; 22 | } 23 | 24 | int main() { 25 | struct bobby a; 26 | a.roflmao = 3; 27 | xxx(); 28 | 29 | ptr_to_func_taking_char_and_float_and_returning_int = func1; 30 | 31 | 32 | ptr_to_ptr_to_func_taking_char_and_float_and_returning_int = &ptr_to_func_taking_char_and_float_and_returning_int; 33 | 34 | ptr_to_func_taking_char_and_float_and_returning_int('a', 1.0f); 35 | (*ptr_to_ptr_to_func_taking_char_and_float_and_returning_int)('b', 2.0f); 36 | 37 | return a.roflmao; 38 | } 39 | -------------------------------------------------------------------------------- /dwarftree.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | from gi.repository import Gtk 3 | from gi.repository import GLib 4 | from gi.repository import Gio 5 | import dwarfmodeltest 6 | from elftools.elf.elffile import ELFFile 7 | from dwarfmodel import DwarfModelBuilder, ChildrenGroup 8 | 9 | import threading 10 | import argparse 11 | import signal 12 | import sys 13 | import os 14 | 15 | class DwarfLoaderThread(threading.Thread): 16 | def __init__(self, window, f, verbose): 17 | super(DwarfLoaderThread, self).__init__() 18 | self.f = f 19 | self.window = window 20 | self.stop_requested = False 21 | self.verbose = verbose 22 | 23 | def request_stop(self): 24 | self.stop_requested = True 25 | 26 | def run(self): 27 | elf = ELFFile(self.f) 28 | 29 | if not elf.has_dwarf_info(): 30 | GLib.idle_add(self.window.display_error, "This file has no DWARF info.") 31 | return 32 | 33 | di = elf.get_dwarf_info() 34 | 35 | builder = DwarfModelBuilder(di, self.verbose) 36 | total = builder.num_cus() 37 | n = 0 38 | 39 | generator = builder.build_step() 40 | file_elem = next(generator) 41 | while not file_elem: 42 | if self.stop_requested: 43 | return 44 | 45 | GLib.idle_add(self.window.load_progress, float(n) / total) 46 | n = n + 1 47 | file_elem = next(generator) 48 | 49 | 50 | #root_elem = builder.build() 51 | 52 | if self.stop_requested: 53 | return 54 | 55 | GLib.idle_add(self.window.done_loading, file_elem) 56 | 57 | 58 | class DwarfUi(Gtk.Window): 59 | def __init__(self, file_to_open = None, verbose = False): 60 | super(DwarfUi, self).__init__(title = "DWARF Tree") 61 | 62 | self.verbose = verbose 63 | 64 | self.connect("delete-event", Gtk.main_quit) 65 | 66 | self.set_default_size(640, 480) 67 | self.maximize() 68 | 69 | box = Gtk.Box(orientation = Gtk.Orientation.VERTICAL) 70 | self.add(box) 71 | 72 | menubar, toolbar = self.build_menus( 73 | os.path.join(os.path.dirname(__file__), "menus.xml")) 74 | 75 | box.pack_start(menubar, False, False, 0) 76 | box.pack_start(toolbar, False, False, 0) 77 | 78 | self.tree = self.build_tree_view() 79 | 80 | tree_scrolled_win = Gtk.ScrolledWindow() 81 | tree_scrolled_win.add(self.tree) 82 | 83 | box.pack_start(tree_scrolled_win, True, True, 0) 84 | 85 | # Status bar stuff 86 | statusbarbox = Gtk.Box(orientation = Gtk.Orientation.HORIZONTAL) 87 | box.pack_end(statusbarbox, False, False, 0) 88 | 89 | self.statusbar = Gtk.Statusbar() 90 | self.statusbar_context_id = self.statusbar.get_context_id("some context") 91 | self.statusbar.push(self.statusbar_context_id, "Welcome !") 92 | 93 | self.loading_progress_bar = Gtk.ProgressBar() 94 | 95 | statusbarbox.pack_start(self.statusbar, True, True, 0) 96 | statusbarbox.pack_end(self.loading_progress_bar, False, False, 0) 97 | 98 | self.loader_thread = None 99 | 100 | if file_to_open: 101 | self.open_file(file_to_open) 102 | 103 | def build_menus(self, menus_xml_file): 104 | uimanager = self.create_ui_manager(menus_xml_file) 105 | 106 | action_group = Gtk.ActionGroup(name = "actions") 107 | 108 | # File menu 109 | action_filemenu = Gtk.Action(name = "FileMenu", label = "File", tooltip = None, stock_id = None) 110 | action_group.add_action(action_filemenu) 111 | 112 | action_fileopen = Gtk.Action(name = "FileOpen", label = "Open", tooltip = "Open a DWARF file", stock_id = Gtk.STOCK_OPEN) 113 | action_group.add_action_with_accel(action_fileopen, None) 114 | action_fileopen.connect("activate", self.on_menu_file_open) 115 | 116 | action_filequit = Gtk.Action(name = "FileQuit", label = "Quit", tooltip = None, stock_id = Gtk.STOCK_QUIT) 117 | action_group.add_action_with_accel(action_filequit, None) 118 | action_filequit.connect("activate", self.on_menu_file_quit) 119 | 120 | # Edit menu 121 | action_editmenu = Gtk.Action(name = "EditMenu", label = "Edit", tooltip = None, stock_id = None) 122 | action_group.add_action(action_editmenu) 123 | 124 | action_editfind = Gtk.Action(name = "EditFind", label = "Find", tooltip = None, stock_id = Gtk.STOCK_FIND) 125 | action_group.add_action(action_editfind) 126 | action_editfind.connect("activate", self.on_menu_edit_find) 127 | 128 | uimanager.insert_action_group(action_group) 129 | 130 | menubar = uimanager.get_widget("/MenuBar") 131 | toolbar = uimanager.get_widget("/ToolBar") 132 | 133 | return menubar, toolbar 134 | 135 | def create_ui_manager(self, menus_xml_file): 136 | uimanager = Gtk.UIManager() 137 | 138 | uimanager.add_ui_from_file(menus_xml_file) 139 | accelgroup = uimanager.get_accel_group() 140 | self.add_accel_group(accelgroup) 141 | 142 | return uimanager 143 | 144 | 145 | def build_tree_view(self): 146 | tree = Gtk.TreeView() 147 | 148 | tree.append_column(Gtk.TreeViewColumn("Element", Gtk.CellRendererText(), text = 0)) 149 | tree.append_column(Gtk.TreeViewColumn("Offset", Gtk.CellRendererText(), text = 1)) 150 | tree.append_column(Gtk.TreeViewColumn("Type", Gtk.CellRendererText(), text = 2)) 151 | 152 | return tree 153 | 154 | def build_tree_store(self, root_element): 155 | store = Gtk.TreeStore(str, str, str) 156 | 157 | if root_element is not None: 158 | 159 | # Create root element 160 | root_iter = store.append(None, [root_element.name, "", ""]) 161 | 162 | self.build_tree_store_rec(store, root_iter, root_element) 163 | 164 | return store 165 | 166 | def build_tree_store_rec(self, store, parent_iter, parent): 167 | for group_id in parent.children_groups: 168 | children_list = parent.children_groups[group_id] 169 | if group_id is not None: 170 | group_name = ChildrenGroup.name(group_id) 171 | # Add a tree element for the group 172 | add_to_iter = store.append(parent_iter, [group_name, "", ""]) 173 | else: 174 | add_to_iter = parent_iter 175 | 176 | for child in children_list: 177 | values = self.build_element_row_values(child) 178 | child_iter = store.append(add_to_iter, values) 179 | 180 | self.build_tree_store_rec(store, child_iter, child) 181 | 182 | def build_element_row_values(self, elem): 183 | ret = [] 184 | 185 | ret.append(elem.name) 186 | ret.append("0x%x" % (elem.die.offset)) 187 | ret.append(elem.type_string if elem.type_string else "") 188 | 189 | return ret 190 | 191 | def open_file(self, filename): 192 | try: 193 | f = open(filename, 'rb') 194 | if self.loader_thread: 195 | self.loader_thread.request_stop() 196 | 197 | self.loader_thread = DwarfLoaderThread(self, f, self.verbose) 198 | self.loader_thread.start() 199 | self.display_status("Loading...") 200 | 201 | except FileNotFoundError as e: 202 | self.display_status("File %s not found..." % (filename)) 203 | 204 | def on_menu_file_open(self, widget): 205 | dialog = Gtk.FileChooserDialog( 206 | title = "Choose an ELF binary", 207 | parent = self, action = Gtk.FileChooserAction.OPEN) 208 | dialog.add_button(Gtk.STOCK_OK, Gtk.ResponseType.OK) 209 | dialog.add_button(Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL) 210 | 211 | resp = dialog.run() 212 | 213 | if resp == Gtk.ResponseType.OK: 214 | self.open_file(dialog.get_filename()) 215 | 216 | dialog.destroy() 217 | 218 | def on_menu_edit_find(self, widget): 219 | print("Pressed find") 220 | 221 | def on_menu_file_quit(self, widget): 222 | Gtk.main_quit() 223 | 224 | def display_error(self, text): 225 | dialog = Gtk.MessageDialog( 226 | parent = self, 227 | text = text, 228 | message_type = Gtk.MessageType.ERROR) 229 | dialog.add_button(Gtk.STOCK_OK, Gtk.ResponseType.OK) 230 | dialog.run() 231 | dialog.destroy() 232 | 233 | def done_loading(self, root_elem): 234 | store = self.build_tree_store(root_elem) 235 | self.tree.set_model(store) 236 | self.display_status("Done loading") 237 | 238 | def display_status(self, text): 239 | self.statusbar.push(self.statusbar_context_id, text) 240 | 241 | def load_progress(self, fraction): 242 | self.loading_progress_bar.set_fraction(fraction) 243 | 244 | def print_version(): 245 | print("DWARF Tree version 0.00001bbb") 246 | 247 | if __name__ == "__main__": 248 | parser = argparse.ArgumentParser() 249 | parser.add_argument('elfbinary', help = 'The ELF binary to analyze', nargs = '?') 250 | parser.add_argument('--verbose', action = "store_true") 251 | parser.add_argument('--version', action = "store_true") 252 | args = parser.parse_args() 253 | 254 | if args.version: 255 | print_version() 256 | sys.exit(0) 257 | 258 | if args.verbose: 259 | print('Verbose mode enabled.') 260 | 261 | win = DwarfUi(args.elfbinary, verbose = args.verbose) 262 | win.show_all() 263 | signal.signal(signal.SIGINT, signal.SIG_DFL) 264 | Gtk.main() 265 | 266 | 267 | -------------------------------------------------------------------------------- /dwarfmodel.py: -------------------------------------------------------------------------------- 1 | import sys 2 | 3 | class ChildrenGroup: 4 | BaseType = 0 5 | StructType = 1 6 | EnumType = 2 7 | ArrayType = 3 8 | Typedef = 4 9 | Enumeration = 5 10 | PointerType = 6 11 | ConstType = 7 12 | VolatileType = 8 13 | 14 | SubProgram = 9 15 | 16 | FormalParameter = 10 17 | LexicalBlock = 11 18 | 19 | Variable = 12 20 | 21 | names = [ 22 | "Basic types", 23 | "Structure types", 24 | "Enumeration types", 25 | "Array types", 26 | "Typedefs", 27 | "Enumerations", 28 | "Pointer types", 29 | "Const types", 30 | "Volatile types", 31 | "Subprograms", 32 | "Formal parameters", 33 | "Lexical Blocks", 34 | "Variables", 35 | ] 36 | 37 | def name(group): 38 | return ChildrenGroup.names[group] 39 | 40 | 41 | class Element: 42 | def __init__(self, name, die, type_string = None): 43 | self.name = name 44 | self.die = die 45 | self.type_string = type_string 46 | 47 | # Dict ChildrenGroup -> list of children of that group 48 | self.children_groups = dict() 49 | 50 | def add_child(self, group, child_elem): 51 | assert(type(child_elem) == Element) 52 | if group not in self.children_groups: 53 | self.children_groups[group] = [] 54 | 55 | self.children_groups[group].append(child_elem) 56 | 57 | def add_children(self, group, child_elements): 58 | assert(type(child_elements) == list) 59 | for x in child_elements: 60 | assert(type(x) == Element) 61 | 62 | if len(child_elements) == 0: 63 | return 64 | 65 | if group not in self.children_groups: 66 | self.children_groups[group] = [] 67 | 68 | self.children_groups[group] += child_elements 69 | 70 | def filter_children_by_tag(die, tag): 71 | return [x for x in die.iter_children() if x.tag == tag] 72 | 73 | def die_get_attr(die, attr_name): 74 | if attr_name in die.attributes: 75 | return die.attributes[attr_name].value 76 | 77 | def die_get_attr_form(die, attr_name): 78 | if attr_name in die.attributes: 79 | return die.attributes[attr_name].form 80 | 81 | def die_get_name(die): 82 | name = die_get_attr(die, 'DW_AT_name') 83 | 84 | if name is not None: 85 | name = name.decode() 86 | 87 | return name 88 | 89 | def die_get_type(die): 90 | return die_get_attr(die, 'DW_AT_type') 91 | 92 | def die_get_upper_bound(die): 93 | if 'DW_AT_upper_bound' in die.attributes and die.attributes['DW_AT_upper_bound'].form == 'DW_FORM_data1': 94 | return die_get_attr(die, 'DW_AT_upper_bound') 95 | else: 96 | return None 97 | 98 | 99 | class DwarfModelBuilder: 100 | # dwarf_info: a pyelftools DWAFRInfo object 101 | def __init__(self, dwarf_info, verbose): 102 | self.dwarf_info = dwarf_info 103 | self.verbose = verbose 104 | 105 | # (cu, relative offset) -> type string 106 | # abs offset = rel offset + cu offset 107 | self.types = dict() 108 | 109 | def debug(self, text): 110 | if self.verbose: 111 | print(text) 112 | 113 | def num_cus(self): 114 | n = 0 115 | for cu in self.dwarf_info.iter_CUs(): 116 | n = n + 1 117 | 118 | return n 119 | 120 | def build(self): 121 | file_elem = Element("File", None) 122 | 123 | for cu in self.dwarf_info.iter_CUs(): 124 | top_die = cu.get_top_DIE() 125 | 126 | self._types_pass(top_die) 127 | cu_elem = self.visit_cu(top_die) 128 | file_elem.add_child(None, cu_elem) 129 | 130 | return file_elem 131 | 132 | def build_step(self): 133 | file_elem = Element("File", None) 134 | yield None 135 | 136 | for cu in self.dwarf_info.iter_CUs(): 137 | top_die = cu.get_top_DIE() 138 | 139 | self._types_pass(top_die) 140 | cu_elem = self.visit_cu(top_die) 141 | file_elem.add_child(None, cu_elem) 142 | yield None 143 | 144 | yield file_elem 145 | 146 | def eventually_points_to_subprogram(self, type_die): 147 | assert(type_die.tag == 'DW_TAG_pointer_type') 148 | 149 | pointed_type_offset = die_get_type(type_die) 150 | type_die = self.lookup_type(type_die.cu, pointed_type_offset) 151 | while True: 152 | print(type_die.tag) 153 | if type_die.tag == 'DW_TAG_subroutine_type': 154 | return True 155 | 156 | if type_die.tag != 'DW_TAG_pointer_type': 157 | return False 158 | 159 | pointed_type_offset = die_get_type(type_die) 160 | type_die = self.lookup_type(type_die.cu, pointed_type_offset) 161 | 162 | def format_type_name(self, type_die): 163 | tag = type_die.tag 164 | 165 | if tag == 'DW_TAG_base_type': 166 | return die_get_name(type_die) 167 | 168 | if tag == 'DW_TAG_structure_type': 169 | name = die_get_name(type_die) 170 | if not name: 171 | name = "" 172 | return "struct " + name 173 | 174 | if tag == 'DW_TAG_union_type': 175 | name = die_get_name(type_die) 176 | if not name: 177 | name = "" 178 | return "union " + name 179 | 180 | if tag == 'DW_TAG_array_type': 181 | subtype = self.lookup_type(type_die.cu, die_get_type(type_die)) 182 | subranges = filter_children_by_tag(type_die, 'DW_TAG_subrange_type') 183 | suffix = "" 184 | 185 | for subrange in subranges: 186 | ub = die_get_upper_bound(subrange) 187 | 188 | if ub: 189 | suffix += "[%d]" % (ub + 1) 190 | else: 191 | suffix += "[?]" 192 | 193 | return self.format_type_name(subtype) + suffix 194 | 195 | if tag == 'DW_TAG_pointer_type': 196 | #print(self.eventually_points_to_subprogram(type_die)) 197 | pointed_type_offset = die_get_type(type_die) 198 | if pointed_type_offset is None: 199 | return "void*" 200 | 201 | pointed_type = self.lookup_type(type_die.cu, pointed_type_offset) 202 | return self.format_type_name(pointed_type) + " *" 203 | 204 | if tag == 'DW_TAG_const_type': 205 | consted_type_offset = die_get_type(type_die) 206 | if consted_type_offset is None: 207 | return "void const" 208 | 209 | typ = self.lookup_type(type_die.cu, consted_type_offset) 210 | return self.format_type_name(typ) + " const" 211 | 212 | if tag == 'DW_TAG_volatile_type': 213 | typ = self.lookup_type(type_die.cu,die_get_type(type_die)) 214 | return self.format_type_name(typ) + " volatile" 215 | 216 | if tag == 'DW_TAG_subroutine_type': 217 | ret_type_offset = die_get_type(type_die) 218 | if ret_type_offset: 219 | ret_type_die = self.lookup_type(type_die.cu, ret_type_offset) 220 | 221 | ret = self.format_type_name(ret_type_die) 222 | else: 223 | ret = "void" 224 | 225 | ret += " function(" 226 | 227 | params = filter_children_by_tag(type_die, 'DW_TAG_formal_parameter') 228 | params_formatted = [] 229 | for param in params: 230 | param_type_offset = die_get_type(param) 231 | param_type_die = self.lookup_type(type_die.cu, param_type_offset) 232 | params_formatted.append(self.format_type_name(param_type_die)) 233 | ret += ', '.join(params_formatted) 234 | 235 | ret += ")" 236 | 237 | return ret 238 | 239 | if tag == 'DW_TAG_typedef': 240 | return die_get_name(type_die) 241 | 242 | if tag == 'DW_TAG_enumeration_type': 243 | name = die_get_name(type_die) 244 | if not name: 245 | name = "" 246 | return "enum " + name 247 | 248 | print(tag) 249 | assert(False) 250 | 251 | def lookup_and_format_type(self, cu, offset): 252 | type_die = self.lookup_type(cu, offset) 253 | 254 | if not type_die: 255 | return "???" 256 | 257 | return self.format_type_name(type_die) 258 | 259 | def lookup_type(self, cu, offset): 260 | self.debug("Type lookup at %x + %x = %x" % (cu.cu_offset, offset, cu.cu_offset + offset)) 261 | if (cu, offset) not in self.types: 262 | self.debug("Returns none!") 263 | return None 264 | 265 | return self.types[(cu, offset)] 266 | 267 | def _types_pass(self, die): 268 | tag = die.tag 269 | 270 | type_tags = ['DW_TAG_structure_type', 271 | 'DW_TAG_base_type', 272 | 'DW_TAG_typedef', 273 | 'DW_TAG_array_type', 274 | 'DW_TAG_pointer_type', 275 | 'DW_TAG_const_type', 276 | 'DW_TAG_subroutine_type', 277 | 'DW_TAG_volatile_type', 278 | 'DW_TAG_union_type', 279 | 'DW_TAG_enumeration_type'] 280 | 281 | if tag in type_tags: 282 | cu = die.cu 283 | offset = die.offset - die.cu.cu_offset 284 | self.debug("adding type at %x" % (offset)) 285 | 286 | assert((cu, offset) not in self.types) 287 | 288 | self.types[(cu, offset)] = die 289 | 290 | for child in die.iter_children(): 291 | self._types_pass(child) 292 | 293 | 294 | def visit_cu(self, cu_die): 295 | name = die_get_name(cu_die) 296 | cu_elem = Element(name, cu_die) 297 | 298 | cu_elem.add_children(ChildrenGroup.BaseType,self.visit_children_of_tag(cu_die, 'DW_TAG_base_type', self.visit_base_type)) 299 | cu_elem.add_children(ChildrenGroup.StructType,self.visit_children_of_tag(cu_die, 'DW_TAG_structure_type', self.visit_struct_type)) 300 | cu_elem.add_children(ChildrenGroup.ArrayType,self.visit_children_of_tag(cu_die, 'DW_TAG_array_type', self.visit_array_type)) 301 | cu_elem.add_children(ChildrenGroup.Typedef,self.visit_children_of_tag(cu_die, 'DW_TAG_typedef', self.visit_typedef)) 302 | cu_elem.add_children(ChildrenGroup.Enumeration,self.visit_children_of_tag(cu_die, 'DW_TAG_enumeration_type', self.visit_enumeration)) 303 | cu_elem.add_children(ChildrenGroup.PointerType,self.visit_children_of_tag(cu_die, 'DW_TAG_pointer_type', self.visit_pointer_types)) 304 | cu_elem.add_children(ChildrenGroup.SubProgram,self.visit_children_of_tag(cu_die, 'DW_TAG_subprogram', self.visit_subprogram)) 305 | cu_elem.add_children(ChildrenGroup.ConstType,self.visit_children_of_tag(cu_die, 'DW_TAG_const_type', self.visit_const_type)) 306 | cu_elem.add_children(ChildrenGroup.VolatileType,self.visit_children_of_tag(cu_die, 'DW_TAG_volatile_type', self.visit_volatile_type)) 307 | 308 | return cu_elem 309 | 310 | def visit_children_of_tag(self, die, tag, callback): 311 | ret = [] 312 | children_dies = filter_children_by_tag(die, tag) 313 | for cd in children_dies: 314 | ret.append(callback(cd)) 315 | 316 | return ret 317 | 318 | def visit_base_type(self, base_type_die): 319 | name = self.format_type_name(base_type_die) 320 | elem = Element(name, base_type_die) 321 | return elem 322 | 323 | def visit_struct_type(self, struct_type_die): 324 | name = self.format_type_name(struct_type_die) 325 | 326 | elem = Element(name, struct_type_die) 327 | 328 | elem.add_children(None, self.visit_children_of_tag(struct_type_die, 'DW_TAG_member', self.visit_type_member)) 329 | 330 | return elem 331 | 332 | def visit_type_member(self, member_type_die): 333 | member_name = die_get_name(member_type_die) 334 | type_offset = die_get_type(member_type_die) 335 | cu = member_type_die.cu 336 | 337 | type_string = self.lookup_and_format_type(cu, type_offset) 338 | member_elem = Element(member_name, member_type_die, type_string = type_string) 339 | 340 | return member_elem 341 | 342 | def visit_array_type(self, array_type_die): 343 | name = self.format_type_name(array_type_die) 344 | array_elem = Element(name, array_type_die) 345 | 346 | return array_elem 347 | 348 | def visit_typedef(self, typedef_die): 349 | name = self.format_type_name(typedef_die) 350 | typedef_elem = Element(name, typedef_die) 351 | 352 | return typedef_elem 353 | 354 | def visit_enumeration(self, enumeration_die): 355 | name = self.format_type_name(enumeration_die) 356 | enum_elem = Element(name, enumeration_die) 357 | 358 | enum_elem.add_children(None, self.visit_children_of_tag(enumeration_die, 'DW_TAG_enumerator', self.visit_enumerator)) 359 | 360 | return enum_elem 361 | 362 | def visit_enumerator(self, enumerator_die): 363 | label = die_get_name(enumerator_die) 364 | num = die_get_attr(enumerator_die, 'DW_AT_const_value') 365 | name = "%s = %d" % (label, num) 366 | 367 | enum_elem = Element(name, enumerator_die) 368 | 369 | return enum_elem 370 | 371 | def visit_pointer_types(self, pointer_type_die): 372 | name = self.format_type_name(pointer_type_die) 373 | pointer_elem = Element(name, pointer_type_die) 374 | 375 | return pointer_elem 376 | 377 | def visit_const_type(self, const_type_die): 378 | name = self.format_type_name(const_type_die) 379 | const_elem = Element(name, const_type_die) 380 | 381 | return const_elem 382 | 383 | def visit_volatile_type(self, volatile_type_die): 384 | name = self.format_type_name(volatile_type_die) 385 | volatile_elem = Element(name, volatile_type_die) 386 | 387 | return volatile_elem 388 | 389 | def visit_subprogram(self, subprogram_type_die): 390 | name = die_get_name(subprogram_type_die) 391 | subprogram_elem = Element(name, subprogram_type_die) 392 | 393 | subprogram_elem.add_children(ChildrenGroup.FormalParameter, self.visit_children_of_tag(subprogram_type_die, 'DW_TAG_formal_parameter', self.visit_formal_parameter)) 394 | subprogram_elem.add_children(ChildrenGroup.LexicalBlock, self.visit_children_of_tag(subprogram_type_die, 'DW_TAG_lexical_block', self.visit_lexical_block)) 395 | subprogram_elem.add_children(ChildrenGroup.Variable, self.visit_children_of_tag(subprogram_type_die, 'DW_TAG_variable', self.visit_variable)) 396 | 397 | return subprogram_elem 398 | 399 | def visit_formal_parameter(self, formal_parameter_die): 400 | name = die_get_name(formal_parameter_die) 401 | type_ = die_get_type(formal_parameter_die) 402 | 403 | elem = Element(name, formal_parameter_die) 404 | 405 | return elem 406 | 407 | def visit_lexical_block(self, lexical_block_die): 408 | low_pc = die_get_attr(lexical_block_die, 'DW_AT_low_pc') 409 | high_pc = die_get_attr(lexical_block_die, 'DW_AT_high_pc') 410 | 411 | form = die_get_attr_form(lexical_block_die, 'DW_AT_high_pc') 412 | if form == 'DW_FORM_data8': 413 | high_pc += low_pc 414 | elif form == 'DW_FORM_addr': 415 | pass 416 | else: 417 | assert False 418 | 419 | name = '0x{:x}-0x{:x}'.format(low_pc, high_pc) 420 | 421 | elem = Element(name, lexical_block_die) 422 | 423 | elem.add_children(ChildrenGroup.LexicalBlock, self.visit_children_of_tag(lexical_block_die, 'DW_TAG_lexical_block', self.visit_lexical_block)) 424 | elem.add_children(ChildrenGroup.Variable, self.visit_children_of_tag(lexical_block_die, 'DW_TAG_variable', self.visit_variable)) 425 | 426 | return elem 427 | 428 | def visit_variable(self, variable_die): 429 | name = die_get_name(variable_die) 430 | 431 | elem = Element(name, variable_die) 432 | 433 | return elem 434 | 435 | --------------------------------------------------------------------------------