├── CHANGELOG ├── COPYING ├── CREDITS ├── Makefile.in ├── README ├── README-CrossCompile ├── bin ├── check-stack.sh ├── genfull └── gengraph ├── build ├── codeviz.p ├── codeviz.spec ├── compilers ├── gcc-patches │ ├── gcc-3.4.6-cdepn.diff │ ├── gcc-4.6.2-cdepn.diff │ └── gcc-7.4.0-cdepn.diff ├── install_gcc-3.4.6.sh ├── install_gcc-4.6.2.sh └── install_gcc-7.4.0.sh ├── configure ├── debian ├── README.debian ├── changelog ├── control ├── copyright ├── dirs ├── files ├── rules └── substvars ├── graphs ├── full.graph-2.6.12-rc2 └── full.graph-2.6.18-rc4-mm2 ├── lib └── CodeViz │ ├── Collect.pm │ ├── CollectCNcc.pm │ ├── CollectCObjdump.pm │ ├── CollectCXref.pm │ ├── CollectCppDepn.pm │ ├── CollectPPStack.pm │ ├── Format.pm │ ├── Graph.pm │ ├── IPC.pm │ ├── Layout.pm │ ├── Output.pm │ ├── PPCStack.pm │ ├── PPOprofile.pm │ ├── PPStack.pm │ ├── SourceMarkup.pm │ └── VRML.pm └── testsuite ├── c ├── Makefile ├── Makefile.in ├── checkgraphs.sh ├── expected-full.graph ├── expected-sub.graph ├── header.h ├── lib.c └── main.c └── cpp ├── Makefile ├── Makefile.in ├── checkgraphs.sh ├── classheader.h ├── classname.cc ├── expected-full.graph ├── expected-sub.graph-default ├── expected-sub.graph-trimmed └── main.cc /CHANGELOG: -------------------------------------------------------------------------------- 1 | Changelog 2 | --------- 3 | Version 1.0.12 4 | o Fix typos in document (Jim Cathey) 5 | o Fix up C++ Mangling (Andrey Valyaev) 6 | o Delete vim swap files (Petr Cerny) 7 | o Handle DESTDIR as an alternative installation root than / (Petr Cerny) 8 | o gcc 4.6.2 (Rafael Aquini) 9 | 10 | Version 1.0.11 11 | o Update the cncc collection method to understand ncc 2.4 (Tim Auckland) 12 | o Add --output-layout to alter what direction the graph is 13 | plotted in (Tim Auckland) 14 | o Add --no-extern switch to remove functions that are 15 | referenced but not defined in the source such as library calls (Tim Auckland) 16 | 17 | Version 1.0.10 18 | o Updated compiler version (Michael Iatrou did all this work) 19 | o Added basic test suite to regress test. 20 | 21 | Version 1.0.7 22 | o Fixed an assumption that C++ functions always had return types (kost) 23 | o Workaround a bug where const functions cause trouble (kost) 24 | o Fix bugs related to C++ functions and spaces (kost) 25 | o Updated the list of kernel functions to ignore for -t (mel) 26 | o Added support for outputting PNG files (mel) 27 | 28 | Version 1.0.6 29 | o Regression fixed where nodes were not being decorated correctly 30 | 31 | Version 1.0.5 32 | o Minor issue when generating graphs of exactly one node fixed 33 | 34 | Version 1.0.4 35 | o More bugs in gcc patch, fixed now and tested 36 | o --all-locs bug fixed 37 | o Graph traversal bug introduced in 1.0.1 for C fixed 38 | 39 | Version 1.0.3 40 | o Bug in gcc patch 41 | 42 | Version 1.0.2 43 | o Ditched support for multiple compilers, left with only 3.4.1 44 | o Vastly superior C++ support, multiple bugs fixed 45 | 46 | Version 1.0.1 47 | o Support for gcc 3.3.2 removed, way too buggy 48 | o Error in gcc 3.2.3 installation script fixed up 49 | o Support for --font switch to specify what font to use for graphs 50 | o Support again available for HTML generation and --shighlight 51 | 52 | Version 1.0 53 | o Final bit of macro recognition tweaking 54 | 55 | Version 0.99 56 | o Be consistent about the use of cdep or cdepn 57 | o Better header processing 58 | o Addition of configure script 59 | 60 | Version 0.24 61 | o Added support for a --version switch 62 | 63 | Version 0.23 64 | o Remove CPP support in the cxref method, it was just too delicate 65 | o Changed the C++ method for cdepn methods to use use cdep files, works well 66 | o CObjDump will now put " around labels with :: 67 | 68 | Version 0.21 69 | o Added missing file 70 | 71 | Version 0.20 72 | o Fixed bug with --plain usage 73 | o Fixed bug with SMP function name mangling with later 2.6 kernels 74 | o Calculate cumulative stack usage with --pp-cstack post-processing module 75 | 76 | Version 0.19 77 | o Mainly code cleanups 78 | o Moved graph rendering to Output.pm that exports just renderGraph() 79 | o Moved printing functions to Format.pm 80 | o Moved IPC functions to IPC.pm 81 | o Moved remaining graph functions to Graph.pm 82 | o Fixed cobjdump for binary analysis 83 | o Added post-processing analysis to genfull to calculate stack usage 84 | o Display stack usage and highlight excessive use for gengraph 85 | 86 | Version 0.18 87 | o Allow output of just the graph file without using dot 88 | o Support for templated base URLs for HTML image maps 89 | o Better support for source-highlight usages 90 | o Allow standard error to be redirected (useful to daemon mode) 91 | o Allow standard out to be redirected (useful to daemon mode) 92 | 93 | Version 0.17 94 | o Major bug fixed that prevented genfull running 95 | o Support for gcc 3.3.2 (Joel Soete) 96 | o Cross-compile instructions (Joel Soete) 97 | 98 | Version 0.16 99 | o Many bug fixes and cleanups related to the HTML rendering 100 | o Better handling of node attributes for code cleanup 101 | o Many code cleanups to reduce complexity, overall less code 102 | o Documentation updates 103 | 104 | Version 0.15 105 | o Show location of a function call (--all-locs) (Mel) 106 | o Graph top-level functions based on regular expressions (Lehr + Mel) 107 | o Various web-page related options added (Lehr + Mel) 108 | 109 | Version 0.14 110 | o More minor bugs 111 | o Support to show/ignore functions based on a regular expression (Lehr) 112 | o Add RPM spec file (Lehr) 113 | o Format nodes that are not traversed differently (Lehr) 114 | 115 | Version 0.13 116 | o Bugfixes 117 | 118 | Version 0.12 119 | o Graphs are now internally represented as DAGs, massive speedups 120 | o graph2vrml removed because it was not going anywhere useful 121 | o Daemon/Client support added 122 | o GIF support added for web pages 123 | o Proper checking for availablity of dot 124 | o Various optimizations and speedups 125 | 126 | Version 0.11 127 | o cdep and cxref methods merged 128 | o cdep method is MUCH more accurate and is able to determine files to ignore 129 | o Output printing module added, only cdep uses it currently 130 | 131 | Version 0.10 132 | o Avoid naming collisions where structure names match functions in cxrefdep 133 | o Improved name collision resolution 134 | o ncc support added for new method cncc which supports function pointers 135 | 136 | Version 0.9 137 | o xref support added which understands macros 138 | o Minor bug fixes and cleanups 139 | 140 | Version 0.8 141 | o Modular data collection so that many collection methods can be easily added 142 | All collection methods are now perl libraries 143 | o C++ support added 144 | o Integrated all scripts together so that there is only two principal scripts 145 | o objdump support so that project does not depend on patched compiled 146 | o Patches to gcc updated to gcc-3.0.4 147 | o Patches added for gcc-2.95.3 and gcc-3.2.3 148 | o glibc workaround added for new version of glib compiling gcc 149 | o Automated download, compile and patch scripts added for each compiler version 150 | 151 | Version 0.7 152 | o Reverse Call Graph Support 153 | o Online man pages and documentation help 154 | 155 | Version 0.5 156 | o Fix up case where graphs with similar function names sometimes get 157 | corrupt. Most time it would work out ok, but other times multiple edges or 158 | unrelated functions were displayed 159 | 160 | o Enforce that the call graph order matches the order in code perfectly. It 161 | was a very rare case that a depth first search of the call graph would give 162 | a misleading view of the code 163 | 164 | o Allow multiple functions to be specified to graph. This is really handy 165 | when a number of API functions map to a much smaller set and it is desirable 166 | to display all the API wrappers in one place 167 | 168 | o Small documentation fix 169 | 170 | Version 0.4 171 | 172 | o The order of functions displayed is now in the same order as the source. 173 | Traversing the graph in depth-first search will be the same order in the 174 | code 175 | 176 | Version 0.3 177 | 178 | o Fixed cdepn.pl to work with 2.5.x kernels 179 | 180 | 181 | -------------------------------------------------------------------------------- /COPYING: -------------------------------------------------------------------------------- 1 | GNU GENERAL PUBLIC LICENSE 2 | Version 2, June 1991 3 | 4 | Copyright (C) 1989, 1991 Free Software Foundation, Inc. 5 | 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 6 | Everyone is permitted to copy and distribute verbatim copies 7 | of this license document, but changing it is not allowed. 8 | 9 | Preamble 10 | 11 | The licenses for most software are designed to take away your 12 | freedom to share and change it. By contrast, the GNU General Public 13 | License is intended to guarantee your freedom to share and change free 14 | software--to make sure the software is free for all its users. This 15 | General Public License applies to most of the Free Software 16 | Foundation's software and to any other program whose authors commit to 17 | using it. (Some other Free Software Foundation software is covered by 18 | the GNU Library General Public License instead.) You can apply it to 19 | your programs, too. 20 | 21 | When we speak of free software, we are referring to freedom, not 22 | price. Our General Public Licenses are designed to make sure that you 23 | have the freedom to distribute copies of free software (and charge for 24 | this service if you wish), that you receive source code or can get it 25 | if you want it, that you can change the software or use pieces of it 26 | in new free programs; and that you know you can do these things. 27 | 28 | To protect your rights, we need to make restrictions that forbid 29 | anyone to deny you these rights or to ask you to surrender the rights. 30 | These restrictions translate to certain responsibilities for you if you 31 | distribute copies of the software, or if you modify it. 32 | 33 | For example, if you distribute copies of such a program, whether 34 | gratis or for a fee, you must give the recipients all the rights that 35 | you have. You must make sure that they, too, receive or can get the 36 | source code. And you must show them these terms so they know their 37 | rights. 38 | 39 | We protect your rights with two steps: (1) copyright the software, and 40 | (2) offer you this license which gives you legal permission to copy, 41 | distribute and/or modify the software. 42 | 43 | Also, for each author's protection and ours, we want to make certain 44 | that everyone understands that there is no warranty for this free 45 | software. If the software is modified by someone else and passed on, we 46 | want its recipients to know that what they have is not the original, so 47 | that any problems introduced by others will not reflect on the original 48 | authors' reputations. 49 | 50 | Finally, any free program is threatened constantly by software 51 | patents. We wish to avoid the danger that redistributors of a free 52 | program will individually obtain patent licenses, in effect making the 53 | program proprietary. To prevent this, we have made it clear that any 54 | patent must be licensed for everyone's free use or not licensed at all. 55 | 56 | The precise terms and conditions for copying, distribution and 57 | modification follow. 58 | 59 | GNU GENERAL PUBLIC LICENSE 60 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 61 | 62 | 0. This License applies to any program or other work which contains 63 | a notice placed by the copyright holder saying it may be distributed 64 | under the terms of this General Public License. The "Program", below, 65 | refers to any such program or work, and a "work based on the Program" 66 | means either the Program or any derivative work under copyright law: 67 | that is to say, a work containing the Program or a portion of it, 68 | either verbatim or with modifications and/or translated into another 69 | language. (Hereinafter, translation is included without limitation in 70 | the term "modification".) Each licensee is addressed as "you". 71 | 72 | Activities other than copying, distribution and modification are not 73 | covered by this License; they are outside its scope. The act of 74 | running the Program is not restricted, and the output from the Program 75 | is covered only if its contents constitute a work based on the 76 | Program (independent of having been made by running the Program). 77 | Whether that is true depends on what the Program does. 78 | 79 | 1. You may copy and distribute verbatim copies of the Program's 80 | source code as you receive it, in any medium, provided that you 81 | conspicuously and appropriately publish on each copy an appropriate 82 | copyright notice and disclaimer of warranty; keep intact all the 83 | notices that refer to this License and to the absence of any warranty; 84 | and give any other recipients of the Program a copy of this License 85 | along with the Program. 86 | 87 | You may charge a fee for the physical act of transferring a copy, and 88 | you may at your option offer warranty protection in exchange for a fee. 89 | 90 | 2. You may modify your copy or copies of the Program or any portion 91 | of it, thus forming a work based on the Program, and copy and 92 | distribute such modifications or work under the terms of Section 1 93 | above, provided that you also meet all of these conditions: 94 | 95 | a) You must cause the modified files to carry prominent notices 96 | stating that you changed the files and the date of any change. 97 | 98 | b) You must cause any work that you distribute or publish, that in 99 | whole or in part contains or is derived from the Program or any 100 | part thereof, to be licensed as a whole at no charge to all third 101 | parties under the terms of this License. 102 | 103 | c) If the modified program normally reads commands interactively 104 | when run, you must cause it, when started running for such 105 | interactive use in the most ordinary way, to print or display an 106 | announcement including an appropriate copyright notice and a 107 | notice that there is no warranty (or else, saying that you provide 108 | a warranty) and that users may redistribute the program under 109 | these conditions, and telling the user how to view a copy of this 110 | License. (Exception: if the Program itself is interactive but 111 | does not normally print such an announcement, your work based on 112 | the Program is not required to print an announcement.) 113 | 114 | These requirements apply to the modified work as a whole. If 115 | identifiable sections of that work are not derived from the Program, 116 | and can be reasonably considered independent and separate works in 117 | themselves, then this License, and its terms, do not apply to those 118 | sections when you distribute them as separate works. But when you 119 | distribute the same sections as part of a whole which is a work based 120 | on the Program, the distribution of the whole must be on the terms of 121 | this License, whose permissions for other licensees extend to the 122 | entire whole, and thus to each and every part regardless of who wrote it. 123 | 124 | Thus, it is not the intent of this section to claim rights or contest 125 | your rights to work written entirely by you; rather, the intent is to 126 | exercise the right to control the distribution of derivative or 127 | collective works based on the Program. 128 | 129 | In addition, mere aggregation of another work not based on the Program 130 | with the Program (or with a work based on the Program) on a volume of 131 | a storage or distribution medium does not bring the other work under 132 | the scope of this License. 133 | 134 | 3. You may copy and distribute the Program (or a work based on it, 135 | under Section 2) in object code or executable form under the terms of 136 | Sections 1 and 2 above provided that you also do one of the following: 137 | 138 | a) Accompany it with the complete corresponding machine-readable 139 | source code, which must be distributed under the terms of Sections 140 | 1 and 2 above on a medium customarily used for software interchange; or, 141 | 142 | b) Accompany it with a written offer, valid for at least three 143 | years, to give any third party, for a charge no more than your 144 | cost of physically performing source distribution, a complete 145 | machine-readable copy of the corresponding source code, to be 146 | distributed under the terms of Sections 1 and 2 above on a medium 147 | customarily used for software interchange; or, 148 | 149 | c) Accompany it with the information you received as to the offer 150 | to distribute corresponding source code. (This alternative is 151 | allowed only for noncommercial distribution and only if you 152 | received the program in object code or executable form with such 153 | an offer, in accord with Subsection b above.) 154 | 155 | The source code for a work means the preferred form of the work for 156 | making modifications to it. For an executable work, complete source 157 | code means all the source code for all modules it contains, plus any 158 | associated interface definition files, plus the scripts used to 159 | control compilation and installation of the executable. However, as a 160 | special exception, the source code distributed need not include 161 | anything that is normally distributed (in either source or binary 162 | form) with the major components (compiler, kernel, and so on) of the 163 | operating system on which the executable runs, unless that component 164 | itself accompanies the executable. 165 | 166 | If distribution of executable or object code is made by offering 167 | access to copy from a designated place, then offering equivalent 168 | access to copy the source code from the same place counts as 169 | distribution of the source code, even though third parties are not 170 | compelled to copy the source along with the object code. 171 | 172 | 4. You may not copy, modify, sublicense, or distribute the Program 173 | except as expressly provided under this License. Any attempt 174 | otherwise to copy, modify, sublicense or distribute the Program is 175 | void, and will automatically terminate your rights under this License. 176 | However, parties who have received copies, or rights, from you under 177 | this License will not have their licenses terminated so long as such 178 | parties remain in full compliance. 179 | 180 | 5. You are not required to accept this License, since you have not 181 | signed it. However, nothing else grants you permission to modify or 182 | distribute the Program or its derivative works. These actions are 183 | prohibited by law if you do not accept this License. Therefore, by 184 | modifying or distributing the Program (or any work based on the 185 | Program), you indicate your acceptance of this License to do so, and 186 | all its terms and conditions for copying, distributing or modifying 187 | the Program or works based on it. 188 | 189 | 6. Each time you redistribute the Program (or any work based on the 190 | Program), the recipient automatically receives a license from the 191 | original licensor to copy, distribute or modify the Program subject to 192 | these terms and conditions. You may not impose any further 193 | restrictions on the recipients' exercise of the rights granted herein. 194 | You are not responsible for enforcing compliance by third parties to 195 | this License. 196 | 197 | 7. If, as a consequence of a court judgment or allegation of patent 198 | infringement or for any other reason (not limited to patent issues), 199 | conditions are imposed on you (whether by court order, agreement or 200 | otherwise) that contradict the conditions of this License, they do not 201 | excuse you from the conditions of this License. If you cannot 202 | distribute so as to satisfy simultaneously your obligations under this 203 | License and any other pertinent obligations, then as a consequence you 204 | may not distribute the Program at all. For example, if a patent 205 | license would not permit royalty-free redistribution of the Program by 206 | all those who receive copies directly or indirectly through you, then 207 | the only way you could satisfy both it and this License would be to 208 | refrain entirely from distribution of the Program. 209 | 210 | If any portion of this section is held invalid or unenforceable under 211 | any particular circumstance, the balance of the section is intended to 212 | apply and the section as a whole is intended to apply in other 213 | circumstances. 214 | 215 | It is not the purpose of this section to induce you to infringe any 216 | patents or other property right claims or to contest validity of any 217 | such claims; this section has the sole purpose of protecting the 218 | integrity of the free software distribution system, which is 219 | implemented by public license practices. Many people have made 220 | generous contributions to the wide range of software distributed 221 | through that system in reliance on consistent application of that 222 | system; it is up to the author/donor to decide if he or she is willing 223 | to distribute software through any other system and a licensee cannot 224 | impose that choice. 225 | 226 | This section is intended to make thoroughly clear what is believed to 227 | be a consequence of the rest of this License. 228 | 229 | 8. If the distribution and/or use of the Program is restricted in 230 | certain countries either by patents or by copyrighted interfaces, the 231 | original copyright holder who places the Program under this License 232 | may add an explicit geographical distribution limitation excluding 233 | those countries, so that distribution is permitted only in or among 234 | countries not thus excluded. In such case, this License incorporates 235 | the limitation as if written in the body of this License. 236 | 237 | 9. The Free Software Foundation may publish revised and/or new versions 238 | of the General Public License from time to time. Such new versions will 239 | be similar in spirit to the present version, but may differ in detail to 240 | address new problems or concerns. 241 | 242 | Each version is given a distinguishing version number. If the Program 243 | specifies a version number of this License which applies to it and "any 244 | later version", you have the option of following the terms and conditions 245 | either of that version or of any later version published by the Free 246 | Software Foundation. If the Program does not specify a version number of 247 | this License, you may choose any version ever published by the Free Software 248 | Foundation. 249 | 250 | 10. If you wish to incorporate parts of the Program into other free 251 | programs whose distribution conditions are different, write to the author 252 | to ask for permission. For software which is copyrighted by the Free 253 | Software Foundation, write to the Free Software Foundation; we sometimes 254 | make exceptions for this. Our decision will be guided by the two goals 255 | of preserving the free status of all derivatives of our free software and 256 | of promoting the sharing and reuse of software generally. 257 | 258 | NO WARRANTY 259 | 260 | 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY 261 | FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN 262 | OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES 263 | PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED 264 | OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 265 | MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS 266 | TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE 267 | PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, 268 | REPAIR OR CORRECTION. 269 | 270 | 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING 271 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR 272 | REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, 273 | INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING 274 | OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED 275 | TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY 276 | YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER 277 | PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE 278 | POSSIBILITY OF SUCH DAMAGES. 279 | 280 | END OF TERMS AND CONDITIONS 281 | 282 | How to Apply These Terms to Your New Programs 283 | 284 | If you develop a new program, and you want it to be of the greatest 285 | possible use to the public, the best way to achieve this is to make it 286 | free software which everyone can redistribute and change under these terms. 287 | 288 | To do so, attach the following notices to the program. It is safest 289 | to attach them to the start of each source file to most effectively 290 | convey the exclusion of warranty; and each file should have at least 291 | the "copyright" line and a pointer to where the full notice is found. 292 | 293 | 294 | Copyright (C) 19yy 295 | 296 | This program is free software; you can redistribute it and/or modify 297 | it under the terms of the GNU General Public License as published by 298 | the Free Software Foundation; either version 2 of the License, or 299 | (at your option) any later version. 300 | 301 | This program is distributed in the hope that it will be useful, 302 | but WITHOUT ANY WARRANTY; without even the implied warranty of 303 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 304 | GNU General Public License for more details. 305 | 306 | You should have received a copy of the GNU General Public License 307 | along with this program; if not, write to the Free Software 308 | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 309 | 310 | 311 | Also add information on how to contact you by electronic and paper mail. 312 | 313 | If the program is interactive, make it output a short notice like this 314 | when it starts in an interactive mode: 315 | 316 | Gnomovision version 69, Copyright (C) 19yy name of author 317 | Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. 318 | This is free software, and you are welcome to redistribute it 319 | under certain conditions; type `show c' for details. 320 | 321 | The hypothetical commands `show w' and `show c' should show the appropriate 322 | parts of the General Public License. Of course, the commands you use may 323 | be called something other than `show w' and `show c'; they could even be 324 | mouse-clicks or menu items--whatever suits your program. 325 | 326 | You should also get your employer (if you work as a programmer) or your 327 | school, if any, to sign a "copyright disclaimer" for the program, if 328 | necessary. Here is a sample; alter the names: 329 | 330 | Yoyodyne, Inc., hereby disclaims all copyright interest in the program 331 | `Gnomovision' (which makes passes at compilers) written by James Hacker. 332 | 333 | , 1 April 1989 334 | Ty Coon, President of Vice 335 | 336 | This General Public License does not permit incorporating your program into 337 | proprietary programs. If your program is a subroutine library, you may 338 | consider it more useful to permit linking proprietary applications with the 339 | library. If this is what you want to do, use the GNU Library General 340 | Public License instead of this License. 341 | -------------------------------------------------------------------------------- /CREDITS: -------------------------------------------------------------------------------- 1 | Mel Gorman 2 | Martin Devera 3 | Robert Lehr 4 | Xanthakis Stelios 5 | Joel Soete 6 | Eric Sandeen 7 | Konstantin Popov 8 | Tim Auckland 9 | -------------------------------------------------------------------------------- /Makefile.in: -------------------------------------------------------------------------------- 1 | TOPLEVEL = @@TOPLEVEL@@ 2 | PREFIX = @@PREFIX@@ 3 | GCCVERSION = @@GCCVERSION@@ 4 | PERLLIB = @@PERLLIB@@ 5 | GCCGRAPH = @@GCCGRAPH@@ 6 | CDEPN_SUPPRESS = yes 7 | export CDEPN_SUPPRESS 8 | 9 | all: 10 | cd $(TOPLEVEL)/compilers; \ 11 | ./install_gcc-$(GCCVERSION).sh $(GCCGRAPH) compile-only 12 | 13 | clean: 14 | rm -rf $(TOPLEVEL)/compilers/gcc-graph/* 15 | 16 | install: install-gcconly install-codeviz 17 | @echo "" 18 | @echo "*** CodeViz is now installed to $(PERFIX) and testsuites passed ***" 19 | @echo "Patched gcc is installed to $(GCCGRAPH). To compile a project" 20 | @echo "for use with CodeViz, genearlly the following will work" 21 | @echo "" 22 | @echo "make CC=$(GCCGRAPH)/bin/gcc or g++" 23 | @echo "" 24 | @echo "To generate a full.graph file for C, use" 25 | @echo "" 26 | @echo "genfull" 27 | @echo "" 28 | @echo "For C++, make sure you use the cppdepn method with" 29 | @echo "" 30 | @echo "genfull -g cppdepn" 31 | @echo "" 32 | @echo "or the results will not be what you expect." 33 | @echo "" 34 | 35 | install-gcconly: 36 | cd $(TOPLEVEL)/compilers/gcc-graph/objdir && make install $(GCCEXTRA_INSTALL) 37 | 38 | install-codeviz: 39 | mkdir -p $(DESTDIR)$(PREFIX)/bin 40 | cp $(TOPLEVEL)/bin/* $(DESTDIR)$(PREFIX)/bin 41 | mkdir -p $(DESTDIR)$(PERLLIB) 42 | cp -rv lib/CodeViz $(DESTDIR)$(PERLLIB) 43 | -------------------------------------------------------------------------------- /README: -------------------------------------------------------------------------------- 1 | WHERE DOES THIS CONTENT COMES FROM? 2 | ----------------------------------- 3 | The website of codeviz was down today and It was difficult to find the source 4 | code for download. I used: 5 | 6 | https://web.archive.org/web/20150502053825/http://www.csn.ul.ie/~mel/projects/codeviz/#download 7 | 8 | to find and download the source code you see here. The only change I made 9 | was adding this header to this file. 10 | 11 | README 12 | ------ 13 | 14 | This is the README for the CodeViz set of scripts. The tools are for 15 | the creation of call graphs for C and C++ so that function flow can be 16 | visualised. They are licensed under the GPL, see the COPYING file for details. 17 | 18 | Introduction 19 | ------------ 20 | 21 | At some stage in everyone's programming career, they will need to read through 22 | a lot of code written by another programmer. An important part of program 23 | comprehension is building a picture of how the program is structured from 24 | a high-level view and call graphs can be an invaluable aid when building 25 | this piecture. This is particularly useful if the original programmer uses 26 | clear function names. 27 | 28 | This project provides the ability to generate call graphs to aid the task of 29 | understanding code. It uses a highly modular set of collection methods and 30 | can be adapted to support any language although only C and C++ are currently 31 | supported. Each collection method has different advantages and disadvantages. 32 | 33 | Installing 34 | ---------- 35 | 36 | cd codeviz 37 | cp ./lib/* -rv /usr/lib/ (Or your preferred perl library path) 38 | cp ./bin/* /usr/local/bin 39 | 40 | Alternatively just run the scripts directly from the package bin/ directory 41 | as the libraries can be found as long as the libs are installed in a global 42 | perl directory or at the lib/ directory is the same level as bin/. 43 | 44 | The graphs are rendered using dot which is part of the GraphViz project. 45 | Install the package for your distribution or obtain it directly from 46 | http://www.graphviz.org 47 | 48 | Scripts 49 | ------- 50 | 51 | genfull - Use this to generate the full call graph for a project. This will 52 | be quite large and probably should be pared down with gengraph. A 53 | number of collection methods are available but cdepn is the 54 | default. Run genfull --man to get a full man page. Do not bother 55 | putting the output full.graph through dot yourself as it is unlikely 56 | to be rendered within a reasonable amount of time 57 | 58 | gengraph - This will generate a small subgraph and postscript file for a 59 | given set of functions. Run gengraph --man for full details 60 | 61 | Generating cdepn Files for genfull 62 | ---------------------------------- 63 | 64 | If the full.graph for the source you are interested in have already been 65 | created, you can skip this section. See ./graphs to see if a full.graph 66 | is available. 67 | 68 | The cobjdump and cppobjdump (for C and C++ respectively) will generate 69 | adequate call graphs but the information is a bit lacking. For example, 70 | the source file of a function declaration is unknown and macros and inline 71 | functions will be totally missing. Ideally, the cdepn method should be used 72 | but it requires a patched version of gcc and g++ to work. The patches and 73 | some scripts are available in the compilers/ directory. 74 | 75 | The patched version of gcc and g++ outputs .cdepn files for every c and c++ 76 | file compiled. This .cdepn file contains information such as when functions 77 | are called, where they are declared and so on. Earlier versions of CodeViz 78 | supported multiple gcc versions but this one only support 7.4.0. 79 | 80 | First, the source tar has to be downloaded. For those who have better things 81 | to do than read the gcc install doc, just do the following 82 | 83 | cd compilers 84 | ncftpget ftp://ftp.gnu.org/pub/gnu/gcc/gcc-7.4.0/gcc-7.4.0.tar.gz 85 | ./install_gcc-7.4.0.sh 86 | 87 | This script will untar gcc, patch it and install it to the supplied path. If 88 | no path is given, it'll be installed to $HOME/gcc-graph . I usually install 89 | it to /usr/local/gcc-graph with 90 | 91 | ./install_gcc-7.4.0.sh /usr/local/gcc-graph 92 | 93 | If you seriously want to patch by hand, just read the script as it goes through 94 | each of the steps one at a time. There is one step to note though. 95 | 96 | For now, we will presume a patched version of gcc and g++ is now in 97 | $HOME/gcc-graph/. Most projects will use the variable CC for deciding 98 | which version of gcc to use. The handiest way to use the patched one is with 99 | something like 100 | 101 | make CC=$HOME/gcc-graph/bin/gcc CXX=$HOME/gcc-graph/bin/g++ 102 | 103 | Or alternatively, adjust your path that gcc-graph will appear before the 104 | normal gcc. As each source file is compiled, the corresponding cdepn file 105 | will be created. 106 | 107 | In the case of building the Linux Kernel, the commands would be; 108 | 109 | make CC=$HOME/gcc-graph/bin/gcc bzImage 110 | make CC=$HOME/gcc-graph/bin/gcc modules 111 | 112 | Similar methods will work for other projects presuming that the Makefile 113 | uses the CC or CXX macros correctly to indicate the compiler to use. If it's 114 | a Makefile of your own type or it does not use proper macros, you may have 115 | to edit the Makefile yourself or else adjust your path to put gcc-graph first. 116 | For example, with bash, the following will work. 117 | 118 | PATH=$HOME/gcc-graph/bin:$PATH 119 | 120 | When building, watch the compiler output to make sure the .cdepn files are being 121 | created. 122 | 123 | Generating nccout files for genfull 124 | ----------------------------------- 125 | 126 | An alternative to using a patched version of gcc is to use ncc 127 | (http://freshmeat.net/projects/ncc) which is a C compiler specifically 128 | designed for code browsing. It comes with it's own navigation tool and 129 | is well worth checking out. 130 | 131 | CodeViz supports ncc with the cncc collection method (just like cdepn is for 132 | use with gcc) and supports C only. The really big thing going for the ncc 133 | collection method is that it can traverse function pointers. If you download 134 | and install ncc, use the cncc collection method if it is C code and function 135 | pointers are common. 136 | 137 | Once ncc is installed, in the case of building the Linux Kernel, the commands would be: 138 | 139 | make -i CC='ncc -ncoo -ncfabs' bzImage 140 | make -i CC='ncc -ncoo -ncfabs' modules 141 | find . -name \*.nccout | xargs cat > code.map.nccout 142 | 143 | Generating full.graph 144 | --------------------- 145 | 146 | Some full.graph files are provided with the tar in the downloads section. If 147 | one you want is not available, read on. 148 | 149 | To create a full.graph, the script genfull is used. run genfull --help to see 150 | all options but the easiest thing to do is run the script with no arguments 151 | in the top level source directory after a compile and a file full.graph will 152 | be created in the top level source directory. 153 | 154 | While it should be possible to put full.graph though dot and see the postscript 155 | file, it is recommended you do not try. A full graph is extremely large and 156 | unlikely to be rendered in a reasonable amount of time. One really should 157 | use the gengraph program to create smaller graphs. 158 | 159 | Problems that might exist with full.graph 160 | ----------------------------------------- 161 | 162 | In more complex code, the full.graph may not be perfect. For example, there may 163 | be naming collisions where there is duplicate function names between modules or 164 | if there is multiple binaries being compiled, genfull will not distinguish 165 | between them. If you think this will be a problem, there is two steps you can 166 | make. 167 | 168 | First, compare the graph generated by cdepn with the one generated by 169 | cobjdump. As cobjdump is analysing a binary, it is highly unlikely the graph 170 | is wrong, it just will have no information on inline functions or macros. With 171 | the linux kernel, this test would look something like 172 | 173 | genfull -g cobjdump -o full.graph-objdump 174 | genfull -g cdepn -o full.graph-cdepn 175 | gengraph -t -d 5 -g full.graph-objdump -f kswapd -o kswapd-objdump.ps 176 | gengraph -t -d 5 -g full.graph-cdepn -f kswapd -o kswapd-cdepn.ps 177 | 178 | This would generate two full.graphs and two call graphs of the function 179 | kswapd() which could be compared to make sure the cdepn graph is accurate. A 180 | similar method can be used for other projects. 181 | 182 | The second problem that may occur is where function names are duplicated 183 | between modules. In this case, the best course of action is to use the -s 184 | switch to genfull to limit which branches of the tree are examined. For 185 | example, in the linux kernel there is an alloc_pages() function in mm/ and 186 | drivers/char/drm . If one was examining the VM alone and naming collisions were 187 | expected to be a problem, genfull could be invoked as 188 | 189 | genfull -s "mm include/linux drivers/block arch/i386" 190 | 191 | which would cover most of the functions of interest. In other projects, it will 192 | be a case of different libraries colliding with each other. For instance, with 193 | avifile, genfull with no arguments will create a horrible mess. Instead, the 194 | -s switch must be used to generate a full.graph for each part of the project. 195 | For example, the player would be graphed with 196 | 197 | genfull -s "player" -o full.graph-player 198 | 199 | and each of the libraries would be graphed separately. 200 | 201 | Generating Call Graphs 202 | ---------------------- 203 | 204 | The script gengraph generates a call graph for a specified function based on 205 | the full.graph file. gengraph --man will provide all the information you need. 206 | The most important switch to note is -g which determines what collection method 207 | to use. Once the script completes, a postscript file will be available which 208 | can be viewed with any postscript viewer. By default, the output filename will 209 | be functionname.ps 210 | 211 | If it takes a long time to generate a graph, it is usually a good idea to first 212 | limit it's depth to something reasonable with -d . We'll take an example of 213 | graphing alloc_pages() with kernel 2.4.20 214 | 215 | Step 1: gengraph -f alloc_pages 216 | Result: Taking way too long, hit ctrl-c and limited by some reasonable depth to 217 | get an idea of what was happening 218 | 219 | Step 2: gengraph -d 10 -f alloc_pages 220 | Result: Output graph is massive, mainly with kernel stock functions of no 221 | interest. Use the -t switch to omit functions that are usually of no interest. 222 | For other projects, edit the gengraph script and go to the line "sub 223 | generate_trimlist", this function has a list of functions to "trim" with the -t 224 | switch is used 225 | 226 | Step 3: gengraph -t -d 10 -f alloc_pages 227 | Result: Output graph is still massive but a glance at the graph shows that a 228 | call to "shrink_cache()" is resulting in a massive graph below it that does not 229 | look like it is directly related to page allocation. Lets just show that 230 | function but not traverse it with the -s switch 231 | 232 | Step 4: gengraph -t -d 10 -s "shrink_cache" -f alloc_pages 233 | Result: Graph size is drastically reduced. Most of the remaining graph 234 | involves two functions "try_to_free_pages_zone()" and "__free_pages_ok". We'll 235 | not traverse try_to_free_pages_zone() and will ignore __free_pages_ok() 236 | altogether with the -i switch 237 | 238 | Step 5: gengraph -t -d 10 -s "shrink_cache try_to_free_pages_zone" -i 239 | "__free_pages_ok" -f alloc_pages 240 | Result: Perfect, shows a nice graph which clearly shows what the important 241 | functions are in relation to just page allocation. Later the branches that were 242 | not traversed in this graph can be graphed separately 243 | 244 | The bottom line is that the first graph is usually too large and needs to be 245 | cut down. How to pare it down in a combination of experience with the code 246 | and common sense. I find it usually helps to just limit the depth first by 247 | 4 and start ignoring functions that are obviously not of current interest 248 | and traverse them later 249 | 250 | Generating Graphs based on Regular Expressions 251 | ---------------------------------------------- 252 | 253 | Support is available for selecting functions to graph, show and ignore based 254 | on regular expressions. The format of the expression is the same as perl 255 | except without the //'s. For example, to generate a graph that d 256 | that look like an alloc function in the kernel, this would work 257 | 258 | gengraph -t -d 4 --func-re "^.?.?alloc(_page)?$" -i "pmd_alloc" -o allocs.ps 259 | 260 | Note that with --func-re in particular, it is important that you use the -o 261 | switch or dot will fail to create a graph with complaints about bad output 262 | filenames. 263 | 264 | Post-Processing Options 265 | ----------------------- 266 | 267 | Both genfull and gengraph support the use of post-procesing steps. Currently, 268 | two are supported. The first is stack usage by a single function. This is x86 269 | specific as it depends on object files regardless of the collection method 270 | used. This is mainly of benefit to the Linux kernel as normal applications 271 | can expand their stack and do not need to worry about stack usage as 272 | much. The second module shows cumulative usage in gengraph between pairs of 273 | functions. This is really handy for showing the usage between a system call 274 | and a lower-level function to identify places where stack is used too much. 275 | 276 | See the man pages for genfull and gengraph for more information on the use 277 | of the post-processing options. 278 | 279 | Daemon/Client Support 280 | --------------------- 281 | 282 | With a large input graph, the longest operation for the generation of the call 283 | graph is the reading of the input file. To compare, to generate a small graph 284 | on the authors machine, it takes 4 seconds to read the input graph and 0.1 285 | seconds to generate the output file. To address, this, gengraph can run as a 286 | daemon if the -q (--daemon) switch is specified. Use -v if you want to see what 287 | it is doing. 288 | 289 | gengraph -q -g /usr/src/linux-2.4.20-clean/full.graph 290 | 291 | When this returns, the daemon is running. To generate a graph using the daemon, 292 | run 293 | gengraph -q -t -d 2 -f alloc_pages 294 | 295 | Note the use of the -q switch which says that gengraph should run as a client 296 | to the daemon instance. If you are bored, compare the difference in running 297 | times between normal gengraph and when it is used as a client :-) . To stop 298 | the daemon, do the following 299 | 300 | echo QUIT > /tmp/codeviz.pipe 301 | 302 | and the daemon will shutdown and cleanup. 303 | 304 | Generating Graphs for the Web 305 | ----------------------------- 306 | 307 | Gengraph is now suitable for use with CGI scripts. To generate GIF output 308 | instead of postfix, use the -w switch. How you choose to implement is up 309 | to yourself but what I did was the following 310 | 311 | o Have CGI script call gengraph to output GIF to /tmp 312 | o In the HTML, have 313 | 314 | Where output.gif is actually some temporary file in /tmp created by the CGI 315 | script with a unique name and readgif is a simply exectuable which reads 316 | GIFs from /tmp and then unlinks them. 317 | 318 | There is no demo of this available because the webserver which hosts this 319 | project is a bit loaded. While I could run a demo, my popularity would take 320 | a bit of a dent. 321 | 322 | There is also support for generating HTML files with source-highlight if you 323 | have it installed. See the detailed manpage for the --shighlight option for 324 | more details. 325 | 326 | Misc Notes 327 | ---------- 328 | 329 | Reports of success or failure, especially with C++, using any of the collection 330 | methods are appreciated. 331 | 332 | Bugs and Feedback 333 | ----------------- 334 | Email any comments, feedback and bug reports to mel@csn.ul.ie. Enjoy..... 335 | 336 | Credits 337 | ------- 338 | 339 | The vast majority of this has been implemented by Mel Gorman 340 | . However, the diff to gcc and original cdepn.pl that 341 | this project was originally based on was written by Martin Devera (Devik) 342 | (http://luxik.cdi.cz/~devik). They have since changed considerably to support 343 | other languages and be more flexible but the original idea was his, thanks 344 | Martin. Encouragement and prodding to support ncc is courtesy of the author 345 | of ncc Xanthakis Stelios (sxanth@ceid.upatras.gr). The main guts of the 346 | implementation of the regular expression support and HTML rendering is 347 | courtesy of Robert Lehr (bozzio@the-lehrs.com). 348 | -------------------------------------------------------------------------------- /README-CrossCompile: -------------------------------------------------------------------------------- 1 | GCC 3.3.2 notes 2 | --------------- 3 | 4 | The patch gcc-3.3.2-cdepn.diff is basically just an adjustment of the 5 | gcc-3.2.3-cdepn.diff patch. 6 | 7 | I only try it against Debian gcc-3.3 (presently gcc-3.3_3.3.2ds5-4) dpkg sources 8 | (+ patches applied) on an hppa platform. 9 | 10 | To obtain a 'temporary' gcc hppa cross-compiler (enough to compile linux 11 | kernel): 12 | - apply the patch in the gcc src tree: patch -p1 -i gcc-3.3.2-cdepn.diff; 13 | - configure gcc (in the build/gcc dir): sources/gcc/configure \ 14 | --target=hppa-linux --host=hppa-linux --build=hppa-linux \ 15 | --prefix=/opt/palinux-cdvis --disable-shared --disable-nls \ 16 | --enable-sjlj-exceptions --disable-threads --enable-languages=c 17 | (to obtain a 64bit compiler just replace the 'target' hppa-linux by hpp64-linux) 18 | - make 19 | - make install (will put gcc into /opt/palinux-cdvis/bin) 20 | 21 | -- 22 | Joel Soete 23 | -------------------------------------------------------------------------------- /bin/check-stack.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 3 | # Usage : check-stack.sh vmlinux $(/sbin/modprobe -l) 4 | # 5 | # Run a compiled ix86 kernel and print large local stack usage. 6 | # 7 | # />:/{s/[<>:]*//g; h; } On lines that contain '>:' (headings like 8 | # c0100000 <_stext>:), remove <, > and : and hold the line. Identifies 9 | # the procedure and its start address. 10 | # 11 | # /subl\?.*\$0x[^,][^,][^,].*,%esp/{ Select lines containing 12 | # subl\?...0x...,%esp but only if there are at least 3 digits between 0x and 13 | # ,%esp. These are local stacks of at least 0x100 bytes. 14 | # 15 | # s/.*$0x\([^,]*\).*/\1/; Extract just the stack adjustment 16 | # /^[89a-f].......$/d; Ignore line with 8 digit offsets that are 17 | # negative. Some compilers adjust the stack on exit, seems to be related 18 | # to goto statements 19 | # G; Append the held line (procedure and start address). 20 | # s/\(.*\)\n.* \(.*\)/\1 \2/; Remove the newline and procedure start 21 | # address. Leaves just stack size and procedure name. 22 | # p; }; Print stack size and procedure name. 23 | # 24 | # /subl\?.*%.*,%esp/{ Selects adjustment of %esp by register, dynamic 25 | # arrays on stack. 26 | # G; Append the held line (procedure and start address). 27 | # s/\(.*\)\n\(.*\)/Dynamic \2 \1/; Reformat to "Dynamic", procedure 28 | # start address, procedure name and the instruction that adjusts the 29 | # stack, including its offset within the proc. 30 | # p; }; Print the dynamic line. 31 | # 32 | # 33 | # Leading spaces in the sed string are required. 34 | # 35 | objdump --disassemble "$@" | \ 36 | sed -ne '/>:/{s/[<>:]*//g; h; } 37 | /subl\?.*\$0x[^,].*,%esp/{ 38 | s/.*\$\(0x[^,]*\).*/\1/; /^[89a-f].......$/d; G; s/\(.*\)\n.* \(.*\)/\1 \2/; p; }; 39 | /subl\?.*%.*,%esp/{ G; s/\(.*\)\n\(.*\)/Dynamic \2 \1/; p; }; ' | \ 40 | sort -r 41 | -------------------------------------------------------------------------------- /bin/genfull: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl 2 | # genfull 3 | # 4 | # This script is responsible for searching through a source tree and 5 | # finding all the cdepn files. A call graph is generated based on the 6 | # individual cdepn files and outputted to a file suitable for use with 7 | # dot and gengraph 8 | my $VERSION="1.0.11"; 9 | 10 | use FindBin qw($Bin); 11 | use lib "$Bin/../lib/"; 12 | 13 | use Getopt::Long; 14 | use Pod::Usage; 15 | use CodeViz::Collect; 16 | use CodeViz::CollectPPStack; 17 | use CodeViz::Format; 18 | use Cwd 'abs_path'; 19 | use strict; 20 | 21 | # Option variables 22 | my $SHOWVERSION; 23 | my $opt_files=-1; 24 | my $opt_toplevel="./"; 25 | my $opt_subdirs="--nosubdirs--"; 26 | my $opt_output="./full.graph"; 27 | my $opt_method="cdepn"; 28 | my $opt_verbose; 29 | my $opt_skip; 30 | my $opt_help; 31 | my $opt_man; 32 | 33 | my @cdepnlist; 34 | my $subdir; 35 | my $subdir_paths; 36 | 37 | # Post processing options 38 | my $PP_STACK=""; 39 | 40 | # Get options 41 | GetOptions( 42 | 'file|f=s' => \$opt_files, 43 | 'toplevel|d=s' => \$opt_toplevel, 44 | 'subdirs|s=s' => \$opt_subdirs, 45 | 'method|g=s' => \$opt_method, 46 | 'output|o=s' => \$opt_output, 47 | 'help|h' => \$opt_help, 48 | 'pp-stack=s' => \$PP_STACK, 49 | 'skip' => \$opt_skip, 50 | 'v|verbose' => \$opt_verbose, 51 | 'version' => \$SHOWVERSION, 52 | 'man|m' => \$opt_man); 53 | pod2usage(-exitstatux => 0, -verbose => 0) if $opt_help; 54 | pod2usage(-exitstatus => 0, -verbose => 2) if $opt_man; 55 | if ($SHOWVERSION) { 56 | print "(CodeViz) genfull $VERSION\n"; 57 | exit 58 | } 59 | set_verbose($opt_verbose); 60 | 61 | # Check the toplevel directory is ok 62 | $opt_toplevel = abs_path($opt_toplevel) . "/"; 63 | die("$opt_toplevel is not a directory") if (! -d $opt_toplevel ); 64 | 65 | # If only specific files or binaries are to be scanned, check to make 66 | # sure they exist and are files 67 | if ($opt_files != -1) { 68 | foreach (split(/ /, $opt_files)) { 69 | die("$_ is not a file") if (! -f $_); 70 | } 71 | } 72 | 73 | # Append full path to subdirs list 74 | if ($opt_subdirs eq "--nosubdirs--") { 75 | $subdir_paths = $opt_toplevel; 76 | } else { 77 | foreach $subdir (split(/ /, $opt_subdirs)) { 78 | $subdir_paths .= "$opt_toplevel$subdir "; 79 | } 80 | } 81 | 82 | # Generate graph unless explicitly skipped 83 | if (!$opt_skip) { 84 | gen_fullgraph($opt_method, $opt_toplevel, $opt_files, $subdir_paths, $opt_output); 85 | } 86 | 87 | # Perform postprocessing if requsted 88 | if ($PP_STACK ne "") { CollectPPStack($opt_output, $PP_STACK); } 89 | 90 | # Below this line is help and manual page information 91 | __END__ 92 | 93 | =head1 NAME 94 | 95 | genfull - Generate a call graph from .cdepn files in a source tree 96 | 97 | =head1 SYNOPSIS 98 | 99 | genfull [options] 100 | 101 | Main Options: 102 | -d, --toplevel Top level source directory (Default: current) 103 | -f, --file Files to scan for data (Default: find all files) 104 | -s, --subdirs Subdirectories to graph (Default: all) 105 | -g, --method Method for collecting data (Default: cdepn) 106 | -o, --output Output graph (Default: ./full.graph) 107 | -h, --help Print this message 108 | --version Print the version number 109 | 110 | Post-Processing Options: 111 | --skip Skip collection and only post-process 112 | --pp-stack Calculate stack usage 113 | 114 | For Linux kernel call graphs, the following calling is recommended 115 | genfull -s "arch/i386 net lib ipc mm fs net kernel init drivers" 116 | 117 | =head1 OPTIONS 118 | 119 | =item B<-d, --toplevel> 120 | 121 | The top level source tree to collect information from. By default, this is 122 | the current working directory. 123 | 124 | =item B<-f, --file> 125 | 126 | A list of files to scan. This is most useful when used in conjunction with 127 | the cobjdump method for generating call graphs. Only compiled binaries 128 | are useful for this collection method and using find to get all binaries 129 | could result in name collisions and overlapped call graphs which would be 130 | useless. It can also be used just to scan a single cdepn file 131 | 132 | =item B<-s, --subdirs> 133 | 134 | If desired, only specified subdirectories will be scanned. These directory 135 | names are relative to the top level source directory. By default, all 136 | subdirectories will be scanned 137 | 138 | =item B<-g, --method> 139 | 140 | Different methods may be used to collect information for call graphs. A 141 | large number of collections are available for both C and C++. B and 142 | B require a patched compiler but B and B 143 | require only objdump to be available. B requires the ncc compiler. 144 | The default method is the B method. The various methods are discussed 145 | in a later section. 146 | 147 | =item B<-o, --output> 148 | 149 | The output graph filename. This will be suitable for graph generation with dot. 150 | By default, it will be called ./full.graph 151 | 152 | =item B<--skip> 153 | 154 | Skip the collection part and just perform post-processing. This is handy 155 | when you already have a full.graph generated and just want to perform the 156 | post-processing. 157 | 158 | =item B<--pp-stack> 159 | 160 | This option calculates the stack usage for each function and places it in 161 | a node attribute called "stackuse" in the full.graph file. To see the options 162 | the post-processing modules supports, call "--pp-stack help", but currently 163 | the only option supported is objfile. This option is only really useful 164 | for the Linux kernel as normal applications grow their stack on demand. 165 | To calculate stack usage for the kernel, use "--pp-stack objfile=vmlinux" 166 | 167 | =head1 DESCRIPTION 168 | 169 | B is responsible for scanning a source tree and collecting 170 | information for the generation of call graphs. Different collection methods 171 | may be used which are discussed in the next section. This is a list of them, 172 | the languages they are meant to be used with are in brackets 173 | 174 | B(C) Collects information from .cdepn files outputted by a patched gcc 175 | 176 | B(C) Analyses a compiled binary which must not be stripped 177 | 178 | B(C) Collects information outputted by ncc 179 | 180 | B(C++) Same as cdepn except for C++ 181 | 182 | B(C++) Same as cobjdump except for C++ 183 | 184 | Once the information is collected, it is outputted to a file as specified 185 | by the B<-o> switch (full.graph by default) which is suitable for rendering 186 | with B which comes with the GraphViz package. The graph that this program 187 | outputs is likely to be considerably large. In this case, B should 188 | be used to generate smaller graphs containing the functions of interest. 189 | 190 | =head1 COLLECTION METHODS 191 | 192 | =item B(C): This relies on a patched compiler to output information 193 | during compilation and produces very accurate call graphs. A patch was 194 | supplied with the CodeViz package for gcc. This patch should be applied and 195 | the source project compiled with the patched compiler. For each .c file, 196 | a .c.cdepn file is created with information relevant to call graphs such as 197 | the source file and line number functions are declared on. This collection 198 | method will identify macros inline functions but not macros. 199 | 200 | 201 | The .cdepn files will not identify macros so the cdepn method takes lessons 202 | from LXR(http://lxr.linux.no). After the .cdepn files are processed, it reads 203 | the C and header files used by the compiled source and parses them. The 204 | .cdepn information is trusted by default but where macros are involved, 205 | the information picked up by parsing like LXR is used instead. 206 | 207 | 208 | This method will produce accurate graphs unless function names are duplicated 209 | between files which can frequently happen, such as with the different arch 210 | layers in the Linux kernel. If there is collisions, there is no way to 211 | resolve which one is right and graphs can get badly messed up. When the 212 | method completes, it'll print out how many collisions were found and how 213 | many functions were affected. If the number of colliding functions is too 214 | high, use -s to limit what directories in the source tree are analysed. 215 | 216 | Example usage: genfull -g cdepn -s /usr/src/linux 217 | 218 | =item B(C): Patching a compiler is not always an option so this 219 | collection method just depends on the availability of B which should 220 | be installed with the binutils package common to most distributions. This 221 | should be used with a compiled binary as object files on their own are 222 | insufficient so the use of the B<-f> switch is recommended to specify the 223 | binary of interest. Your mileage will vary considerably with this method 224 | as assembler output is highly dependent on the architecture type, compiler 225 | optimizations and so on. This method will not recognise inline functions 226 | or macros. 227 | 228 | Example usage: genfull -g cobjdump -s /usr/src/linux -f /usr/src/linux/vmlinux 229 | 230 | =item B(C): This method relies on the availability of ncc 231 | (http://students.ceid.upatras.gr/~sxanth/ncc/index.html) and having the 232 | tree compiled with it to output .nccout (just like cdepn needs a patched gcc 233 | available). The ncc website and project has ample information on how to use 234 | ncc and CodeViz is able to parse the .nccout files it outputs. This method 235 | is similar in performance to B with one important difference. B 236 | is able to understand and traverse function pointers which no other method 237 | can so. If you are examining code that depends heavily on function pointers 238 | or dispatch tables, this is the collection method for you. 239 | 240 | Example usage: genfull -g cncc -s /usr/src/linux 241 | 242 | This method will collect all the .nccout files below the 243 | current directory or just one file if used together with -f. The advantage 244 | of ncc analysis is that the call graph includes the pointer to function calls. 245 | Each pointer to function is reported as a pseudo-function that calls all 246 | the values assigned to it. 247 | 248 | Example usage: genfull -g cncc -f /usr/src/linux/code.map.nccout 249 | 250 | =item B(C++): This is essentially the same as B except that 251 | it should be used for C++ projects. 252 | 253 | Example usage: genfull -g cppdepn -s /usr/src/avifile-0.6 254 | 255 | =item B: This is essentially the same as B except 256 | that it should be used for C++ projects. 257 | 258 | Example usage: genfull -g cppobjdump -s /usr/src/avifile-0.6 -f /usr/src/avifile-0.6/player/aviplay 259 | 260 | =head1 AUTHOR 261 | 262 | Written by Mel Gorman (mel@csn.ul.ie) 263 | 264 | Original idea by Martin Devera (Devik) 265 | 266 | Help supporting ncc from Xanthakis Stelios (sxanth@ceid.upatras.gr) 267 | 268 | =head1 REPORTING BUGS 269 | 270 | Report bugs to mel@csn.ul.ie 271 | 272 | =cut 273 | -------------------------------------------------------------------------------- /build: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/petersenna/codeviz/cc5bd4ae0ca46bf1812d570c34d09f6ef8521fa6/build -------------------------------------------------------------------------------- /codeviz.p: -------------------------------------------------------------------------------- 1 | Makefile | 2 2 | README | 8 - 3 | compilers/gcc-patches/gcc-3.4.1-cdepn.diff | 185 ----------------------------- 4 | compilers/gcc-patches/gcc-3.4.6-cdepn.diff | 184 ++++++++++++++++++++++++++++ 5 | compilers/install_gcc-3.4.1.sh | 79 ------------ 6 | compilers/install_gcc-3.4.6.sh | 79 ++++++++++++ 7 | configure | 6 8 | 7 files changed, 271 insertions(+), 272 deletions(-) 9 | diff -urN codeviz-1.0.9-3.4.1/Makefile codeviz-1.0.9-3.4.6/Makefile 10 | --- codeviz-1.0.9-3.4.1/Makefile 2005-09-20 12:24:02.000000000 +0300 11 | +++ codeviz-1.0.9-3.4.6/Makefile 2006-06-22 22:20:32.000000000 +0300 12 | @@ -1,6 +1,6 @@ 13 | TOPLEVEL = /home/mel/Projects/codeviz-1.0.8 14 | PREFIX = /usr/local 15 | -GCCVERSION = 3.4.1 16 | +GCCVERSION = 3.4.6 17 | PERLLIB = /usr/local/lib/perl/5.8.4 18 | GCCGRAPH = /usr/local/gccgraph 19 | 20 | diff -urN codeviz-1.0.9-3.4.1/README codeviz-1.0.9-3.4.6/README 21 | --- codeviz-1.0.9-3.4.1/README 2004-08-11 01:02:29.000000000 +0300 22 | +++ codeviz-1.0.9-3.4.6/README 2006-06-22 22:20:43.000000000 +0300 23 | @@ -65,20 +65,20 @@ 24 | The patched version of gcc and g++ outputs .cdepn files for every c and c++ 25 | file compiled. This .cdepn file contains information such as when functions 26 | are called, where they are declared and so on. Earlier versions of CodeViz 27 | -supported multiple gcc versions but this one only support 3.4.1. 28 | +supported multiple gcc versions but this one only support 3.4.6. 29 | 30 | First, the source tar has to be downloaded. For those who have better things 31 | to do than read the gcc install doc, just do the following 32 | 33 | cd compilers 34 | -ncftpget ftp://ftp.gnu.org/pub/gnu/gcc/gcc-3.4.1/gcc-3.4.1.tar.gz 35 | -./install_gcc-3.4.1.sh 36 | +ncftpget ftp://ftp.gnu.org/pub/gnu/gcc/gcc-3.4.6/gcc-3.4.6.tar.gz 37 | +./install_gcc-3.4.6.sh 38 | 39 | This script will untar gcc, patch it and install it to the supplied path. If 40 | no path is given, it'll be installed to $HOME/gcc-graph . I usually install 41 | it to /usr/local/gcc-graph with 42 | 43 | -./install_gcc-3.4.1.sh /usr/local/gcc-graph 44 | +./install_gcc-3.4.6.sh /usr/local/gcc-graph 45 | 46 | If you seriously want to patch by hand, just read the script as it goes through 47 | each of the steps one at a time. There is one step to note though. 48 | diff -urN codeviz-1.0.9-3.4.1/compilers/gcc-patches/gcc-3.4.1-cdepn.diff codeviz-1.0.9-3.4.6/compilers/gcc-patches/gcc-3.4.1-cdepn.diff 49 | --- codeviz-1.0.9-3.4.1/compilers/gcc-patches/gcc-3.4.1-cdepn.diff 2004-08-19 23:09:00.000000000 +0300 50 | +++ codeviz-1.0.9-3.4.6/compilers/gcc-patches/gcc-3.4.1-cdepn.diff 1970-01-01 02:00:00.000000000 +0200 51 | @@ -1,185 +0,0 @@ 52 | -diff -ru gcc-3.4.1-clean/gcc/cgraph.c gcc-3.4.1-cdepn/gcc/cgraph.c 53 | ---- gcc-3.4.1-clean/gcc/cgraph.c 2004-06-01 00:43:51.000000000 +0100 54 | -+++ gcc-3.4.1-cdepn/gcc/cgraph.c 2004-08-19 19:28:42.000000000 +0100 55 | -@@ -68,7 +68,8 @@ 56 | - static GTY(()) struct cgraph_varpool_node *cgraph_varpool_nodes; 57 | - 58 | - static struct cgraph_edge *create_edge (struct cgraph_node *, 59 | -- struct cgraph_node *); 60 | -+ struct cgraph_node *, 61 | -+ location_t call_location); 62 | - static hashval_t hash_node (const void *); 63 | - static int eq_node (const void *, const void *); 64 | - 65 | -@@ -152,7 +153,7 @@ 66 | - /* Create edge from CALLER to CALLEE in the cgraph. */ 67 | - 68 | - static struct cgraph_edge * 69 | --create_edge (struct cgraph_node *caller, struct cgraph_node *callee) 70 | -+create_edge (struct cgraph_node *caller, struct cgraph_node *callee, location_t call_location) 71 | - { 72 | - struct cgraph_edge *edge = ggc_alloc (sizeof (struct cgraph_edge)); 73 | - struct cgraph_edge *edge2; 74 | -@@ -180,6 +181,7 @@ 75 | - 76 | - edge->caller = caller; 77 | - edge->callee = callee; 78 | -+ edge->call_location = call_location; 79 | - edge->next_caller = callee->callers; 80 | - edge->next_callee = caller->callees; 81 | - caller->callees = edge; 82 | -@@ -295,7 +297,7 @@ 83 | - struct cgraph_edge * 84 | - cgraph_record_call (tree caller, tree callee) 85 | - { 86 | -- return create_edge (cgraph_node (caller), cgraph_node (callee)); 87 | -+ return create_edge (cgraph_node (caller), cgraph_node (callee), input_location); 88 | - } 89 | - 90 | - void 91 | -Only in gcc-3.4.1-cdepn/gcc: cgraph.c.cdepn 92 | -diff -ru gcc-3.4.1-clean/gcc/cgraph.h gcc-3.4.1-cdepn/gcc/cgraph.h 93 | ---- gcc-3.4.1-clean/gcc/cgraph.h 2004-01-23 23:35:54.000000000 +0000 94 | -+++ gcc-3.4.1-cdepn/gcc/cgraph.h 2004-08-19 19:28:42.000000000 +0100 95 | -@@ -126,6 +126,9 @@ 96 | - /* When NULL, inline this call. When non-NULL, points to the explanation 97 | - why function was not inlined. */ 98 | - const char *inline_failed; 99 | -+ 100 | -+ /* CodeViz: Location the call occurred at */ 101 | -+ location_t call_location; 102 | - }; 103 | - 104 | - /* The cgraph_varpool data structure. 105 | -diff -ru gcc-3.4.1-clean/gcc/cgraphunit.c gcc-3.4.1-cdepn/gcc/cgraphunit.c 106 | ---- gcc-3.4.1-clean/gcc/cgraphunit.c 2004-05-06 00:24:28.000000000 +0100 107 | -+++ gcc-3.4.1-cdepn/gcc/cgraphunit.c 2004-08-19 19:28:43.000000000 +0100 108 | -@@ -320,7 +320,10 @@ 109 | - cgraph_analyze_function (struct cgraph_node *node) 110 | - { 111 | - tree decl = node->decl; 112 | -+ tree thisTree, calleeTree; 113 | -+ FILE *fnref_f; 114 | - struct cgraph_edge *e; 115 | -+ struct cgraph_edge *calleeEdge; 116 | - 117 | - current_function_decl = decl; 118 | - 119 | -@@ -358,6 +361,33 @@ 120 | - node->analyzed = true; 121 | - current_function_decl = NULL; 122 | - 123 | -+ /* CodeViz: Output information on this node */ 124 | -+ thisTree = node->decl; 125 | -+ if ((fnref_f = cdepn_open(NULL))) 126 | -+ { 127 | -+ fprintf(fnref_f,"F {%s} {%s:%d}\n", 128 | -+ lang_hooks.decl_printable_name (thisTree, 2), 129 | -+ DECL_SOURCE_FILE (thisTree), DECL_SOURCE_LINE (thisTree)); 130 | -+ 131 | -+ } 132 | -+ 133 | -+ /* CodeViz: Output information on all functions this node calls */ 134 | -+ for (calleeEdge = node->callees; calleeEdge; calleeEdge = calleeEdge->next_callee) 135 | -+ { 136 | -+ calleeTree = calleeEdge->callee->decl; 137 | -+ if (thisTree != NULL && 138 | -+ calleeTree != NULL && 139 | -+ (fnref_f = cdepn_open(NULL)) != NULL) 140 | -+ { 141 | -+ fprintf(fnref_f, "C {%s} {%s:%d} {%s}\n", 142 | -+ lang_hooks.decl_printable_name (thisTree, 2), 143 | -+ calleeEdge->call_location.file, calleeEdge->call_location.line, 144 | -+ lang_hooks.decl_printable_name (calleeTree, 2)); 145 | -+ } 146 | -+ else 147 | -+ printf("CODEVIZ: Unexpected NULL encountered\n"); 148 | -+ } 149 | -+ 150 | - /* Possibly warn about unused parameters. */ 151 | - if (warn_unused_parameter) 152 | - do_warn_unused_parameter (decl); 153 | -diff -ru gcc-3.4.1-clean/gcc/toplev.c gcc-3.4.1-cdepn/gcc/toplev.c 154 | ---- gcc-3.4.1-clean/gcc/toplev.c 2004-02-20 08:40:49.000000000 +0000 155 | -+++ gcc-3.4.1-cdepn/gcc/toplev.c 2004-08-19 20:59:21.000000000 +0100 156 | -@@ -4665,6 +4665,52 @@ 157 | - timevar_print (stderr); 158 | - } 159 | - 160 | -+/* 161 | -+ * codeviz: Open the cdepn file. This is called with a filename by main() 162 | -+ * and with just NULL for every other instance to return just the handle 163 | -+ */ 164 | -+FILE *g_fnref_f = NULL; 165 | -+char cdepnfile[256] = "--wonthappen--"; 166 | -+ 167 | -+FILE *cdepn_open(char *filename) { 168 | -+ struct stat cdepnstat; 169 | -+ int errval; 170 | -+ time_t currtime; 171 | -+ if (filename && g_fnref_f == NULL) { 172 | -+ strcpy(cdepnfile, filename); 173 | -+ strcat(cdepnfile, ".cdepn"); 174 | -+ 175 | -+ /* 176 | -+ * Decide whether to open write or append. There appears to be a weird 177 | -+ * bug that decides to open the file twice, overwriting all the cdepn 178 | -+ * information put there before 179 | -+ */ 180 | -+ errval = stat(cdepnfile, &cdepnstat); 181 | -+ currtime = time(NULL); 182 | -+ if (errval == -1 || currtime - cdepnstat.st_mtime > 5) { 183 | -+ g_fnref_f = fopen(cdepnfile, "w"); 184 | -+ fprintf(stderr, "opened dep file %s\n",cdepnfile); 185 | -+ } else { 186 | -+ g_fnref_f = fopen(cdepnfile, "a"); 187 | -+ fprintf(stderr, "append dep file %s\n",cdepnfile); 188 | -+ } 189 | -+ 190 | -+ fflush(stderr); 191 | -+ } 192 | -+ 193 | -+ return g_fnref_f; 194 | -+} 195 | -+ 196 | -+void cdepn_close(void) { 197 | -+ if (g_fnref_f) fclose(g_fnref_f); 198 | -+ g_fnref_f = NULL; 199 | -+} 200 | -+ 201 | -+int cdepn_checkprint(void *fncheck) { 202 | -+ return 1; 203 | -+ /*return (void *)fncheck == (void *)decl_name; */ 204 | -+} 205 | -+ 206 | - /* Entry point of cc1, cc1plus, jc1, f771, etc. 207 | - Exit code is FATAL_EXIT_CODE if can't open files or if there were 208 | - any errors, or SUCCESS_EXIT_CODE if compilation succeeded. 209 | -@@ -4686,8 +4732,11 @@ 210 | - randomize (); 211 | - 212 | - /* Exit early if we can (e.g. -help). */ 213 | -- if (!exit_after_options) 214 | -+ if (!exit_after_options) { 215 | -+ cdepn_open(main_input_filename); 216 | - do_compile (); 217 | -+ cdepn_close(); 218 | -+ } 219 | - 220 | - if (errorcount || sorrycount) 221 | - return (FATAL_EXIT_CODE); 222 | -diff -ru gcc-3.4.1-clean/gcc/tree.h gcc-3.4.1-cdepn/gcc/tree.h 223 | ---- gcc-3.4.1-clean/gcc/tree.h 2004-02-08 01:52:43.000000000 +0000 224 | -+++ gcc-3.4.1-cdepn/gcc/tree.h 2004-08-19 19:28:43.000000000 +0100 225 | -@@ -3112,4 +3112,11 @@ 226 | - extern int tree_node_counts[]; 227 | - extern int tree_node_sizes[]; 228 | - 229 | -+/* 230 | -+ * CodeViz functions to get the output file handle for cdepn files 231 | -+ */ 232 | -+FILE *cdepn_open(char *filename); 233 | -+void cdepn_close(void); 234 | -+int cdepn_checkprint(void *fncheck); 235 | -+ 236 | - #endif /* GCC_TREE_H */ 237 | diff -urN codeviz-1.0.9-3.4.1/compilers/gcc-patches/gcc-3.4.6-cdepn.diff codeviz-1.0.9-3.4.6/compilers/gcc-patches/gcc-3.4.6-cdepn.diff 238 | --- codeviz-1.0.9-3.4.1/compilers/gcc-patches/gcc-3.4.6-cdepn.diff 1970-01-01 02:00:00.000000000 +0200 239 | +++ codeviz-1.0.9-3.4.6/compilers/gcc-patches/gcc-3.4.6-cdepn.diff 2006-06-22 22:22:40.000000000 +0300 240 | @@ -0,0 +1,184 @@ 241 | +diff -ur gcc-3.4.6-clean/gcc/cgraph.c gcc-3.4.6-cdepn/gcc/cgraph.c 242 | +--- gcc-3.4.6-clean/gcc/cgraph.c 2004-06-01 02:43:51.000000000 +0300 243 | ++++ gcc-3.4.6-cdepn/gcc/cgraph.c 2006-06-21 20:34:04.000000000 +0300 244 | +@@ -68,7 +68,8 @@ 245 | + static GTY(()) struct cgraph_varpool_node *cgraph_varpool_nodes; 246 | + 247 | + static struct cgraph_edge *create_edge (struct cgraph_node *, 248 | +- struct cgraph_node *); 249 | ++ struct cgraph_node *, 250 | ++ location_t call_location); 251 | + static hashval_t hash_node (const void *); 252 | + static int eq_node (const void *, const void *); 253 | + 254 | +@@ -152,7 +153,7 @@ 255 | + /* Create edge from CALLER to CALLEE in the cgraph. */ 256 | + 257 | + static struct cgraph_edge * 258 | +-create_edge (struct cgraph_node *caller, struct cgraph_node *callee) 259 | ++create_edge (struct cgraph_node *caller, struct cgraph_node *callee, location_t call_location) 260 | + { 261 | + struct cgraph_edge *edge = ggc_alloc (sizeof (struct cgraph_edge)); 262 | + struct cgraph_edge *edge2; 263 | +@@ -180,6 +181,7 @@ 264 | + 265 | + edge->caller = caller; 266 | + edge->callee = callee; 267 | ++ edge->call_location = call_location; 268 | + edge->next_caller = callee->callers; 269 | + edge->next_callee = caller->callees; 270 | + caller->callees = edge; 271 | +@@ -295,7 +297,7 @@ 272 | + struct cgraph_edge * 273 | + cgraph_record_call (tree caller, tree callee) 274 | + { 275 | +- return create_edge (cgraph_node (caller), cgraph_node (callee)); 276 | ++ return create_edge (cgraph_node (caller), cgraph_node (callee), input_location); 277 | + } 278 | + 279 | + void 280 | +diff -ur gcc-3.4.6-clean/gcc/cgraph.h gcc-3.4.6-cdepn/gcc/cgraph.h 281 | +--- gcc-3.4.6-clean/gcc/cgraph.h 2004-01-24 01:36:03.000000000 +0200 282 | ++++ gcc-3.4.6-cdepn/gcc/cgraph.h 2006-06-21 20:34:04.000000000 +0300 283 | +@@ -126,6 +126,9 @@ 284 | + /* When NULL, inline this call. When non-NULL, points to the explanation 285 | + why function was not inlined. */ 286 | + const char *inline_failed; 287 | ++ 288 | ++ /* CodeViz: Location the call occurred at */ 289 | ++ location_t call_location; 290 | + }; 291 | + 292 | + /* The cgraph_varpool data structure. 293 | +diff -ur gcc-3.4.6-clean/gcc/cgraphunit.c gcc-3.4.6-cdepn/gcc/cgraphunit.c 294 | +--- gcc-3.4.6-clean/gcc/cgraphunit.c 2004-05-06 02:24:30.000000000 +0300 295 | ++++ gcc-3.4.6-cdepn/gcc/cgraphunit.c 2006-06-21 20:34:04.000000000 +0300 296 | +@@ -320,7 +320,10 @@ 297 | + cgraph_analyze_function (struct cgraph_node *node) 298 | + { 299 | + tree decl = node->decl; 300 | ++ tree thisTree, calleeTree; 301 | ++ FILE *fnref_f; 302 | + struct cgraph_edge *e; 303 | ++ struct cgraph_edge *calleeEdge; 304 | + 305 | + current_function_decl = decl; 306 | + 307 | +@@ -358,6 +361,33 @@ 308 | + node->analyzed = true; 309 | + current_function_decl = NULL; 310 | + 311 | ++ /* CodeViz: Output information on this node */ 312 | ++ thisTree = node->decl; 313 | ++ if ((fnref_f = cdepn_open(NULL))) 314 | ++ { 315 | ++ fprintf(fnref_f,"F {%s} {%s:%d}\n", 316 | ++ lang_hooks.decl_printable_name (thisTree, 2), 317 | ++ DECL_SOURCE_FILE (thisTree), DECL_SOURCE_LINE (thisTree)); 318 | ++ 319 | ++ } 320 | ++ 321 | ++ /* CodeViz: Output information on all functions this node calls */ 322 | ++ for (calleeEdge = node->callees; calleeEdge; calleeEdge = calleeEdge->next_callee) 323 | ++ { 324 | ++ calleeTree = calleeEdge->callee->decl; 325 | ++ if (thisTree != NULL && 326 | ++ calleeTree != NULL && 327 | ++ (fnref_f = cdepn_open(NULL)) != NULL) 328 | ++ { 329 | ++ fprintf(fnref_f, "C {%s} {%s:%d} {%s}\n", 330 | ++ lang_hooks.decl_printable_name (thisTree, 2), 331 | ++ calleeEdge->call_location.file, calleeEdge->call_location.line, 332 | ++ lang_hooks.decl_printable_name (calleeTree, 2)); 333 | ++ } 334 | ++ else 335 | ++ printf("CODEVIZ: Unexpected NULL encountered\n"); 336 | ++ } 337 | ++ 338 | + /* Possibly warn about unused parameters. */ 339 | + if (warn_unused_parameter) 340 | + do_warn_unused_parameter (decl); 341 | +diff -ur gcc-3.4.6-clean/gcc/toplev.c gcc-3.4.6-cdepn/gcc/toplev.c 342 | +--- gcc-3.4.6-clean/gcc/toplev.c 2005-11-09 09:51:51.000000000 +0200 343 | ++++ gcc-3.4.6-cdepn/gcc/toplev.c 2006-06-21 20:34:04.000000000 +0300 344 | +@@ -4675,6 +4675,52 @@ 345 | + timevar_print (stderr); 346 | + } 347 | + 348 | ++/* 349 | ++ * codeviz: Open the cdepn file. This is called with a filename by main() 350 | ++ * and with just NULL for every other instance to return just the handle 351 | ++ */ 352 | ++FILE *g_fnref_f = NULL; 353 | ++char cdepnfile[256] = "--wonthappen--"; 354 | ++ 355 | ++FILE *cdepn_open(char *filename) { 356 | ++ struct stat cdepnstat; 357 | ++ int errval; 358 | ++ time_t currtime; 359 | ++ if (filename && g_fnref_f == NULL) { 360 | ++ strcpy(cdepnfile, filename); 361 | ++ strcat(cdepnfile, ".cdepn"); 362 | ++ 363 | ++ /* 364 | ++ * Decide whether to open write or append. There appears to be a weird 365 | ++ * bug that decides to open the file twice, overwriting all the cdepn 366 | ++ * information put there before 367 | ++ */ 368 | ++ errval = stat(cdepnfile, &cdepnstat); 369 | ++ currtime = time(NULL); 370 | ++ if (errval == -1 || currtime - cdepnstat.st_mtime > 5) { 371 | ++ g_fnref_f = fopen(cdepnfile, "w"); 372 | ++ fprintf(stderr, "opened dep file %s\n",cdepnfile); 373 | ++ } else { 374 | ++ g_fnref_f = fopen(cdepnfile, "a"); 375 | ++ fprintf(stderr, "append dep file %s\n",cdepnfile); 376 | ++ } 377 | ++ 378 | ++ fflush(stderr); 379 | ++ } 380 | ++ 381 | ++ return g_fnref_f; 382 | ++} 383 | ++ 384 | ++void cdepn_close(void) { 385 | ++ if (g_fnref_f) fclose(g_fnref_f); 386 | ++ g_fnref_f = NULL; 387 | ++} 388 | ++ 389 | ++int cdepn_checkprint(void *fncheck) { 390 | ++ return 1; 391 | ++ /*return (void *)fncheck == (void *)decl_name; */ 392 | ++} 393 | ++ 394 | + /* Entry point of cc1, cc1plus, jc1, f771, etc. 395 | + Exit code is FATAL_EXIT_CODE if can't open files or if there were 396 | + any errors, or SUCCESS_EXIT_CODE if compilation succeeded. 397 | +@@ -4696,8 +4742,11 @@ 398 | + randomize (); 399 | + 400 | + /* Exit early if we can (e.g. -help). */ 401 | +- if (!exit_after_options) 402 | ++ if (!exit_after_options) { 403 | ++ cdepn_open(main_input_filename); 404 | + do_compile (); 405 | ++ cdepn_close(); 406 | ++ } 407 | + 408 | + if (errorcount || sorrycount) 409 | + return (FATAL_EXIT_CODE); 410 | +diff -ur gcc-3.4.6-clean/gcc/tree.h gcc-3.4.6-cdepn/gcc/tree.h 411 | +--- gcc-3.4.6-clean/gcc/tree.h 2005-01-16 18:01:28.000000000 +0200 412 | ++++ gcc-3.4.6-cdepn/gcc/tree.h 2006-06-21 20:34:04.000000000 +0300 413 | +@@ -3115,4 +3115,11 @@ 414 | + extern int tree_node_counts[]; 415 | + extern int tree_node_sizes[]; 416 | + 417 | ++/* 418 | ++ * CodeViz functions to get the output file handle for cdepn files 419 | ++ */ 420 | ++FILE *cdepn_open(char *filename); 421 | ++void cdepn_close(void); 422 | ++int cdepn_checkprint(void *fncheck); 423 | ++ 424 | + #endif /* GCC_TREE_H */ 425 | diff -urN codeviz-1.0.9-3.4.1/compilers/install_gcc-3.4.1.sh codeviz-1.0.9-3.4.6/compilers/install_gcc-3.4.1.sh 426 | --- codeviz-1.0.9-3.4.1/compilers/install_gcc-3.4.1.sh 2005-09-20 12:24:37.000000000 +0300 427 | +++ codeviz-1.0.9-3.4.6/compilers/install_gcc-3.4.1.sh 1970-01-01 02:00:00.000000000 +0200 428 | @@ -1,79 +0,0 @@ 429 | -#!/bin/bash 430 | - 431 | -INSTALL_PATH=$HOME/gcc-graph 432 | -if [ "$1" != "" ]; then INSTALL_PATH=$1; fi 433 | -if [ "$2" = "compile-only" ]; then export COMPILE_ONLY=yes; fi 434 | -echo Installing gcc to $INSTALL_PATH 435 | - 436 | -NCFTP=`which ncftpget` 437 | -EXIT=$? 438 | -if [ "$EXIT" != "0" ]; then 439 | - NCFTP=ftp 440 | -fi 441 | - 442 | -if [ ! -e gcc-3.4.1.tar.gz ]; then 443 | - echo gcc-3.4.1.tar.gz not found, downloading 444 | - $NCFTP ftp://ftp.gnu.org/pub/gnu/gcc/gcc-3.4.1/gcc-3.4.1.tar.gz 445 | - if [ ! -e gcc-3.4.1.tar.gz ]; then 446 | - echo Failed to download gcc, download gcc-3.4.1.tar.gz from www.gnu.org 447 | - exit 448 | - fi 449 | -fi 450 | - 451 | -# Untar gcc 452 | -rm -rf gcc-graph/objdir 2> /dev/null 453 | -mkdir -p gcc-graph/objdir 454 | -echo Untarring gcc... 455 | -tar -zxf gcc-3.4.1.tar.gz -C gcc-graph || exit 456 | - 457 | -# Apply patch 458 | -cd gcc-graph/gcc-3.4.1 459 | -patch -p1 < ../../gcc-patches/gcc-3.4.1-cdepn.diff 460 | -cd ../objdir 461 | - 462 | -# Configure and compile 463 | -../gcc-3.4.1/configure --prefix=$INSTALL_PATH --enable-shared --enable-languages=c,c++ || exit 464 | -make bootstrap 465 | - 466 | -RETVAL=$? 467 | -PLATFORM=i686-pc-linux-gnu 468 | -if [ $RETVAL != 0 ]; then 469 | - if [ ! -e $PLATFORM/libiberty/config.h ]; then 470 | - echo Checking if this is CygWin 471 | - echo Note: This is untested, if building with Cygwin works, please email mel@csn.ul.ie with 472 | - echo a report 473 | - export PLATFORM=i686-pc-cygwin 474 | - if [ ! -e $PLATFORM/libiberty/config.h ]; then 475 | - echo Do not know how to fix this compile error up, exiting... 476 | - exit -1 477 | - fi 478 | - fi 479 | - cd $PLATFORM/libiberty/ 480 | - cat config.h | sed -e 's/.*undef HAVE_LIMITS_H.*/\#define HAVE_LIMITS_H 1/' > config.h.tmp && mv config.h.tmp config.h 481 | - cat config.h | sed -e 's/.*undef HAVE_STDLIB_H.*/\#define HAVE_STDLIB_H 1/' > config.h.tmp && mv config.h.tmp config.h 482 | - cat config.h | sed -e 's/.*undef HAVE_UNISTD_H.*/\#define HAVE_UNISTD_H 1/' > config.h.tmp && mv config.h.tmp config.h 483 | - cat config.h | sed -e 's/.*undef HAVE_SYS_STAT_H.*/\#define HAVE_LIMITS_H 1/' > config.h.tmp && mv config.h.tmp config.h 484 | - if [ "$PLATFORM" = "i686-pc-cygwin" ]; then 485 | - echo "#undef HAVE_GETTIMEOFDAY" >> config.h 486 | - fi 487 | - 488 | - TEST=`grep HAVE_SYS_STAT_H config.h` 489 | - if [ "$TEST" = "" ]; then 490 | - echo "#undef HAVE_SYS_STAT_H" >> config.h 491 | - echo "#define HAVE_SYS_STAT_H 1" >> config.h 492 | - fi 493 | - cd ../../ 494 | - make 495 | - 496 | - RETVAL=$? 497 | - if [ $RETVAL != 0 ]; then 498 | - echo 499 | - echo Compile saved after trying to fix up config.h, do not know what to do 500 | - echo This is likely a CodeViz rather than a gcc problem 501 | - exit -1 502 | - fi 503 | -fi 504 | - 505 | -if [ "$COMPILE_ONLY" != "yes" ]; then 506 | - make install 507 | -fi 508 | diff -urN codeviz-1.0.9-3.4.1/compilers/install_gcc-3.4.6.sh codeviz-1.0.9-3.4.6/compilers/install_gcc-3.4.6.sh 509 | --- codeviz-1.0.9-3.4.1/compilers/install_gcc-3.4.6.sh 1970-01-01 02:00:00.000000000 +0200 510 | +++ codeviz-1.0.9-3.4.6/compilers/install_gcc-3.4.6.sh 2006-06-22 22:21:01.000000000 +0300 511 | @@ -0,0 +1,79 @@ 512 | +#!/bin/bash 513 | + 514 | +INSTALL_PATH=$HOME/gcc-graph 515 | +if [ "$1" != "" ]; then INSTALL_PATH=$1; fi 516 | +if [ "$2" = "compile-only" ]; then export COMPILE_ONLY=yes; fi 517 | +echo Installing gcc to $INSTALL_PATH 518 | + 519 | +NCFTP=`which ncftpget` 520 | +EXIT=$? 521 | +if [ "$EXIT" != "0" ]; then 522 | + NCFTP=ftp 523 | +fi 524 | + 525 | +if [ ! -e gcc-3.4.6.tar.gz ]; then 526 | + echo gcc-3.4.6.tar.gz not found, downloading 527 | + $NCFTP ftp://ftp.gnu.org/pub/gnu/gcc/gcc-3.4.6/gcc-3.4.6.tar.gz 528 | + if [ ! -e gcc-3.4.6.tar.gz ]; then 529 | + echo Failed to download gcc, download gcc-3.4.6.tar.gz from www.gnu.org 530 | + exit 531 | + fi 532 | +fi 533 | + 534 | +# Untar gcc 535 | +rm -rf gcc-graph/objdir 2> /dev/null 536 | +mkdir -p gcc-graph/objdir 537 | +echo Untarring gcc... 538 | +tar -zxf gcc-3.4.6.tar.gz -C gcc-graph || exit 539 | + 540 | +# Apply patch 541 | +cd gcc-graph/gcc-3.4.6 542 | +patch -p1 < ../../gcc-patches/gcc-3.4.6-cdepn.diff 543 | +cd ../objdir 544 | + 545 | +# Configure and compile 546 | +../gcc-3.4.6/configure --prefix=$INSTALL_PATH --enable-shared --enable-languages=c,c++ || exit 547 | +make bootstrap 548 | + 549 | +RETVAL=$? 550 | +PLATFORM=i686-pc-linux-gnu 551 | +if [ $RETVAL != 0 ]; then 552 | + if [ ! -e $PLATFORM/libiberty/config.h ]; then 553 | + echo Checking if this is CygWin 554 | + echo Note: This is untested, if building with Cygwin works, please email mel@csn.ul.ie with 555 | + echo a report 556 | + export PLATFORM=i686-pc-cygwin 557 | + if [ ! -e $PLATFORM/libiberty/config.h ]; then 558 | + echo Do not know how to fix this compile error up, exiting... 559 | + exit -1 560 | + fi 561 | + fi 562 | + cd $PLATFORM/libiberty/ 563 | + cat config.h | sed -e 's/.*undef HAVE_LIMITS_H.*/\#define HAVE_LIMITS_H 1/' > config.h.tmp && mv config.h.tmp config.h 564 | + cat config.h | sed -e 's/.*undef HAVE_STDLIB_H.*/\#define HAVE_STDLIB_H 1/' > config.h.tmp && mv config.h.tmp config.h 565 | + cat config.h | sed -e 's/.*undef HAVE_UNISTD_H.*/\#define HAVE_UNISTD_H 1/' > config.h.tmp && mv config.h.tmp config.h 566 | + cat config.h | sed -e 's/.*undef HAVE_SYS_STAT_H.*/\#define HAVE_LIMITS_H 1/' > config.h.tmp && mv config.h.tmp config.h 567 | + if [ "$PLATFORM" = "i686-pc-cygwin" ]; then 568 | + echo "#undef HAVE_GETTIMEOFDAY" >> config.h 569 | + fi 570 | + 571 | + TEST=`grep HAVE_SYS_STAT_H config.h` 572 | + if [ "$TEST" = "" ]; then 573 | + echo "#undef HAVE_SYS_STAT_H" >> config.h 574 | + echo "#define HAVE_SYS_STAT_H 1" >> config.h 575 | + fi 576 | + cd ../../ 577 | + make 578 | + 579 | + RETVAL=$? 580 | + if [ $RETVAL != 0 ]; then 581 | + echo 582 | + echo Compile saved after trying to fix up config.h, do not know what to do 583 | + echo This is likely a CodeViz rather than a gcc problem 584 | + exit -1 585 | + fi 586 | +fi 587 | + 588 | +if [ "$COMPILE_ONLY" != "yes" ]; then 589 | + make install 590 | +fi 591 | diff -urN codeviz-1.0.9-3.4.1/configure codeviz-1.0.9-3.4.6/configure 592 | --- codeviz-1.0.9-3.4.1/configure 2005-07-11 21:07:41.000000000 +0300 593 | +++ codeviz-1.0.9-3.4.6/configure 2006-06-22 22:21:10.000000000 +0300 594 | @@ -6,7 +6,7 @@ 595 | # the scripts. It is meant to behave similar to ordinary configure scripts 596 | 597 | PREFIX=/usr/local 598 | -GCCVERSION=3.4.1 599 | +GCCVERSION=3.4.6 600 | GCCGRAPH=-unset- 601 | 602 | # Print program usage 603 | @@ -17,8 +17,8 @@ 604 | echo " -h, --help display this help and exit" 605 | echo " --prefix=PREFIX install architecture-independent files in PREFIX" 606 | echo " [Default: /usr/local]" 607 | - echo " --gcc=VERSION version of gcc to use: 3.4.1 only available" 608 | - echo " [Default: 3.4.1]" 609 | + echo " --gcc=VERSION version of gcc to use: 3.4.6 only available" 610 | + echo " [Default: 3.4.6]" 611 | echo " --gccgraph=PATH install patched gcc to this path" 612 | echo " [Default: $HOME/gccgraph]" 613 | echo " --perllib=PATH Where to install the perl libraries" 614 | -------------------------------------------------------------------------------- /codeviz.spec: -------------------------------------------------------------------------------- 1 | %define _specver $Id: codeviz.spec,v 1.1 2003/10/26 19:47:43 mel Exp $ 2 | %define _name codeviz 3 | %define _pkg %{_name} 4 | %define _ver 0.13 5 | %define _rel 3boz 6 | %define _nv %{_name}-%{_ver} 7 | %define _namever %{_nv} 8 | %define _nameverrel %{_name}-%{_ver}-%{_rel} 9 | 10 | %define _filelist %{_nameverrel}-filelist 11 | 12 | # compress man, info and POD pages. 13 | %define _brp_compress /usr/lib/rpm/brp-compress 14 | %define __brp_compress [ -x %{_brp_compress} ] && %{_brp_compress} 15 | 16 | Summary: A call graph generation utility for C/C++ 17 | Name: %{_pkg} 18 | Version: %{_ver} 19 | Release: %{_rel} 20 | Copyright: distributable 21 | Group: Development/Tools 22 | Packager: %{_packager} 23 | Source0: http://www.skynet.ie/~mel/projects/codeviz/%{_nv}.tar.gz 24 | Patch0: patch.new-options 25 | BuildRoot: %{_buildtmp}/%{_nameverrel}-buildroot/ 26 | BuildArch: noarch 27 | 28 | %description 29 | CodeViz provides the ability to generate call graphs to aid the task 30 | of understanding code. It uses a highly modular set of collection 31 | methods and can be adapted to support any language although only C and 32 | C++ are currently supported. 33 | 34 | build-id ---> %_specver 35 | 36 | %prep 37 | %setup 38 | %patch0 39 | 40 | %build 41 | 42 | %install 43 | { i="$RPM_BUILD_ROOT"; [ "$i" != "/" ] && rm -rf $i; } 44 | 45 | gen_filelist() 46 | { 47 | _d=$1;shift 48 | _l=$1;shift 49 | find $_d | perl -nl \ 50 | -e "\$_d='$_d';" \ 51 | -e 'if ( ! -d ) { $_f=1; undef $_p; }' \ 52 | -e 'elsif ( m,$_d.*%{_name}, ) { $_f=1; $_p="%dir "; }' \ 53 | -e 'if ( $_f ) {' \ 54 | -e ' s,/*$_d/*,/,;' \ 55 | -e ' printf "%s\n", "$_p$_";' \ 56 | -e ' undef $_f }' \ 57 | > $_l 58 | 59 | if [ ! -f $_l -o ! -s $_l ] 60 | then 61 | echo "ERROR: EMPTY FILE LIST" 62 | exit -1 63 | fi 64 | } 65 | 66 | _r=$RPM_BUILD_ROOT 67 | eval "_perl_`perl -V:installsitelib`" 68 | %{__mkdir_p} -m 755 $_r/%{_bindir} \ 69 | $_r/$_perl_installsitelib ]\ 70 | $_r/%{_docdir}/%{_nv} 71 | %{__install} -m 755 bin/* $_r/%{_bindir} 72 | %{__cp} -pr lib/* $_r/$_perl_installsitelib 73 | %{__cp} -pr CHANGELOG \ 74 | README \ 75 | compilers \ 76 | graphs \ 77 | $_r/%{_docdir}/%{_nv} 78 | 79 | gen_filelist $RPM_BUILD_ROOT %{_filelist} 80 | 81 | %clean 82 | #echo The maid is off on `date +%A`. 83 | for i in "$RPM_BUILD_ROOT" "$RPM_BUILD_DIR/%{_namever}" "%_buildtmp"; do 84 | [ "$i" != "/" ] && rm -rf $i 85 | done 86 | 87 | %files -f %{_filelist} 88 | %defattr(-,root,root) 89 | 90 | %changelog 91 | * Fri Oct 17 2003 Robert Lehr 92 | - initial revision for private RPM 93 | -------------------------------------------------------------------------------- /compilers/gcc-patches/gcc-3.4.6-cdepn.diff: -------------------------------------------------------------------------------- 1 | diff -ur gcc-3.4.6-clean/gcc/cgraph.c gcc-3.4.6-cdepn/gcc/cgraph.c 2 | --- gcc-3.4.6-clean/gcc/cgraph.c 2004-06-01 02:43:51.000000000 +0300 3 | +++ gcc-3.4.6-cdepn/gcc/cgraph.c 2006-06-21 20:34:04.000000000 +0300 4 | @@ -68,7 +68,8 @@ 5 | static GTY(()) struct cgraph_varpool_node *cgraph_varpool_nodes; 6 | 7 | static struct cgraph_edge *create_edge (struct cgraph_node *, 8 | - struct cgraph_node *); 9 | + struct cgraph_node *, 10 | + location_t call_location); 11 | static hashval_t hash_node (const void *); 12 | static int eq_node (const void *, const void *); 13 | 14 | @@ -152,7 +153,7 @@ 15 | /* Create edge from CALLER to CALLEE in the cgraph. */ 16 | 17 | static struct cgraph_edge * 18 | -create_edge (struct cgraph_node *caller, struct cgraph_node *callee) 19 | +create_edge (struct cgraph_node *caller, struct cgraph_node *callee, location_t call_location) 20 | { 21 | struct cgraph_edge *edge = ggc_alloc (sizeof (struct cgraph_edge)); 22 | struct cgraph_edge *edge2; 23 | @@ -180,6 +181,7 @@ 24 | 25 | edge->caller = caller; 26 | edge->callee = callee; 27 | + edge->call_location = call_location; 28 | edge->next_caller = callee->callers; 29 | edge->next_callee = caller->callees; 30 | caller->callees = edge; 31 | @@ -295,7 +297,7 @@ 32 | struct cgraph_edge * 33 | cgraph_record_call (tree caller, tree callee) 34 | { 35 | - return create_edge (cgraph_node (caller), cgraph_node (callee)); 36 | + return create_edge (cgraph_node (caller), cgraph_node (callee), input_location); 37 | } 38 | 39 | void 40 | diff -ur gcc-3.4.6-clean/gcc/cgraph.h gcc-3.4.6-cdepn/gcc/cgraph.h 41 | --- gcc-3.4.6-clean/gcc/cgraph.h 2004-01-24 01:36:03.000000000 +0200 42 | +++ gcc-3.4.6-cdepn/gcc/cgraph.h 2006-06-21 20:34:04.000000000 +0300 43 | @@ -126,6 +126,9 @@ 44 | /* When NULL, inline this call. When non-NULL, points to the explanation 45 | why function was not inlined. */ 46 | const char *inline_failed; 47 | + 48 | + /* CodeViz: Location the call occurred at */ 49 | + location_t call_location; 50 | }; 51 | 52 | /* The cgraph_varpool data structure. 53 | diff -ur gcc-3.4.6-clean/gcc/cgraphunit.c gcc-3.4.6-cdepn/gcc/cgraphunit.c 54 | --- gcc-3.4.6-clean/gcc/cgraphunit.c 2004-05-06 02:24:30.000000000 +0300 55 | +++ gcc-3.4.6-cdepn/gcc/cgraphunit.c 2006-06-21 20:34:04.000000000 +0300 56 | @@ -320,7 +320,10 @@ 57 | cgraph_analyze_function (struct cgraph_node *node) 58 | { 59 | tree decl = node->decl; 60 | + tree thisTree, calleeTree; 61 | + FILE *fnref_f; 62 | struct cgraph_edge *e; 63 | + struct cgraph_edge *calleeEdge; 64 | 65 | current_function_decl = decl; 66 | 67 | @@ -358,6 +361,33 @@ 68 | node->analyzed = true; 69 | current_function_decl = NULL; 70 | 71 | + /* CodeViz: Output information on this node */ 72 | + thisTree = node->decl; 73 | + if ((fnref_f = cdepn_open(NULL))) 74 | + { 75 | + fprintf(fnref_f,"F {%s} {%s:%d}\n", 76 | + lang_hooks.decl_printable_name (thisTree, 2), 77 | + DECL_SOURCE_FILE (thisTree), DECL_SOURCE_LINE (thisTree)); 78 | + 79 | + } 80 | + 81 | + /* CodeViz: Output information on all functions this node calls */ 82 | + for (calleeEdge = node->callees; calleeEdge; calleeEdge = calleeEdge->next_callee) 83 | + { 84 | + calleeTree = calleeEdge->callee->decl; 85 | + if (thisTree != NULL && 86 | + calleeTree != NULL && 87 | + (fnref_f = cdepn_open(NULL)) != NULL) 88 | + { 89 | + fprintf(fnref_f, "C {%s} {%s:%d} {%s}\n", 90 | + lang_hooks.decl_printable_name (thisTree, 2), 91 | + calleeEdge->call_location.file, calleeEdge->call_location.line, 92 | + lang_hooks.decl_printable_name (calleeTree, 2)); 93 | + } 94 | + else 95 | + printf("CODEVIZ: Unexpected NULL encountered\n"); 96 | + } 97 | + 98 | /* Possibly warn about unused parameters. */ 99 | if (warn_unused_parameter) 100 | do_warn_unused_parameter (decl); 101 | diff -ur gcc-3.4.6-clean/gcc/toplev.c gcc-3.4.6-cdepn/gcc/toplev.c 102 | --- gcc-3.4.6-clean/gcc/toplev.c 2005-11-09 09:51:51.000000000 +0200 103 | +++ gcc-3.4.6-cdepn/gcc/toplev.c 2006-06-21 20:34:04.000000000 +0300 104 | @@ -4675,6 +4675,52 @@ 105 | timevar_print (stderr); 106 | } 107 | 108 | +/* 109 | + * codeviz: Open the cdepn file. This is called with a filename by main() 110 | + * and with just NULL for every other instance to return just the handle 111 | + */ 112 | +FILE *g_fnref_f = NULL; 113 | +char cdepnfile[256] = "--wonthappen--"; 114 | + 115 | +FILE *cdepn_open(char *filename) { 116 | + struct stat cdepnstat; 117 | + int errval; 118 | + time_t currtime; 119 | + if (filename && g_fnref_f == NULL) { 120 | + strcpy(cdepnfile, filename); 121 | + strcat(cdepnfile, ".cdepn"); 122 | + 123 | + /* 124 | + * Decide whether to open write or append. There appears to be a weird 125 | + * bug that decides to open the file twice, overwriting all the cdepn 126 | + * information put there before 127 | + */ 128 | + errval = stat(cdepnfile, &cdepnstat); 129 | + currtime = time(NULL); 130 | + if (errval == -1 || currtime - cdepnstat.st_mtime > 5) { 131 | + g_fnref_f = fopen(cdepnfile, "w"); 132 | + fprintf(stderr, "opened dep file %s\n",cdepnfile); 133 | + } else { 134 | + g_fnref_f = fopen(cdepnfile, "a"); 135 | + fprintf(stderr, "append dep file %s\n",cdepnfile); 136 | + } 137 | + 138 | + fflush(stderr); 139 | + } 140 | + 141 | + return g_fnref_f; 142 | +} 143 | + 144 | +void cdepn_close(void) { 145 | + if (g_fnref_f) fclose(g_fnref_f); 146 | + g_fnref_f = NULL; 147 | +} 148 | + 149 | +int cdepn_checkprint(void *fncheck) { 150 | + return 1; 151 | + /*return (void *)fncheck == (void *)decl_name; */ 152 | +} 153 | + 154 | /* Entry point of cc1, cc1plus, jc1, f771, etc. 155 | Exit code is FATAL_EXIT_CODE if can't open files or if there were 156 | any errors, or SUCCESS_EXIT_CODE if compilation succeeded. 157 | @@ -4696,8 +4742,11 @@ 158 | randomize (); 159 | 160 | /* Exit early if we can (e.g. -help). */ 161 | - if (!exit_after_options) 162 | + if (!exit_after_options) { 163 | + cdepn_open(main_input_filename); 164 | do_compile (); 165 | + cdepn_close(); 166 | + } 167 | 168 | if (errorcount || sorrycount) 169 | return (FATAL_EXIT_CODE); 170 | diff -ur gcc-3.4.6-clean/gcc/tree.h gcc-3.4.6-cdepn/gcc/tree.h 171 | --- gcc-3.4.6-clean/gcc/tree.h 2005-01-16 18:01:28.000000000 +0200 172 | +++ gcc-3.4.6-cdepn/gcc/tree.h 2006-06-21 20:34:04.000000000 +0300 173 | @@ -3115,4 +3115,11 @@ 174 | extern int tree_node_counts[]; 175 | extern int tree_node_sizes[]; 176 | 177 | +/* 178 | + * CodeViz functions to get the output file handle for cdepn files 179 | + */ 180 | +FILE *cdepn_open(char *filename); 181 | +void cdepn_close(void); 182 | +int cdepn_checkprint(void *fncheck); 183 | + 184 | #endif /* GCC_TREE_H */ 185 | -------------------------------------------------------------------------------- /compilers/gcc-patches/gcc-4.6.2-cdepn.diff: -------------------------------------------------------------------------------- 1 | diff -pruN gcc-4.6.2-clean/gcc/cgraph.c gcc-4.6.2-cdepn/gcc/cgraph.c 2 | --- gcc-4.6.2-clean/gcc/cgraph.c 2011-06-06 14:16:35.000000000 -0300 3 | +++ gcc-4.6.2-cdepn/gcc/cgraph.c 2012-05-19 19:04:03.470561109 -0300 4 | @@ -990,7 +990,8 @@ initialize_inline_failed (struct cgraph_ 5 | 6 | static struct cgraph_edge * 7 | cgraph_create_edge_1 (struct cgraph_node *caller, struct cgraph_node *callee, 8 | - gimple call_stmt, gcov_type count, int freq, int nest) 9 | + gimple call_stmt, gcov_type count, int freq, 10 | + int nest, location_t call_location) 11 | { 12 | struct cgraph_edge *edge; 13 | 14 | @@ -1043,6 +1044,7 @@ cgraph_create_edge_1 (struct cgraph_node 15 | 16 | edge->indirect_info = NULL; 17 | edge->indirect_inlining_edge = 0; 18 | + edge->call_location = call_location; 19 | 20 | return edge; 21 | } 22 | @@ -1054,7 +1056,8 @@ cgraph_create_edge (struct cgraph_node * 23 | gimple call_stmt, gcov_type count, int freq, int nest) 24 | { 25 | struct cgraph_edge *edge = cgraph_create_edge_1 (caller, callee, call_stmt, 26 | - count, freq, nest); 27 | + count, freq, 28 | + nest, input_location); 29 | 30 | edge->indirect_unknown_callee = 0; 31 | initialize_inline_failed (edge); 32 | @@ -1093,7 +1096,8 @@ cgraph_create_indirect_edge (struct cgra 33 | gcov_type count, int freq, int nest) 34 | { 35 | struct cgraph_edge *edge = cgraph_create_edge_1 (caller, NULL, call_stmt, 36 | - count, freq, nest); 37 | + count, freq, 38 | + nest, input_location); 39 | 40 | edge->indirect_unknown_callee = 1; 41 | initialize_inline_failed (edge); 42 | diff -pruN gcc-4.6.2-clean/gcc/cgraph.h gcc-4.6.2-cdepn/gcc/cgraph.h 43 | --- gcc-4.6.2-clean/gcc/cgraph.h 2011-03-04 15:49:23.000000000 -0300 44 | +++ gcc-4.6.2-cdepn/gcc/cgraph.h 2012-05-19 19:04:03.338557458 -0300 45 | @@ -443,6 +443,9 @@ struct GTY((chain_next ("%h.next_caller" 46 | unsigned int call_stmt_cannot_inline_p : 1; 47 | /* Can this call throw externally? */ 48 | unsigned int can_throw_external : 1; 49 | + 50 | + /* CodeViz: Location the call occurred at */ 51 | + location_t call_location; 52 | }; 53 | 54 | #define CGRAPH_FREQ_BASE 1000 55 | diff -pruN gcc-4.6.2-clean/gcc/cgraphunit.c gcc-4.6.2-cdepn/gcc/cgraphunit.c 56 | --- gcc-4.6.2-clean/gcc/cgraphunit.c 2011-03-11 10:27:26.000000000 -0300 57 | +++ gcc-4.6.2-cdepn/gcc/cgraphunit.c 2012-05-19 19:04:03.070550009 -0300 58 | @@ -772,12 +772,17 @@ cgraph_output_pending_asms (void) 59 | cgraph_asm_nodes = NULL; 60 | } 61 | 62 | +extern int cdepn_dump; 63 | /* Analyze the function scheduled to be output. */ 64 | static void 65 | cgraph_analyze_function (struct cgraph_node *node) 66 | { 67 | tree save = current_function_decl; 68 | tree decl = node->decl; 69 | + tree thisTree, calleeTree; 70 | + FILE *fnref_f; 71 | + struct cgraph_edge *calleeEdge; 72 | + expanded_location xloc; 73 | 74 | current_function_decl = decl; 75 | push_cfun (DECL_STRUCT_FUNCTION (decl)); 76 | @@ -802,10 +807,39 @@ cgraph_analyze_function (struct cgraph_n 77 | 78 | pop_cfun (); 79 | current_function_decl = save; 80 | + 81 | + if (cdepn_dump) { 82 | + /* CodeViz: Output information on this node */ 83 | + thisTree = node->decl; 84 | + if ((fnref_f = cdepn_open(NULL))) 85 | + { 86 | + fprintf(fnref_f,"F {%s} {%s:%d}\n", 87 | + lang_hooks.decl_printable_name (thisTree, 2), 88 | + DECL_SOURCE_FILE (thisTree), DECL_SOURCE_LINE (thisTree)); 89 | + 90 | + } 91 | + 92 | + /* CodeViz: Output information on all functions this node calls */ 93 | + for (calleeEdge = node->callees; calleeEdge; 94 | + calleeEdge = calleeEdge->next_callee) { 95 | + calleeTree = calleeEdge->callee->decl; 96 | + if (thisTree != NULL && 97 | + calleeTree != NULL && 98 | + (fnref_f = cdepn_open(NULL)) != NULL) 99 | + { 100 | + xloc = expand_location(calleeEdge->call_location); 101 | + fprintf(fnref_f, "C {%s} {%s:%d} {%s}\n", 102 | + lang_hooks.decl_printable_name (thisTree, 2), 103 | + xloc.file, xloc.line, 104 | + lang_hooks.decl_printable_name (calleeTree, 2)); 105 | + } 106 | + else 107 | + printf("CODEVIZ: Unexpected NULL encountered\n"); 108 | + } 109 | + } 110 | } 111 | 112 | /* Process attributes common for vars and functions. */ 113 | - 114 | static void 115 | process_common_attributes (tree decl) 116 | { 117 | diff -pruN gcc-4.6.2-clean/gcc/toplev.c gcc-4.6.2-cdepn/gcc/toplev.c 118 | --- gcc-4.6.2-clean/gcc/toplev.c 2011-02-03 06:29:03.000000000 -0200 119 | +++ gcc-4.6.2-cdepn/gcc/toplev.c 2012-05-19 19:04:03.070550009 -0300 120 | @@ -1907,6 +1907,53 @@ do_compile (void) 121 | timevar_print (stderr); 122 | } 123 | 124 | +/* 125 | + * codeviz: Open the cdepn file. This is called with a filename by main() 126 | + * and with just NULL for every other instance to return just the handle 127 | + */ 128 | +FILE *g_fnref_f = NULL; 129 | +char cdepnfile[256] = "--wonthappen--"; 130 | +int cdepn_dump = 0; 131 | + 132 | +FILE *cdepn_open(char *filename) { 133 | + struct stat cdepnstat; 134 | + int errval; 135 | + time_t currtime; 136 | + if (filename && g_fnref_f == NULL) { 137 | + strcpy(cdepnfile, filename); 138 | + strcat(cdepnfile, ".cdepn"); 139 | + 140 | + /* 141 | + * Decide whether to open write or append. There appears to be a weird 142 | + * bug that decides to open the file twice, overwriting all the cdepn 143 | + * information put there before 144 | + */ 145 | + errval = stat(cdepnfile, &cdepnstat); 146 | + currtime = time(NULL); 147 | + if (errval == -1 || currtime - cdepnstat.st_mtime > 5) { 148 | + g_fnref_f = fopen(cdepnfile, "w"); 149 | + fprintf(stderr, "opened dep file %s\n",cdepnfile); 150 | + } else { 151 | + g_fnref_f = fopen(cdepnfile, "a"); 152 | + fprintf(stderr, "append dep file %s\n",cdepnfile); 153 | + } 154 | + 155 | + fflush(stderr); 156 | + } 157 | + 158 | + return g_fnref_f; 159 | +} 160 | + 161 | +void cdepn_close(void) { 162 | + if (g_fnref_f) fclose(g_fnref_f); 163 | + g_fnref_f = NULL; 164 | +} 165 | + 166 | +int cdepn_checkprint(void *fncheck) { 167 | + return 1; 168 | + /*return (void *)fncheck == (void *)decl_name; */ 169 | +} 170 | + 171 | /* Entry point of cc1, cc1plus, jc1, f771, etc. 172 | Exit code is FATAL_EXIT_CODE if can't open files or if there were 173 | any errors, or SUCCESS_EXIT_CODE if compilation succeeded. 174 | @@ -1959,8 +2006,14 @@ toplev_main (int argc, char **argv) 175 | print_plugins_help (stderr, ""); 176 | 177 | /* Exit early if we can (e.g. -help). */ 178 | - if (!exit_after_options) 179 | + if (!exit_after_options) { 180 | + cdepn_dump = ((getenv("CDEPN_SUPPRESS")) ? 0 : 1); 181 | + if (cdepn_dump) 182 | + cdepn_open(main_input_filename); 183 | do_compile (); 184 | + if (cdepn_dump) 185 | + cdepn_close(); 186 | + } 187 | 188 | if (warningcount || errorcount) 189 | print_ignored_options (); 190 | diff -pruN gcc-4.6.2-clean/gcc/tree.h gcc-4.6.2-cdepn/gcc/tree.h 191 | --- gcc-4.6.2-clean/gcc/tree.h 2011-10-06 16:57:52.000000000 -0300 192 | +++ gcc-4.6.2-cdepn/gcc/tree.h 2012-05-19 19:04:03.594564570 -0300 193 | @@ -5724,4 +5724,11 @@ is_lang_specific (tree t) 194 | /* In gimple-low.c. */ 195 | extern bool block_may_fallthru (const_tree); 196 | 197 | +/* 198 | + * CodeViz functions to get the output file handle for cdepn files 199 | + */ 200 | +FILE *cdepn_open(char *filename); 201 | +void cdepn_close(void); 202 | +int cdepn_checkprint(void *fncheck); 203 | + 204 | #endif /* GCC_TREE_H */ 205 | -------------------------------------------------------------------------------- /compilers/gcc-patches/gcc-7.4.0-cdepn.diff: -------------------------------------------------------------------------------- 1 | diff -pruN gcc-7.4.0/gcc/cgraph.c gcc-graph/gcc-7.4.0/gcc/cgraph.c 2 | --- gcc-7.4.0/gcc/cgraph.c 2017-04-12 00:38:19.476381000 +0800 3 | +++ gcc-graph/gcc-7.4.0/gcc/cgraph.c 2019-06-04 08:29:32.457106530 +0800 4 | @@ -809,7 +809,7 @@ cgraph_edge::set_call_stmt (gcall *new_s 5 | cgraph_edge * 6 | symbol_table::create_edge (cgraph_node *caller, cgraph_node *callee, 7 | gcall *call_stmt, gcov_type count, int freq, 8 | - bool indir_unknown_callee) 9 | + bool indir_unknown_callee, location_t call_location) 10 | { 11 | cgraph_edge *edge; 12 | 13 | @@ -875,6 +875,7 @@ symbol_table::create_edge (cgraph_node * 14 | 15 | edge->indirect_info = NULL; 16 | edge->indirect_inlining_edge = 0; 17 | + edge->call_location = call_location; 18 | edge->speculative = false; 19 | edge->indirect_unknown_callee = indir_unknown_callee; 20 | if (opt_for_fn (edge->caller->decl, flag_devirtualize) 21 | @@ -897,7 +898,7 @@ cgraph_node::create_edge (cgraph_node *c 22 | gcall *call_stmt, gcov_type count, int freq) 23 | { 24 | cgraph_edge *edge = symtab->create_edge (this, callee, call_stmt, count, 25 | - freq, false); 26 | + freq, false, input_location); 27 | 28 | initialize_inline_failed (edge); 29 | 30 | @@ -935,7 +936,7 @@ cgraph_node::create_indirect_edge (gcall 31 | bool compute_indirect_info) 32 | { 33 | cgraph_edge *edge = symtab->create_edge (this, NULL, call_stmt, 34 | - count, freq, true); 35 | + count, freq, true, input_location); 36 | tree target; 37 | 38 | initialize_inline_failed (edge); 39 | diff -pruN gcc-7.4.0/gcc/cgraph.h gcc-graph/gcc-7.4.0/gcc/cgraph.h 40 | --- gcc-7.4.0/gcc/cgraph.h 2018-03-07 04:04:20.188219000 +0800 41 | +++ gcc-graph/gcc-7.4.0/gcc/cgraph.h 2019-06-04 08:37:43.402180199 +0800 42 | @@ -1732,6 +1732,8 @@ struct GTY((chain_next ("%h.next_caller" 43 | /* Return true if call must bind to current definition. */ 44 | bool binds_to_current_def_p (); 45 | 46 | + /* CodeViz: Location the call occurred at */ 47 | + location_t call_location; 48 | private: 49 | /* Remove the edge from the list of the callers of the callee. */ 50 | void remove_caller (void); 51 | @@ -2242,7 +2244,7 @@ private: 52 | edge). */ 53 | cgraph_edge *create_edge (cgraph_node *caller, cgraph_node *callee, 54 | gcall *call_stmt, gcov_type count, int freq, 55 | - bool indir_unknown_callee); 56 | + bool indir_unknown_callee, location_t call_location); 57 | 58 | /* Put the edge onto the free list. */ 59 | void free_edge (cgraph_edge *e); 60 | diff -pruN gcc-7.4.0/gcc/cgraphunit.c gcc-graph/gcc-7.4.0/gcc/cgraphunit.c 61 | --- gcc-7.4.0/gcc/cgraphunit.c 2018-01-12 13:32:31.212894000 +0800 62 | +++ gcc-graph/gcc-7.4.0/gcc/cgraphunit.c 2019-06-04 15:45:14.285317801 +0800 63 | @@ -589,6 +589,7 @@ cgraph_node::add_new_function (tree fnde 64 | DECL_FUNCTION_PERSONALITY (fndecl) = lang_hooks.eh_personality (); 65 | } 66 | 67 | +extern int cdepn_dump; 68 | /* Analyze the function scheduled to be output. */ 69 | void 70 | cgraph_node::analyze (void) 71 | @@ -603,6 +604,11 @@ cgraph_node::analyze (void) 72 | location_t saved_loc = input_location; 73 | input_location = DECL_SOURCE_LOCATION (decl); 74 | 75 | + tree calleeTree; 76 | + FILE *fnref_f; 77 | + struct cgraph_edge *calleeEdge; 78 | + expanded_location xloc; 79 | + 80 | if (thunk.thunk_p) 81 | { 82 | cgraph_node *t = cgraph_node::get (thunk.alias); 83 | @@ -678,6 +684,37 @@ cgraph_node::analyze (void) 84 | analyzed = true; 85 | 86 | input_location = saved_loc; 87 | + 88 | + if (cdepn_dump) 89 | + { 90 | + /* CodeViz: Output information on this node */ 91 | + //thisTree = node->decl; 92 | + if ((fnref_f = cdepn_open(NULL))) 93 | + { 94 | + fprintf(fnref_f,"F {%s} {%s:%d}\n", 95 | + lang_hooks.decl_printable_name(decl, 2), 96 | + DECL_SOURCE_FILE(decl), DECL_SOURCE_LINE(decl)); 97 | + } 98 | + 99 | + /* CodeViz: Output information on all functions this node calls */ 100 | + for (calleeEdge = callees; calleeEdge; 101 | + calleeEdge = calleeEdge->next_callee) 102 | + { 103 | + calleeTree = calleeEdge->callee->decl; 104 | + if (decl != NULL && 105 | + calleeTree != NULL && 106 | + (fnref_f = cdepn_open(NULL)) != NULL) 107 | + { 108 | + xloc = expand_location(calleeEdge->call_location); 109 | + fprintf(fnref_f, "C {%s} {%s:%d} {%s}\n", 110 | + lang_hooks.decl_printable_name(decl, 2), 111 | + xloc.file, xloc.line, 112 | + lang_hooks.decl_printable_name(calleeTree, 2)); 113 | + } 114 | + else 115 | + printf("CODEVIZ: Unexpected NULL encountered\n"); 116 | + } 117 | + } 118 | } 119 | 120 | /* C++ frontend produce same body aliases all over the place, even before PCH 121 | diff -pruN gcc-7.4.0/gcc/toplev.c gcc-graph/gcc-7.4.0/gcc/toplev.c 122 | --- gcc-7.4.0/gcc/toplev.c 2017-09-15 16:18:34.015147000 +0800 123 | +++ gcc-graph/gcc-7.4.0/gcc/toplev.c 2019-06-04 15:48:05.834704434 +0800 124 | @@ -2073,6 +2073,60 @@ toplev::run_self_tests () 125 | #endif /* #if CHECKING_P */ 126 | } 127 | 128 | +/* 129 | + * codeviz: Open the cdepn file. This is called with a filename by main() 130 | + * and with just NULL for every other instance to return just the handle 131 | + */ 132 | +FILE *g_fnref_f = NULL; 133 | +char cdepnfile[256] = "--wonthappen--"; 134 | +int cdepn_dump = 0; 135 | + 136 | +FILE *cdepn_open(const char *filename) 137 | +{ 138 | + struct stat cdepnstat; 139 | + int errval; 140 | + time_t currtime; 141 | + if (filename && g_fnref_f == NULL) 142 | + { 143 | + strcpy(cdepnfile, filename); 144 | + strcat(cdepnfile, ".cdepn"); 145 | + 146 | + /* 147 | + * Decide whether to open write or append. There appears to be a weird 148 | + * bug that decides to open the file twice, overwriting all the cdepn 149 | + * information put there before 150 | + */ 151 | + errval = stat(cdepnfile, &cdepnstat); 152 | + currtime = time(NULL); 153 | + if (errval == -1 || currtime - cdepnstat.st_mtime > 5) 154 | + { 155 | + g_fnref_f = fopen(cdepnfile, "w"); 156 | + fprintf(stderr, "opened dep file %s\n",cdepnfile); 157 | + } 158 | + else 159 | + { 160 | + g_fnref_f = fopen(cdepnfile, "a"); 161 | + fprintf(stderr, "append dep file %s\n", cdepnfile); 162 | + } 163 | + 164 | + fflush(stderr); 165 | + } 166 | + 167 | + return g_fnref_f; 168 | +} 169 | + 170 | +void cdepn_close(void) 171 | +{ 172 | + if (g_fnref_f) fclose(g_fnref_f); 173 | + g_fnref_f = NULL; 174 | +} 175 | + 176 | +int cdepn_checkprint(void *fncheck) 177 | +{ 178 | + return 1; 179 | + /*return (void *)fncheck == (void *)decl_name; */ 180 | +} 181 | + 182 | /* Entry point of cc1, cc1plus, jc1, f771, etc. 183 | Exit code is FATAL_EXIT_CODE if can't open files or if there were 184 | any errors, or SUCCESS_EXIT_CODE if compilation succeeded. 185 | @@ -2130,13 +2184,19 @@ toplev::main (int argc, char **argv) 186 | if (help_flag) 187 | print_plugins_help (stderr, ""); 188 | 189 | - /* Exit early if we can (e.g. -help). */ 190 | + /* Exit early if we can (e.g. -help). */ 191 | if (!exit_after_options) 192 | - { 193 | - if (m_use_TV_TOTAL) 194 | - start_timevars (); 195 | - do_compile (); 196 | - } 197 | + { 198 | + if (m_use_TV_TOTAL) 199 | + start_timevars(); 200 | + 201 | + cdepn_dump = ((getenv("CDEPN_SUPPRESS")) ? 0 : 1); 202 | + if (cdepn_dump) 203 | + cdepn_open(main_input_filename); 204 | + do_compile (); 205 | + if (cdepn_dump) 206 | + cdepn_close(); 207 | + } 208 | 209 | if (warningcount || errorcount || werrorcount) 210 | print_ignored_options (); 211 | diff -pruN gcc-7.4.0/gcc/tree.h gcc-graph/gcc-7.4.0/gcc/tree.h 212 | --- gcc-7.4.0/gcc/tree.h 2017-11-30 06:13:34.210836000 +0800 213 | +++ gcc-graph/gcc-7.4.0/gcc/tree.h 2019-06-04 15:48:22.778051253 +0800 214 | @@ -5500,4 +5500,11 @@ desired_pro_or_demotion_p (const_tree to 215 | return to_type_precision <= TYPE_PRECISION (from_type); 216 | } 217 | 218 | +/* 219 | + * CodeViz functions to get the output file handle for cdepn files 220 | + */ 221 | +FILE *cdepn_open(const char *filename); 222 | +void cdepn_close(void); 223 | +int cdepn_checkprint(void *fncheck); 224 | + 225 | #endif /* GCC_TREE_H */ 226 | -------------------------------------------------------------------------------- /compilers/install_gcc-3.4.6.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | INSTALL_PATH=$HOME/gcc-graph 4 | if [ "$1" != "" ]; then INSTALL_PATH=$1; fi 5 | if [ "$2" = "compile-only" ]; then export COMPILE_ONLY=yes; fi 6 | echo Installing gcc to $INSTALL_PATH 7 | 8 | NCFTP=`which ncftpget` 9 | EXIT=$? 10 | if [ "$EXIT" != "0" ]; then 11 | NCFTP=ftp 12 | fi 13 | 14 | if [ ! -e gcc-3.4.6.tar.gz ]; then 15 | echo gcc-3.4.6.tar.gz not found, downloading 16 | $NCFTP ftp://ftp.gnu.org/pub/gnu/gcc/gcc-3.4.6/gcc-3.4.6.tar.gz 17 | if [ ! -e gcc-3.4.6.tar.gz ]; then 18 | echo Failed to download gcc, download gcc-3.4.6.tar.gz from www.gnu.org 19 | exit 20 | fi 21 | fi 22 | 23 | # Untar gcc 24 | rm -rf gcc-graph/objdir 2> /dev/null 25 | mkdir -p gcc-graph/objdir 26 | echo Untarring gcc... 27 | tar -zxf gcc-3.4.6.tar.gz -C gcc-graph || exit 28 | 29 | # Apply patch 30 | cd gcc-graph/gcc-3.4.6 31 | patch -p1 < ../../gcc-patches/gcc-3.4.6-cdepn.diff 32 | cd ../objdir 33 | 34 | # Configure and compile 35 | ../gcc-3.4.6/configure --prefix=$INSTALL_PATH --enable-shared --enable-languages=c,c++ || exit 36 | make bootstrap 37 | 38 | RETVAL=$? 39 | PLATFORM=i686-pc-linux-gnu 40 | if [ $RETVAL != 0 ]; then 41 | if [ ! -e $PLATFORM/libiberty/config.h ]; then 42 | echo Checking if this is CygWin 43 | echo Note: This is untested, if building with Cygwin works, please email mel@csn.ul.ie with 44 | echo a report 45 | export PLATFORM=i686-pc-cygwin 46 | if [ ! -e $PLATFORM/libiberty/config.h ]; then 47 | echo Do not know how to fix this compile error up, exiting... 48 | exit -1 49 | fi 50 | fi 51 | cd $PLATFORM/libiberty/ 52 | cat config.h | sed -e 's/.*undef HAVE_LIMITS_H.*/\#define HAVE_LIMITS_H 1/' > config.h.tmp && mv config.h.tmp config.h 53 | cat config.h | sed -e 's/.*undef HAVE_STDLIB_H.*/\#define HAVE_STDLIB_H 1/' > config.h.tmp && mv config.h.tmp config.h 54 | cat config.h | sed -e 's/.*undef HAVE_UNISTD_H.*/\#define HAVE_UNISTD_H 1/' > config.h.tmp && mv config.h.tmp config.h 55 | cat config.h | sed -e 's/.*undef HAVE_SYS_STAT_H.*/\#define HAVE_LIMITS_H 1/' > config.h.tmp && mv config.h.tmp config.h 56 | if [ "$PLATFORM" = "i686-pc-cygwin" ]; then 57 | echo "#undef HAVE_GETTIMEOFDAY" >> config.h 58 | fi 59 | 60 | TEST=`grep HAVE_SYS_STAT_H config.h` 61 | if [ "$TEST" = "" ]; then 62 | echo "#undef HAVE_SYS_STAT_H" >> config.h 63 | echo "#define HAVE_SYS_STAT_H 1" >> config.h 64 | fi 65 | cd ../../ 66 | make 67 | 68 | RETVAL=$? 69 | if [ $RETVAL != 0 ]; then 70 | echo 71 | echo Compile saved after trying to fix up config.h, do not know what to do 72 | echo This is likely a CodeViz rather than a gcc problem 73 | exit -1 74 | fi 75 | fi 76 | 77 | if [ "$COMPILE_ONLY" != "yes" ]; then 78 | make install 79 | fi 80 | -------------------------------------------------------------------------------- /compilers/install_gcc-4.6.2.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | INSTALL_PATH=$HOME/gcc-graph 4 | if [ "$1" != "" ]; then INSTALL_PATH=$1; fi 5 | if [ "$2" = "compile-only" ]; then export COMPILE_ONLY=yes; fi 6 | echo Installing gcc to $INSTALL_PATH 7 | 8 | NCFTP=`which ncftpget` 9 | EXIT=$? 10 | if [ "$EXIT" != "0" ]; then 11 | NCFTP=ftp 12 | fi 13 | 14 | if [ ! -e gcc-4.6.2.tar.gz ]; then 15 | echo gcc-4.6.2.tar.gz not found, downloading 16 | $NCFTP ftp://ftp.gnu.org/pub/gnu/gcc/gcc-4.6.2/gcc-4.6.2.tar.gz 17 | if [ ! -e gcc-4.6.2.tar.gz ]; then 18 | echo Failed to download gcc, download gcc-4.6.2.tar.gz from www.gnu.org 19 | exit 20 | fi 21 | fi 22 | 23 | # Untar gcc 24 | rm -rf gcc-graph/objdir 2> /dev/null 25 | mkdir -p gcc-graph/objdir 26 | echo Untarring gcc... 27 | tar -zxf gcc-4.6.2.tar.gz -C gcc-graph || exit 28 | 29 | # Apply patch 30 | cd gcc-graph/gcc-4.6.2 31 | patch -p1 < ../../gcc-patches/gcc-4.6.2-cdepn.diff 32 | cd ../objdir 33 | 34 | # Configure and compile 35 | ../gcc-4.6.2/configure --prefix=$INSTALL_PATH --enable-shared --enable-languages=c,c++ || exit 36 | make bootstrap 37 | 38 | RETVAL=$? 39 | PLATFORM=i686-pc-linux-gnu 40 | if [ $RETVAL != 0 ]; then 41 | if [ ! -e $PLATFORM/libiberty/config.h ]; then 42 | echo Checking if this is CygWin 43 | echo Note: This is untested, if building with Cygwin works, please email mel@csn.ul.ie with 44 | echo a report 45 | export PLATFORM=i686-pc-cygwin 46 | if [ ! -e $PLATFORM/libiberty/config.h ]; then 47 | echo Do not know how to fix this compile error up, exiting... 48 | exit -1 49 | fi 50 | fi 51 | cd $PLATFORM/libiberty/ 52 | cat config.h | sed -e 's/.*undef HAVE_LIMITS_H.*/\#define HAVE_LIMITS_H 1/' > config.h.tmp && mv config.h.tmp config.h 53 | cat config.h | sed -e 's/.*undef HAVE_STDLIB_H.*/\#define HAVE_STDLIB_H 1/' > config.h.tmp && mv config.h.tmp config.h 54 | cat config.h | sed -e 's/.*undef HAVE_UNISTD_H.*/\#define HAVE_UNISTD_H 1/' > config.h.tmp && mv config.h.tmp config.h 55 | cat config.h | sed -e 's/.*undef HAVE_SYS_STAT_H.*/\#define HAVE_LIMITS_H 1/' > config.h.tmp && mv config.h.tmp config.h 56 | if [ "$PLATFORM" = "i686-pc-cygwin" ]; then 57 | echo "#undef HAVE_GETTIMEOFDAY" >> config.h 58 | fi 59 | 60 | TEST=`grep HAVE_SYS_STAT_H config.h` 61 | if [ "$TEST" = "" ]; then 62 | echo "#undef HAVE_SYS_STAT_H" >> config.h 63 | echo "#define HAVE_SYS_STAT_H 1" >> config.h 64 | fi 65 | cd ../../ 66 | make 67 | 68 | RETVAL=$? 69 | if [ $RETVAL != 0 ]; then 70 | echo 71 | echo Compile saved after trying to fix up config.h, do not know what to do 72 | echo This is likely a CodeViz rather than a gcc problem 73 | exit -1 74 | fi 75 | fi 76 | 77 | if [ "$COMPILE_ONLY" != "yes" ]; then 78 | make install 79 | fi 80 | -------------------------------------------------------------------------------- /compilers/install_gcc-7.4.0.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | INSTALL_PATH=$HOME/gcc-graph 4 | if [ "$1" != "" ]; then INSTALL_PATH=$1; fi 5 | if [ "$2" = "compile-only" ]; then export COMPILE_ONLY=yes; fi 6 | echo Installing gcc to $INSTALL_PATH 7 | 8 | NCFTP=`which ncftpget` 9 | EXIT=$? 10 | if [ "$EXIT" != "0" ]; then 11 | NCFTP=ftp 12 | fi 13 | 14 | if [ ! -e gcc-7.4.0.tar.gz ]; then 15 | echo gcc-7.4.0.tar.gz not found, downloading 16 | $NCFTP ftp://ftp.gnu.org/pub/gnu/gcc/gcc-7.4.0/gcc-7.4.0.tar.gz 17 | if [ ! -e gcc-7.4.0.tar.gz ]; then 18 | echo Failed to download gcc, download gcc-7.4.0.tar.gz from www.gnu.org 19 | exit 20 | fi 21 | fi 22 | 23 | # Untar gcc 24 | rm -rf gcc-graph/objdir 2> /dev/null 25 | mkdir -p gcc-graph/objdir 26 | echo Untarring gcc... 27 | tar -zxf gcc-7.4.0.tar.gz -C gcc-graph || exit 28 | 29 | # Apply patch 30 | cd gcc-graph/gcc-7.4.0 31 | patch -p1 < ../../gcc-patches/gcc-7.4.0-cdepn.diff 32 | cd ../objdir 33 | 34 | # Configure and compile 35 | ../gcc-7.4.0/configure --prefix=$INSTALL_PATH --enable-shared --enable-languages=c,c++ || exit 36 | make bootstrap 37 | 38 | RETVAL=$? 39 | PLATFORM=i686-pc-linux-gnu 40 | if [ $RETVAL != 0 ]; then 41 | if [ ! -e $PLATFORM/libiberty/config.h ]; then 42 | echo Checking if this is CygWin 43 | echo Note: This is untested, if building with Cygwin works, please email mel@csn.ul.ie with 44 | echo a report 45 | export PLATFORM=i686-pc-cygwin 46 | if [ ! -e $PLATFORM/libiberty/config.h ]; then 47 | echo Do not know how to fix this compile error up, exiting... 48 | exit -1 49 | fi 50 | fi 51 | cd $PLATFORM/libiberty/ 52 | cat config.h | sed -e 's/.*undef HAVE_LIMITS_H.*/\#define HAVE_LIMITS_H 1/' > config.h.tmp && mv config.h.tmp config.h 53 | cat config.h | sed -e 's/.*undef HAVE_STDLIB_H.*/\#define HAVE_STDLIB_H 1/' > config.h.tmp && mv config.h.tmp config.h 54 | cat config.h | sed -e 's/.*undef HAVE_UNISTD_H.*/\#define HAVE_UNISTD_H 1/' > config.h.tmp && mv config.h.tmp config.h 55 | cat config.h | sed -e 's/.*undef HAVE_SYS_STAT_H.*/\#define HAVE_LIMITS_H 1/' > config.h.tmp && mv config.h.tmp config.h 56 | if [ "$PLATFORM" = "i686-pc-cygwin" ]; then 57 | echo "#undef HAVE_GETTIMEOFDAY" >> config.h 58 | fi 59 | 60 | TEST=`grep HAVE_SYS_STAT_H config.h` 61 | if [ "$TEST" = "" ]; then 62 | echo "#undef HAVE_SYS_STAT_H" >> config.h 63 | echo "#define HAVE_SYS_STAT_H 1" >> config.h 64 | fi 65 | cd ../../ 66 | make 67 | 68 | RETVAL=$? 69 | if [ $RETVAL != 0 ]; then 70 | echo 71 | echo Compile saved after trying to fix up config.h, do not know what to do 72 | echo This is likely a CodeViz rather than a gcc problem 73 | exit -1 74 | fi 75 | fi 76 | 77 | if [ "$COMPILE_ONLY" != "yes" ]; then 78 | make install 79 | fi 80 | -------------------------------------------------------------------------------- /configure: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 3 | # configure 4 | # 5 | # This is the configure script for CodeViz to compile a patched gcc and install 6 | # the scripts. It is meant to behave similar to ordinary configure scripts 7 | 8 | PREFIX=/usr/local 9 | GCCVERSION=4.6.2 10 | GCCGRAPH=-unset- 11 | 12 | # Print program usage 13 | usage() { 14 | echo "Usage: configure [OPTION] [VAR=VALUE]" 15 | echo 16 | echo "Configuration:" 17 | echo " -h, --help display this help and exit" 18 | echo " --prefix=PREFIX install architecture-independent files in PREFIX" 19 | echo " [Default: /usr/local]" 20 | echo " --gcc=VERSION version of gcc to use: 4.6.2 only available" 21 | echo " [Default: 4.6.2]" 22 | echo " --gccgraph=PATH install patched gcc to this path" 23 | echo " [Default: $HOME/gccgraph]" 24 | echo " --perllib=PATH Where to install the perl libraries" 25 | echo " [Default: auto-detected]" 26 | echo 27 | 28 | echo Make options are 29 | echo "all Compile a patched version of gcc" 30 | echo "install Install all scripts and patched version of gcc" 31 | echo "install-gcconly Install only the patched version of gcc" 32 | echo "install-codeviz Install only the codeviz scripts" 33 | echo 34 | exit 35 | } 36 | 37 | # Function to check a program is in the path 38 | checkprog() { 39 | PROG=$1 40 | PACKAGE=$2 41 | echo -n checking for $PROG... 42 | 43 | TEST=`which $PROG` 44 | if [ "$TEST" != "" ]; then 45 | echo $TEST; 46 | else 47 | echo not found 48 | echo FATAL: The program $PROG was not in your path. This is probably available for your distribution 49 | echo " with the $PACKAGE package. Install this before running configure again" 50 | echo 51 | exit 52 | fi 53 | 54 | } 55 | 56 | # Parse command line arguements 57 | eval set -- "$@" 58 | while true ; do 59 | if [ "$1" == "" ]; then break; fi 60 | 61 | PARAM=`echo $1 | awk -F = '{print $1}'` 62 | case "$PARAM" in 63 | -h|--help) usage;; 64 | --prefix) export PREFIX=`echo $1 | awk -F = '{print $2}'` 65 | shift;; 66 | --gcc) export GCCVERSION=`echo $1 | awk -F = '{print $2}'` 67 | shift;; 68 | --gccgraph) export GCCGRAPH=`echo $1 | awk -F = '{print $2}'` 69 | shift;; 70 | 71 | --perllib) export PERLLIB=`echo $1 | awk -F = '{print $2}'` 72 | shift;; 73 | *) echo "Unknown option: \"$1\""; echo; usage;; 74 | esac 75 | done 76 | 77 | # Make sure prefix is valid 78 | if [ ! -d $PREFIX ]; then 79 | echo An invalid prefix \($PREFIX\) was specified 80 | exit 81 | fi 82 | 83 | # Check gccgraph is going somewhere 84 | if [ "$GCCGRAPH" = "-unset-" ]; then 85 | GCCGRAPH=$PREFIX/gccgraph 86 | fi 87 | 88 | # Check required programs are available 89 | checkprog dot graphviz 90 | checkprog make make 91 | checkprog gcc gcc 92 | 93 | # Check that dot can generate graphs 94 | TEMP=`mktemp 2> /dev/null` 95 | TEMPERR=`mktemp 2> /dev/null` 96 | if [ "$TEMP" = "" ]; then 97 | TEMP=`mktemp -t /tmp 2> /dev/null` 98 | TEMPERR=`mktemp -t /tmp 2> /dev/null` 99 | fi 100 | echo -n checking dot can generate graphs... 101 | echo 'digraph testgraph { node [ fontname=Helvetica, fontsize=12 ]; a->b; }' | dot -Tps > $TEMP 2> $TEMPERR 102 | TEST=`head -1 $TEMP | grep "%!"` 103 | if [ "$TEST" = "" ]; then 104 | echo no 105 | echo FATAL: dot does not appear to be able to generate graphs 106 | rm $TEMP 107 | rm $TMEPERR 108 | exit 109 | fi 110 | echo yes 111 | 112 | # Get the perl library installation path 113 | echo -n checking perl library path... 114 | if [ "$PERLLIB" = "" ]; then 115 | for i in `perl -X -e 'foreach $INC (@INC) { print "$INC\n" }' 2> /dev/null`; do 116 | TEST=`echo $i | grep $PREFIX` 117 | if [ "$TEST" != "" ]; then 118 | export PERLLIB=$TEST 119 | break 120 | fi 121 | done 122 | 123 | if [ "$PERLLIB" = "" ]; then 124 | export PERLLIB=$PREFIX/lib 125 | fi 126 | fi 127 | echo $PERLLIB 128 | 129 | # Create the toplevel Makefile 130 | echo Creating Makefile 131 | PREFIX_ESCAPED=`echo $PREFIX | sed -e 's/\//\\\\\//g'` 132 | GCCGRAPH_ESCAPED=`echo $GCCGRAPH | sed -e 's/\//\\\\\//g'` 133 | PERLLIB_ESCAPED=`echo $PERLLIB | sed -e 's/\//\\\\\//g'` 134 | TOPLEVEL_ESCAPED=`pwd | sed -e 's/\//\\\\\//g'` 135 | cat Makefile.in | \ 136 | sed -e s/@@PREFIX@@/$PREFIX_ESCAPED/g | \ 137 | sed -e s/@@GCCVERSION@@/$GCCVERSION/g | \ 138 | sed -e s/@@PERLLIB@@/$PERLLIB_ESCAPED/g | \ 139 | sed -e s/@@TOPLEVEL@@/$TOPLEVEL_ESCAPED/g | \ 140 | sed -e s/@@GCCGRAPH@@/$GCCGRAPH_ESCAPED/g > Makefile 141 | 142 | echo Creating testsuite/c/Makefile 143 | cat testsuite/c/Makefile.in | \ 144 | sed -e s/@@GCCGRAPH@@/$GCCGRAPH_ESCAPED\\/bin\\/gcc/g > testsuite/c/Makefile 145 | 146 | echo 147 | echo Configured. Running \"make\" will compile a patched version of gcc suitable 148 | echo for use with codeviz. Running \"make install\" when it completes will install 149 | echo the patched version of gcc to $GCCPATCH and the other codeviz scripts under 150 | echo $PREFIX. When compiling other programs for use with codeviz, make sure you 151 | echo use the patched version of gcc. For example, to build a project based on C, 152 | echo the following should work\; 153 | echo 154 | echo make CC=$GCCPATCH/bin/gcc 155 | echo 156 | echo Configuration: 157 | echo " PREFIX = $PREFIX" 158 | echo " GCC version to patch = $GCCVERSION" 159 | echo " Patched GCC install path = $GCCGRAPH" 160 | echo 161 | 162 | 163 | -------------------------------------------------------------------------------- /debian/README.debian: -------------------------------------------------------------------------------- 1 | codeviz for Debian 2 | ---------------------- 3 | 4 | Comments regarding the Package 5 | 6 | root , Fri, 4 Jun 2004 10:07:37 +0100 7 | -------------------------------------------------------------------------------- /debian/changelog: -------------------------------------------------------------------------------- 1 | codeviz (1.0-1) unstable; urgency=low 2 | 3 | * Initial release. 4 | 5 | -- root Fri, 4 Jun 2004 10:07:37 +0100 6 | -------------------------------------------------------------------------------- /debian/control: -------------------------------------------------------------------------------- 1 | Source: codeviz 2 | Section: devel 3 | Priority: optional 4 | Maintainer: Mel Gorman 5 | Standards-Version: 3.5.8 6 | Build-Depends: debmake 7 | 8 | Package: codeviz 9 | Architecture: any 10 | Depends: graphviz (>= 1.10.0) 11 | Description: CodeViz tool basic package 12 | -------------------------------------------------------------------------------- /debian/copyright: -------------------------------------------------------------------------------- 1 | This package was debianized by root root@monocle.csn.ul.ie on 2 | Fri, 4 Jun 2004 10:07:37 +0100. 3 | 4 | It was downloaded from 5 | 6 | Copyright: 7 | 8 | 9 | -------------------------------------------------------------------------------- /debian/dirs: -------------------------------------------------------------------------------- 1 | usr/bin 2 | usr/sbin 3 | -------------------------------------------------------------------------------- /debian/files: -------------------------------------------------------------------------------- 1 | codeviz_1.0-1_i386.deb devel optional 2 | -------------------------------------------------------------------------------- /debian/rules: -------------------------------------------------------------------------------- 1 | #!/usr/bin/make -f 2 | # Made with the aid of debmake, by Christoph Lameter, 3 | # based on the sample debian/rules file for GNU hello by Ian Jackson. 4 | 5 | package=codeviz 6 | 7 | build: 8 | $(checkdir) 9 | ./configure --prefix=/usr --perllib=`pwd`/debian/tmp/usr/lib/perl5 10 | $(MAKE) CFLAGS="-O2 -g -Wall" 11 | touch build 12 | 13 | clean: 14 | $(checkdir) 15 | rm -f build 16 | -$(MAKE) distclean 17 | rm -f `find . -name "*~"` 18 | rm -rf debian/tmp debian/files* core debian/substvars 19 | 20 | binary-indep: checkroot build 21 | $(checkdir) 22 | # There are no architecture-independent files to be uploaded 23 | # generated by this package. If there were any they would be 24 | # made here. 25 | 26 | binary-arch: checkroot build 27 | $(checkdir) 28 | rm -rf debian/tmp 29 | install -d debian/tmp 30 | cd debian/tmp && install -d `cat ../dirs` 31 | $(MAKE) install PREFIX=`pwd`/debian/tmp/usr GCCEXTRA_INSTALL=prefix=`pwd`/debian/tmp/usr/local/gccgraph 32 | # Must have debmake installed for this to work. Otherwise please copy 33 | # /usr/bin/debstd into the debian directory and change debstd to debian/debstd 34 | debstd CHANGELOG README README-CrossCompile 35 | dpkg-gencontrol -isp 36 | chown -R root:root debian/tmp 37 | chmod -R go=rX debian/tmp 38 | dpkg --build debian/tmp .. 39 | 40 | define checkdir 41 | test -f debian/rules 42 | endef 43 | 44 | binary: binary-indep binary-arch 45 | 46 | checkroot: 47 | $(checkdir) 48 | test root = "`whoami`" 49 | 50 | .PHONY: binary binary-arch binary-indep clean checkroot 51 | -------------------------------------------------------------------------------- /debian/substvars: -------------------------------------------------------------------------------- 1 | shlibs:Depends=libc6 (>= 2.3.2.ds1-4), libgcc1 (>= 1:3.3.1-1) 2 | -------------------------------------------------------------------------------- /lib/CodeViz/Collect.pm: -------------------------------------------------------------------------------- 1 | # Collect.pm 2 | # 3 | # This is the high level library for collecting data for generating the 4 | # full.graph file. At the time of writing, the only method is through the 5 | # reading of .cdepn files in a source directory but there will be more in 6 | # the future for other collection methods and languages. When a new one 7 | # is created, it is added via this library. Different collection methods 8 | # are simply identified by string 9 | # 10 | # Each collection module is expected to export one function. The return value 11 | # should be 0 on success and -1 on failure. The return value is initialised to 12 | # -2 so that unrecognised methoid invocation can be recognised 13 | # 14 | 15 | use lib "."; 16 | package CodeViz::Collect; 17 | use CodeViz::CollectCXref; 18 | use CodeViz::CollectCppDepn; 19 | use CodeViz::CollectCObjdump; 20 | use CodeViz::CollectCNcc; 21 | use CodeViz::Graph; 22 | require Exporter; 23 | use vars qw (@ISA @EXPORT); 24 | use strict; 25 | no strict 'refs'; 26 | 27 | @ISA = qw(Exporter); 28 | @EXPORT = qw(&gen_fullgraph); 29 | 30 | # gen_fullgraph - Collect data and output a full graph 31 | # $method - Data collection method 32 | # $toplevel - Top level source directory 33 | # $files - Specific files that are to be scanned or used 34 | # $subdirs - List of subdirectories to graph 35 | # $output - Output graph name 36 | # 37 | sub gen_fullgraph { 38 | my ($method, $toplevel, $files, $subdirs, $output) = @_; 39 | my $handle; 40 | my $retval=-2; 41 | 42 | $handle = openGraph($output); 43 | 44 | # C Handlers 45 | $retval = generate_cdepn ($toplevel, $files, $subdirs, $handle) if $method eq "cdepn"; 46 | $retval = generate_cncc ($toplevel, $files, $subdirs, $handle) if $method eq "cncc"; 47 | $retval = generate_cobjdump ($toplevel, $files, $subdirs, $handle) if $method eq "cobjdump"; 48 | 49 | # C++ Handlers 50 | $retval = generate_cppobjdump($toplevel, $files, $subdirs, $handle) if $method eq "cppobjdump"; 51 | $retval = generate_cppdep($toplevel, $files, $subdirs, $handle) if $method eq "cppdepn"; 52 | 53 | closeGraph($handle); 54 | 55 | if ($retval == -2) { 56 | print "Collection method '$method' unknown\n"; 57 | } 58 | 59 | return $retval; 60 | } 61 | -------------------------------------------------------------------------------- /lib/CodeViz/CollectCNcc.pm: -------------------------------------------------------------------------------- 1 | # CollectCNcc.pm 2 | # 3 | # This module is responsible for collecting call graph information via 4 | # .nccout files generated by ncc. This requires ncc to be downloaded 5 | # from http://students.ceid.upatras.gr/~sxanth/ncc/index.html 6 | # 7 | # Format of .nccout files is 8 | # 9 | # D: somefunction() - Function beginning (i.e. sets currfunc) 10 | # F: callee() - Function call 11 | # F: *strcture.field() - Call of function pointer in structure 12 | # G: variable - Reference a global variable 13 | # S: structure.field - struct reference 14 | # 15 | # Currently, only function declaration and calls are used. Function pointers 16 | # are ignored for the moment 17 | # 18 | 19 | package CodeViz::CollectCNcc; 20 | use CodeViz::Graph; 21 | require Exporter; 22 | use vars qw (@ISA @EXPORT); 23 | use strict; 24 | no strict 'refs'; 25 | 26 | @ISA = qw(Exporter); 27 | @EXPORT = qw(&generate_cncc); 28 | 29 | my $propdepth=2; 30 | 31 | # generate_cncc - Collect data from C .nccout files and the graph 32 | # $toplevel - Top level source directory 33 | # $files - Specific files that are to be scanned 34 | # $subdirs - List of subdirectories to graph 35 | # $handle - File handle to output graph 36 | sub generate_cncc { 37 | my ($toplevel, $files, $subdirs, $handle) = @_; 38 | my $toplevel_escaped; 39 | my %F; # Function declaration hash table 40 | my %M; # Flags if function called 41 | my %C; # Call graph edge. Global as sorting function needs it 42 | my @sortedC; # Sorted call graph 43 | my %printed; # Hash table storing edges already printed 44 | my $file; # Current source being parsed 45 | my $i; # Index variable 46 | my ($f1, $f2); # Two functions 47 | my $pfile; # store file line 48 | 49 | # Get the top level escaped path 50 | $toplevel_escaped = $toplevel; 51 | $toplevel_escaped =~ s/\//\\\//g; 52 | 53 | # Begin scanning for files. 54 | if ($files != -1) { 55 | open(FIND, "echo $files|") or die("Failed to open pipe to 'echo'"); 56 | } else { 57 | open(FIND, "find $subdirs -name \"*.nccout\"|") or die("Failed to open pipe to 'find'"); 58 | } 59 | 60 | while(!eof(FIND)) { 61 | 62 | # Remove the toplevel source directory name 63 | $file = ; 64 | chomp($file); 65 | $file =~ s/$toplevel_escaped//; 66 | 67 | # Open input file 68 | print "Opening: $file\n"; 69 | open (F,"$toplevel$file") || return; 70 | 71 | # Read this input file 72 | while (!eof(F)) { 73 | $_ = ; 74 | # Lines beginning with D are function declarations 75 | # Lines beginning with F are calling a function 76 | # Lines beginning with P set the pfile variable 77 | # Lines beginning with L are function start-line end-line 78 | if (/^D: (.+)\(\)/) { 79 | $f1 = $1; 80 | $M{$f1}=3; 81 | } elsif (/^F: (.+)\(\)/) { 82 | $f2 = $1; 83 | $C{"$f1~$f2"}="$file:-1"; 84 | } elsif (/^P: (.+)/) { 85 | $pfile = $1; 86 | } elsif (/^L: (.+)\(\) (.+) (.+)/) { 87 | $F{$1} = "$pfile:$2:"; 88 | } 89 | } 90 | 91 | close F; 92 | } 93 | close FIND; 94 | 95 | print "Propagating call graph\n"; 96 | for($i=0;$i<$propdepth;$i++) { 97 | foreach (keys %C) { 98 | next if (!/^(.+)~(.+)$/); 99 | $M{$2} |= 1 if ($M{$1} & 1); 100 | $M{$1} |= 2 if ($M{$2} & 2); 101 | } 102 | } 103 | 104 | # print result 105 | print "Sorting function calls\n"; 106 | @sortedC = sort FuncFileSort keys %C; 107 | # Function sorting function. Functions are sorted by 108 | # filename alphabetically and then line number. This 109 | # is done to ensure the functions are outputted in 110 | # the right call order 111 | sub FuncFileSort { 112 | my ($lFunc, $rFunc); 113 | my ($lNum, $rNum); 114 | my $result; 115 | 116 | ($lFunc, $lNum) = split(/~/, $C{$a}); 117 | ($rFunc, $rNum) = split(/~/, $C{$b}); 118 | 119 | # Compare the filenames and return the result 120 | # if they are not the same 121 | $result = $lFunc cmp $rFunc; 122 | if ($result != 0) { return $result; } 123 | 124 | # Filenames are the same, so return the comparison 125 | # of the line numbers 126 | return $lNum <=> $rNum; 127 | } 128 | 129 | print "Outputting graph labels\n"; 130 | while (($f1, $f2) = each %F) { 131 | printGraph($handle, "$f1 [label=\"$f1\\n$f2\"];\n"); 132 | } 133 | 134 | print "Outputting call graph\n"; 135 | foreach (@sortedC) { 136 | next if (!/^(.+)~(.+)$/); 137 | $f1=$1; $f2=$2; 138 | next if (!($M{$f1} > 0)); # ignore not flagged caller 139 | 140 | # Strip away SMP mangling on symbols. This is very 141 | # Linux specific but the names of the functions are 142 | # so weird, I cannot see it happening anywhere else. 143 | $f1 =~ s/_Rsmp_([0-9a-f]{8})$//; 144 | $f2 =~ s/_Rsmp_([0-9a-f]{8})$//; 145 | $f1 =~ s/_R([0-9a-f]{8})$//; 146 | $f2 =~ s/_R([0-9a-f]{8})$//; 147 | 148 | if ($printed{"$f1-$f2"} != 1) 149 | { 150 | $printed{"$f1-$f2"} = 1; 151 | printGraph($handle, "$f1 -> $f2;\n"); 152 | } 153 | 154 | } 155 | print "Done\n"; 156 | return 0; 157 | } 158 | 159 | 1; 160 | -------------------------------------------------------------------------------- /lib/CodeViz/CollectCObjdump.pm: -------------------------------------------------------------------------------- 1 | # CollectCObjdump.pm 2 | # 3 | # This module is responsible for collecting call graph information by 4 | # calling objdump on each object file created. The restriction is that 5 | # the files must not be stripped. This module will fail if the 6 | # intermediatary object files are not created for each C file but it 7 | # is assumed that this is the prevalent build method and not likely to 8 | # change. In theory, this could work with compiled binaries but it is 9 | # not supported yet 10 | # 11 | 12 | package CodeViz::CollectCObjdump; 13 | use CodeViz::Graph; 14 | use Cwd 'abs_path'; 15 | require Exporter; 16 | use vars qw (@ISA @EXPORT); 17 | use strict; 18 | no strict 'refs'; 19 | 20 | # List of sections to dump for code. text is the one used normally and 21 | # init is commonly used in the Linux kernel 22 | my $dumpsections = "text init"; 23 | 24 | # List of possible assembler instructions for function calls. 25 | my @asm_calllist = ("call", "jmp", "bl"); 26 | 27 | my $propdepth = 2; 28 | 29 | @ISA = qw(Exporter); 30 | @EXPORT = qw(&generate_cobjdump &generate_cppobjdump); 31 | 32 | # generate_cobjdump - Collect data from binary files compiled with gcc 33 | # $toplevel - Top level source directory 34 | # $files - Specific files (probably binaries) to scan 35 | # $subdirs - List of subdirectories to graph 36 | # $handle - File handle to output graph 37 | sub generate_cobjdump { 38 | my ($toplevel, $files, $subdirs, $handle) = @_; 39 | analyse_binaries($toplevel, $files, $subdirs, $handle, 0); 40 | } 41 | 42 | # generate_cppobjdump - Collect data from binary files compiled with g++ 43 | # $toplevel - Top level source directory 44 | # $files - Specific files (probably binaries) to scan 45 | # $subdirs - List of subdirectories to graph 46 | # $handle - File handle to output graph 47 | sub generate_cppobjdump { 48 | my ($toplevel, $files, $subdirs, $handle) = @_; 49 | analyse_binaries($toplevel, $files, $subdirs, $handle, 1); 50 | } 51 | 52 | # analyse_binaries - Collects the actual information 53 | # Takes the same parameters as generate_cobjdump except for 54 | # $cpp - Boolean set to 1 if analysing c++ 55 | 56 | sub analyse_binaries { 57 | my ($toplevel, $files, $subdirs, $handle, $cpp) = @_; 58 | my $obj; # Name of object file 59 | my %F; # Function declaration hash table 60 | my %M; # Flags if function called 61 | my %C; # Call graph edge. Global as sorting function needs it 62 | my @sortedC; # Sorted call graph 63 | my %printed; # Hash table storing edges already printed 64 | my $i; # Index variable 65 | my ($f1, $f2); # Two functions 66 | my ($currFunc, $currAddr); # Current function being read from objdump and address 67 | my ($callFunc, $callAddr); # Function being called from current func 68 | my $section; 69 | my $op; 70 | 71 | # Use find to get all cdep files and process them with cdepn() 72 | if ($files != -1) { 73 | open(FIND, "echo $files|") or die("Failed to open pipe to 'echo'"); 74 | } else { 75 | open(FIND, "find $subdirs -type f -name \"*\" -perm +111|") 76 | or die("Failed to open pipe to 'find'"); 77 | } 78 | 79 | while(!eof(FIND)) { 80 | 81 | # Open input file 82 | $obj = ; 83 | chomp($obj); 84 | syswrite STDOUT, "Opening: $obj"; 85 | 86 | foreach $section (split(/ /, $dumpsections)) { 87 | open (F,"objdump -C -d --section=.text --section=.$section $obj|") || next; 88 | syswrite STDOUT, "...$section"; 89 | 90 | # Read this input file 91 | while () { 92 | # Function labels from objdump look like 93 | # address : which is what this 94 | # regular expression searched for 95 | if (/^([0-9a-f]+) <(.*?)(\(.*\)\s*(const)?)?>:/) { 96 | $currAddr = $1; 97 | $currFunc = $2; 98 | 99 | $F{$currFunc} = "$obj:0x$currAddr"; 100 | $M{$currFunc}=3; 101 | } 102 | 103 | # A function call will look something like 104 | # addr: opcodes asmop 105 | # Where asmop will be some instruction as listed 106 | # in the $asm_calllist array 107 | 108 | # address asmop addr 109 | if (/(^\s*[0-9a-f]+):.*\s+([a-z]+)\s+[0-9a-f]+\s+<(.*?)(\(.*\)\s*(const)?)?(\+0x[0-9a-f]+)?>/ && $3 ne $currFunc) { 110 | foreach (@asm_calllist) { 111 | if ($_ eq $2) { 112 | $callAddr = $1; 113 | $callFunc = $3; 114 | 115 | $callFunc =~ s/\+.*//; 116 | 117 | # Some as for function declarations, strip parameter information for c++ 118 | $C{"$currFunc~$callFunc"} = "$obj:0x$callAddr"; 119 | last; 120 | } 121 | } 122 | } 123 | } 124 | 125 | close F; 126 | } 127 | syswrite STDOUT, "\n"; 128 | } 129 | close FIND; 130 | 131 | print "Propagating call graph\n"; 132 | for($i=0;$i<$propdepth;$i++) { 133 | foreach (keys %C) { 134 | next if (!/^(.+)~(.+)$/); 135 | $M{$2} |= 1 if ($M{$1} & 1); 136 | $M{$1} |= 2 if ($M{$2} & 2); 137 | } 138 | } 139 | 140 | # print result 141 | print "Sorting function calls\n"; 142 | @sortedC = sort FuncFileSort keys %C; 143 | # Function sorting function. Functions are sorted by 144 | # filename alphabetically and then line number. This 145 | # is done to ensure the functions are outputted in 146 | # the right call order 147 | sub FuncFileSort { 148 | my ($lFunc, $rFunc); 149 | my ($lNum, $rNum); 150 | my $result; 151 | 152 | ($lFunc, $lNum) = split(/~/, $C{$a}); 153 | ($rFunc, $rNum) = split(/~/, $C{$b}); 154 | 155 | # Compare the filenames and return the result 156 | # if they are not the same 157 | $result = $lFunc cmp $rFunc; 158 | if ($result != 0) { return $result; } 159 | 160 | # Filenames are the same, so return the comparison 161 | # of the line numbers 162 | return $lNum <=> $rNum; 163 | } 164 | 165 | print "Outputting graph labels\n"; 166 | while (($f1, $f2) = each %F) { 167 | my $ef1 = $f1; 168 | if ($cpp && $ef1 =~ /::/) { $ef1 = "\"$ef1\""; } 169 | printGraph($handle, "$ef1 [label=\"$f1\\n$f2\"];\n"); 170 | } 171 | 172 | print "Outputting call graph\n"; 173 | foreach (@sortedC) { 174 | next if (!/^(.+)~(.+)$/); 175 | $f1=$1; $f2=$2; 176 | next if (!($M{$f1} > 0)); # ignore not flagged caller 177 | 178 | if ($printed{"$f1-$f2"} != 1) 179 | { 180 | $printed{"$f1-$f2"} = 1; 181 | if ($cpp) { 182 | 183 | if ($f1 =~ /::/) { $f1 = "\"$f1\""; } 184 | if ($f2 =~ /::/) { $f2 = "\"$f2\""; } 185 | } 186 | printGraph($handle, "$f1 -> $f2;\n"); 187 | } 188 | 189 | } 190 | print "Done\n"; 191 | return 0; 192 | } 193 | 194 | 1; 195 | -------------------------------------------------------------------------------- /lib/CodeViz/CollectCXref.pm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/petersenna/codeviz/cc5bd4ae0ca46bf1812d570c34d09f6ef8521fa6/lib/CodeViz/CollectCXref.pm -------------------------------------------------------------------------------- /lib/CodeViz/CollectCppDepn.pm: -------------------------------------------------------------------------------- 1 | # CollectCppDepn.pm 2 | # 3 | # This module is responsible for collecting call graph information via 4 | # cdepn files for C++ using cdepn files. The CXref method is far superior 5 | # for C files as it is able to analyse the source. However, the parser is 6 | # too C specific and it makes really stupid errors for C++. This method is 7 | # not as extensive but it's simplicity makes it solid for C++ 8 | # 9 | 10 | package CodeViz::CollectCppDepn; 11 | use CodeViz::Graph; 12 | use CodeViz::Format; 13 | require Exporter; 14 | use vars qw (@ISA @EXPORT); 15 | use strict; 16 | no strict 'refs'; 17 | 18 | @ISA = qw(Exporter); 19 | @EXPORT = qw(&generate_cppdep); 20 | 21 | my $propdepth=2; 22 | 23 | # generate_cppdep - Collect data from C++ .cdepn files and the graph 24 | # $toplevel - Top level source directory 25 | # $files - Specific files that are to be scanned 26 | # $subdirs - List of subdirectories to graph 27 | # $handle - File handle to output graph 28 | sub generate_cppdep { 29 | my ($toplevel, $files, $subdirs, $handle) = @_; 30 | analyse_cdepn($toplevel, $files, $subdirs, $handle, 1); 31 | } 32 | 33 | sub parseDeclaration($) { 34 | my ($decl) = $_[0]; 35 | 36 | # Split by elements to remove the return type 37 | my @elements = split(/ /, $decl); 38 | 39 | # kost@ : skip all the elements, if any, until the one with a '(' or 40 | # containing "::operator" - these elements are the type specifiers 41 | # for the return element; 42 | 43 | my $index = 0; 44 | while ($index <= $#elements && 45 | @elements[$index] !~ /\(/ && @elements[$index] !~ /::operator/) { 46 | $index++; 47 | } 48 | 49 | # kost@ : is this template-related?? I have no idea.. someone more 50 | # knowledgeable should check this code - so far it's out: 51 | #if (@elements[0] =~ // && $index <= $#elements) { $index++; } 54 | # $index++; 55 | #} 56 | 57 | # Get the function name 58 | $decl=""; 59 | while ($index <= $#elements) { 60 | $decl .= $elements[$index]; 61 | if ($decl !~ /,$/) { $decl .= " "; } 62 | $index++; 63 | } 64 | 65 | $decl =~ s/\s*$//; 66 | $decl =~ s/\}$//; 67 | $decl =~ s/^\{//; 68 | return $decl; 69 | } 70 | 71 | # analyse_cdepn - Collects the actual information 72 | # Takes the same parameters as generate_cobjdump except for 73 | # $cpp - Boolean set to 1 if analysing c++ 74 | sub analyse_cdepn { 75 | my ($toplevel, $files, $subdirs, $handle, $cpp) = @_; 76 | my $toplevel_escaped; 77 | my @f; 78 | my %F; # Function declaration hash table 79 | my %M; # Flags if function called 80 | my %C; # Call graph edge. Global as sorting function needs it 81 | my @sortedC; # Sorted call graph 82 | my %printed; # Hash table storing edges already printed 83 | my $i; # Index variable 84 | my ($f1, $f2); # Two functions 85 | 86 | # Get the top level escaped path 87 | $toplevel_escaped = $toplevel; 88 | $toplevel_escaped =~ s/\//\\\//g; 89 | 90 | # Begin scanning for files. If specific files have been requested, 91 | # then use them else use find to locate .cdepn files 92 | my $start = printstart("Finding input files"); 93 | if ($files != -1) { 94 | open(FIND, "echo $files|") or die("Failed to open pipe to 'echo'"); 95 | } else { 96 | open(FIND, "find $subdirs -print |") or die("Failed to open pipe to 'find'"); 97 | } 98 | while () { 99 | chop; 100 | my $file = $_; 101 | push(@f, $file) if $file =~ /\.(h|hh)$/i; # Duplicated in lib/LXR/Common.pm 102 | if ($file =~ /.cdepn$/) { 103 | $file =~ s/\.cdepn$//g; 104 | push(@f, $file); 105 | } 106 | 107 | } 108 | close(FIND); 109 | printcomplete($start, $#f+1 . " files found"); 110 | 111 | # Read each of the files 112 | $start = printstart("Reading cdepn files"); 113 | my $fnum=0; 114 | my $file; 115 | foreach $file (@f) { 116 | 117 | # Remove the toplevel source directory name 118 | $file =~ s/$toplevel_escaped//; 119 | 120 | # Open input file 121 | $fnum++; 122 | printprogress($file, -1, $fnum, $#f+1); 123 | open (F,"$toplevel$file.cdepn") || next; 124 | 125 | # Read this input file 126 | while () { 127 | $_ =~ s/$toplevel_escaped//; 128 | next if ($_ =~ /static destructors/); 129 | next if ($_ =~ /static init/); 130 | next if ($_ =~ /operator new/); 131 | next if ($_ =~ /operator delete/); 132 | 133 | # Lines beginning with F are function declarations 134 | # This check sees if the filename between the {} 135 | # has a / at the beginning or not. If it does, it 136 | # has been included from an external file and 137 | # should be ignored, otherwise record it as a function 138 | # declaration 139 | if (/^F {(.*)} {(.+):(.+)}/) { 140 | my $loc="$2:$3"; 141 | $f1 = parseDeclaration($1); 142 | 143 | #if ($cpp) { $f1 =~ s/<.*>//g; } 144 | $F{$f1} = "$2:$3"; 145 | $M{$f1}=3; 146 | } elsif (/^C {(.*)} {(.+):(.+)}\s+(.+)/) { 147 | my $loc = "$2:$3"; 148 | # Lines beginning with C are calling a function 149 | # The key is hashed as "caller:callee" and the 150 | # value is "filename:linenumber" 151 | $f1 = parseDeclaration($1); 152 | $f2 = parseDeclaration($4); 153 | 154 | #if ($cpp) { $f1 =~ s/<.*>//g; } 155 | #if ($cpp) { $f2 =~ s/<.*>//g; } 156 | 157 | $C{"$f1~$f2"}="$loc"; 158 | } 159 | } 160 | 161 | close F; 162 | } 163 | printcomplete($start, "$fnum cdepn files read"); 164 | close FIND; 165 | 166 | $start = printstart("Propagating call graph"); 167 | for($i=0;$i<$propdepth;$i++) { 168 | foreach (keys %C) { 169 | next if (!/^(.+)~(.+)$/); 170 | $M{$2} |= 1 if ($M{$1} & 1); 171 | $M{$1} |= 2 if ($M{$2} & 2); 172 | } 173 | } 174 | printcomplete($start, "Propagation complete"); 175 | 176 | # print result 177 | $start = printstart("Sorting function calls"); 178 | @sortedC = sort FuncFileSort keys %C; 179 | printcomplete($start, "Functions sorted"); 180 | 181 | # Function sorting function. Functions are sorted by 182 | # filename alphabetically and then line number. This 183 | # is done to ensure the functions are outputted in 184 | # the right call order 185 | sub FuncFileSort { 186 | my ($lFunc, $rFunc); 187 | my ($lNum, $rNum); 188 | my $result; 189 | 190 | ($lFunc, $lNum) = split(/~/, $C{$a}); 191 | ($rFunc, $rNum) = split(/~/, $C{$b}); 192 | 193 | # Compare the filenames and return the result 194 | # if they are not the same 195 | $result = $lFunc cmp $rFunc; 196 | if ($result != 0) { return $result; } 197 | 198 | # Filenames are the same, so return the comparison 199 | # of the line numbers 200 | return $lNum <=> $rNum; 201 | } 202 | 203 | $start = printstart("Dumping graph information"); 204 | while (($f1, $f2) = each %F) { 205 | my $ef1 = $f1; 206 | printGraph($handle, "\"$ef1\" [label=\"$f1\\n$f2\"];\n"); 207 | } 208 | 209 | foreach (@sortedC) { 210 | next if (!/^(.+)~(.+)$/); 211 | $f1=$1; $f2=$2; 212 | next if (!($M{$f1} > 0)); # ignore not flagged caller 213 | 214 | # Strip away SMP mangling on symbols. This is very 215 | # Linux specific but the names of the functions are 216 | # so weird, I cannot see it happening anywhere else. 217 | $f1 =~ s/_Rsmp_([0-9a-f]{8})$//; 218 | $f2 =~ s/_Rsmp_([0-9a-f]{8})$//; 219 | 220 | if ($printed{"$f1-$f2"} != 1) 221 | { 222 | $printed{"$f1-$f2"} = 1; 223 | my $loc = $C{"$f1~$f2"}; 224 | $f1 = "\"$f1\""; 225 | $f2 = "\"$f2\""; 226 | printGraph($handle, "$f1 -> $f2 [label=\"" . $loc . "\"];\n"); 227 | } 228 | 229 | } 230 | printcomplete($start, "Graph dumping complete"); 231 | return 0; 232 | } 233 | 234 | 1; 235 | -------------------------------------------------------------------------------- /lib/CodeViz/CollectPPStack.pm: -------------------------------------------------------------------------------- 1 | # CollectPPStack.pm 2 | # 3 | # This is a post-processing module for the collection of stack usage in functions 4 | # See the usage function for the options 5 | 6 | package CodeViz::CollectPPStack; 7 | require Exporter; 8 | use vars qw (@ISA @EXPORT); 9 | use strict; 10 | use CodeViz::Format; 11 | no strict 'refs'; 12 | 13 | @ISA = qw(Exporter); 14 | @EXPORT = qw(&CollectPPStack); 15 | 16 | sub usage() { 17 | print <; 63 | if ($line !~ /^0x([0-9a-fA-F]+) (.*)/) { next; } 64 | 65 | $susage{$2} = hex $1; 66 | } 67 | close(PPPIPE); 68 | 69 | # Read the full.graph file and insert the stack related information. 70 | # Place the processed file in full.graph.pp and then transfer it 71 | open(PPFILE, $fullgraph) || die("Failed to open full graph '$fullgraph'"); 72 | open(PPOUT, ">$fullgraph.pp") || die("Failed to open temporary file '$fullgraph.pp"); 73 | 74 | printstart("Inserting stack information into $fullgraph"); 75 | while (!eof(PPFILE)) { 76 | my $line = ; 77 | 78 | if ($line =~ /(.*) \[.*\];/) { 79 | my $func = $1; 80 | 81 | # This is a node description, see have we stack information on it 82 | if ($susage{$func} != 0) { 83 | chomp($line); 84 | $line =~ s/\];//; 85 | $line .= ", stackuse=$susage{$func}];\n"; 86 | } 87 | } 88 | 89 | print PPOUT $line; 90 | } 91 | 92 | close(PPFILE); 93 | close(PPOUT); 94 | 95 | system("mv $fullgraph.pp $fullgraph"); 96 | 97 | printcomplete($start, "Post-Processing: Stack usage"); 98 | 99 | } 100 | 101 | 1; 102 | -------------------------------------------------------------------------------- /lib/CodeViz/Format.pm: -------------------------------------------------------------------------------- 1 | # Format.pm 2 | # 3 | # Simple functions for outputting things nicely such as progress reports 4 | # 5 | 6 | use lib "."; 7 | package CodeViz::Format; 8 | require Exporter; 9 | use vars qw (@ISA @EXPORT); 10 | use strict; 11 | no strict 'refs'; 12 | 13 | @ISA = qw(Exporter); 14 | @EXPORT = qw(&printstart &printline &printprogress &printwarning &printcollision &print_collision_count &printcomplete &printerror &printverbose &die_nice &set_verbose &set_daemon); 15 | 16 | my $VERBOSE=0; # Verbosity level 17 | my $DAEMON=0; # Set to 1 if program is a daemon 18 | my $pass=0; # Which pass we are on 19 | my $pcursor=0; # Current position of cursor 20 | my $lastprint=0; # Last time something was printed 21 | my $lastline=""; # Last line that was printed 22 | 23 | ## 24 | # Print a start message for genfull using printraw 25 | sub printstart { 26 | my ($message) = @_; 27 | $pass++; 28 | printraw("Starting pass $pass: $message\n"); 29 | return time; 30 | } 31 | 32 | ## 33 | # Print message exactly as it appears. This writes the message to the 34 | # same line which is desirable for genfull but probably not for gengraph. 35 | sub printraw { 36 | my ($message, $noremember) = @_; 37 | my $blank; 38 | 39 | $blank = sprintf "%-" . $pcursor. "s", " "; 40 | syswrite STDOUT, "\r$blank"; 41 | syswrite STDOUT, "\r$message"; 42 | $pcursor = length($message); 43 | 44 | if ($noremember == 0) { $lastline = $message; } 45 | } 46 | 47 | ## 48 | # Print a single line 49 | sub printline { 50 | my $message = $_[0]; 51 | printraw("(Pass $pass) $message"); 52 | } 53 | 54 | ## 55 | # Print a progress report for genfull 56 | sub printprogress { 57 | my ($fname, $fsize, $fnum, $ftotal) = @_; 58 | my $message; 59 | my $now = time; 60 | 61 | # Print the file size in a nice fashion. 62 | # 0 => file is being skipped 63 | # -1 => file size is unknown 64 | 65 | # Only print out once a second at most 66 | if ($now eq $lastprint) { return; } 67 | $lastprint = $now; 68 | 69 | if ($fsize == 0) { $fsize = "skipping"; } 70 | else { if ($fsize == -1) { $fsize = "scanning"; } } 71 | 72 | # Format the filename so it is not more than 35 characters 73 | if (length($fname) > 30) { 74 | $fname = "..." . substr $fname, length($fname)-27, 27; 75 | } 76 | $message = sprintf "(Pass $pass) %-30s (%8s), file %d of %d...", 77 | $fname, $fsize, $fnum, $ftotal; 78 | 79 | # Write message 80 | printraw($message); 81 | } 82 | 83 | ## 84 | # Print a report on a collision found. specific to genfull 85 | sub printcollision { 86 | my ($func, $first, $second) = @_; 87 | 88 | printraw("\rWARNING: Function name collision for $func.....\n", 1); 89 | printraw(" First occurance in $first\n", 1); 90 | printraw(" Second occurance in $second\n", 1); 91 | printraw($lastline); 92 | } 93 | 94 | ## 95 | # Print a report on the number of collisions that occured 96 | sub print_collision_count { 97 | my ($collisions, $resolved, $funccount) = @_; 98 | if ($collisions > 0 && $collisions != $resolved) { 99 | print STDOUT <$filename") || die ("Failed to open output graph '$filename'\n"); 35 | print OPENGRAPH "digraph fullgraph {\n"; 36 | print OPENGRAPH "node [ fontname=$DEFAULT_FONT, fontsize=$DEFAULT_FONTSIZE ];\n"; 37 | return "OPENGRAPH"; 38 | } 39 | 40 | # resolveNode - Given a function name, try and resolve it's full name 41 | # $nodeName - Name of the node to resolve 42 | sub resolveNode($) { 43 | my ($nodeName) = $_[0]; 44 | my ($resolveList) = $resolveMap{$nodeName}; 45 | 46 | # If there are no mappings, return and hope for the best 47 | if ($resolveList eq "") { return $nodeName; } 48 | 49 | # Get the full list. If there is only one, return it 50 | my @resolveElements = split(/\|/, $resolveList); 51 | if ($#resolveElements == 0) { return $resolveElements[0]; } 52 | 53 | # Else, there are more than one and it is an ambiguous graph. Request 54 | # which one is of interest 55 | print "There are multiple functions that match the requested $nodeName.\n"; 56 | print "Rerun with one of the following selected for -f;\n"; 57 | my $element; 58 | foreach $element (@resolveElements) { 59 | print "$element\n"; 60 | } 61 | } 62 | 63 | # closeGraph - Print footer and close graph file 64 | # $handle: Name of file to close 65 | # 66 | sub closeGraph { 67 | print OPENGRAPH "}"; 68 | close OPENGRAPH; 69 | } 70 | 71 | # printGraph - Print an output line to a graph file 72 | sub printGraph { 73 | my ($handle, $line) = @_; 74 | print OPENGRAPH $line; 75 | } 76 | 77 | # createNode - Create a single node 78 | # $name - name to assign to this node 79 | # $label - label to use for displaying 80 | # %dag - Graph to add this node to 81 | # 82 | # Check if a node exists in a particular graph yet and if it does not, 83 | # create it with some default values. 84 | sub createNode { 85 | my ($name, $label, $dag) = @_; 86 | 87 | # Strip out "'s that may have been inserted for scopes 88 | $name =~ s/\"//g; 89 | 90 | if (!defined($$dag{$name})) { 91 | $$dag{$name}->{'name'} = $name; 92 | $$dag{$name}->{'label'} = $label; 93 | $$dag{$name}->{'outbound'} = 0; 94 | $$dag{$name}->{'inbount'} = 0; 95 | } 96 | 97 | # Get the filename from the label if possible 98 | if ($label =~ /:/) { 99 | my ($dummy, $file) = split /\\n/, $label; 100 | $file =~ s/:.*//; 101 | $$dag{$name}->{'file'} = $file; 102 | } 103 | } 104 | 105 | # createEdge - Create an edge between two nodes 106 | # $from - From node 107 | # $to - To node 108 | # $loc - Location the call took place 109 | sub createEdge { 110 | my ($from, $to, $loc) = @_; 111 | my ($dx, $dy); 112 | 113 | # Make sure labels are assigned 114 | if (!defined($$from->{'label'})) { $$from->{'label'} = $$from->{'name'}; } 115 | if (!defined($$to->{'label'})) { $$to->{'label'} = $$to->{'name'}; } 116 | 117 | # Create edge 118 | push(@{$$from->{'callees'}}, $to); 119 | push(@{$$to->{'callers'}}, $from); 120 | push(@{$$from->{'callocs'}}, '"' . $$to->{'label'} . '"' . "~$loc"); 121 | $$from->{'outbound'}++; 122 | $$to->{'inbound'}++; 123 | } 124 | 125 | # getNodeAttribute - Returns the value of a given attribute 126 | sub getNodeAttribute { 127 | my ($desiredkey, $node) = @_; 128 | my ($attrib, $key, $value); 129 | 130 | my $nodeAttribs = $$node->{'attributes'}; 131 | return $$nodeAttribs{$desiredkey}; 132 | } 133 | 134 | # setNodeAttribute - Sets the value of the given attribute 135 | sub setNodeAttribute { 136 | my ($desiredkey, $newvalue, $node) = @_; 137 | 138 | my $nodeAttribs = $$node->{'attributes'}; 139 | $$nodeAttribs{$desiredkey} = $newvalue; 140 | 141 | $$node->{'attributes'} = $nodeAttribs; 142 | } 143 | 144 | # addHTMLAttributes - Add attributes that are specific to HTML 145 | # $nodeName - Node name to set the HTML attributes for 146 | # $URL - Template URL to use for links 147 | sub addHTMLAttributes { 148 | my ($nodeName, $URL, $label, $dag) = @_; 149 | my $dummy; 150 | 151 | # Only add HTML attributes if label looks like it supports it 152 | if ($label !~ /:/) { return; } 153 | 154 | # Else create some HTML attributes 155 | my ($dummy, $fileline) = split /\\n/, $label; 156 | my ($file, $line) = split /:/, $fileline; 157 | 158 | $URL =~ s/%n/$nodeName/; 159 | $URL =~ s/%f/$file/; 160 | $URL =~ s/%l/$line/; 161 | 162 | setNodeAttribute("URL", $URL, \$$dag{$nodeName}); 163 | setNodeAttribute("tooltip", "$nodeName(), $file, line $line", \$$dag{$nodeName}); 164 | } 165 | 166 | # printNode - Print a node and all it's attributes in dot-friendly format 167 | # $node - Node to print 168 | # $fd - File description to write to 169 | sub printNode { 170 | my ($node, $fd, $LOCATION, $dag) = @_; 171 | my ($name, $attributes); 172 | 173 | # Get the node name 174 | # Quote certain functions, particularly 175 | # o Class members with the scope operator :: 176 | # o Function pointers 177 | $name = $$dag{$node}->{'name'}; 178 | $name = "\"$name\""; 179 | 180 | # Render the node attributes if it has any 181 | my $nodeAttribs = $$dag{$node}->{'attributes'}; 182 | my $key; 183 | my $allattribs; 184 | foreach $key (keys %$nodeAttribs) { 185 | if ($key eq "") { next; } 186 | if ($allattribs ne "") { $allattribs .= ", "; } 187 | $allattribs .= "$key=\"" . $$nodeAttribs{$key} . "\""; 188 | } 189 | 190 | # Print the node 191 | if ($allattribs ne "") { 192 | print $fd "$name [ $allattribs ];\n"; 193 | } 194 | } 195 | 196 | 197 | # This function reads the full input graph from the file that is requsted and 198 | # builds the DAG based on it. Most of the graph functionality is in 199 | # CodeViz::Graph 200 | sub read_inputgraph($$$$$$$) { 201 | my ($GRAPH, $LOCATION, $OUTPUT_TYPE, $BASEURL, $font, $fontsize, $dag) = @_; 202 | my $HEADER; 203 | my $delim; 204 | my $line; 205 | my ($caller, $callee, $loc, $other); 206 | 207 | # Open input graph and read the header 208 | open(INGRAPH, $GRAPH) || die_nice ("$GRAPH not found, use genfull\n"); 209 | $HEADER = ; 210 | $HEADER .= ; 211 | $HEADER =~ s/$DEFAULT_FONT/$font/; 212 | $HEADER =~ s/fontsize=$DEFAULT_FONTSIZE/fontsize=$fontsize/; 213 | 214 | # Read full input graph 215 | $delim = $/ ; $/ = ";\n"; 216 | printverbose("Reading input call graph\n"); 217 | 218 | while (! eof INGRAPH) { 219 | $line = ; 220 | if ($line ne "}") { 221 | 222 | # Check if this is a function call 223 | if ($line =~ /->/) { 224 | 225 | # Extract information about the call 226 | if ($line =~ /(.+) -> (.+) \[label="(.*)"\]/) { 227 | # Extract caller, callee and call locations from new-style graphs 228 | $caller = $1; 229 | $callee = $2; 230 | $loc = $3; 231 | 232 | } else { 233 | if ($line =~ /(.+) -> (.+);/) { 234 | # Extract just caller and callee from old-style graphs 235 | $caller = $1; 236 | $callee = $2; 237 | $loc = ""; 238 | } 239 | } 240 | $caller =~ s/\"//g; 241 | $callee =~ s/\"//g; 242 | 243 | # Make sure the nodes exist 244 | if (!defined($$dag{$caller})) { createNode($caller, $caller, $dag); } 245 | if (!defined($$dag{$callee})) { createNode($callee, $callee, $dag); } 246 | 247 | # Create an edge in the graph 248 | createEdge(\$$dag{$caller}, \$$dag{$callee}, $loc); 249 | 250 | } else { 251 | # Check if this is a location declaration 252 | if ($line =~ /(.+) +\[.*label="(.*)".*\]/ ) { 253 | my ($node, $label); 254 | $node = $1; 255 | $label = $2; 256 | $node =~ s/\"//g; 257 | 258 | # As graphs now include parameter information, record a mapping 259 | # of nodes without the parameter information to the nodes with 260 | # the parameter information. This can be used later by resolveNode() 261 | # to decide if there are multiple functions with the same name 262 | if ($node =~ /(.*)\(.*\)/) { 263 | $resolveMap{$1} .= $node . "|"; 264 | } 265 | 266 | # Create a new node, with label and HTML specific attributes if asked 267 | createNode($node, $label, $dag); 268 | if ($LOCATION) { setNodeAttribute("label", $label, \$$dag{$node}); } 269 | if ($OUTPUT_TYPE =~ /html/) { addHTMLAttributes($node, $BASEURL, $label, $dag); } 270 | 271 | # Set the node attributes 272 | $line =~ /(.+) +\[(.*)\]/; 273 | my $allattribs = $2; 274 | my @elements = split(/,/, $allattribs); 275 | my $element=""; 276 | my $index=0; 277 | while ($index <= $#elements) { 278 | $element .= $elements[$index]; 279 | if ($index < $#elements) { $element .= ","; } 280 | my $halfcount = ($element =~ tr/\"//) / 2; 281 | my $intcount = int $halfcount; 282 | if ($halfcount == $intcount) { 283 | my ($key, $value) = split /=/, $element; 284 | $element=""; 285 | 286 | # Skip label 287 | if ($key eq "label") { $index++; next; } 288 | 289 | # Else add the node attribute 290 | $value =~ s/^\"//; 291 | $value =~ s/\"$//; 292 | setNodeAttribute($key, $value, \$$dag{$node}); 293 | } 294 | $index++; 295 | } 296 | } 297 | 298 | } 299 | 300 | # All other lines are ignored. genfull never generates superflous lines 301 | # but you never know what people do themselves 302 | } 303 | } 304 | $/ = $delim; 305 | close INGRAPH; 306 | printverbose("Input call graph read\n"); 307 | return $HEADER; 308 | } 309 | 310 | 311 | 1; 312 | -------------------------------------------------------------------------------- /lib/CodeViz/IPC.pm: -------------------------------------------------------------------------------- 1 | # IPC.pm 2 | # 3 | # This package deals with client/daemon communication for codeviz. The 4 | # communicatgion mechanism is via a named pipe in /tmp so only one daemon 5 | # can exist at a time. The data sent is the arguments delimited by #()# 6 | 7 | package CodeViz::IPC; 8 | require Exporter; 9 | use vars qw(@ISA @EXPORT); 10 | use strict; 11 | use CodeViz::Format; 12 | use File::Temp qw/ tempfile tempdir /; 13 | use Cwd; 14 | use Cwd 'abs_path'; 15 | use Fcntl; 16 | no strict 'refs'; 17 | 18 | @ISA = qw(Exporter); 19 | @EXPORT = qw(&daemon_open &client_open &daemon_close &client_close &client_write &daemon_read); 20 | 21 | # PIPE for daemon and the input buffer for daemons 22 | # The pipe is opened with sysopen() and 23 | # accessed with sysread() and syswrite(). This was to avoid buffered IO and 24 | # have select() work as expected 25 | my $PIPE="/tmp/codeviz.pipe"; 26 | my $input_buffer; 27 | 28 | # Alternative LDSO, see gengraph for explanation 29 | my $LDSO=""; 30 | 31 | sub daemon_open() { 32 | my $flags = ''; 33 | printverbose("Opening pipe for reading\n"); 34 | 35 | # Check a pipe does not already exist and if it does, have it removed 36 | check_pipe_exists(); 37 | 38 | # Create new pipe 39 | printverbose("Creating input pipe\n"); 40 | system("$LDSO mkfifo -m 666 $PIPE"); 41 | if (! -p $PIPE) { die_nice("Failed to mknod pipe\n"); } 42 | 43 | # Open the pipe for reading 44 | if (!sysopen(DPIPE, $PIPE, O_RDONLY|O_NDELAY, 0666)) { 45 | die_nice("Failed to open $PIPE\n"); 46 | } 47 | } 48 | 49 | # Open pipe for writing. Used by the client writing parameters to the daemon 50 | sub client_open() { 51 | printverbose("Opening pipe for writing\n"); 52 | 53 | # Check that a pipe exists and is a pipe 54 | if (! -e $PIPE) { die_nice("ERROR: $PIPE does not exist"); } 55 | if (! -p $PIPE) { die_nice("ERROR: $PIPE is not a pipe"); } 56 | 57 | # Open the pipe for writing 58 | sysopen(DPIPE, $PIPE, O_WRONLY|O_SYNC) || die_nice("ERROR: Failed open $PIPE for writing\n"); 59 | } 60 | 61 | # Shutdown daemon 62 | sub daemon_close() { 63 | printverbose("Shuttdown down daemon\n"); 64 | 65 | # Check that a pipe exists and is a pipe 66 | if (! -e $PIPE) { print("Daemon is not running\n"); exit(-1); } 67 | if (! -p $PIPE) { print("Daemon is not running\n"); exit(-1); } 68 | 69 | # Open the pipe for writing or exit if it fails as a daemon 70 | if (!sysopen(DPIPE, $PIPE, O_WRONLY|O_NONBLOCK)) { 71 | print("Daemon is not running\n"); 72 | exit(-1); 73 | } 74 | 75 | # Shutdown remote daemon 76 | print DPIPE "QUIT\n"; 77 | close DPIPE; 78 | 79 | exit; 80 | } 81 | 82 | 83 | sub client_close() { 84 | printverbose("Closing input pipe\n"); 85 | close DPIPE; 86 | } 87 | 88 | # This function is called if gengraph is being used in client mode. 89 | sub client_write($$$$$$$$$$$$$$$$) { 90 | 91 | # Get parameters, matched exactly to gengraph 92 | my ($TRIM, $OUTPUT_TYPE, $ALL_LOCS, $LOCATION, $REVERSE, $FUNC, $FUNC_RX, $MAXDEPTH, $IGNORE, $IGNORE_RX, $SHOW, $SHOW_RX, $PLAIN_OUTPUT, $OUTPUT, $VERBOSE, $STDOUT) = @_; 93 | 94 | my $sleep_count; 95 | printverbose("Writing arguements to pipe\n"); 96 | 97 | # Set output if appropriate 98 | if ( $OUTPUT eq "--unset--" ) { 99 | ($OUTPUT) = split(/ /, $FUNC); 100 | $OUTPUT .= $OUTPUT_TYPE; 101 | } 102 | 103 | # Prepend path if necessary 104 | if ($OUTPUT !~ /^\//) { $OUTPUT = abs_path(&getcwd) . "/$OUTPUT"; } 105 | 106 | # Unlink graph if it already exists 107 | if ( -e $OUTPUT ) { unlink($OUTPUT); } 108 | 109 | # Create a temporary file to catch errors 110 | my $TEMPDIR = tempdir( CLEANUP => 0 ); 111 | my ($TMPFD, $TEMP) = tempfile( "codevizXXXX", DIR => $TEMPDIR ); 112 | close($TMPFD); 113 | printverbose("Opened $TEMP for error log\n"); 114 | 115 | # Call the daemon to generate the graph 116 | syswrite DPIPE, "$TRIM#()#$OUTPUT_TYPE#()#$ALL_LOCS#()#$LOCATION#()#$REVERSE#()#$FUNC#()#$FUNC_RX#()#$MAXDEPTH#()#$IGNORE#()#$IGNORE_RX#()#()#$SHOW#()#$SHOW_RX#()#$PLAIN_OUTPUT#()#$OUTPUT#()#$VERBOSE#()#$STDOUT#()#$TEMP#()#\n"; 117 | client_close(); 118 | 119 | # Wait 120 seconds until the error file or output file is created. If the 120 | # error file is created, watch it until something useful happens 121 | $sleep_count=1200; 122 | printverbose("Waiting for output or error log\n"); 123 | while ($sleep_count && (!-e $TEMP && ! -e $OUTPUT)) { 124 | $sleep_count--; 125 | select(undef, undef, undef, 0.1); 126 | } 127 | 128 | if (!$sleep_count) { print STDOUT "WARNING: Graph took longer than 120 seconds to generate. Gave up\n"; } 129 | 130 | # Either the output file or the error file exists 131 | if (!-e $OUTPUT) { 132 | $sleep_count=1200; 133 | printverbose("Waiting on error log\n"); 134 | while ($sleep_count && (! -e $OUTPUT)) { 135 | 136 | # Read a line from the error file 137 | open(ERRLOG, "$TEMP") || die_nice("Failed to open error log"); 138 | my $err_line = ; 139 | 140 | if ($err_line eq "FAILED\n") { 141 | $err_line = ; 142 | 143 | # Some buggy clients may be waiting on the existance of output 144 | open(OUTPUT, ">$OUTPUT"); 145 | 146 | # Unlink the temp files 147 | unlink($TEMP); 148 | unlink($TEMPDIR); 149 | 150 | print "Failed to create graph: $err_line"; 151 | exit; 152 | } 153 | close(ERRLOG); 154 | 155 | # Sleep for a tenth of a second 156 | $sleep_count--; 157 | select(undef, undef, undef, 0.1); 158 | } 159 | } 160 | 161 | # Unlink the temp files 162 | unlink($TEMP); 163 | unlink($TEMPDIR); 164 | 165 | 166 | if (!$sleep_count) { print STDOUT "WARNING: Graph took longer than 120 seconds to generate. Gave up\n"; } 167 | } 168 | 169 | # This function is used when in daemon mode to read input from the pipe. Input 170 | # is read in with sysread in large blocks and then broken up into lines and 171 | # returned to the caller line by line. Normal perl functions are not used 172 | # because they don't block even if there is no data avaialble meaning the 173 | # daemon would have to sleep and wake up every second checking for data 174 | sub daemon_read() { 175 | my $offset=-1; 176 | my $line; 177 | my $length; 178 | my ($bytes, $times); 179 | my ($rin, $rout); 180 | 181 | # Initialise the number of times to sleep 182 | $times = 13; 183 | 184 | printverbose("Waiting for input\n"); 185 | 186 | # Find if a full line has been read yet 187 | $offset = index $input_buffer, "\n"; 188 | 189 | # If a line is not ready, try and read some input 190 | while ($offset == -1) { 191 | 192 | # Use select() to block on pipe until data is available 193 | $rin = ''; 194 | vec($rin,fileno(DPIPE),1) = 1; 195 | select($rout=$rin, undef, undef, undef); 196 | 197 | # Read from the pipe 198 | $length = length($input_buffer); 199 | $bytes = sysread DPIPE, $input_buffer, 4096, $length; 200 | 201 | # Find if a full line has been read yet 202 | $offset = index $input_buffer, "\n"; 203 | 204 | # If no bytes were read, sleep for up to 3 seconds before reopening 205 | # the pipe so that a select() will block 206 | if (!$bytes && $offset == -1) { 207 | 208 | # Sleep for 0.1 second intervals for the first second and 1 second after 209 | $times--; 210 | if ($times > 3) { select(undef, undef, undef, 0.1); next; } 211 | else { sleep(1); next; } 212 | 213 | # Else reopen the pipe so the process will block on select() 214 | printverbose("Reopening pipe\n"); 215 | close(DPIPE); 216 | if (!sysopen(DPIPE, $PIPE, O_RDONLY|O_NDELAY, 0666)) { 217 | unlink($PIPE); 218 | die_nice("Failed to reopen $PIPE\n"); 219 | } 220 | } 221 | 222 | # Reset the number of times to sleep before reopening the pipe. Remember 223 | # that a partial line may only have been read this time around 224 | $times = 13; 225 | 226 | } 227 | 228 | # Read the line and truncate input_buffer to remove this line 229 | $line = substr $input_buffer, 0, $offset; 230 | $input_buffer = substr $input_buffer, $offset+1, length($input_buffer); 231 | 232 | # Check if we should exit. It is possible that some clients will lose their 233 | # requests if the daemon is really busy but thats too bad. The proper way 234 | # to fix this is have a global var indicating that the system is exiting 235 | # and then quit when no input is available from the pipe and input_buffer 236 | # is empty 237 | if ($line eq "QUIT") { 238 | printverbose("Exiting daemon\n"); 239 | pipe_close(); 240 | unlink($PIPE); 241 | exit; 242 | } 243 | 244 | # Parse the input line 245 | my @retarray; 246 | my $index=0; 247 | foreach (split(/#\(\)#/, $line)) { 248 | $retarray[$index] = $_; 249 | $index++; 250 | } 251 | 252 | return @retarray; 253 | } 254 | 255 | # Check if the pipe already exists and is active. If it is, this daemon exits. 256 | # Otherwise the pipe is simply unlinked 257 | sub check_pipe_exists() { 258 | printverbose("Checking for existing pipe\n"); 259 | if (-e $PIPE) { 260 | 261 | if (-p $PIPE) { 262 | # Open pipe 263 | if (sysopen(DPIPE, $PIPE, O_WRONLY|O_NDELAY, 0644)){ 264 | close(DPIPE); 265 | print("CodeViz daemon already appears to be running\n"); 266 | exit(-1); 267 | } 268 | } 269 | 270 | # Unlink the file that is there 271 | unlink($PIPE); 272 | } 273 | } 274 | 275 | 1; 276 | -------------------------------------------------------------------------------- /lib/CodeViz/Layout.pm: -------------------------------------------------------------------------------- 1 | # Layout.pm 2 | # 3 | # Module to layout graph elements in some eye pleasing manner depending on 4 | # the input algorithm 5 | # 6 | # doSpring() - Layout the nodes based on a spring algorithm 7 | 8 | package CodeViz::Layout; 9 | require Exporter; 10 | use vars qw (@ISA @EXPORT); 11 | use strict; 12 | no strict 'refs'; 13 | 14 | @ISA = qw(Exporter); 15 | @EXPORT = qw(&doSpring); 16 | 17 | # Spring Algorithm parameters 18 | my $relaxedLength = 2; 19 | my $springy = 2; 20 | 21 | sub doSpring { 22 | my %dag = @_; 23 | my $rLength = $relaxedLength; 24 | my $springC = $springy; 25 | my $springU = $springC * $rLength * $rLength / (2.718 * 2.718); 26 | my $relaxed = 0; 27 | my $loop=0; 28 | my $peakForce=0; 29 | my $lastForce=0; 30 | my $force; 31 | my $dForce; 32 | my ($x1, $y1, $z1, $x2, $y2, $z2); 33 | my ($dx, $dy, $dz); 34 | my ($rx, $ry, $rz); 35 | my ($fnode, $tnode); 36 | 37 | my %adjacentLabels; 38 | my @unadjacent; 39 | 40 | while (!$relaxed && $loop < 2000) { 41 | $loop++; 42 | if ($loop % 20 == 0) { print "Loop: $loop\n"; } 43 | $peakForce=0; 44 | 45 | foreach $fnode (%dag) { 46 | $x1 = $fnode->{'x'}; 47 | $y1 = $fnode->{'y'}; 48 | $z1 = $fnode->{'z'}; 49 | $dx=0; 50 | $dy=0; 51 | $dz=0; 52 | 53 | # Calculate adjacent nodes 54 | foreach $tnode (@{$fnode->{'targets'}}) { 55 | $adjacentLabels{$tnode->{'label'}} = 1; 56 | $x2 = $tnode->{'x'}; 57 | $y2 = $tnode->{'y'}; 58 | $z2 = $tnode->{'z'}; 59 | 60 | # Calculate difference between nodes 61 | $rx = $x2 - $x1; 62 | $ry = $y2 - $y1; 63 | $rz = $z2 - $z1; 64 | 65 | $rLength = getLength(0,0,0, $rx, $ry, $rz); 66 | $force = calcForce($rLength, 1); 67 | 68 | # Calculate distance to move 69 | $dx += $rx * ($force / $rLength); 70 | $dy += $ry * ($force / $rLength); 71 | $dz += $rz * ($force / $rLength); 72 | } 73 | 74 | # Calculate unadjacent nodes 75 | foreach $tnode (@{$fnode->{'targets'}}) { 76 | $adjacentLabels{$tnode->{'label'}} = 1; 77 | if ($adjacentLabels{$tnode->{'label'}} != 1) { 78 | $x2 = $tnode->{'x'}; 79 | $y2 = $tnode->{'y'}; 80 | $z2 = $tnode->{'z'}; 81 | 82 | # Calculate difference between nods 83 | $rx = $x2 - $x1; 84 | $ry = $y2 - $y1; 85 | $rz = $z2 - $z1; 86 | 87 | $rLength = getLength(0,0,0, $rx, $ry, $rz); 88 | $force = calcForce($rLength, 0); 89 | 90 | # Calculate distance to move 91 | $dx += $rx * ($force / $rLength); 92 | $dy += $ry * ($force / $rLength); 93 | $dz += $rz * ($force / $rLength); 94 | 95 | } 96 | } 97 | 98 | # Adjust position of node 99 | $fnode->{'x'} = $x1 + $dx; 100 | $fnode->{'y'} = $y1 + $dy; 101 | $fnode->{'z'} = $z1 + $dz; 102 | 103 | # Calculate force 104 | $dForce = getLength(0,0,0, $dx, $dy, $dz); 105 | if ($peakForce < $dForce) { $peakForce = $dForce; } 106 | if (abs($lastForce - $peakForce) < 0.2) { $relaxed=1; } 107 | } 108 | 109 | } 110 | } 111 | sub calcForce($$$) { 112 | my ($len, $adj) = @_; 113 | my $rel = $len / $relaxedLength; 114 | 115 | if ($adj) { 116 | if ($rel > 0) { return $springy * log($rel); } 117 | else { return -10; } 118 | } else { 119 | if ($rel > 0) { return -5 * $springy / ($rel * $rel); } 120 | else { return 10; } 121 | } 122 | } 123 | 124 | # Returns the distance between two points 125 | sub getLength($$$$$$) { 126 | my ($x1, $y1, $z1, $x2, $y2, $z2) = @_; 127 | my ($dx, $dy, $dz); 128 | my ($dsquared, $dist); 129 | 130 | $dx = ($x1 - $x2); 131 | $dy = ($y1 - $y2); 132 | $dz = ($z1 - $z2); 133 | 134 | $dsquared = $dx*$dx + $dy*$dy + $dz*$dz; 135 | $dist = sqrt($dsquared); 136 | 137 | return $dist; 138 | } 139 | -------------------------------------------------------------------------------- /lib/CodeViz/Output.pm: -------------------------------------------------------------------------------- 1 | # Output.pm 2 | # 3 | # This library delegates which handler should be used to render the dot 4 | # graph. Most output mechanisms are some wrapper around dot 5 | 6 | package CodeViz::Output; 7 | require Exporter; 8 | use File::Copy; 9 | use CodeViz::Format; 10 | use vars qw (@ISA @EXPORT); 11 | use strict; 12 | no strict 'refs'; 13 | 14 | @ISA = qw(Exporter); 15 | @EXPORT = qw(&renderGraph &test_dot_installed &test_dot_generate); 16 | 17 | my $DOT="dot"; # Path to dot program 18 | 19 | ## 20 | # renderGraph - Renders a graph in the desired output format 21 | # $type - Output format 22 | # $in - Filename of the input graph 23 | # $out - Filename to output the graph to 24 | sub renderGraph { 25 | my ($type, $in, $out) = @_; 26 | my $rendered=0; 27 | 28 | printverbose("Rendering graph for output type: $type\n"); 29 | if ($type eq "ps") { renderPostscript($in,$out); $rendered=1; } 30 | if ($type eq "postscript") { renderPostscript($in,$out); $rendered=1; } 31 | if ($type eq "gif") { renderGif($in,$out); $rendered=1; } 32 | if ($type eq "png") { renderPng($in,$out); $rendered=1; } 33 | if ($type eq "html") { renderHtml($in,$out,0); 34 | my $tmpout = $out; 35 | $tmpout =~ s/\.[a-zA-Z]*$//; 36 | $tmpout .= ".gif"; 37 | renderGif($in, $tmpout); $rendered=1; } 38 | if ($type eq "tersehtml") { renderHtml($in,$out,1); $rendered=1; } 39 | if ($type eq "plain") { renderPlain($in, $out); $rendered=1; } 40 | 41 | # Output functions are expected to output to $outputGraph.dot and 42 | # have it moved to the real filename here. This is for daemon mode 43 | # so that clients know the daemon is finished when and only when 44 | # the final graph appears 45 | if (-e "$out.dot") { move("$out.dot", $out); } 46 | 47 | # Return 1 if the output format was recognised 48 | return $rendered; 49 | } 50 | 51 | ## 52 | # renderPostscript - Render the graph in postscript with dot 53 | sub renderPostscript { 54 | my ($inputGraph, $outputGraph) = @_; 55 | printverbose("Rendering postscript with dot\n"); 56 | system("$DOT -Tps -o $outputGraph.dot 2>&1 > /dev/null < $inputGraph"); 57 | } 58 | 59 | ## 60 | # renderPlain - Just output it plain 61 | sub renderPlain { 62 | my ($inputGraph, $outputGraph) = @_; 63 | printverbose("Rendering plain output\n"); 64 | } 65 | 66 | ## 67 | # renderGif - Render the graph in gif format with dot 68 | sub renderGif { 69 | my ($inputGraph, $outputGraph) = @_; 70 | printverbose("Rendering gif with dot\n"); 71 | system("$DOT -Tgif -o $outputGraph.dot 2>&1 > /dev/null < $inputGraph"); 72 | move("$outputGraph.dot", $outputGraph); 73 | } 74 | 75 | ## 76 | # renderPng - Render the graph in png format with dot 77 | sub renderPng { 78 | my ($inputGraph, $outputGraph) = @_; 79 | printverbose("Rendering png with dot\n"); 80 | system("$DOT -Tpng -o $outputGraph.dot 2>&1 > /dev/null < $inputGraph"); 81 | move("$outputGraph.dot", $outputGraph); 82 | } 83 | 84 | 85 | ## 86 | # renderHtml - Render a graph in HTML format 87 | sub renderHtml { 88 | my ($inputGraph, $outputGraph, $tersehtml) = @_; 89 | 90 | # Remove terse from teh extension name if necessary 91 | if ($tersehtml) { $outputGraph =~ s/tersehtml$/html/; } 92 | 93 | # Render GIF first 94 | renderGif($inputGraph, $outputGraph); 95 | 96 | printverbose("Generating HTML files\n"); 97 | my $base= ( $outputGraph =~ /(.*)\..*$/ )[0]; 98 | if ($base eq "") { $base = $outputGraph; } 99 | 100 | # generate and read the image-map 101 | my $cmapfile= "$base.cmap"; 102 | system("$DOT -Tcmap -o $cmapfile < $inputGraph"); 103 | open( CMAP, "< $cmapfile"); 104 | my @cmap= ; 105 | close CMAP; 106 | 107 | # create the HTML file for the function. 108 | my $funchtml= "$base.html"; 109 | my @html; 110 | if (!$tersehtml) { 111 | @html = < 113 | 114 | %%FUNC%%() 115 | %%CMAP%% 116 | 117 | 118 |

