123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234 |
- /* generated from gcc rtl data using -fdump-rtl-expand commandline option and rtl2dot.py python script, see below */
- digraph callgraph {
- "main" -> "prepare4newdata";
- "main" -> "exit";
- "main" -> "maingtk";
- "maingtk" -> "static_maingtk";
- "static_maingtk" -> "gtk_window_get_type";
- "static_maingtk" -> "gtk_adjustment_new";
- "static_maingtk" -> "splay_tree_has_data";
- "static_maingtk" -> "gtk_drawing_area_new";
- "static_maingtk" -> "gtk_container_add";
- "static_maingtk" -> "gtk_widget_set_events";
- "static_maingtk" -> "gtk_window_new";
- "static_maingtk" -> "gtk_box_new";
- "static_maingtk" -> "printf";
- "static_maingtk" -> "update_status_text";
- "update_status_text" -> "static_update_status_text";
- "static_update_status_text" -> "snprintf";
- "static_update_status_text" -> "memset";
- "static_update_status_text" -> "gtk_text_buffer_set_text";
- "static_maingtk" -> "gtk_text_view_get_buffer";
- "static_maingtk" -> "gtk_spin_button_new";
- "static_maingtk" -> "gtk_button_new_with_label";
- "static_maingtk" -> "gtk_menu_item_get_type";
- "static_maingtk" -> "gtk_text_view_get_type";
- "static_maingtk" -> "once_init";
- "static_maingtk" -> "gtk_window_set_title";
- "static_maingtk" -> "gtk_menu_bar_new";
- "static_maingtk" -> "gtk_widget_add_events";
- "static_maingtk" -> "gtk_main";
- "static_maingtk" -> "gtk_window_set_default_size";
- "static_maingtk" -> "gtk_toggle_button_get_type";
- "static_maingtk" -> "gtk_label_new";
- "static_maingtk" -> "calculate";
- "static_maingtk" -> "gtk_widget_set_app_paintable";
- "static_maingtk" -> "randomgraph";
- "static_maingtk" -> "gtk_menu_new";
- "static_maingtk" -> "calculate_init";
- "static_maingtk" -> "gtk_box_pack_start";
- "static_maingtk" -> "gtk_widget_show";
- "static_maingtk" -> "gtk_box_get_type";
- "static_maingtk" -> "prepare4newdata";
- "static_maingtk" -> "gtk_text_view_new";
- "static_maingtk" -> "parse";
- "static_maingtk" -> "gtk_container_get_type";
- "static_maingtk" -> "gtk_adjustment_set_value";
- "static_maingtk" -> "gtk_text_buffer_set_text";
- "static_maingtk" -> "g_type_check_instance_cast";
- "static_maingtk" -> "fflush";
- "static_maingtk" -> "gtk_menu_item_set_submenu";
- "static_maingtk" -> "on_treeview_window_destroy";
- "static_maingtk" -> "gtk_check_button_new_with_label";
- "static_maingtk" -> "gtk_init_check";
- "static_maingtk" -> "gtk_menu_item_new_with_mnemonic";
- "static_maingtk" -> "gtk_toggle_button_set_active";
- "static_maingtk" -> "gtk_scale_set_draw_value";
- "static_maingtk" -> "gtk_scale_get_type";
- "static_maingtk" -> "g_signal_connect_data";
- "static_maingtk" -> "gtk_scale_new";
- "static_maingtk" -> "gtk_adjustment_get_type";
- "static_maingtk" -> "gtk_text_view_set_editable";
- "main" -> "myfinalmemcheck";
- "main" -> "time";
- "main" -> "colorcode_clear";
- "main" -> "commandline_options";
- "main" -> "setlocale";
- "main" -> "console_saveas";
- "console_saveas" -> "strrchr";
- "console_saveas" -> "fprintf";
- "console_saveas" -> "maingtk_saveaspng";
- "console_saveas" -> "maingtk_saveassvg";
- "console_saveas" -> "strcmp";
- "main" -> "srand";
- }
- @
- # rtl2dot
- Create C callgraphs from gcc rtldumps via GraphViz.
- Based on [egypt](http://www.gson.org/egypt/egypt.html), rewritten in python with added support for configurable root nodes and omission by regex.
- May or may not work with C++ code.
- ## Usage
- Compile your code with `-fdump-rtl-expand` (eg. by running `make CFLAGS=-fdump-rtl-expand`).
- This will generate some new files, most commonly with the extension `.expand`.
- Run `rtl2dot myproject.beepbop.expand | dot -Tsvg > myproject.svg` to get a graph of the `main` function of your project.
- Valid options are:
- * `--ignore <regex>` Regular expression describing function names to be ignored
- * `--root <function>` Select the function to use as root node of the graph
- * `--local` Ignore functions that are not defined within the rtl dump (most likely library functions)
- Any other arguments are treated as input files. If no input files are given, input is expected on stdin.
- ### Example
- `./rtl2dot.py smtpd.expand --root core_loop --ignore "client_send|logprintf|common_*" --local | dot -Tsvg > smtpd.svg`
- ## License
- This program is free software. It comes without any warranty, to
- the extent permitted by applicable law. You can redistribute it
- and/or modify it under the terms of the Do What The Fuck You Want
- To Public License, Version 2, as published by Sam Hocevar and
- reproduced below.
- DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
- Version 2, December 2004
- Copyright (C) 2004 Sam Hocevar <sam@hocevar.net>
- Everyone is permitted to copy and distribute verbatim or modified
- copies of this license document, and changing it is allowed as long
- as the name is changed.
- DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
- TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
- 0. You just DO WHAT THE FUCK YOU WANT TO.
- #!/usr/bin/env python3
- #
- # Author: cbdev <cb@cbcdn.com>
- # Reference: https://github.com/cbdevnet/rtl2dot
- #
- #This program is free software. It comes without any warranty, to
- #the extent permitted by applicable law. You can redistribute it
- #and/or modify it under the terms of the Do What The Fuck You Want
- #To Public License, Version 2, as published by Sam Hocevar and
- #reproduced below.
- #
- #DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
- #Version 2, December 2004
- #
- #Copyright (C) 2004 Sam Hocevar <sam@hocevar.net>
- #
- # Everyone is permitted to copy and distribute verbatim or modified
- # copies of this license document, and changing it is allowed as long
- # as the name is changed.
- #
- #DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
- #TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
- #
- # 0. You just DO WHAT THE FUCK YOU WANT TO.
- #
- import fileinput
- import re
- import sys
- root = "main"
- ignore = None
- infiles = []
- local = False
- i = 1
- # There probably should be sanity checks here, but lets face it: If you cant pass arguments right, this isnt for you
- while i < len(sys.argv):
- if sys.argv[i] == "--ignore":
- ignore = re.compile(sys.argv[i + 1])
- i += 1
- elif sys.argv[i] == "--root":
- root = sys.argv[i + 1]
- i += 1
- elif sys.argv[i] == "--local":
- local = True
- elif sys.argv[i] == "--help" or sys.argv[i] == "-h":
- print("Generate call graphs of C programs from gcc rtldumps")
- print("Options:")
- print("\t--ignore <regex>\t\tFunctions to omit from the resulting graph")
- print("\t--root <function>\t\tWhich function to use as root node (default: main)")
- print("\t--local\t\t\t\tOmit functions not defined in the dump (eg. library calls)")
- sys.exit(0)
- else:
- infiles.append(sys.argv[i])
- i+=1
- current = ""
- calls = {}
- func_old = re.compile("^;; Function (?P<func>\S+)\s*$")
- func_new = re.compile("^;; Function (?P<mangle>.*)\s+\((?P<func>\S+)(,.*)?\).*$")
- funcall = re.compile("^.*\(call.*\"(?P<target>.*)\".*$")
- symref = re.compile("^.*\(symbol_ref.*\"(?P<target>.*)\".*$")
- def enter(func):
- global current, calls
- current = func
- if calls.get(current, None) is not None:
- print("Ambiguous function name " + current, file=sys.stderr)
- else:
- calls[current] = {}
- def call(func, facility):
- global current, calls
- if calls[current].get(func, None) is not None and calls[current][func] != facility:
- print("Ambiguous calling reference to " + func, file=sys.stderr)
- calls[current][func] = facility
- def dump(func):
- global calls
- if calls.get(func, None) is None:
- # edge node
- return
- for ref in calls[func].keys():
- if calls[func][ref] == "call":
- # Invalidate the reference to avoid loops
- calls[func][ref] = None
- if local and calls.get(ref, None) is None:
- # non-local function
- continue
- if ignore is None or re.match(ignore, ref) is None:
- print('"' + func + '" -> "' + ref + '";')
- dump(ref)
- # Scan the rtl dump into the dict
- for line in fileinput.input(infiles):
- if re.match(func_old, line) is not None:
- # print "OLD", re.match(func_old, line).group("func")
- enter(re.match(func_old, line).group("func"))
- elif re.match(func_new, line) is not None:
- # print "NEW", re.match(func_new, line).group("func"), "Mangled:", re.match(func_new, line).group("mangle")
- enter(re.match(func_new, line).group("func"))
- elif re.match(funcall, line) is not None:
- # print "CALL", re.match(funcall, line).group("target")
- call(re.match(funcall, line).group("target"), "call")
- elif re.match(symref, line) is not None:
- # print "REF", re.match(symref, line).group("target")
- call(re.match(symref, line).group("target"), "ref")
- print("digraph callgraph {")
- dump(root)
- print("}")
|