├── menus.xml
├── .gitignore
├── README.md
├── dwarfmodeltest.py
├── test.c
├── dwarftree.py
└── dwarfmodel.py
/menus.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
7 |
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 | 
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 |
--------------------------------------------------------------------------------