%%FUNC%%()

119 | 120 | 121 | 122 | EOF 123 | } else { 124 | @html = <%%CMAP%% 126 | 127 | EOF 128 | } 129 | 130 | printverbose("Generating main HTML: $funchtml\n"); 131 | open( HTML, "> $funchtml"); 132 | # this works b/c $base <= $OUTPUT <= $afunc <= the first func in the list. 133 | print HTML map { s/%%FUNC%%/$base/g; s/%%CMAP%%/@cmap/; $_ } @html; 134 | close HTML; 135 | 136 | } 137 | 138 | ## 139 | # test_dot_installed - Finds the path to dot from the graphviz package 140 | sub test_dot_installed() { 141 | my $dir; 142 | my $found=''; 143 | printverbose("Testing GraphViz\n"); 144 | 145 | if ( ! -e $DOT ) { 146 | # Check that dot is in path 147 | foreach $dir (split(/:/, $ENV{"PATH"})) { 148 | if (-e "$dir/dot") { if ($found eq '') {$found=$dir;} } 149 | } 150 | 151 | if ($found eq '') { 152 | die_nice("dot from GraphViz could not be found in the path. Install GraphViz 153 | from your distribution CD or download from http://www.graphviz.org/ . 154 | 155 | Daemon exiting\n"); 156 | } else { $DOT = "$found/dot"; } 157 | } 158 | 159 | printverbose("Dot found at: $DOT\n"); 160 | } 161 | 162 | # Test that dot can generate proper graphs 163 | # $type - Test for a given output type. Currently only gif is tested as it is only weird one 164 | # $header - The header to use for generating graphs. Should be read from full.graph 165 | # returns - The header that was finally used to generate graphs 166 | sub test_dot_generate($$$) { 167 | my ($type, $font, $header) = @_; 168 | my $line; 169 | 170 | if ($type eq "ps" || $type eq "postscript") { 171 | # Check that dot can generate a postscript graph 172 | printverbose("Testing GraphViz Postscript Generation\n"); 173 | unlink("/tmp/codeviz_test.ps"); 174 | open(TPIPE, "|$DOT -Tps -o /tmp/codeviz_test.ps"); 175 | print TPIPE $header; 176 | print TPIPE "code -> viz;\n"; 177 | print TPIPE "};"; 178 | close TPIPE; 179 | if (! -e "/tmp/codeviz_test.ps") { 180 | die_nice("Dot is unable to generate a simple postscript file in /tmp/\n"); 181 | } 182 | unlink("/tmp/codeviz_test.ps"); 183 | } 184 | 185 | if ($type eq "gif" || $type =~ /html/) { 186 | # Check that dot can generate a GIF graph 187 | printverbose("Testing GraphViz GIF Generation with $font\n"); 188 | unlink("/tmp/codeviz_test.gif"); 189 | open(TPIPE, "|$DOT -Tgif -o /tmp/codeviz_test.gif 2> /tmp/codeviz.err"); 190 | print TPIPE $header; 191 | print TPIPE "code -> viz;\n"; 192 | print TPIPE "};"; 193 | close TPIPE; 194 | if (! -e "/tmp/codeviz_test.gif") { 195 | printverbose("Generation with $font failed. Trying Arial\n"); 196 | } 197 | 198 | # Check that no error occured while generating GIFs. On my machine, 199 | # $font cannot be used to generate GIFs but Arial can. This is not a 200 | # critical error but the GIF output is horrible otherwise 201 | if (open (TPIPE, "/tmp/codeviz.err")) { 202 | $line = ; 203 | close TPIPE; 204 | if ($line =~ /Could not find/ || ! -e "/tmp/codeviz_test.gif") { 205 | # An error occured :-( 206 | # Check if this works with the Arial font. Dot on my machine wouldn't 207 | # work with $font but did with Arial. I am guessing that Arial is 208 | # a much more common format 209 | printwarning("Cannot render with $font font. Falling back to Arial\n"); 210 | $header =~ s/$font/Arial/; 211 | open(TPIPE, "|$DOT -Tgif -o /tmp/codeviz_test.gif 2> /tmp/codeviz.err"); 212 | print TPIPE $header; 213 | print TPIPE "code -> viz;\n"; 214 | print TPIPE "};"; 215 | close TPIPE; 216 | 217 | # Test for errors again 218 | if (open (TPIPE, "/tmp/codeviz.err")) { 219 | $line = ; 220 | close TPIPE; 221 | if ($line =~ /Could not find/) { 222 | print STDERR "\nWARNING: Could not generate GIFs with $font or Arial fonts\n"; 223 | print STDERR " GIF call graphs generated for browsers are likely to\n"; 224 | print STDERR " to look horrible. On Debian, this fonts are available\n"; 225 | print STDERR " with the msttcorefonts package. Other distributions\n"; 226 | print STDERR " should have similar packages.\n\n"; 227 | } 228 | } 229 | } 230 | } 231 | unlink("/tmp/codeviz.err"); 232 | unlink("/tmp/codeviz_test.gif"); 233 | } 234 | 235 | return $header; 236 | } 237 | 238 | 1; 239 | -------------------------------------------------------------------------------- /lib/CodeViz/PPCStack.pm: -------------------------------------------------------------------------------- 1 | # PPCStack.pm 2 | # 3 | # This is a post-processing module that uses the cumulative stackusage 4 | # between pairs of functions. A pair is separated by a - and subsequent 5 | # pairs are separated by a , 6 | 7 | package CodeViz::PPCStack; 8 | require Exporter; 9 | use vars qw (@ISA @EXPORT); 10 | use strict; 11 | use CodeViz::Graph; 12 | use CodeViz::Format; 13 | no strict 'refs'; 14 | 15 | @ISA = qw(Exporter); 16 | @EXPORT = qw(&PPCStack); 17 | 18 | my @path; 19 | 20 | sub usage() { 21 | print < $to)"); 92 | return; 93 | } 94 | if ($$ingraph{$to} != 1) { 95 | printerror("Function $to is not in the output graph, ignoring cumulative stack usage for pair ($from -> $to)"); 96 | return; 97 | } 98 | 99 | # Find the path between the two functions 100 | my %visited; 101 | my $i; 102 | undef @path; 103 | my $found = findPath($from, $to, $dag, $ingraph, \%visited, 0); 104 | 105 | # Return as failure if a path was not found 106 | if ($found == 0) { 107 | printerror("No path between $from and $to was found, ignoring this pair"); 108 | return; 109 | } 110 | 111 | # Calculate the cumulative stack usage for the node 112 | my $usage = $startUsage; 113 | my $i; 114 | for ($i = 0; $i <= $#path; $i++) { 115 | # Check if this node has had usage set already 116 | my $thisCUsage = getNodeAttribute("cstackuse", \$$dag{$path[$i]}); 117 | if ($thisCUsage != 0) { 118 | printerror("Node " . $path[$i] . " already has cumulative usage calculated($thisCUsage), skipping\n"); 119 | next; 120 | } 121 | 122 | # Calculate the cumulative usage for this node and set 123 | my $thisUsage = getNodeAttribute("stackuse", \$$dag{$path[$i]}); 124 | $usage += $thisUsage; 125 | setNodeAttribute("cstackuse", $usage, \$$dag{$path[$i]}); 126 | 127 | # Color the node. Light blue normal, dark blue if using too much 128 | setNodeAttribute("style", "filled, bold", \$$dag{$path[$i]}); 129 | if ($usage > $largeUsage) { 130 | setNodeAttribute("fillcolor", "#5050A0", \$$dag{$path[$i]}); 131 | } else { 132 | setNodeAttribute("fillcolor", "#A0A0F0", \$$dag{$path[$i]}); 133 | } 134 | 135 | # Set the node label 136 | my $label = getNodeAttribute("label", \$$dag{$path[$i]}); 137 | if ($label ne "") { $label .= "\\ncstackuse=$usage"; } 138 | else { $label = $path[$i] . "\\ncstackuse=$usage"; } 139 | setNodeAttribute("label", $label, \$$dag{$path[$i]}); 140 | } 141 | 142 | } 143 | 144 | ## 145 | # Find a path between two functions. Paths which involve functions that 146 | # are not in the call graph are ignored. Otherwise, it is a bog-standard 147 | # depth-first recursive search of the graph 148 | sub findPath { 149 | my ($nodeName, $to, $dag, $ingraph, $path, $visited, $depth) = @_; 150 | 151 | printverbose("Searching: $nodeName\n"); 152 | 153 | # If we have already visited this node, return 154 | if ($$visited{$nodeName} == 1) { return 0; } 155 | $$visited{$nodeName} = 1; 156 | 157 | # Return fail if this node is not in the output graph 158 | if ($$ingraph{$nodeName} != 1) { return 0; } 159 | 160 | # Return success if we have found the desired node 161 | if ($nodeName eq $to) { 162 | printverbose("Path found\n"); 163 | $path[$depth] = $nodeName; 164 | return 1; 165 | } 166 | 167 | # Else we need to continue searching 168 | my $node; 169 | my @callers = @{$$dag{$nodeName}->{'callees'}}; 170 | foreach $node (@callers) { 171 | my $found = findPath($$node->{'name'}, $to, $dag, $ingraph, $path, $visited, $depth+1); 172 | if ($found == 1) { 173 | # Hurray, this node was in the desired path 174 | $path[$depth] = $nodeName; 175 | return 1; 176 | } 177 | } 178 | 179 | # Was not found anywhere below this node 180 | return 0; 181 | } 182 | 183 | 1; 184 | -------------------------------------------------------------------------------- /lib/CodeViz/PPOprofile.pm: -------------------------------------------------------------------------------- 1 | # PPStack.pm 2 | # 3 | # This is a post-processing module that uses an excerpt from oprofile 4 | # to determine how much time was spent in each function 5 | 6 | package CodeViz::PPOprofile; 7 | require Exporter; 8 | use vars qw (@ISA @EXPORT); 9 | use strict; 10 | use CodeViz::Graph; 11 | use CodeViz::Format; 12 | no strict 'refs'; 13 | 14 | @ISA = qw(Exporter); 15 | @EXPORT = qw(&PPOprofile); 16 | 17 | sub usage() { 18 | print <; 61 | $fieldno = 1; 62 | my $lastfield; 63 | foreach $field (split /\s+/, $line) { 64 | if ($fieldno == $eventfield) { 65 | $eventvalue = $field; 66 | } 67 | $lastfield = $field; 68 | $fieldno++; 69 | } 70 | $funccosts{$lastfield} = $eventvalue; 71 | } 72 | close(PROFILE); 73 | printverbose("PPOprofile: Closed profile\n"); 74 | 75 | # Process the full graph 76 | printverbose("PPOprofile: Processing graph\n"); 77 | foreach $func (keys %$dag) { 78 | 79 | # Get the node label and stack usage information 80 | my $label = getNodeAttribute("label", \$$dag{$func}); 81 | 82 | if ($funccosts{$func} == 0) { 83 | $funccosts{$func} = 0; 84 | } 85 | 86 | # Add the function cost label 87 | if ($label ne "") { $label .= "\\ncost=$funccosts{$func}"; } 88 | else { $label = "$func\\ncost=$funccosts{$func}"; } 89 | setNodeAttribute("label", $label, \$$dag{$func}); 90 | } 91 | printverbose("PPOprofile: Done\n"); 92 | } 93 | 94 | 1; 95 | -------------------------------------------------------------------------------- /lib/CodeViz/PPStack.pm: -------------------------------------------------------------------------------- 1 | # PPStack.pm 2 | # 3 | # This is a post-processing module that uses the stackusage information in 4 | # full.graph to alter the output graph generated by gengraph appropriately 5 | # See the usage function for the options 6 | 7 | package CodeViz::PPStack; 8 | require Exporter; 9 | use vars qw (@ISA @EXPORT); 10 | use strict; 11 | use CodeViz::Graph; 12 | use CodeViz::Format; 13 | no strict 'refs'; 14 | 15 | @ISA = qw(Exporter); 16 | @EXPORT = qw(&PPStack); 17 | 18 | sub usage() { 19 | print <= $largestack) { 73 | setNodeAttribute("fillcolor", "#F00000", \$$dag{$func}); 74 | setNodeAttribute("style", "filled", \$$dag{$func}); 75 | } 76 | 77 | } 78 | 79 | } 80 | 81 | 1; 82 | -------------------------------------------------------------------------------- /lib/CodeViz/SourceMarkup.pm: -------------------------------------------------------------------------------- 1 | # SourceMarkup.pm 2 | # 3 | # This file contains a routine to render source as HTML files 4 | # 5 | package CodeViz::SourceMarkup; 6 | require Exporter; 7 | use File::Copy; 8 | use CodeViz::Format; 9 | use CodeViz::Output; 10 | use vars qw (@ISA @EXPORT); 11 | use strict; 12 | no strict 'refs'; 13 | 14 | @ISA = qw(Exporter); 15 | @EXPORT = qw(&sourceMarkup &test_shighlight_installed); 16 | 17 | my $SHIGHLIGHT="source-highlight"; 18 | 19 | sub sourceMarkup($$$$) { 20 | my ($css, $sourceRoot, $sourceHighlight, $sourceFiles) = @_; 21 | 22 | if ($sourceHighlight) { sourceHighlight($css, $sourceRoot, $sourceFiles); } 23 | else { 24 | 25 | print("WARNING: --shighlight must be specified to have HTML-marked up pages. Requires source-highlight to be installed.\n"); 26 | } 27 | } 28 | 29 | sub sourceHighlight($$$$) { 30 | my ($css, $sourceRoot, $sourceFilesPtr) = @_; 31 | my %sourceFiles = %$sourceFilesPtr; 32 | 33 | if ($css ne "") { $css = "-c $css"; } 34 | 35 | # Create root directory for HTML files 36 | my $htmlroot = "$sourceRoot/html_sources"; 37 | mkdir($htmlroot); 38 | 39 | foreach my $source ( keys %sourceFiles ) { 40 | my $htmlpath = "$htmlroot/"; 41 | my $pathpart; 42 | my $sourcepath = $source; 43 | 44 | # Create the directory needed to store the HTML file 45 | $sourcepath =~ /(.*)\/.*$/; $sourcepath=$1; 46 | foreach $pathpart (split /\//, $sourcepath) { 47 | $htmlpath .= "$pathpart/"; 48 | mkdir($htmlpath); 49 | } 50 | 51 | # Generate the HTML source file 52 | my $htmlfile= "$htmlroot/$source.html"; 53 | printverbose("Processing source file: $sourceRoot/$source\n"); 54 | if ( -e "$sourceRoot/$source" ) { 55 | printverbose("Generating source HTML: $htmlfile\n"); 56 | open( SOURCE, "$SHIGHLIGHT $css -i $sourceRoot/$source -n -s cpp --out-format=html |"); 57 | open( HTML, "> $htmlfile") || die("Failed to open HTML file: $htmlfile"); 58 | while ( ) { 59 | s,^(\d+): (.span class="function".(\w+)./span.),$1<\/A>: $2, 60 | if /class="function"/; 61 | print HTML; 62 | } 63 | close HTML; 64 | close SOURCE; 65 | } 66 | } 67 | } 68 | 69 | # Test to see if source-highlight is installed 70 | sub test_shighlight_installed() { 71 | my $dir; 72 | my $found=''; 73 | 74 | printverbose("Testing source-highlight\n"); 75 | 76 | if ( ! -e $SHIGHLIGHT ) { 77 | # Check that dot is in path 78 | foreach $dir (split(/:/, $ENV{"PATH"})) { 79 | if (-e "$dir/source-highlight") { if ($found eq '') {$found=$dir;} } 80 | } 81 | 82 | if ($found eq '') { 83 | print("Notice: source-highlight could not be found in the path. HTML-marked up source will not be generated\n"); 84 | } else { $SHIGHLIGHT = "$found/source-highlight"; } 85 | } 86 | 87 | printverbose("Source-highlight found at: $SHIGHLIGHT\n"); 88 | } 89 | 90 | 91 | -------------------------------------------------------------------------------- /lib/CodeViz/VRML.pm: -------------------------------------------------------------------------------- 1 | # VRML.pm 2 | # VRML Render package for graphs in perl. Each node in the graph is expected 3 | # to be a hash array 4 | # 5 | # (c) Mel Gorman 2002 6 | 7 | package CodeViz::VRML; 8 | use Math::Complex; 9 | require Exporter; 10 | use vars qw (@ISA @EXPORT); 11 | use strict; 12 | no strict 'refs'; 13 | 14 | @ISA = qw(Exporter); 15 | @EXPORT = qw(&VRMLRender &createCamera); 16 | 17 | my %cameras; 18 | my $numCameras=0; 19 | 20 | # Graph drawing parameters 21 | my $NODE_RADIUS = 0.5; # Radius of a node 22 | my $NODE_COLOR = "1 0.95 0.7"; # Color of a node 23 | my $DUMB_RADIUS = 0.25; # Radius of a dummy node 24 | my $DUMB_COLOR = "1 0 0"; # Color of a dummy node 25 | my $EDGE_DIAMETER = 0.1; # Diameter of an edge 26 | my $EDGE_COLOR = "0.5 0.5 1"; # Color of an edge 27 | my $SKY_COLOR = "0.9 0.9 1"; # Color of the background 28 | my $FONT_SIZE = 1; # Font size 29 | my $TRANSPARENCY = "0.5"; # How transparent items are 30 | 31 | # Subroutine to render a supplied DAG to the output filename 32 | sub VRMLRender { 33 | my ($outputFile, %dag) = @_; 34 | my ($callernode, $calleenode); 35 | 36 | # Open output file 37 | if (!open(VRML, ">$outputFile")) { 38 | print "Failed to open output VRML file ($outputFile)\n"; 39 | return 0; 40 | } 41 | 42 | printVRMLHead(); 43 | 44 | # Render all nodes 45 | foreach $callernode (%dag) { 46 | printVRMLNode(\$callernode); 47 | } 48 | 49 | # Render all edges 50 | foreach $callernode (%dag) { 51 | foreach $calleenode (@{$callernode->{'targets'}}) { 52 | 53 | printVRMLEdge(\$callernode, $calleenode); 54 | } 55 | } 56 | printVRMLFoot(); 57 | close VRML; 58 | } 59 | 60 | sub createCamera { 61 | my ($x, $y, $z) = @_; 62 | 63 | $cameras{$numCameras}->{'x'} = $x; 64 | $cameras{$numCameras}->{'y'} = $y; 65 | $cameras{$numCameras}->{'z'} = $z; 66 | $numCameras++; 67 | } 68 | 69 | sub printVRMLHead { 70 | my ($x, $y, $z, $index); 71 | 72 | print VRML <{'x'}; 81 | $y = $cameras{$index}->{'y'}; 82 | $z = $cameras{$index}->{'z'}; 83 | print VRML <{'x'}; 132 | $y1 = $$fnode->{'y'}; 133 | $z1 = $$fnode->{'z'}; 134 | $x2 = $$tnode->{'x'}; 135 | $y2 = $$tnode->{'y'}; 136 | $z2 = $$tnode->{'z'}; 137 | 138 | 139 | $mx = ($x1 + $x2) / 2; 140 | $my = ($y1 + $y2) / 2; 141 | $mz = ($z1 + $z2) / 2; 142 | 143 | $dx = ($x1 - $x2); 144 | $dy = ($y1 - $y2); 145 | $dz = ($z1 - $z2); 146 | 147 | $dist = getLength($x1, $y1, $z1, $x2, $y2, $z2); 148 | 149 | if ($dy == 0) { $dy = 0.01; } 150 | if ($dist == 0) { $dist = 0.01; } 151 | 152 | $rx = -atan(-$dz/$dy); 153 | $rf = asin($dx/$dist); 154 | 155 | $dy = -$dy; 156 | $dist -= 1; 157 | 158 | print VRML <{'x'}; 192 | $y = $$node->{'y'}; 193 | $z = $$node->{'z'}; 194 | $tx = $x; 195 | $ty = $y; 196 | $tz = $z; 197 | $label = $$node->{'label'}; 198 | if ($label eq "") { return; } 199 | 200 | # Try and center the text a bit 201 | $len = length($label); 202 | $tx -= $len / 8; 203 | 204 | print VRML < "printf" [label="lib.c:6"]; 8 | "_processStream" -> "_processStream" [label="lib.c:9"]; 9 | "processStream" -> "_processStream" [label="lib.c:15"]; 10 | "manipulateStream" -> "printf" [label="lib.c:19"]; 11 | "main" -> "printf" [label="main.c:15 main.c:10"]; 12 | "main" -> "malloc" [label="main.c:13"]; 13 | "main" -> "exit" [label="main.c:30 main.c:16"]; 14 | "main" -> "processStream" [label="main.c:25"]; 15 | "main" -> "manipulateStream" [label="main.c:26"]; 16 | "main" -> "free" [label="main.c:29"]; 17 | } -------------------------------------------------------------------------------- /testsuite/c/expected-sub.graph: -------------------------------------------------------------------------------- 1 | digraph fullgraph { 2 | node [ fontname=Helvetica, fontsize=12 ]; 3 | rankdir=TB; 4 | "main" -> "printf"; 5 | "main" -> "malloc"; 6 | "main" -> "exit"; 7 | "main" -> "processStream"; 8 | "processStream" -> "_processStream"; 9 | "_processStream" -> "printf"; 10 | "_processStream" -> "_processStream"; 11 | "main" -> "manipulateStream"; 12 | "manipulateStream" -> "printf"; 13 | "main" -> "free"; 14 | "main" [ fillcolor="#dddddd", style="filled,bold", shape="box" ]; 15 | } 16 | -------------------------------------------------------------------------------- /testsuite/c/header.h: -------------------------------------------------------------------------------- 1 | #ifndef __HEADER_H 2 | #define __HEADER_H 3 | 4 | int processStream(char *byteStream, int length); 5 | int manipulateStream(char *byteStream, int length); 6 | 7 | #endif 8 | -------------------------------------------------------------------------------- /testsuite/c/lib.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "header.h" 3 | 4 | /* This is stupid obviously, am looking for a type of graph */ 5 | int _processStream(char *byteStream, int length, int depth) { 6 | printf("At depth %d\n", depth); 7 | if (length != depth) { 8 | byteStream[depth]++; 9 | _processStream(byteStream, length, depth+1); 10 | } 11 | return 0; 12 | } 13 | 14 | int processStream(char *byteStream, int length) { 15 | return _processStream(byteStream, length, 0); 16 | } 17 | 18 | int manipulateStream(char *byteStream, int length) { 19 | printf("Called manipulateStream\n"); 20 | return 1; 21 | } 22 | 23 | -------------------------------------------------------------------------------- /testsuite/c/main.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "header.h" 4 | 5 | #define STREAM_LENGTH 100 6 | 7 | int main() { 8 | char *stream; 9 | int i; 10 | printf("Starting test program\n"); 11 | 12 | /* Allocate stream */ 13 | stream = malloc(STREAM_LENGTH * sizeof(char)); 14 | if (stream == NULL) { 15 | printf("malloc() failed\n"); 16 | exit(EXIT_FAILURE); 17 | } 18 | 19 | /* Fill in information */ 20 | for (i = 0; i < STREAM_LENGTH; i++) { 21 | stream[i] = i; 22 | } 23 | 24 | /* Call other functions */ 25 | processStream(stream, STREAM_LENGTH); 26 | manipulateStream(stream, STREAM_LENGTH); 27 | 28 | /* Free stream and exit */ 29 | free(stream); 30 | exit(EXIT_SUCCESS); 31 | } 32 | -------------------------------------------------------------------------------- /testsuite/cpp/Makefile: -------------------------------------------------------------------------------- 1 | CXX=/usr/local/gccgraph/bin/g++ 2 | CFLAGS=-Wall -g 3 | TESTSUITE_OBJS = main.o classname.o 4 | 5 | %.o: %.c 6 | $(CXX) -c -o $@ $< $(CFLAGS) 7 | 8 | all: testsuite 9 | ../../bin/genfull -g cppdepn 10 | ../../bin/gengraph -f main -k 11 | mv sub.graph sub.graph-default 12 | ../../bin/gengraph -f main -k --ignore-re '.*::operator.*' 13 | mv sub.graph sub.graph-trimmed 14 | ./checkgraphs.sh 15 | 16 | testsuite: $(TESTSUITE_OBJS) 17 | $(CXX) -o $@ $^ $(CFLAGS) 18 | 19 | clean: 20 | rm -f $(TESTSUITE_OBJS) testsuite full.graph sub.graph* *.ps *.cdepn core 21 | -------------------------------------------------------------------------------- /testsuite/cpp/Makefile.in: -------------------------------------------------------------------------------- 1 | CXX=@@GCCGRAPH@@ 2 | CFLAGS=-Wall -g 3 | TESTSUITE_OBJS = main.o classname.o 4 | 5 | %.o: %.c 6 | $(CXX) -c -o $@ $< $(CFLAGS) 7 | 8 | all: testsuite 9 | ../../bin/genfull -g cppdepn 10 | ../../bin/gengraph -f main -k 11 | mv sub.graph sub.graph-default 12 | ../../bin/gengraph -f main -k --ignore-re '.*::operator.*' 13 | mv sub.graph sub.graph-trimmed 14 | ./checkgraphs.sh 15 | 16 | testsuite: $(TESTSUITE_OBJS) 17 | $(CXX) -o $@ $^ $(CFLAGS) 18 | 19 | clean: 20 | rm -f $(TESTSUITE_OBJS) testsuite full.graph sub.graph* *.ps *.cdepn core 21 | -------------------------------------------------------------------------------- /testsuite/cpp/checkgraphs.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Check existance of files 4 | if [ ! -e full.graph ]; then 5 | echo full.graph does not exist 6 | exit 1 7 | fi 8 | if [ ! -e sub.graph-default ]; then 9 | echo sub.graph-default does not exist 10 | exit 1 11 | fi 12 | if [ ! -e sub.graph-trimmed ]; then 13 | echo sub.graph-trimmed does not exist 14 | exit 1 15 | fi 16 | 17 | # Check differences 18 | FULL=`diff expected-full.graph full.graph | wc -l` 19 | SUB_DEFAULT=`diff expected-sub.graph-default sub.graph-default | wc -l` 20 | SUB_TRIMMED=`diff expected-sub.graph-trimmed sub.graph-trimmed | wc -l` 21 | 22 | if [ "$FULL" != "0" ]; then 23 | echo Line count on full.graph does not match 24 | exit 1 25 | fi 26 | if [ "$SUB_DEFAULT" != "0" ]; then 27 | echo Line count on sub.graph-default does not match 28 | exit 1 29 | fi 30 | 31 | if [ "$SUB_TRIMMED" != "0" ]; then 32 | echo Line count on sub.graph-trimmed does not match 33 | exit 1 34 | fi 35 | 36 | # All good 37 | echo Graphs match expected output 38 | exit 0 39 | -------------------------------------------------------------------------------- /testsuite/cpp/classheader.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Simple declaration for a supporting class 3 | */ 4 | #ifndef __CLASSHEADER_H 5 | #define __CLASSHEADER_H 6 | 7 | class classname { 8 | private: 9 | int privateValue1; 10 | int privateValue2; 11 | int sum; 12 | 13 | void setValue1(int val) { 14 | privateValue1 = val; 15 | sum = privateValue1 + privateValue2; 16 | } 17 | 18 | void setValue2(int val) { 19 | privateValue2 = val; 20 | sum = privateValue1 + privateValue2; 21 | } 22 | 23 | public: 24 | void setValues(int val1, int val2); 25 | void printValues(); 26 | }; 27 | 28 | #endif 29 | -------------------------------------------------------------------------------- /testsuite/cpp/classname.cc: -------------------------------------------------------------------------------- 1 | /* 2 | * Implementation of classname 3 | */ 4 | #include "classheader.h" 5 | #include 6 | #include 7 | 8 | using namespace std; 9 | 10 | void classname::setValues(int val1, int val2) { 11 | setValue1(val1); 12 | setValue2(val2); 13 | } 14 | 15 | void classname::printValues() { 16 | cout << "Value 1: " < "std::operator<<(std::basic_ostream&,const char*) [with _Traits = std::char_traits]"; 5 | "main()" -> "simpleStaticFunc(int,int)"; 6 | "simpleStaticFunc(int,int)" -> "simpleStaticFunc(int,int,int)"; 7 | "main()" -> "classname::setValues(int,int)"; 8 | "classname::setValues(int,int)" -> "classname::setValue1(int)"; 9 | "classname::setValues(int,int)" -> "classname::setValue2(int)"; 10 | "main()" -> "classname::printValues()"; 11 | "classname::printValues()" -> "_Traits>::operator<<(std::basic_ostream<_CharT,_Traits>&(*)(std::basic_ostream<_CharT,_Traits>&)) [with _CharT = char,_Traits = std::char_traits]"; 12 | "classname::printValues()" -> "_Traits>::operator<<(int) [with _CharT = char,_Traits = std::char_traits]"; 13 | "_Traits>::operator<<(int) [with _CharT = char,_Traits = std::char_traits]" -> "std::operator&(std::_Ios_Fmtflags,std::_Ios_Fmtflags)"; 14 | "_Traits>::operator<<(int) [with _CharT = char,_Traits = std::char_traits]" -> "std::ios_base::flags() const"; 15 | "_Traits>::operator<<(int) [with _CharT = char,_Traits = std::char_traits]" -> "_Traits>::operator<<(long unsigned int) [with _CharT = char,_Traits = std::char_traits]"; 16 | "_Traits>::operator<<(int) [with _CharT = char,_Traits = std::char_traits]" -> "_Traits>::operator<<(long int) [with _CharT = char,_Traits = std::char_traits]"; 17 | "classname::printValues()" -> "std::operator<<(std::basic_ostream&,const char*) [with _Traits = std::char_traits]"; 18 | "main()" -> "exit(int)"; 19 | "_Traits>::operator<<(std::basic_ostream<_CharT,_Traits>&(*)(std::basic_ostream<_CharT,_Traits>&)) [with _CharT = char,_Traits = std::char_traits]" [ with _CharT =" char," ]; 20 | "main()" [ fillcolor="#dddddd", style="filled,bold", shape="box" ]; 21 | "_Traits>::operator<<(int) [with _CharT = char,_Traits = std::char_traits]" [ with _CharT =" char," ]; 22 | } 23 | -------------------------------------------------------------------------------- /testsuite/cpp/expected-sub.graph-trimmed: -------------------------------------------------------------------------------- 1 | digraph fullgraph { 2 | node [ fontname=Helvetica, fontsize=12 ]; 3 | rankdir=TB; 4 | "main()" -> "simpleStaticFunc(int,int)"; 5 | "simpleStaticFunc(int,int)" -> "simpleStaticFunc(int,int,int)"; 6 | "main()" -> "classname::setValues(int,int)"; 7 | "classname::setValues(int,int)" -> "classname::setValue1(int)"; 8 | "classname::setValues(int,int)" -> "classname::setValue2(int)"; 9 | "main()" -> "classname::printValues()"; 10 | "main()" -> "exit(int)"; 11 | "main()" [ fillcolor="#dddddd", style="filled,bold", shape="box" ]; 12 | } 13 | -------------------------------------------------------------------------------- /testsuite/cpp/main.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "classheader.h" 4 | 5 | using namespace std; 6 | 7 | int simpleStaticFunc(int a, int b, int c) { 8 | /* ooh, fear the magic */ 9 | return a + b + c; 10 | } 11 | int simpleStaticFunc(int a, int b) { 12 | return simpleStaticFunc(a, b, 0); 13 | } 14 | 15 | int main() { 16 | int a = 5, b = 10, c; 17 | cout <<"Starting test program\n"; 18 | 19 | /* Call the statics */ 20 | c = simpleStaticFunc(a, b); 21 | 22 | /* Work with the class */ 23 | classname *workerClass = new classname(); 24 | workerClass->setValues(5, 4); 25 | workerClass->printValues(); 26 | 27 | exit(EXIT_SUCCESS); 28 | } 29 | --------------------------------------------------------------------------------