rtl2dot.py.dot 8.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234
  1. /* generated from gcc rtl data using -fdump-rtl-expand commandline option and rtl2dot.py python script, see below */
  2. digraph callgraph {
  3. "main" -> "prepare4newdata";
  4. "main" -> "exit";
  5. "main" -> "maingtk";
  6. "maingtk" -> "static_maingtk";
  7. "static_maingtk" -> "gtk_window_get_type";
  8. "static_maingtk" -> "gtk_adjustment_new";
  9. "static_maingtk" -> "splay_tree_has_data";
  10. "static_maingtk" -> "gtk_drawing_area_new";
  11. "static_maingtk" -> "gtk_container_add";
  12. "static_maingtk" -> "gtk_widget_set_events";
  13. "static_maingtk" -> "gtk_window_new";
  14. "static_maingtk" -> "gtk_box_new";
  15. "static_maingtk" -> "printf";
  16. "static_maingtk" -> "update_status_text";
  17. "update_status_text" -> "static_update_status_text";
  18. "static_update_status_text" -> "snprintf";
  19. "static_update_status_text" -> "memset";
  20. "static_update_status_text" -> "gtk_text_buffer_set_text";
  21. "static_maingtk" -> "gtk_text_view_get_buffer";
  22. "static_maingtk" -> "gtk_spin_button_new";
  23. "static_maingtk" -> "gtk_button_new_with_label";
  24. "static_maingtk" -> "gtk_menu_item_get_type";
  25. "static_maingtk" -> "gtk_text_view_get_type";
  26. "static_maingtk" -> "once_init";
  27. "static_maingtk" -> "gtk_window_set_title";
  28. "static_maingtk" -> "gtk_menu_bar_new";
  29. "static_maingtk" -> "gtk_widget_add_events";
  30. "static_maingtk" -> "gtk_main";
  31. "static_maingtk" -> "gtk_window_set_default_size";
  32. "static_maingtk" -> "gtk_toggle_button_get_type";
  33. "static_maingtk" -> "gtk_label_new";
  34. "static_maingtk" -> "calculate";
  35. "static_maingtk" -> "gtk_widget_set_app_paintable";
  36. "static_maingtk" -> "randomgraph";
  37. "static_maingtk" -> "gtk_menu_new";
  38. "static_maingtk" -> "calculate_init";
  39. "static_maingtk" -> "gtk_box_pack_start";
  40. "static_maingtk" -> "gtk_widget_show";
  41. "static_maingtk" -> "gtk_box_get_type";
  42. "static_maingtk" -> "prepare4newdata";
  43. "static_maingtk" -> "gtk_text_view_new";
  44. "static_maingtk" -> "parse";
  45. "static_maingtk" -> "gtk_container_get_type";
  46. "static_maingtk" -> "gtk_adjustment_set_value";
  47. "static_maingtk" -> "gtk_text_buffer_set_text";
  48. "static_maingtk" -> "g_type_check_instance_cast";
  49. "static_maingtk" -> "fflush";
  50. "static_maingtk" -> "gtk_menu_item_set_submenu";
  51. "static_maingtk" -> "on_treeview_window_destroy";
  52. "static_maingtk" -> "gtk_check_button_new_with_label";
  53. "static_maingtk" -> "gtk_init_check";
  54. "static_maingtk" -> "gtk_menu_item_new_with_mnemonic";
  55. "static_maingtk" -> "gtk_toggle_button_set_active";
  56. "static_maingtk" -> "gtk_scale_set_draw_value";
  57. "static_maingtk" -> "gtk_scale_get_type";
  58. "static_maingtk" -> "g_signal_connect_data";
  59. "static_maingtk" -> "gtk_scale_new";
  60. "static_maingtk" -> "gtk_adjustment_get_type";
  61. "static_maingtk" -> "gtk_text_view_set_editable";
  62. "main" -> "myfinalmemcheck";
  63. "main" -> "time";
  64. "main" -> "colorcode_clear";
  65. "main" -> "commandline_options";
  66. "main" -> "setlocale";
  67. "main" -> "console_saveas";
  68. "console_saveas" -> "strrchr";
  69. "console_saveas" -> "fprintf";
  70. "console_saveas" -> "maingtk_saveaspng";
  71. "console_saveas" -> "maingtk_saveassvg";
  72. "console_saveas" -> "strcmp";
  73. "main" -> "srand";
  74. }
  75. @
  76. # rtl2dot
  77. Create C callgraphs from gcc rtldumps via GraphViz.
  78. Based on [egypt](http://www.gson.org/egypt/egypt.html), rewritten in python with added support for configurable root nodes and omission by regex.
  79. May or may not work with C++ code.
  80. ## Usage
  81. Compile your code with `-fdump-rtl-expand` (eg. by running `make CFLAGS=-fdump-rtl-expand`).
  82. This will generate some new files, most commonly with the extension `.expand`.
  83. Run `rtl2dot myproject.beepbop.expand | dot -Tsvg > myproject.svg` to get a graph of the `main` function of your project.
  84. Valid options are:
  85. * `--ignore <regex>` Regular expression describing function names to be ignored
  86. * `--root <function>` Select the function to use as root node of the graph
  87. * `--local` Ignore functions that are not defined within the rtl dump (most likely library functions)
  88. Any other arguments are treated as input files. If no input files are given, input is expected on stdin.
  89. ### Example
  90. `./rtl2dot.py smtpd.expand --root core_loop --ignore "client_send|logprintf|common_*" --local | dot -Tsvg > smtpd.svg`
  91. ## License
  92. This program is free software. It comes without any warranty, to
  93. the extent permitted by applicable law. You can redistribute it
  94. and/or modify it under the terms of the Do What The Fuck You Want
  95. To Public License, Version 2, as published by Sam Hocevar and
  96. reproduced below.
  97. DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
  98. Version 2, December 2004
  99. Copyright (C) 2004 Sam Hocevar <sam@hocevar.net>
  100. Everyone is permitted to copy and distribute verbatim or modified
  101. copies of this license document, and changing it is allowed as long
  102. as the name is changed.
  103. DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
  104. TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
  105. 0. You just DO WHAT THE FUCK YOU WANT TO.
  106. #!/usr/bin/env python3
  107. #
  108. # Author: cbdev <cb@cbcdn.com>
  109. # Reference: https://github.com/cbdevnet/rtl2dot
  110. #
  111. #This program is free software. It comes without any warranty, to
  112. #the extent permitted by applicable law. You can redistribute it
  113. #and/or modify it under the terms of the Do What The Fuck You Want
  114. #To Public License, Version 2, as published by Sam Hocevar and
  115. #reproduced below.
  116. #
  117. #DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
  118. #Version 2, December 2004
  119. #
  120. #Copyright (C) 2004 Sam Hocevar <sam@hocevar.net>
  121. #
  122. # Everyone is permitted to copy and distribute verbatim or modified
  123. # copies of this license document, and changing it is allowed as long
  124. # as the name is changed.
  125. #
  126. #DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
  127. #TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
  128. #
  129. # 0. You just DO WHAT THE FUCK YOU WANT TO.
  130. #
  131. import fileinput
  132. import re
  133. import sys
  134. root = "main"
  135. ignore = None
  136. infiles = []
  137. local = False
  138. i = 1
  139. # There probably should be sanity checks here, but lets face it: If you cant pass arguments right, this isnt for you
  140. while i < len(sys.argv):
  141. if sys.argv[i] == "--ignore":
  142. ignore = re.compile(sys.argv[i + 1])
  143. i += 1
  144. elif sys.argv[i] == "--root":
  145. root = sys.argv[i + 1]
  146. i += 1
  147. elif sys.argv[i] == "--local":
  148. local = True
  149. elif sys.argv[i] == "--help" or sys.argv[i] == "-h":
  150. print("Generate call graphs of C programs from gcc rtldumps")
  151. print("Options:")
  152. print("\t--ignore <regex>\t\tFunctions to omit from the resulting graph")
  153. print("\t--root <function>\t\tWhich function to use as root node (default: main)")
  154. print("\t--local\t\t\t\tOmit functions not defined in the dump (eg. library calls)")
  155. sys.exit(0)
  156. else:
  157. infiles.append(sys.argv[i])
  158. i+=1
  159. current = ""
  160. calls = {}
  161. func_old = re.compile("^;; Function (?P<func>\S+)\s*$")
  162. func_new = re.compile("^;; Function (?P<mangle>.*)\s+\((?P<func>\S+)(,.*)?\).*$")
  163. funcall = re.compile("^.*\(call.*\"(?P<target>.*)\".*$")
  164. symref = re.compile("^.*\(symbol_ref.*\"(?P<target>.*)\".*$")
  165. def enter(func):
  166. global current, calls
  167. current = func
  168. if calls.get(current, None) is not None:
  169. print("Ambiguous function name " + current, file=sys.stderr)
  170. else:
  171. calls[current] = {}
  172. def call(func, facility):
  173. global current, calls
  174. if calls[current].get(func, None) is not None and calls[current][func] != facility:
  175. print("Ambiguous calling reference to " + func, file=sys.stderr)
  176. calls[current][func] = facility
  177. def dump(func):
  178. global calls
  179. if calls.get(func, None) is None:
  180. # edge node
  181. return
  182. for ref in calls[func].keys():
  183. if calls[func][ref] == "call":
  184. # Invalidate the reference to avoid loops
  185. calls[func][ref] = None
  186. if local and calls.get(ref, None) is None:
  187. # non-local function
  188. continue
  189. if ignore is None or re.match(ignore, ref) is None:
  190. print('"' + func + '" -> "' + ref + '";')
  191. dump(ref)
  192. # Scan the rtl dump into the dict
  193. for line in fileinput.input(infiles):
  194. if re.match(func_old, line) is not None:
  195. # print "OLD", re.match(func_old, line).group("func")
  196. enter(re.match(func_old, line).group("func"))
  197. elif re.match(func_new, line) is not None:
  198. # print "NEW", re.match(func_new, line).group("func"), "Mangled:", re.match(func_new, line).group("mangle")
  199. enter(re.match(func_new, line).group("func"))
  200. elif re.match(funcall, line) is not None:
  201. # print "CALL", re.match(funcall, line).group("target")
  202. call(re.match(funcall, line).group("target"), "call")
  203. elif re.match(symref, line) is not None:
  204. # print "REF", re.match(symref, line).group("target")
  205. call(re.match(symref, line).group("target"), "ref")
  206. print("digraph callgraph {")
  207. dump(root)
  208. print("}")