├── CMakeLists.txt ├── COPYING ├── MANIFEST ├── NEWS ├── README ├── README.ctracer ├── cmake └── modules │ └── FindDWARF.cmake ├── codiff.c ├── config.h.cmake ├── ctf.h ├── ctf_encoder.c ├── ctf_encoder.h ├── ctf_loader.c ├── ctfdwdiff ├── ctracer.c ├── dtagnames.c ├── dutil.c ├── dutil.h ├── dwarf_loader.c ├── dwarves.c ├── dwarves.h ├── dwarves_emit.c ├── dwarves_emit.h ├── dwarves_fprintf.c ├── dwarves_reorganize.c ├── dwarves_reorganize.h ├── elf_symtab.c ├── elf_symtab.h ├── elfcreator.c ├── elfcreator.h ├── gobuffer.c ├── gobuffer.h ├── hash.h ├── lib ├── Makefile ├── ctracer_relay.c ├── ctracer_relay.h └── linux.blacklist.cu ├── libctf.c ├── libctf.h ├── list.h ├── man-pages └── pahole.1 ├── ostra ├── ostra-cg └── python │ └── ostra.py ├── pahole.c ├── pdwtags.c ├── pfunct.c ├── pglobal.c ├── prefcnt.c ├── rbtree.c ├── rbtree.h ├── regtest ├── rpm └── SPECS │ └── dwarves.spec ├── scncopy.c ├── strings.c ├── strings.h └── syscse.c /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | project(pahole C) 2 | cmake_minimum_required(VERSION 2.4.8) 3 | cmake_policy(SET CMP0005 NEW) 4 | 5 | INCLUDE_DIRECTORIES( ${CMAKE_CURRENT_BINARY_DIR} ${CMAKE_CURRENT_SOURCE_DIR} ) 6 | 7 | # Try to parse this later, Helio just showed me a KDE4 example to support 8 | # x86-64 builds. 9 | # the following are directories where stuff will be installed to 10 | set(__LIB "" CACHE STRING "Define suffix of directory name (32/64)" ) 11 | 12 | macro(_set_fancy _var _value _comment) 13 | if (NOT DEFINED ${_var}) 14 | set(${_var} ${_value}) 15 | else (NOT DEFINED ${_var}) 16 | set(${_var} "${${_var}}" CACHE PATH "${_comment}") 17 | endif (NOT DEFINED ${_var}) 18 | endmacro(_set_fancy) 19 | 20 | # where to look first for cmake modules, 21 | # before ${CMAKE_ROOT}/Modules/ is checked 22 | set(CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/cmake/modules") 23 | 24 | if (NOT CMAKE_BUILD_TYPE) 25 | set (CMAKE_BUILD_TYPE Debug CACHE STRING 26 | "Choose the type of build, options are: None Debug Release RelWithDebInfo MinSizeRel." 27 | FORCE) 28 | endif (NOT CMAKE_BUILD_TYPE) 29 | 30 | add_definitions(-D_GNU_SOURCE -DDWARVES_VERSION="v1.9") 31 | find_package(DWARF REQUIRED) 32 | find_package(ZLIB REQUIRED) 33 | 34 | _set_fancy(LIB_INSTALL_DIR "${EXEC_INSTALL_PREFIX}${CMAKE_INSTALL_PREFIX}/${__LIB}" "libdir") 35 | 36 | set(dwarves_LIB_SRCS dwarves.c dwarves_fprintf.c gobuffer strings 37 | ctf_encoder.c ctf_loader.c libctf.c dwarf_loader.c 38 | dutil.c elf_symtab.c rbtree.c) 39 | add_library(dwarves SHARED ${dwarves_LIB_SRCS}) 40 | set_target_properties(dwarves PROPERTIES VERSION 1.0.0 SOVERSION 1) 41 | set_target_properties(dwarves PROPERTIES LINK_INTERFACE_LIBRARIES "") 42 | target_link_libraries(dwarves ${DWARF_LIBRARIES} ${ZLIB_LIBRARIES}) 43 | 44 | set(dwarves_emit_LIB_SRCS dwarves_emit.c) 45 | add_library(dwarves_emit SHARED ${dwarves_emit_LIB_SRCS}) 46 | set_target_properties(dwarves_emit PROPERTIES VERSION 1.0.0 SOVERSION 1) 47 | target_link_libraries(dwarves_emit dwarves) 48 | 49 | set(dwarves_reorganize_LIB_SRCS dwarves_reorganize.c) 50 | add_library(dwarves_reorganize SHARED ${dwarves_reorganize_LIB_SRCS}) 51 | set_target_properties(dwarves_reorganize PROPERTIES VERSION 1.0.0 SOVERSION 1) 52 | target_link_libraries(dwarves_reorganize dwarves) 53 | 54 | set(codiff_SRCS codiff.c) 55 | add_executable(codiff ${codiff_SRCS}) 56 | target_link_libraries(codiff dwarves) 57 | 58 | set(ctracer_SRCS ctracer.c) 59 | add_executable(ctracer ${ctracer_SRCS}) 60 | target_link_libraries(ctracer dwarves dwarves_emit dwarves_reorganize ${ELF_LIBRARY}) 61 | 62 | set(dtagnames_SRCS dtagnames.c) 63 | add_executable(dtagnames ${dtagnames_SRCS}) 64 | target_link_libraries(dtagnames dwarves) 65 | 66 | set(pahole_SRCS pahole.c) 67 | add_executable(pahole ${pahole_SRCS}) 68 | target_link_libraries(pahole dwarves dwarves_reorganize) 69 | 70 | set(pdwtags_SRCS pdwtags.c) 71 | add_executable(pdwtags ${pdwtags_SRCS}) 72 | target_link_libraries(pdwtags dwarves) 73 | 74 | set(pglobal_SRCS pglobal.c) 75 | add_executable(pglobal ${pglobal_SRCS}) 76 | target_link_libraries(pglobal dwarves) 77 | 78 | set(pfunct_SRCS pfunct.c ) 79 | add_executable(pfunct ${pfunct_SRCS}) 80 | target_link_libraries(pfunct dwarves dwarves_emit ${ELF_LIBRARY}) 81 | 82 | set(prefcnt_SRCS prefcnt.c) 83 | add_executable(prefcnt ${prefcnt_SRCS}) 84 | target_link_libraries(prefcnt dwarves) 85 | 86 | set(scncopy_SRCS scncopy.c elfcreator.c) 87 | add_executable(scncopy ${scncopy_SRCS}) 88 | target_link_libraries(scncopy dwarves ${ELF_LIBRARY}) 89 | 90 | set(syscse_SRCS syscse.c) 91 | add_executable(syscse ${syscse_SRCS}) 92 | target_link_libraries(syscse dwarves) 93 | 94 | install(TARGETS codiff ctracer dtagnames pahole pdwtags 95 | pfunct pglobal prefcnt scncopy syscse RUNTIME DESTINATION 96 | ${CMAKE_INSTALL_PREFIX}/bin) 97 | install(TARGETS dwarves LIBRARY DESTINATION ${LIB_INSTALL_DIR}) 98 | install(TARGETS dwarves dwarves_emit dwarves_reorganize LIBRARY DESTINATION ${LIB_INSTALL_DIR}) 99 | install(FILES dwarves.h dwarves_emit.h dwarves_reorganize.h 100 | dutil.h gobuffer.h list.h rbtree.h strings.h 101 | DESTINATION ${CMAKE_INSTALL_PREFIX}/include/dwarves/) 102 | install(FILES man-pages/pahole.1 DESTINATION ${CMAKE_INSTALL_PREFIX}/share/man/man1/) 103 | install(PROGRAMS ostra/ostra-cg DESTINATION ${CMAKE_INSTALL_PREFIX}/bin) 104 | install(FILES ostra/python/ostra.py DESTINATION ${CMAKE_INSTALL_PREFIX}/share/dwarves/runtime/python) 105 | install(FILES lib/Makefile lib/ctracer_relay.c lib/ctracer_relay.h lib/linux.blacklist.cu 106 | DESTINATION ${CMAKE_INSTALL_PREFIX}/share/dwarves/runtime) 107 | -------------------------------------------------------------------------------- /COPYING: -------------------------------------------------------------------------------- 1 | GNU GENERAL PUBLIC LICENSE 2 | Version 2, June 1991 3 | 4 | Copyright (C) 1989, 1991 Free Software Foundation, Inc., 5 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 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 Lesser 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) 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 along 307 | with this program; if not, write to the Free Software Foundation, Inc., 308 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 309 | 310 | Also add information on how to contact you by electronic and paper mail. 311 | 312 | If the program is interactive, make it output a short notice like this 313 | when it starts in an interactive mode: 314 | 315 | Gnomovision version 69, Copyright (C) year name of author 316 | Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. 317 | This is free software, and you are welcome to redistribute it 318 | under certain conditions; type `show c' for details. 319 | 320 | The hypothetical commands `show w' and `show c' should show the appropriate 321 | parts of the General Public License. Of course, the commands you use may 322 | be called something other than `show w' and `show c'; they could even be 323 | mouse-clicks or menu items--whatever suits your program. 324 | 325 | You should also get your employer (if you work as a programmer) or your 326 | school, if any, to sign a "copyright disclaimer" for the program, if 327 | necessary. Here is a sample; alter the names: 328 | 329 | Yoyodyne, Inc., hereby disclaims all copyright interest in the program 330 | `Gnomovision' (which makes passes at compilers) written by James Hacker. 331 | 332 | , 1 April 1989 333 | Ty Coon, President of Vice 334 | 335 | This General Public License does not permit incorporating your program into 336 | proprietary programs. If your program is a subroutine library, you may 337 | consider it more useful to permit linking proprietary applications with the 338 | library. If this is what you want to do, use the GNU Lesser General 339 | Public License instead of this License. 340 | -------------------------------------------------------------------------------- /MANIFEST: -------------------------------------------------------------------------------- 1 | config.h.cmake 2 | ctf_encoder.c 3 | ctf_encoder.h 4 | ctf_loader.c 5 | dwarf_loader.c 6 | dwarves.c 7 | dwarves.h 8 | dwarves_emit.c 9 | dwarves_emit.h 10 | dwarves_fprintf.c 11 | dwarves_reorganize.c 12 | dwarves_reorganize.h 13 | cmake/modules/FindDWARF.cmake 14 | CMakeLists.txt 15 | codiff.c 16 | ctracer.c 17 | dtagnames.c 18 | elfcreator.c 19 | elfcreator.h 20 | elf_symtab.c 21 | elf_symtab.h 22 | gobuffer.c 23 | gobuffer.h 24 | hash.h 25 | list.h 26 | MANIFEST 27 | man-pages/pahole.1 28 | pahole.c 29 | pdwtags.c 30 | pfunct.c 31 | pglobal.c 32 | prefcnt.c 33 | rbtree.c 34 | rbtree.h 35 | scncopy.c 36 | syscse.c 37 | strings.c 38 | strings.h 39 | dutil.c 40 | dutil.h 41 | NEWS 42 | README 43 | README.ctracer 44 | rpm/SPECS/dwarves.spec 45 | lib/Makefile 46 | lib/ctracer_relay.c 47 | lib/ctracer_relay.h 48 | lib/linux.blacklist.cu 49 | ostra/ostra-cg 50 | ostra/python/ostra.py 51 | ctf.h 52 | libctf.c 53 | libctf.h 54 | regtest 55 | -------------------------------------------------------------------------------- /NEWS: -------------------------------------------------------------------------------- 1 | v1.10 2 | 3 | Wed May 30 2012 4 | 5 | . Initial DWARF4 support, by Tom Tromey 6 | 7 | . Add stubs for some new GNU Tags 8 | 9 | . Fix build on older systems 10 | 11 | . Fix a crash when pahole is called with -R -S, from Tal Kelrich 12 | 13 | v1.9: 14 | 15 | Ignore DW_TAG_template_{type,value}_parameter, fixing a bug reported at: 16 | 17 | https://bugzilla.redhat.com/show_bug.cgi?id=654471 18 | 19 | More work is needed to properly support these tags. 20 | 21 | ----------------------------------------- 22 | 23 | After a long time without a new release because I was trying to get the CTF 24 | support completed, and due to the very strong gravity force in the Linux kernel 25 | perf tools, here it is 1.8, with lots of performance improvements, bug fixes 26 | and changes to better use these tools in scripts. 27 | 28 | For full details please take a look at the git changesets, repo available at: 29 | 30 | http://git.kernel.org/cgit/devel/pahole/pahole.git 31 | 32 | - Arnaldo 33 | 34 | pahole: 35 | 36 | . Allow list of structs to be passed to pahole. 37 | 38 | E.g.: 'pahole -C str_node,strings' 39 | 40 | Suggested by Zack Weinberg , for scripting. 41 | 42 | . Introduce --hex to print offsets and sizes in hexadecimal 43 | 44 | codiff: 45 | 46 | . Improve detection of removal and addition of members in structs 47 | 48 | . Detect changes in padding and the number of holes/bit_holes 49 | 50 | pfunct: 51 | 52 | . --no_parm_names 53 | 54 | Because CTF doesn't encodes the names of the parameters and I want to 55 | test the upcoming CTF function section code in ctftwdiff. 56 | 57 | . pfunct --addr 58 | 59 | Using an rbtree to find in which function the given addr is. 60 | 61 | libdwarves: 62 | 63 | . Greatly reduce the data structures footprint and lookup by recoding 64 | the IDs as short integers, that was done to facilitate support for CTF 65 | but benefited the core libraries greatly. 66 | 67 | . Handle GCC support for vector instructions 68 | 69 | So now it recognizes, as printed by pdwtags: 70 | 71 | 908 typedef int __m64 __attribute__ ((__vector_size__ (8))); size: 8 72 | 909 int array __attribute__ ((__vector_size__ (8))); size: 8 73 | 910 int array __attribute__ ((__vector_size__ (4))); size: 4 74 | 911 short int array __attribute__ ((__vector_size__ (2))); size: 2 75 | 912 char array __attribute__ ((__vector_size__ (1))); size: 1 76 | 77 | . Destructors were added so that no leaks are left if this library is to 78 | be used in other tools that don't end the program when done using this lib. 79 | 80 | . Allow the tools to pass a callback that is used after loading each object 81 | file (CU/Compile Unit), so that we can more quickly find tags and stop 82 | the processing sooner, or at least delete the CU if it doesn't have anything 83 | needed by the tool. This _greatly_ speeded up most of the tools. 84 | 85 | . Tools now can pass a debug format "path", specifying the order it wants to 86 | try, so that if a file have both DWARF and CTF, specifying 'ctf,dwarf' will 87 | use the CTF info. 88 | 89 | . Now the formatting routines are in a separate file, dwarves_fprintf.c. This 90 | was done for organizational purposes but also to pave the way for multiple 91 | formatting backends, so that we can print, for instance, in CSV the structs, 92 | for easier scripting like done by several folks out there. 93 | 94 | . Handle volatile typedef bitfields, like: 95 | 96 | struct _GClosure { 97 | volatile guint ref_count:15; /* 0:17 4 */ 98 | volatile guint meta_marshal:1; /* 0:16 4 */ 99 | volatile guint n_guards:1; /* 0:15 4 */ 100 | 101 | . Load java 'interfaces' as a struct/class. 102 | 103 | . Fix buffer expansion bug, detected thanks to boost that provided things like: 104 | 105 | virtual int undefine(class 106 | grammar_helper > *); /* 110 | linkage=_ZN5boost6spirit4impl14grammar_helperINS0_7grammarINS_6detail5graph11dot_skipperENS0_14parser_contextINS0_5nil_tEEEEES6_NS0_7scannerINS0_10multi_passISt16istream_i 111 | */ 112 | 113 | . Allow optional addr information loading, speeding up some apps that don't 114 | use such addresses (or in modes where addrs aren't used) such as pahole. 115 | 116 | . Use a obstacks, speeding up apps as measured with the perf tools. 117 | 118 | . Support zero sized arrays in the middle of a struct. 119 | 120 | . Fix padding calculation in the reorganize routines. 121 | 122 | . Fix bitfield demotion in the reorganize routines. 123 | 124 | . Support "using" pointing to data members (C++). 125 | 126 | . Properly support pointers to const, reported by Jan Engelhardt : 127 | 128 | . Support more compact DW_AT_data_member_location form, pointed out by Mark 129 | Wielaard and reported by Mike Snitzer 130 | 131 | Experimental CTF support: 132 | 133 | libdwarves was reorganized so that it can support multiple debugging formats, 134 | with the first one being supported being the Compact C Type Format that comes 135 | from the OpenSolaris world. 136 | 137 | David S. Miller contributed an initial CTF decoder and from there I wrote an 138 | encoder. 139 | 140 | To test this a regression testing harness (regtest in the sources) that will 141 | take files with DWARF info and from there encode its contents in CTF in another 142 | ELF section in the same file (.SUN_ctf). Then it will decode both the DWARF 143 | and CTF sections and compare the results for pahole running with some new 144 | flags that cope with some subtleties in the way CTF encodes things. 145 | 146 | --flat_arrays 147 | 148 | We have just one dimension in CTF, with the total number of entries, 149 | in DWARF we can express this, but not in CTF: 150 | 151 | __u8 addr[0][6]; /* 4 0 */ 152 | 153 | So --flat_arrays will show it as: 154 | 155 | __u8 addr[0]; /* 4 0 */ 156 | 157 | --show_private_classes 158 | --fixup_silly_bitfields 159 | 160 | To cope with things like 'char foo:8' that since CTF has only the 161 | number of bits, can't be expressed as we don't know if it is a 162 | bitfield or just a char without the ':8' suffix. 163 | 164 | --first_obj_only 165 | 166 | Look only at the first object file in a file with multiple object 167 | files, like vmlinux. This is because the CTF support is not complete yet, 168 | needing the merging of types in multiple object files to be done. 169 | 170 | --classes_as_structs 171 | 172 | CTF has only a type for structs, not for classes like DWARF (DW_TAG_class_type 173 | is not present in CTF), so print them all as 'struct'. 174 | 175 | Running with the above limitations produce just a few mismatches, related to 176 | packed structs and enumerations and bitfields. 177 | -------------------------------------------------------------------------------- /README: -------------------------------------------------------------------------------- 1 | Build instructions: 2 | 3 | 1. install cmake 4 | 2. mkdir build 5 | 3. cd build 6 | 4. cmake -D__LIB=lib .. 7 | 5. make install 8 | 9 | Default is to be installed on /usr/local, see rpm spec file for 10 | installing on other places. 11 | 12 | Known to work scenarios: 13 | 14 | Mandriva Cooker: 15 | 16 | cmake 2.4.5-1mdv2007.1 17 | libelfutils1-devel 0.123-1mdv2007.1 18 | 19 | Debian Unstable: 20 | 21 | cmake 2.4.5-1 22 | libdw-dev 0.123-2 23 | 24 | Fedora Core 6: 25 | 26 | cmake 2.4.5-2.fc6 27 | elfutils-devel 0.126-1.fc6 28 | -------------------------------------------------------------------------------- /README.ctracer: -------------------------------------------------------------------------------- 1 | Basic instructions to use ctracer: 2 | 3 | 1. Install dwarves, if you are not that excited about building it I'm 4 | keeping rpms for Fedora Core 6 here: 5 | 6 | http://oops.ghostprotocols.net:81/acme/dwarves/rpm/ 7 | 8 | The .src.rpm is there in case you want to rebuild it for another 9 | rpm based distro. 10 | 11 | Since fedora 9 you just have to run: 12 | 13 | yum install dwarves 14 | 15 | 2. build the kernel with CONFIG_DEBUG_INFO=y, i.e. gcc -g, that will 16 | insert the DWARF info needed by all the pahole tools, ctracer, etc, or 17 | just install the kernel-debuginfo rpm package on FC6, other distros 18 | have it with a different name, its just the kernel built with debug 19 | info. 20 | 21 | 3. Assuming you installed the kernel-debuginfo package, to run ctracer 22 | on your workstation, just do the following steps: 23 | 24 | mkdir foo 25 | cd foo 26 | ln -s /usr/share/dwarves/runtime/* . 27 | make CLASS=sock # to trace struct sock methods, this one is safe, try others 28 | # and tell me your horror (or success :-) ) story. 29 | 30 | (kbuild gurus, send suggestions to simplify this procedure! :-) ) 31 | 32 | 4. load the resulting module: 33 | 34 | insmod ctracer.ko 35 | 36 | dmesg will show how many probes were successfully installed 37 | 38 | 5. Do some related activity (ssh, in the above example should do) 39 | 40 | 6. Make sure debugfs is mounted 41 | 42 | [root@filo ~]# mount -t debugfs none_debugfs /sys/kernel/debug/ 43 | 44 | 7. Get the log: 45 | 46 | cat /sys/kernel/debug/ctracer0 > /tmp/ctracer.log 47 | 48 | 8. Generate the callgraph! 49 | 50 | make callgraph 51 | 52 | 9. rmmod ctracer 53 | 54 | Change the shipped Makefile accordingly to build a module for qemu or another test 55 | machine. 56 | 57 | The relay transport is mostly ready and will be included in the upcoming changesets. 58 | -------------------------------------------------------------------------------- /cmake/modules/FindDWARF.cmake: -------------------------------------------------------------------------------- 1 | # - Find Dwarf 2 | # Find the dwarf.h header from elf utils 3 | # 4 | # DWARF_INCLUDE_DIR - where to find dwarf.h, etc. 5 | # DWARF_LIBRARIES - List of libraries when using elf utils. 6 | # DWARF_FOUND - True if fdo found. 7 | 8 | message(STATUS "Checking availability of DWARF and ELF development libraries") 9 | 10 | INCLUDE(CheckLibraryExists) 11 | 12 | if (DWARF_INCLUDE_DIR AND LIBDW_INCLUDE_DIR AND DWARF_LIBRARY AND ELF_LIBRARY) 13 | # Already in cache, be silent 14 | set(DWARF_FIND_QUIETLY TRUE) 15 | endif (DWARF_INCLUDE_DIR AND LIBDW_INCLUDE_DIR AND DWARF_LIBRARY AND ELF_LIBRARY) 16 | 17 | find_path(DWARF_INCLUDE_DIR dwarf.h 18 | /usr/include 19 | /usr/local/include 20 | /usr/include/libdwarf 21 | ~/usr/local/include 22 | ) 23 | 24 | find_path(LIBDW_INCLUDE_DIR elfutils/libdw.h 25 | /usr/include 26 | /usr/local/include 27 | ~/usr/local/include 28 | ) 29 | 30 | find_library(DWARF_LIBRARY 31 | NAMES dw dwarf 32 | PATHS /usr/lib /usr/local/lib /usr/lib64 /usr/local/lib64 ~/usr/local/lib ~/usr/local/lib64 33 | ) 34 | 35 | find_library(ELF_LIBRARY 36 | NAMES elf 37 | PATHS /usr/lib /usr/local/lib /usr/lib64 /usr/local/lib64 ~/usr/local/lib ~/usr/local/lib64 38 | ) 39 | 40 | find_library(EBL_LIBRARY 41 | NAMES ebl 42 | PATHS /usr/lib /usr/local/lib /usr/lib64 /usr/local/lib64 ~/usr/local/lib ~/usr/local/lib64 43 | ) 44 | 45 | if (DWARF_INCLUDE_DIR AND LIBDW_INCLUDE_DIR AND DWARF_LIBRARY AND ELF_LIBRARY AND EBL_LIBRARY) 46 | set(DWARF_FOUND TRUE) 47 | set(DWARF_LIBRARIES ${DWARF_LIBRARY} ${ELF_LIBRARY} ${EBL_LIBRARY}) 48 | 49 | set(CMAKE_REQUIRED_LIBRARIES ${DWARF_LIBRARIES}) 50 | # check if libdw have the dwfl_module_build_id routine, i.e. if it supports the buildid 51 | # mechanism to match binaries to detached debug info sections (the -debuginfo packages 52 | # in distributions such as fedora). We do it against libelf because, IIRC, some distros 53 | # include libdw linked statically into libelf. 54 | check_library_exists(elf dwfl_module_build_id "" HAVE_DWFL_MODULE_BUILD_ID) 55 | else (DWARF_INCLUDE_DIR AND LIBDW_INCLUDE_DIR AND DWARF_LIBRARY AND ELF_LIBRARY AND EBL_LIBRARY) 56 | set(DWARF_FOUND FALSE) 57 | set(DWARF_LIBRARIES) 58 | endif (DWARF_INCLUDE_DIR AND LIBDW_INCLUDE_DIR AND DWARF_LIBRARY AND ELF_LIBRARY AND EBL_LIBRARY) 59 | 60 | if (DWARF_FOUND) 61 | if (NOT DWARF_FIND_QUIETLY) 62 | message(STATUS "Found dwarf.h header: ${DWARF_INCLUDE_DIR}") 63 | message(STATUS "Found elfutils/libdw.h header: ${LIBDW_INCLUDE_DIR}") 64 | message(STATUS "Found libdw library: ${DWARF_LIBRARY}") 65 | message(STATUS "Found libelf library: ${ELF_LIBRARY}") 66 | message(STATUS "Found libebl library: ${EBL_LIBRARY}") 67 | endif (NOT DWARF_FIND_QUIETLY) 68 | else (DWARF_FOUND) 69 | if (DWARF_FIND_REQUIRED) 70 | # Check if we are in a Red Hat (RHEL) or Fedora system to tell 71 | # exactly which packages should be installed. Please send 72 | # patches for other distributions. 73 | find_path(FEDORA fedora-release /etc) 74 | find_path(REDHAT redhat-release /etc) 75 | if (FEDORA OR REDHAT) 76 | if (NOT DWARF_INCLUDE_DIR OR NOT LIBDW_INCLUDE_DIR OR NOT EBL_LIBRARY) 77 | message(STATUS "Please install the elfutils-devel package") 78 | endif (NOT DWARF_INCLUDE_DIR OR NOT LIBDW_INCLUDE_DIR OR NOT EBL_LIBRARY) 79 | if (NOT DWARF_LIBRARY) 80 | message(STATUS "Please install the elfutils-libs package") 81 | endif (NOT DWARF_LIBRARY) 82 | if (NOT ELF_LIBRARY) 83 | message(STATUS "Please install the elfutils-libelf package") 84 | endif (NOT ELF_LIBRARY) 85 | else (FEDORA OR REDHAT) 86 | if (NOT DWARF_INCLUDE_DIR) 87 | message(STATUS "Could NOT find dwarf include dir") 88 | endif (NOT DWARF_INCLUDE_DIR) 89 | if (NOT LIBDW_INCLUDE_DIR) 90 | message(STATUS "Could NOT find libdw include dir") 91 | endif (NOT LIBDW_INCLUDE_DIR) 92 | if (NOT EBL_LIBRARY) 93 | message(STATUS "Could NOT find libebl library") 94 | endif (NOT EBL_LIBRARY) 95 | if (NOT DWARF_LIBRARY) 96 | message(STATUS "Could NOT find libdw library") 97 | endif (NOT DWARF_LIBRARY) 98 | if (NOT ELF_LIBRARY) 99 | message(STATUS "Could NOT find libelf library") 100 | endif (NOT ELF_LIBRARY) 101 | endif (FEDORA OR REDHAT) 102 | message(FATAL_ERROR "Could NOT find some ELF and DWARF libraries, please install the missing packages") 103 | endif (DWARF_FIND_REQUIRED) 104 | endif (DWARF_FOUND) 105 | 106 | mark_as_advanced(DWARF_INCLUDE_DIR LIBDW_INCLUDE_DIR DWARF_LIBRARY ELF_LIBRARY EBL_LIBRARY) 107 | include_directories(${DWARF_INCLUDE_DIR} ${LIBDW_INCLUDE_DIR}) 108 | configure_file(${CMAKE_CURRENT_SOURCE_DIR}/config.h.cmake ${CMAKE_CURRENT_SOURCE_DIR}/config.h) 109 | 110 | message(STATUS "Checking availability of DWARF and ELF development libraries - done") 111 | -------------------------------------------------------------------------------- /config.h.cmake: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (C) 2007 Arnaldo Carvalho de Melo 3 | 4 | This program is free software; you can redistribute it and/or modify it 5 | under the terms of version 2 of the GNU General Public License as 6 | published by the Free Software Foundation. 7 | */ 8 | 9 | #cmakedefine HAVE_DWFL_MODULE_BUILD_ID 10 | -------------------------------------------------------------------------------- /ctf.h: -------------------------------------------------------------------------------- 1 | #ifndef _CTF_H 2 | #define _CTF_H 3 | 4 | #include 5 | 6 | struct ctf_header { 7 | uint16_t ctf_magic; /* Header magic value */ 8 | #define CTF_MAGIC 0xcff1 9 | #define CTF_MAGIC_SWAP 0xf1cf 10 | 11 | uint8_t ctf_version; /* Header version */ 12 | #define CTF_VERSION 2 13 | 14 | uint8_t ctf_flags; /* Header flags */ 15 | #define CTF_FLAGS_COMPR 0x01 16 | 17 | uint32_t ctf_parent_label; /* Label of parent CTF object */ 18 | uint32_t ctf_parent_name; /* Name of parent CTF object */ 19 | 20 | /* All offsets are in bytes are relative to the end of 21 | * this header. 22 | */ 23 | uint32_t ctf_label_off; /* Offset of label section */ 24 | uint32_t ctf_object_off; /* Offset of data object section */ 25 | uint32_t ctf_func_off; /* Offset of function section */ 26 | uint32_t ctf_type_off; /* Offset of type section */ 27 | uint32_t ctf_str_off; /* Offset of string section */ 28 | uint32_t ctf_str_len; /* Length of string section */ 29 | }; 30 | 31 | #define CTF_REF_OFFSET(REF) ((REF) & 0x7fffffff) 32 | #define CTF_REF_TBL_ID(REF) (((REF) >> 31) & 0x1) 33 | #define CTF_STR_TBL_ID_0 0 34 | #define CTF_STR_TBL_ID_1 1 35 | 36 | #define CTF_REF_ENCODE(TBL, OFF) (((TBL) << 31) | (OFF)) 37 | 38 | struct ctf_label_ent { 39 | uint32_t ctf_label_ref; 40 | uint32_t ctf_type_index; 41 | }; 42 | 43 | /* Types are encoded with ctf_short_type so long as the ctf_size 44 | * field can be fully represented in a uint16_t. If not, then 45 | * the ctf_size is given the value 0xffff and ctf_full_type is 46 | * used. 47 | */ 48 | struct ctf_short_type { 49 | uint32_t ctf_name; 50 | uint16_t ctf_info; 51 | union { 52 | uint16_t ctf_size; 53 | uint16_t ctf_type; 54 | }; 55 | }; 56 | 57 | struct ctf_full_type { 58 | struct ctf_short_type base; 59 | uint32_t ctf_size_high; 60 | uint32_t ctf_size_low; 61 | }; 62 | 63 | #define CTF_GET_KIND(VAL) (((VAL) >> 11) & 0x1f) 64 | #define CTF_GET_VLEN(VAL) ((VAL) & 0x3ff) 65 | #define CTF_ISROOT(VAL) (((VAL) & 0x400) != 0) 66 | 67 | #define CTF_INFO_ENCODE(KIND, VLEN, ISROOT) \ 68 | (((ISROOT) ? 0x400 : 0) | ((KIND) << 11) | (VLEN)) 69 | 70 | #define CTF_TYPE_KIND_UNKN 0 /* Unknown */ 71 | #define CTF_TYPE_KIND_INT 1 /* Integer */ 72 | #define CTF_TYPE_KIND_FLT 2 /* Float */ 73 | #define CTF_TYPE_KIND_PTR 3 /* Pointer */ 74 | #define CTF_TYPE_KIND_ARR 4 /* Array */ 75 | #define CTF_TYPE_KIND_FUNC 5 /* Function */ 76 | #define CTF_TYPE_KIND_STR 6 /* Struct */ 77 | #define CTF_TYPE_KIND_UNION 7 /* Union */ 78 | #define CTF_TYPE_KIND_ENUM 8 /* Enumeration */ 79 | #define CTF_TYPE_KIND_FWD 9 /* Forward */ 80 | #define CTF_TYPE_KIND_TYPDEF 10 /* Typedef */ 81 | #define CTF_TYPE_KIND_VOLATILE 11 /* Volatile */ 82 | #define CTF_TYPE_KIND_CONST 12 /* Const */ 83 | #define CTF_TYPE_KIND_RESTRICT 13 /* Restrict */ 84 | #define CTF_TYPE_KIND_MAX 31 85 | 86 | #define CTF_TYPE_INT_ATTRS(VAL) ((VAL) >> 24) 87 | #define CTF_TYPE_INT_OFFSET(VAL) (((VAL) >> 16) & 0xff) 88 | #define CTF_TYPE_INT_BITS(VAL) ((VAL) & 0xffff) 89 | 90 | #define CTF_TYPE_INT_ENCODE(ATTRS, OFF, BITS) \ 91 | (((ATTRS) << 24) | ((OFF) << 16) | (BITS)) 92 | 93 | /* Integer type attributes */ 94 | #define CTF_TYPE_INT_SIGNED 0x1 95 | #define CTF_TYPE_INT_CHAR 0x2 96 | #define CTF_TYPE_INT_BOOL 0x4 97 | #define CTF_TYPE_INT_VARARGS 0x8 98 | 99 | #define CTF_TYPE_FP_ATTRS(VAL) ((VAL) >> 24) 100 | #define CTF_TYPE_FP_OFFSET(VAL) (((VAL) >> 16) & 0xff) 101 | #define CTF_TYPE_FP_BITS(VAL) ((VAL) & 0xffff) 102 | 103 | #define CTF_TYPE_FP_ENCODE(ATTRS, OFF, BITS) \ 104 | (((ATTRS) << 24) | ((OFF) << 16) | (BITS)) 105 | 106 | /* Possible values for the float type attribute field */ 107 | #define CTF_TYPE_FP_SINGLE 1 108 | #define CTF_TYPE_FP_DOUBLE 2 109 | #define CTF_TYPE_FP_CMPLX 3 110 | #define CTF_TYPE_FP_CMPLX_DBL 4 111 | #define CTF_TYPE_FP_CMPLX_LDBL 5 112 | #define CTF_TYPE_FP_LDBL 6 113 | #define CTF_TYPE_FP_INTVL 7 114 | #define CTF_TYPE_FP_INTVL_DBL 8 115 | #define CTF_TYPE_FP_INTVL_LDBL 9 116 | #define CTF_TYPE_FP_IMGRY 10 117 | #define CTF_TYPE_FP_IMGRY_DBL 11 118 | #define CTF_TYPE_FP_IMGRY_LDBL 12 119 | #define CTF_TYPE_FP_MAX 12 120 | 121 | struct ctf_enum { 122 | uint32_t ctf_enum_name; 123 | uint32_t ctf_enum_val; 124 | }; 125 | 126 | struct ctf_array { 127 | uint16_t ctf_array_type; 128 | uint16_t ctf_array_index_type; 129 | uint32_t ctf_array_nelems; 130 | }; 131 | 132 | /* Struct members are encoded with either ctf_short_member or 133 | * ctf_full_member, depending upon the 'size' of the struct or 134 | * union being defined. If it is less than CTF_SHORT_MEMBER_LIMIT 135 | * then ctf_short_member objects are used to encode, else 136 | * ctf_full_member is used. 137 | */ 138 | #define CTF_SHORT_MEMBER_LIMIT 8192 139 | 140 | struct ctf_short_member { 141 | uint32_t ctf_member_name; 142 | uint16_t ctf_member_type; 143 | uint16_t ctf_member_offset; 144 | }; 145 | 146 | struct ctf_full_member { 147 | uint32_t ctf_member_name; 148 | uint16_t ctf_member_type; 149 | uint16_t ctf_member_unused; 150 | uint32_t ctf_member_offset_high; 151 | uint32_t ctf_member_offset_low; 152 | }; 153 | 154 | #endif /* _CTF_H */ 155 | -------------------------------------------------------------------------------- /ctf_encoder.c: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (C) 2009 Red Hat Inc. 3 | Copyright (C) 2009 Arnaldo Carvalho de Melo 4 | 5 | This program is free software; you can redistribute it and/or modify it 6 | under the terms of version 2 of the GNU General Public License as 7 | published by the Free Software Foundation. 8 | */ 9 | 10 | #include "dwarves.h" 11 | #include "libctf.h" 12 | #include "ctf.h" 13 | #include "hash.h" 14 | #include "elf_symtab.h" 15 | 16 | static int tag__check_id_drift(const struct tag *tag, 17 | uint16_t core_id, uint16_t ctf_id) 18 | { 19 | if (ctf_id != core_id) { 20 | fprintf(stderr, "%s: %s id drift, core: %u, libctf: %d\n", 21 | __func__, dwarf_tag_name(tag->tag), core_id, ctf_id); 22 | return -1; 23 | } 24 | return 0; 25 | } 26 | 27 | static int dwarf_to_ctf_type(uint16_t tag) 28 | { 29 | switch (tag) { 30 | case DW_TAG_const_type: return CTF_TYPE_KIND_CONST; 31 | case DW_TAG_pointer_type: return CTF_TYPE_KIND_PTR; 32 | case DW_TAG_restrict_type: return CTF_TYPE_KIND_RESTRICT; 33 | case DW_TAG_volatile_type: return CTF_TYPE_KIND_VOLATILE; 34 | case DW_TAG_class_type: 35 | case DW_TAG_structure_type: return CTF_TYPE_KIND_STR; 36 | case DW_TAG_union_type: return CTF_TYPE_KIND_UNION; 37 | } 38 | return 0xffff; 39 | } 40 | 41 | static int base_type__encode(struct tag *tag, uint16_t core_id, 42 | struct ctf *ctf) 43 | { 44 | struct base_type *bt = tag__base_type(tag); 45 | int ctf_id = ctf__add_base_type(ctf, bt->name, bt->bit_size); 46 | 47 | if (ctf_id < 0 || tag__check_id_drift(tag, core_id, ctf_id)) 48 | return -1; 49 | 50 | return 0; 51 | } 52 | 53 | static int pointer_type__encode(struct tag *tag, uint16_t core_id, 54 | struct ctf *ctf) 55 | { 56 | int ctf_id = ctf__add_short_type(ctf, dwarf_to_ctf_type(tag->tag), 57 | tag->type, 0); 58 | 59 | if (ctf_id < 0 || tag__check_id_drift(tag, core_id, ctf_id)) 60 | return -1; 61 | 62 | return 0; 63 | } 64 | 65 | static int typedef__encode(struct tag *tag, uint16_t core_id, struct ctf *ctf) 66 | { 67 | int ctf_id = ctf__add_short_type(ctf, CTF_TYPE_KIND_TYPDEF, tag->type, 68 | tag__namespace(tag)->name); 69 | 70 | if (ctf_id < 0 || tag__check_id_drift(tag, core_id, ctf_id)) 71 | return -1; 72 | 73 | return 0; 74 | } 75 | 76 | static int fwd_decl__encode(struct tag *tag, uint16_t core_id, struct ctf *ctf) 77 | { 78 | int ctf_id = ctf__add_fwd_decl(ctf, tag__namespace(tag)->name); 79 | 80 | if (ctf_id < 0 || tag__check_id_drift(tag, core_id, ctf_id)) 81 | return -1; 82 | 83 | return 0; 84 | } 85 | 86 | static int structure_type__encode(struct tag *tag, uint16_t core_id, 87 | struct ctf *ctf) 88 | { 89 | struct type *type = tag__type(tag); 90 | int64_t position; 91 | int ctf_id = ctf__add_struct(ctf, dwarf_to_ctf_type(tag->tag), 92 | type->namespace.name, type->size, 93 | type->nr_members, &position); 94 | 95 | if (ctf_id < 0 || tag__check_id_drift(tag, core_id, ctf_id)) 96 | return -1; 97 | 98 | const bool is_short = type->size < CTF_SHORT_MEMBER_LIMIT; 99 | struct class_member *pos; 100 | type__for_each_data_member(type, pos) { 101 | if (is_short) 102 | ctf__add_short_member(ctf, pos->name, pos->tag.type, 103 | pos->bit_offset, &position); 104 | else 105 | ctf__add_full_member(ctf, pos->name, pos->tag.type, 106 | pos->bit_offset, &position); 107 | } 108 | 109 | return 0; 110 | } 111 | 112 | static uint32_t array_type__nelems(struct tag *tag) 113 | { 114 | int i; 115 | uint32_t nelem = 1; 116 | struct array_type *array = tag__array_type(tag); 117 | 118 | for (i = array->dimensions - 1; i >= 0; --i) 119 | nelem *= array->nr_entries[i]; 120 | 121 | return nelem; 122 | } 123 | 124 | static int array_type__encode(struct tag *tag, uint16_t core_id, 125 | struct ctf *ctf) 126 | { 127 | const uint32_t nelems = array_type__nelems(tag); 128 | int ctf_id = ctf__add_array(ctf, tag->type, 0, nelems); 129 | 130 | if (ctf_id < 0 || tag__check_id_drift(tag, core_id, ctf_id)) 131 | return -1; 132 | 133 | return 0; 134 | } 135 | 136 | static int subroutine_type__encode(struct tag *tag, uint16_t core_id, 137 | struct ctf *ctf) 138 | { 139 | struct parameter *pos; 140 | int64_t position; 141 | struct ftype *ftype = tag__ftype(tag); 142 | int ctf_id = ctf__add_function_type(ctf, tag->type, ftype->nr_parms, 143 | ftype->unspec_parms, &position); 144 | 145 | if (ctf_id < 0 || tag__check_id_drift(tag, core_id, ctf_id)) 146 | return -1; 147 | 148 | ftype__for_each_parameter(ftype, pos) 149 | ctf__add_parameter(ctf, pos->tag.type, &position); 150 | 151 | return 0; 152 | } 153 | 154 | static int enumeration_type__encode(struct tag *tag, uint16_t core_id, 155 | struct ctf *ctf) 156 | { 157 | struct type *etype = tag__type(tag); 158 | int64_t position; 159 | int ctf_id = ctf__add_enumeration_type(ctf, etype->namespace.name, 160 | etype->size, etype->nr_members, 161 | &position); 162 | 163 | if (ctf_id < 0 || tag__check_id_drift(tag, core_id, ctf_id)) 164 | return -1; 165 | 166 | struct enumerator *pos; 167 | type__for_each_enumerator(etype, pos) 168 | ctf__add_enumerator(ctf, pos->name, pos->value, &position); 169 | 170 | return 0; 171 | } 172 | 173 | static void tag__encode_ctf(struct tag *tag, uint16_t core_id, struct ctf *ctf) 174 | { 175 | switch (tag->tag) { 176 | case DW_TAG_base_type: 177 | base_type__encode(tag, core_id, ctf); 178 | break; 179 | case DW_TAG_const_type: 180 | case DW_TAG_pointer_type: 181 | case DW_TAG_restrict_type: 182 | case DW_TAG_volatile_type: 183 | pointer_type__encode(tag, core_id, ctf); 184 | break; 185 | case DW_TAG_typedef: 186 | typedef__encode(tag, core_id, ctf); 187 | break; 188 | case DW_TAG_structure_type: 189 | case DW_TAG_union_type: 190 | case DW_TAG_class_type: 191 | if (tag__type(tag)->declaration) 192 | fwd_decl__encode(tag, core_id, ctf); 193 | else 194 | structure_type__encode(tag, core_id, ctf); 195 | break; 196 | case DW_TAG_array_type: 197 | array_type__encode(tag, core_id, ctf); 198 | break; 199 | case DW_TAG_subroutine_type: 200 | subroutine_type__encode(tag, core_id, ctf); 201 | break; 202 | case DW_TAG_enumeration_type: 203 | enumeration_type__encode(tag, core_id, ctf); 204 | break; 205 | } 206 | } 207 | 208 | #define HASHADDR__BITS 8 209 | #define HASHADDR__SIZE (1UL << HASHADDR__BITS) 210 | #define hashaddr__fn(key) hash_64(key, HASHADDR__BITS) 211 | 212 | static struct function *hashaddr__find_function(const struct hlist_head hashtable[], 213 | const uint64_t addr) 214 | { 215 | struct function *function; 216 | struct hlist_node *pos; 217 | uint16_t bucket = hashaddr__fn(addr); 218 | const struct hlist_head *head = &hashtable[bucket]; 219 | 220 | hlist_for_each_entry(function, pos, head, tool_hnode) { 221 | if (function->lexblock.ip.addr == addr) 222 | return function; 223 | } 224 | 225 | return NULL; 226 | } 227 | 228 | static struct variable *hashaddr__find_variable(const struct hlist_head hashtable[], 229 | const uint64_t addr) 230 | { 231 | struct variable *variable; 232 | struct hlist_node *pos; 233 | uint16_t bucket = hashaddr__fn(addr); 234 | const struct hlist_head *head = &hashtable[bucket]; 235 | 236 | hlist_for_each_entry(variable, pos, head, tool_hnode) { 237 | if (variable->ip.addr == addr) 238 | return variable; 239 | } 240 | 241 | return NULL; 242 | } 243 | 244 | /* 245 | * FIXME: Its in the DWARF loader, we have to find a better handoff 246 | * mechanizm... 247 | */ 248 | extern struct strings *strings; 249 | 250 | int cu__encode_ctf(struct cu *cu, int verbose) 251 | { 252 | int err = -1; 253 | struct ctf *ctf = ctf__new(cu->filename, cu->elf); 254 | 255 | if (ctf == NULL) 256 | goto out; 257 | 258 | if (cu__cache_symtab(cu) < 0) 259 | goto out_delete; 260 | 261 | ctf__set_strings(ctf, &strings->gb); 262 | 263 | uint32_t id; 264 | struct tag *pos; 265 | cu__for_each_type(cu, id, pos) 266 | tag__encode_ctf(pos, id, ctf); 267 | 268 | struct hlist_head hash_addr[HASHADDR__SIZE]; 269 | 270 | for (id = 0; id < HASHADDR__SIZE; ++id) 271 | INIT_HLIST_HEAD(&hash_addr[id]); 272 | 273 | struct function *function; 274 | cu__for_each_function(cu, id, function) { 275 | uint64_t addr = function->lexblock.ip.addr; 276 | struct hlist_head *head = &hash_addr[hashaddr__fn(addr)]; 277 | hlist_add_head(&function->tool_hnode, head); 278 | } 279 | 280 | uint64_t addr; 281 | GElf_Sym sym; 282 | const char *sym_name; 283 | cu__for_each_cached_symtab_entry(cu, id, sym, sym_name) { 284 | if (ctf__ignore_symtab_function(&sym, sym_name)) 285 | continue; 286 | 287 | addr = elf_sym__value(&sym); 288 | int64_t position; 289 | function = hashaddr__find_function(hash_addr, addr); 290 | if (function == NULL) { 291 | if (verbose) 292 | fprintf(stderr, 293 | "function %4d: %-20s %#Lx %5u NOT FOUND!\n", 294 | id, sym_name, (long long unsigned)addr, 295 | elf_sym__size(&sym)); 296 | err = ctf__add_function(ctf, 0, 0, 0, &position); 297 | if (err != 0) 298 | goto out_err_ctf; 299 | continue; 300 | } 301 | 302 | const struct ftype *ftype = &function->proto; 303 | err = ctf__add_function(ctf, function->proto.tag.type, 304 | ftype->nr_parms, 305 | ftype->unspec_parms, &position); 306 | 307 | if (err != 0) 308 | goto out_err_ctf; 309 | 310 | struct parameter *pos; 311 | ftype__for_each_parameter(ftype, pos) 312 | ctf__add_function_parameter(ctf, pos->tag.type, &position); 313 | } 314 | 315 | for (id = 0; id < HASHADDR__SIZE; ++id) 316 | INIT_HLIST_HEAD(&hash_addr[id]); 317 | 318 | struct variable *var; 319 | cu__for_each_variable(cu, id, pos) { 320 | var = tag__variable(pos); 321 | if (var->location != LOCATION_GLOBAL) 322 | continue; 323 | struct hlist_head *head = &hash_addr[hashaddr__fn(var->ip.addr)]; 324 | hlist_add_head(&var->tool_hnode, head); 325 | } 326 | 327 | cu__for_each_cached_symtab_entry(cu, id, sym, sym_name) { 328 | if (ctf__ignore_symtab_object(&sym, sym_name)) 329 | continue; 330 | addr = elf_sym__value(&sym); 331 | 332 | var = hashaddr__find_variable(hash_addr, addr); 333 | if (var == NULL) { 334 | if (verbose) 335 | fprintf(stderr, 336 | "variable %4d: %-20s %#Lx %5u NOT FOUND!\n", 337 | id, sym_name, (long long unsigned)addr, 338 | elf_sym__size(&sym)); 339 | err = ctf__add_object(ctf, 0); 340 | if (err != 0) 341 | goto out_err_ctf; 342 | continue; 343 | } 344 | 345 | err = ctf__add_object(ctf, var->ip.tag.type); 346 | if (err != 0) 347 | goto out_err_ctf; 348 | } 349 | 350 | ctf__encode(ctf, CTF_FLAGS_COMPR); 351 | 352 | err = 0; 353 | out_delete: 354 | ctf__delete(ctf); 355 | out: 356 | return err; 357 | out_err_ctf: 358 | fprintf(stderr, 359 | "%4d: %-20s %#llx %5u failed encoding, " 360 | "ABORTING!\n", id, sym_name, 361 | (unsigned long long)addr, elf_sym__size(&sym)); 362 | goto out_delete; 363 | } 364 | -------------------------------------------------------------------------------- /ctf_encoder.h: -------------------------------------------------------------------------------- 1 | #ifndef _CTF_ENCODER_H_ 2 | #define _CTF_ENCODER_H_ 1 3 | /* 4 | Copyright (C) 2009 Red Hat Inc. 5 | Copyright (C) 2009 Arnaldo Carvalho de Melo 6 | 7 | This program is free software; you can redistribute it and/or modify it 8 | under the terms of version 2 of the GNU General Public License as 9 | published by the Free Software Foundation. 10 | */ 11 | 12 | struct cu; 13 | 14 | int cu__encode_ctf(struct cu *self, int verbose); 15 | 16 | #endif /* _CTF_ENCODER_H_ */ 17 | -------------------------------------------------------------------------------- /ctfdwdiff: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | results_dir=/tmp/ctfdwdiff 4 | 5 | diff_tool() { 6 | local tool=$1 7 | local dwarf_options=$2 8 | local ctf_options=$3 9 | local obj=$4 10 | 11 | diff=$results_dir/$obj.$tool.diff 12 | ctf=$results_dir/$obj.$tool.ctf.c 13 | dwarf=$results_dir/$obj.$tool.dwarf.c 14 | $tool -F ctf $ctf_options $obj > $ctf 15 | $tool -F dwarf $dwarf_options $obj > $dwarf 16 | diff -up $dwarf $ctf > $diff 17 | if [ -s $diff ] ; then 18 | [ $# -gt 4 ] && vim $diff 19 | exit 0 20 | else 21 | rm -f $diff $ctf $dwarf 22 | fi 23 | } 24 | 25 | diff_one() { 26 | local obj=$1 27 | diff_tool "pahole" "--flat_arrays --show_private_classes --fixup_silly_bitfields" " " $obj $2 28 | diff_tool "pfunct" "-V --no_parm_names" "-V" $obj $2 29 | } 30 | 31 | 32 | diff_dir() { 33 | find . -type d | \ 34 | while read dir ; do 35 | cd $dir 36 | ls *.o 2> /dev/null | 37 | while read obj ; do 38 | ncus=$(readelf -wi $obj | grep DW_TAG_compile_unit | wc -l) 39 | if [ $ncus -ne 1 ] ; then 40 | continue 41 | fi 42 | echo $obj 43 | pahole -Z $obj 44 | diff_one $obj $1 45 | done 46 | cd - > /dev/null 47 | done 48 | } 49 | 50 | rm -rf $results_dir 51 | mkdir $results_dir 52 | 53 | if [ $# -lt 2 ] ; then 54 | diff_dir 55 | else 56 | diff_one $* 57 | fi 58 | -------------------------------------------------------------------------------- /dtagnames.c: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (C) 2006 Mandriva Conectiva S.A. 3 | Copyright (C) 2006 Arnaldo Carvalho de Melo 4 | 5 | This program is free software; you can redistribute it and/or modify it 6 | under the terms of version 2 of the GNU General Public License as 7 | published by the Free Software Foundation. 8 | */ 9 | 10 | #include 11 | #include 12 | #include 13 | 14 | #include "dwarves.h" 15 | #include "dutil.h" 16 | 17 | static void print_malloc_stats(void) 18 | { 19 | struct mallinfo m = mallinfo(); 20 | 21 | fprintf(stderr, "size: %u\n", m.uordblks); 22 | } 23 | 24 | static int class__tag_name(struct tag *tag, struct cu *cu __unused, 25 | void *cookie __unused) 26 | { 27 | puts(dwarf_tag_name(tag->tag)); 28 | return 0; 29 | } 30 | 31 | static int cu__dump_class_tag_names(struct cu *cu, void *cookie __unused) 32 | { 33 | cu__for_all_tags(cu, class__tag_name, NULL); 34 | return 0; 35 | } 36 | 37 | static void cus__dump_class_tag_names(struct cus *cus) 38 | { 39 | cus__for_each_cu(cus, cu__dump_class_tag_names, NULL, NULL); 40 | } 41 | 42 | int main(int argc __unused, char *argv[]) 43 | { 44 | int err, rc = EXIT_FAILURE; 45 | struct cus *cus = cus__new(); 46 | 47 | if (dwarves__init(0) || cus == NULL) { 48 | fputs("dtagnames: insufficient memory\n", stderr); 49 | goto out; 50 | } 51 | 52 | err = cus__load_files(cus, NULL, argv + 1); 53 | if (err != 0) 54 | goto out; 55 | 56 | cus__dump_class_tag_names(cus); 57 | print_malloc_stats(); 58 | rc = EXIT_SUCCESS; 59 | out: 60 | cus__delete(cus); 61 | dwarves__exit(); 62 | return rc; 63 | } 64 | -------------------------------------------------------------------------------- /dutil.c: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (C) 2007 Arnaldo Carvalho de Melo 3 | 4 | This program is free software; you can redistribute it and/or modify it 5 | under the terms of version 2 of the GNU General Public License as 6 | published by the Free Software Foundation. 7 | */ 8 | 9 | 10 | #include "dutil.h" 11 | 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | 18 | void *zalloc(const size_t size) 19 | { 20 | void *s = malloc(size); 21 | if (s != NULL) 22 | memset(s, 0, size); 23 | return s; 24 | } 25 | 26 | struct str_node *str_node__new(const char *s, bool dupstr) 27 | { 28 | struct str_node *snode = malloc(sizeof(*snode)); 29 | 30 | if (snode != NULL){ 31 | if (dupstr) { 32 | s = strdup(s); 33 | if (s == NULL) 34 | goto out_delete; 35 | } 36 | snode->s = s; 37 | } 38 | 39 | return snode; 40 | 41 | out_delete: 42 | free(snode); 43 | return NULL; 44 | } 45 | 46 | static void str_node__delete(struct str_node *snode, bool dupstr) 47 | { 48 | if (dupstr) 49 | free((void *)snode->s); 50 | free(snode); 51 | } 52 | 53 | int strlist__add(struct strlist *slist, const char *new_entry) 54 | { 55 | struct rb_node **p = &slist->entries.rb_node; 56 | struct rb_node *parent = NULL; 57 | struct str_node *sn; 58 | 59 | while (*p != NULL) { 60 | int rc; 61 | 62 | parent = *p; 63 | sn = rb_entry(parent, struct str_node, rb_node); 64 | rc = strcmp(sn->s, new_entry); 65 | 66 | if (rc > 0) 67 | p = &(*p)->rb_left; 68 | else if (rc < 0) 69 | p = &(*p)->rb_right; 70 | else 71 | return -EEXIST; 72 | } 73 | 74 | sn = str_node__new(new_entry, slist->dupstr); 75 | if (sn == NULL) 76 | return -ENOMEM; 77 | 78 | rb_link_node(&sn->rb_node, parent, p); 79 | rb_insert_color(&sn->rb_node, &slist->entries); 80 | 81 | return 0; 82 | } 83 | 84 | int strlist__load(struct strlist *slist, const char *filename) 85 | { 86 | char entry[1024]; 87 | int err = -1; 88 | FILE *fp = fopen(filename, "r"); 89 | 90 | if (fp == NULL) 91 | return -1; 92 | 93 | while (fgets(entry, sizeof(entry), fp) != NULL) { 94 | const size_t len = strlen(entry); 95 | 96 | if (len == 0) 97 | continue; 98 | entry[len - 1] = '\0'; 99 | 100 | if (strlist__add(slist, entry) != 0) 101 | goto out; 102 | } 103 | 104 | err = 0; 105 | out: 106 | fclose(fp); 107 | return err; 108 | } 109 | 110 | struct strlist *strlist__new(bool dupstr) 111 | { 112 | struct strlist *slist = malloc(sizeof(*slist)); 113 | 114 | if (slist != NULL) { 115 | slist->entries = RB_ROOT; 116 | slist->dupstr = dupstr; 117 | } 118 | 119 | return slist; 120 | } 121 | 122 | void strlist__delete(struct strlist *slist) 123 | { 124 | if (slist != NULL) { 125 | struct str_node *pos; 126 | struct rb_node *next = rb_first(&slist->entries); 127 | 128 | while (next) { 129 | pos = rb_entry(next, struct str_node, rb_node); 130 | next = rb_next(&pos->rb_node); 131 | strlist__remove(slist, pos); 132 | } 133 | slist->entries = RB_ROOT; 134 | free(slist); 135 | } 136 | } 137 | 138 | void strlist__remove(struct strlist *slist, struct str_node *sn) 139 | { 140 | rb_erase(&sn->rb_node, &slist->entries); 141 | str_node__delete(sn, slist->dupstr); 142 | } 143 | 144 | bool strlist__has_entry(struct strlist *slist, const char *entry) 145 | { 146 | struct rb_node **p = &slist->entries.rb_node; 147 | struct rb_node *parent = NULL; 148 | 149 | while (*p != NULL) { 150 | struct str_node *sn; 151 | int rc; 152 | 153 | parent = *p; 154 | sn = rb_entry(parent, struct str_node, rb_node); 155 | rc = strcmp(sn->s, entry); 156 | 157 | if (rc > 0) 158 | p = &(*p)->rb_left; 159 | else if (rc < 0) 160 | p = &(*p)->rb_right; 161 | else 162 | return true; 163 | } 164 | 165 | return false; 166 | } 167 | 168 | Elf_Scn *elf_section_by_name(Elf *elf, GElf_Ehdr *ep, 169 | GElf_Shdr *shp, const char *name, size_t *index) 170 | { 171 | Elf_Scn *sec = NULL; 172 | size_t cnt = 1; 173 | 174 | while ((sec = elf_nextscn(elf, sec)) != NULL) { 175 | char *str; 176 | 177 | gelf_getshdr(sec, shp); 178 | str = elf_strptr(elf, ep->e_shstrndx, shp->sh_name); 179 | if (!strcmp(name, str)) { 180 | if (index) 181 | *index = cnt; 182 | break; 183 | } 184 | ++cnt; 185 | } 186 | 187 | return sec; 188 | } 189 | -------------------------------------------------------------------------------- /dutil.h: -------------------------------------------------------------------------------- 1 | #ifndef _DUTIL_H_ 2 | #define _DUTIL_H_ 1 3 | /* 4 | * Copyright (C) 2007..2009 Arnaldo Carvalho de Melo 5 | * 6 | * This program is free software; you can redistribute it and/or modify it 7 | * under the terms of version 2 of the GNU General Public License as 8 | * published by the Free Software Foundation. 9 | * 10 | * Some functions came from the Linux Kernel sources, copyrighted by a 11 | * cast of dozens, please see the Linux Kernel git history for details. 12 | */ 13 | 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include "rbtree.h" 19 | 20 | #ifndef __unused 21 | #define __unused __attribute__ ((unused)) 22 | #endif 23 | 24 | #ifndef __pure 25 | #define __pure __attribute__ ((pure)) 26 | #endif 27 | 28 | #define roundup(x,y) ((((x) + ((y) - 1)) / (y)) * (y)) 29 | 30 | static inline __attribute__((const)) bool is_power_of_2(unsigned long n) 31 | { 32 | return (n != 0 && ((n & (n - 1)) == 0)); 33 | } 34 | 35 | /* We need define two variables, argp_program_version_hook and 36 | argp_program_bug_address, in all programs. argp.h declares these 37 | variables as non-const (which is correct in general). But we can 38 | do better, it is not going to change. So we want to move them into 39 | the .rodata section. Define macros to do the trick. */ 40 | #define ARGP_PROGRAM_VERSION_HOOK_DEF \ 41 | void (*const apvh) (FILE *, struct argp_state *) \ 42 | __asm ("argp_program_version_hook") 43 | #define ARGP_PROGRAM_BUG_ADDRESS_DEF \ 44 | const char *const apba__ __asm ("argp_program_bug_address") 45 | 46 | struct str_node { 47 | struct rb_node rb_node; 48 | const char *s; 49 | }; 50 | 51 | struct strlist { 52 | struct rb_root entries; 53 | bool dupstr; 54 | }; 55 | 56 | struct strlist *strlist__new(bool dupstr); 57 | void strlist__delete(struct strlist *self); 58 | 59 | void strlist__remove(struct strlist *self, struct str_node *sn); 60 | int strlist__load(struct strlist *self, const char *filename); 61 | int strlist__add(struct strlist *self, const char *str); 62 | 63 | bool strlist__has_entry(struct strlist *self, const char *entry); 64 | 65 | static inline bool strlist__empty(const struct strlist *self) 66 | { 67 | return rb_first(&self->entries) == NULL; 68 | } 69 | 70 | void *zalloc(const size_t size); 71 | 72 | Elf_Scn *elf_section_by_name(Elf *elf, GElf_Ehdr *ep, 73 | GElf_Shdr *shp, const char *name, size_t *index); 74 | 75 | #ifndef SHT_GNU_ATTRIBUTES 76 | /* Just a way to check if we're using an old elfutils version */ 77 | static inline int elf_getshdrstrndx(Elf *elf, size_t *dst) 78 | { 79 | return elf_getshstrndx(elf, dst); 80 | } 81 | #endif 82 | 83 | #endif /* _DUTIL_H_ */ 84 | -------------------------------------------------------------------------------- /dwarves_emit.c: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (C) 2006 Mandriva Conectiva S.A. 3 | Copyright (C) 2006 Arnaldo Carvalho de Melo 4 | Copyright (C) 2007 Red Hat Inc. 5 | Copyright (C) 2007 Arnaldo Carvalho de Melo 6 | 7 | This program is free software; you can redistribute it and/or modify it 8 | under the terms of version 2 of the GNU General Public License as 9 | published by the Free Software Foundation. 10 | */ 11 | 12 | #include 13 | 14 | #include "list.h" 15 | #include "dwarves_emit.h" 16 | #include "dwarves.h" 17 | 18 | void type_emissions__init(struct type_emissions *emissions) 19 | { 20 | INIT_LIST_HEAD(&emissions->definitions); 21 | INIT_LIST_HEAD(&emissions->fwd_decls); 22 | } 23 | 24 | static void type_emissions__add_definition(struct type_emissions *emissions, 25 | struct type *type) 26 | { 27 | type->definition_emitted = 1; 28 | if (!list_empty(&type->node)) 29 | list_del(&type->node); 30 | list_add_tail(&type->node, &emissions->definitions); 31 | } 32 | 33 | static void type_emissions__add_fwd_decl(struct type_emissions *emissions, 34 | struct type *type) 35 | { 36 | type->fwd_decl_emitted = 1; 37 | if (list_empty(&type->node)) 38 | list_add_tail(&type->node, &emissions->fwd_decls); 39 | } 40 | 41 | struct type *type_emissions__find_definition(const struct type_emissions *emissions, 42 | const struct cu *cu, 43 | const char *name) 44 | { 45 | struct type *pos; 46 | 47 | if (name == NULL) 48 | return NULL; 49 | 50 | list_for_each_entry(pos, &emissions->definitions, node) 51 | if (type__name(pos, cu) != NULL && 52 | strcmp(type__name(pos, cu), name) == 0) 53 | return pos; 54 | 55 | return NULL; 56 | } 57 | 58 | static struct type *type_emissions__find_fwd_decl(const struct type_emissions *emissions, 59 | const struct cu *cu, 60 | const char *name) 61 | { 62 | struct type *pos; 63 | 64 | list_for_each_entry(pos, &emissions->fwd_decls, node) 65 | if (strcmp(type__name(pos, cu), name) == 0) 66 | return pos; 67 | 68 | return NULL; 69 | } 70 | 71 | static int enumeration__emit_definitions(struct tag *tag, struct cu *cu, 72 | struct type_emissions *emissions, 73 | const struct conf_fprintf *conf, 74 | FILE *fp) 75 | { 76 | struct type *etype = tag__type(tag); 77 | 78 | /* Have we already emitted this in this CU? */ 79 | if (etype->definition_emitted) 80 | return 0; 81 | 82 | /* Ok, lets look at the previous CUs: */ 83 | if (type_emissions__find_definition(emissions, cu, 84 | type__name(etype, cu)) != NULL) { 85 | /* 86 | * Yes, so lets mark it visited on this CU too, 87 | * to speed up the lookup. 88 | */ 89 | etype->definition_emitted = 1; 90 | return 0; 91 | } 92 | 93 | enumeration__fprintf(tag, cu, conf, fp); 94 | fputs(";\n", fp); 95 | type_emissions__add_definition(emissions, etype); 96 | return 1; 97 | } 98 | 99 | static int tag__emit_definitions(struct tag *tag, struct cu *cu, 100 | struct type_emissions *emissions, FILE *fp); 101 | 102 | static int typedef__emit_definitions(struct tag *tdef, struct cu *cu, 103 | struct type_emissions *emissions, FILE *fp) 104 | { 105 | struct type *def = tag__type(tdef); 106 | struct tag *type, *ptr_type; 107 | int is_pointer = 0; 108 | 109 | /* Have we already emitted this in this CU? */ 110 | if (def->definition_emitted) 111 | return 0; 112 | 113 | /* Ok, lets look at the previous CUs: */ 114 | if (type_emissions__find_definition(emissions, cu, 115 | type__name(def, cu)) != NULL) { 116 | /* 117 | * Yes, so lets mark it visited on this CU too, 118 | * to speed up the lookup. 119 | */ 120 | def->definition_emitted = 1; 121 | return 0; 122 | } 123 | 124 | type = cu__type(cu, tdef->type); 125 | tag__assert_search_result(type); 126 | 127 | switch (type->tag) { 128 | case DW_TAG_array_type: 129 | tag__emit_definitions(type, cu, emissions, fp); 130 | break; 131 | case DW_TAG_typedef: 132 | typedef__emit_definitions(type, cu, emissions, fp); 133 | break; 134 | case DW_TAG_pointer_type: 135 | ptr_type = cu__type(cu, type->type); 136 | tag__assert_search_result(ptr_type); 137 | if (ptr_type->tag != DW_TAG_subroutine_type) 138 | break; 139 | type = ptr_type; 140 | is_pointer = 1; 141 | /* Fall thru */ 142 | case DW_TAG_subroutine_type: 143 | ftype__emit_definitions(tag__ftype(type), cu, emissions, fp); 144 | break; 145 | case DW_TAG_enumeration_type: { 146 | struct type *ctype = tag__type(type); 147 | struct conf_fprintf conf = { 148 | .suffix = NULL, 149 | }; 150 | 151 | if (type__name(ctype, cu) == NULL) { 152 | fputs("typedef ", fp); 153 | conf.suffix = type__name(def, cu); 154 | enumeration__emit_definitions(type, cu, emissions, 155 | &conf, fp); 156 | goto out; 157 | } else 158 | enumeration__emit_definitions(type, cu, emissions, 159 | &conf, fp); 160 | } 161 | break; 162 | case DW_TAG_structure_type: 163 | case DW_TAG_union_type: { 164 | struct type *ctype = tag__type(type); 165 | 166 | if (type__name(ctype, cu) == NULL) { 167 | if (type__emit_definitions(type, cu, emissions, fp)) 168 | type__emit(type, cu, "typedef", 169 | type__name(def, cu), fp); 170 | goto out; 171 | } else if (type__emit_definitions(type, cu, emissions, fp)) 172 | type__emit(type, cu, NULL, NULL, fp); 173 | } 174 | } 175 | 176 | /* 177 | * Recheck if the typedef was emitted, as there are cases, like 178 | * wait_queue_t in the Linux kernel, that is against struct 179 | * __wait_queue, that has a wait_queue_func_t member, a function 180 | * typedef that has as one of its parameters a... wait_queue_t, that 181 | * will thus be emitted before the function typedef, making a no go to 182 | * redefine the typedef after struct __wait_queue. 183 | */ 184 | if (!def->definition_emitted) { 185 | typedef__fprintf(tdef, cu, NULL, fp); 186 | fputs(";\n", fp); 187 | } 188 | out: 189 | type_emissions__add_definition(emissions, def); 190 | return 1; 191 | } 192 | 193 | int type__emit_fwd_decl(struct type *ctype, const struct cu *cu, 194 | struct type_emissions *emissions, FILE *fp) 195 | { 196 | /* Have we already emitted this in this CU? */ 197 | if (ctype->fwd_decl_emitted) 198 | return 0; 199 | 200 | /* Ok, lets look at the previous CUs: */ 201 | if (type_emissions__find_fwd_decl(emissions, cu, 202 | type__name(ctype, cu)) != NULL) { 203 | /* 204 | * Yes, so lets mark it visited on this CU too, 205 | * to speed up the lookup. 206 | */ 207 | ctype->fwd_decl_emitted = 1; 208 | return 0; 209 | } 210 | 211 | fprintf(fp, "%s %s;\n", 212 | tag__is_union(&ctype->namespace.tag) ? "union" : "struct", 213 | type__name(ctype, cu)); 214 | type_emissions__add_fwd_decl(emissions, ctype); 215 | return 1; 216 | } 217 | 218 | static int tag__emit_definitions(struct tag *tag, struct cu *cu, 219 | struct type_emissions *emissions, FILE *fp) 220 | { 221 | struct tag *type = cu__type(cu, tag->type); 222 | int pointer = 0; 223 | 224 | if (type == NULL) 225 | return 0; 226 | next_indirection: 227 | switch (type->tag) { 228 | case DW_TAG_pointer_type: 229 | case DW_TAG_reference_type: 230 | pointer = 1; 231 | /* Fall thru */ 232 | case DW_TAG_array_type: 233 | case DW_TAG_const_type: 234 | case DW_TAG_volatile_type: 235 | type = cu__type(cu, type->type); 236 | if (type == NULL) 237 | return 0; 238 | goto next_indirection; 239 | case DW_TAG_typedef: 240 | return typedef__emit_definitions(type, cu, emissions, fp); 241 | case DW_TAG_enumeration_type: 242 | if (type__name(tag__type(type), cu) != NULL) { 243 | struct conf_fprintf conf = { 244 | .suffix = NULL, 245 | }; 246 | return enumeration__emit_definitions(type, cu, emissions, 247 | &conf, fp); 248 | } 249 | break; 250 | case DW_TAG_structure_type: 251 | case DW_TAG_union_type: 252 | if (pointer) 253 | return type__emit_fwd_decl(tag__type(type), cu, 254 | emissions, fp); 255 | if (type__emit_definitions(type, cu, emissions, fp)) 256 | type__emit(type, cu, NULL, NULL, fp); 257 | return 1; 258 | case DW_TAG_subroutine_type: 259 | return ftype__emit_definitions(tag__ftype(type), cu, 260 | emissions, fp); 261 | } 262 | 263 | return 0; 264 | } 265 | 266 | int ftype__emit_definitions(struct ftype *ftype, struct cu *cu, 267 | struct type_emissions *emissions, FILE *fp) 268 | { 269 | struct parameter *pos; 270 | /* First check the function return type */ 271 | int printed = tag__emit_definitions(&ftype->tag, cu, emissions, fp); 272 | 273 | /* Then its parameters */ 274 | list_for_each_entry(pos, &ftype->parms, tag.node) 275 | if (tag__emit_definitions(&pos->tag, cu, emissions, fp)) 276 | printed = 1; 277 | 278 | if (printed) 279 | fputc('\n', fp); 280 | return printed; 281 | } 282 | 283 | int type__emit_definitions(struct tag *tag, struct cu *cu, 284 | struct type_emissions *emissions, FILE *fp) 285 | { 286 | struct type *ctype = tag__type(tag); 287 | struct class_member *pos; 288 | 289 | if (ctype->definition_emitted) 290 | return 0; 291 | 292 | /* Ok, lets look at the previous CUs: */ 293 | if (type_emissions__find_definition(emissions, cu, 294 | type__name(ctype, cu)) != NULL) { 295 | ctype->definition_emitted = 1; 296 | return 0; 297 | } 298 | 299 | type_emissions__add_definition(emissions, ctype); 300 | 301 | type__for_each_member(ctype, pos) 302 | if (tag__emit_definitions(&pos->tag, cu, emissions, fp)) 303 | fputc('\n', fp); 304 | 305 | return 1; 306 | } 307 | 308 | void type__emit(struct tag *tag, struct cu *cu, 309 | const char *prefix, const char *suffix, FILE *fp) 310 | { 311 | struct type *ctype = tag__type(tag); 312 | 313 | if (type__name(ctype, cu) != NULL || 314 | suffix != NULL || prefix != NULL) { 315 | struct conf_fprintf conf = { 316 | .prefix = prefix, 317 | .suffix = suffix, 318 | .emit_stats = 1, 319 | }; 320 | tag__fprintf(tag, cu, &conf, fp); 321 | fputc('\n', fp); 322 | } 323 | } 324 | -------------------------------------------------------------------------------- /dwarves_emit.h: -------------------------------------------------------------------------------- 1 | #ifndef _DWARVES_EMIT_H_ 2 | #define _DWARVES_EMIT_H_ 1 3 | /* 4 | Copyright (C) 2006 Mandriva Conectiva S.A. 5 | Copyright (C) 2006 Arnaldo Carvalho de Melo 6 | Copyright (C) 2007 Arnaldo Carvalho de Melo 7 | 8 | This program is free software; you can redistribute it and/or modify it 9 | under the terms of version 2 of the GNU General Public License as 10 | published by the Free Software Foundation. 11 | */ 12 | 13 | #include 14 | #include "list.h" 15 | 16 | struct cu; 17 | struct ftype; 18 | struct tag; 19 | struct type; 20 | 21 | struct type_emissions { 22 | struct list_head definitions; /* struct type entries */ 23 | struct list_head fwd_decls; /* struct class entries */ 24 | }; 25 | 26 | void type_emissions__init(struct type_emissions *self); 27 | 28 | int ftype__emit_definitions(struct ftype *self, struct cu *cu, 29 | struct type_emissions *emissions, FILE *fp); 30 | int type__emit_definitions(struct tag *self, struct cu *cu, 31 | struct type_emissions *emissions, FILE *fp); 32 | int type__emit_fwd_decl(struct type *ctype, const struct cu *cu, 33 | struct type_emissions *emissions, FILE *fp); 34 | void type__emit(struct tag *tag_self, struct cu *cu, 35 | const char *prefix, const char *suffix, FILE *fp); 36 | struct type *type_emissions__find_definition(const struct type_emissions *self, 37 | const struct cu *cu, 38 | const char *name); 39 | 40 | #endif /* _DWARVES_EMIT_H_ */ 41 | -------------------------------------------------------------------------------- /dwarves_reorganize.h: -------------------------------------------------------------------------------- 1 | #ifndef _DWARVES_REORGANIZE_H_ 2 | #define _DWARVES_REORGANIZE_H_ 1 3 | /* 4 | Copyright (C) 2006 Mandriva Conectiva S.A. 5 | Copyright (C) 2006 Arnaldo Carvalho de Melo 6 | Copyright (C) 2007 Arnaldo Carvalho de Melo 7 | 8 | This program is free software; you can redistribute it and/or modify it 9 | under the terms of version 2 of the GNU General Public License as 10 | published by the Free Software Foundation. 11 | */ 12 | 13 | 14 | #include 15 | #include 16 | 17 | struct class; 18 | struct cu; 19 | struct class_member; 20 | 21 | void class__subtract_offsets_from(struct class *self, struct class_member *from, 22 | const uint16_t size); 23 | 24 | void class__add_offsets_from(struct class *self, struct class_member *from, 25 | const uint16_t size); 26 | 27 | void class__fixup_alignment(struct class *self, const struct cu *cu); 28 | 29 | void class__reorganize(struct class *self, const struct cu *cu, 30 | const int verbose, FILE *fp); 31 | 32 | #endif /* _DWARVES_REORGANIZE_H_ */ 33 | -------------------------------------------------------------------------------- /elf_symtab.c: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (C) 2009 Red Hat Inc. 3 | Copyright (C) 2009 Arnaldo Carvalho de Melo 4 | 5 | This program is free software; you can redistribute it and/or modify it 6 | under the terms of version 2 of the GNU General Public License as 7 | published by the Free Software Foundation. 8 | */ 9 | 10 | #include 11 | #include 12 | #include 13 | 14 | #include "dutil.h" 15 | #include "elf_symtab.h" 16 | 17 | #define HASHSYMS__BITS 8 18 | #define HASHSYMS__SIZE (1UL << HASHSYMS__BITS) 19 | 20 | struct elf_symtab *elf_symtab__new(const char *name, Elf *elf, GElf_Ehdr *ehdr) 21 | { 22 | if (name == NULL) 23 | name = ".symtab"; 24 | 25 | GElf_Shdr shdr; 26 | Elf_Scn *sec = elf_section_by_name(elf, ehdr, &shdr, name, NULL); 27 | 28 | if (sec == NULL) 29 | return NULL; 30 | 31 | if (gelf_getshdr(sec, &shdr) == NULL) 32 | return NULL; 33 | 34 | struct elf_symtab *symtab = malloc(sizeof(*symtab)); 35 | if (symtab == NULL) 36 | return NULL; 37 | 38 | symtab->name = strdup(name); 39 | if (symtab->name == NULL) 40 | goto out_delete; 41 | 42 | symtab->syms = elf_getdata(sec, NULL); 43 | if (symtab->syms == NULL) 44 | goto out_free_name; 45 | 46 | sec = elf_getscn(elf, shdr.sh_link); 47 | if (sec == NULL) 48 | goto out_free_name; 49 | 50 | symtab->symstrs = elf_getdata(sec, NULL); 51 | if (symtab->symstrs == NULL) 52 | goto out_free_name; 53 | 54 | symtab->nr_syms = shdr.sh_size / shdr.sh_entsize; 55 | 56 | return symtab; 57 | out_free_name: 58 | free(symtab->name); 59 | out_delete: 60 | free(symtab); 61 | return NULL; 62 | } 63 | 64 | void elf_symtab__delete(struct elf_symtab *symtab) 65 | { 66 | if (symtab == NULL) 67 | return; 68 | free(symtab->name); 69 | free(symtab); 70 | } 71 | -------------------------------------------------------------------------------- /elf_symtab.h: -------------------------------------------------------------------------------- 1 | #ifndef _ELF_SYMTAB_H_ 2 | #define _ELF_SYMTAB_H_ 1 3 | /* 4 | Copyright (C) 2009 Red Hat Inc. 5 | Copyright (C) 2009 Arnaldo Carvalho de Melo 6 | 7 | This program is free software; you can redistribute it and/or modify it 8 | under the terms of version 2 of the GNU General Public License as 9 | published by the Free Software Foundation. 10 | */ 11 | 12 | #include 13 | #include 14 | #include 15 | #include 16 | 17 | struct elf_symtab { 18 | uint32_t nr_syms; 19 | Elf_Data *syms; 20 | Elf_Data *symstrs; 21 | char *name; 22 | }; 23 | 24 | struct elf_symtab *elf_symtab__new(const char *name, Elf *elf, GElf_Ehdr *ehdr); 25 | void elf_symtab__delete(struct elf_symtab *self); 26 | 27 | static inline uint32_t elf_symtab__nr_symbols(const struct elf_symtab *self) 28 | { 29 | return self->nr_syms; 30 | } 31 | 32 | static inline const char *elf_sym__name(const GElf_Sym *sym, 33 | const struct elf_symtab *symtab) 34 | { 35 | return symtab->symstrs->d_buf + sym->st_name; 36 | } 37 | 38 | static inline uint8_t elf_sym__type(const GElf_Sym *sym) 39 | { 40 | return GELF_ST_TYPE(sym->st_info); 41 | } 42 | 43 | static inline uint16_t elf_sym__section(const GElf_Sym *sym) 44 | { 45 | return sym->st_shndx; 46 | } 47 | 48 | static inline uint8_t elf_sym__bind(const GElf_Sym *sym) 49 | { 50 | return GELF_ST_BIND(sym->st_info); 51 | } 52 | 53 | static inline uint8_t elf_sym__visibility(const GElf_Sym *sym) 54 | { 55 | return GELF_ST_VISIBILITY(sym->st_other); 56 | } 57 | 58 | static inline uint32_t elf_sym__size(const GElf_Sym *sym) 59 | { 60 | return sym->st_size; 61 | } 62 | 63 | static inline uint64_t elf_sym__value(const GElf_Sym *sym) 64 | { 65 | return sym->st_value; 66 | } 67 | 68 | static inline bool elf_sym__is_local_function(const GElf_Sym *sym) 69 | { 70 | return elf_sym__type(sym) == STT_FUNC && 71 | sym->st_name != 0 && 72 | sym->st_shndx != SHN_UNDEF; 73 | } 74 | 75 | static inline bool elf_sym__is_local_object(const GElf_Sym *sym) 76 | { 77 | return elf_sym__type(sym) == STT_OBJECT && 78 | sym->st_name != 0 && 79 | sym->st_shndx != SHN_UNDEF; 80 | } 81 | 82 | /** 83 | * elf_symtab__for_each_symbol - iterate thru all the symbols 84 | * 85 | * @self: struct elf_symtab instance to iterate 86 | * @index: uint32_t index 87 | * @sym: GElf_Sym iterator 88 | */ 89 | #define elf_symtab__for_each_symbol(self, index, sym) \ 90 | for (index = 0, gelf_getsym(self->syms, index, &sym);\ 91 | index < self->nr_syms; \ 92 | index++, gelf_getsym(self->syms, index, &sym)) 93 | 94 | #endif /* _ELF_SYMTAB_H_ */ 95 | -------------------------------------------------------------------------------- /elfcreator.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2009 Red Hat, Inc. 3 | * 4 | * This program is free software; you can redistribute it and/or modify it 5 | * under the terms of version 2 of the GNU General Public License as 6 | * published by the Free Software Foundation. 7 | * 8 | * Author: Peter Jones 9 | */ 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | 20 | #include "elfcreator.h" 21 | 22 | struct elf_creator { 23 | const char *path; 24 | int fd; 25 | 26 | Elf *elf; 27 | GElf_Ehdr *ehdr, ehdr_mem; 28 | 29 | Elf *oldelf; 30 | /* just because we have to look this up /so/ often... */ 31 | Elf_Scn *dynscn; 32 | GElf_Shdr *dynshdr, dynshdr_mem; 33 | Elf_Data *dyndata; 34 | }; 35 | 36 | static void clear(ElfCreator *ctor, int do_unlink) 37 | { 38 | if (do_unlink) { 39 | if (ctor->elf) 40 | elf_end(ctor->elf); 41 | if (ctor->fd >= 0) 42 | close(ctor->fd); 43 | if (ctor->path) 44 | unlink(ctor->path); 45 | } else { 46 | if (ctor->elf) { 47 | elf_update(ctor->elf, ELF_C_WRITE_MMAP); 48 | elf_end(ctor->elf); 49 | } 50 | if (ctor->fd >= 0) 51 | close(ctor->fd); 52 | } 53 | memset(ctor, '\0', sizeof(*ctor)); 54 | } 55 | 56 | ElfCreator *elfcreator_begin(char *path, Elf *elf) { 57 | ElfCreator *ctor = NULL; 58 | GElf_Ehdr ehdr_mem, *ehdr; 59 | GElf_Half machine; 60 | 61 | if (!(ctor = calloc(1, sizeof(*ctor)))) 62 | return NULL; 63 | 64 | clear(ctor, 0); 65 | 66 | ctor->path = path; 67 | ctor->oldelf = elf; 68 | 69 | ehdr = gelf_getehdr(elf, &ehdr_mem); 70 | machine = ehdr->e_machine; 71 | 72 | if ((ctor->fd = open(path, O_RDWR|O_CREAT|O_TRUNC, 0755)) < 0) { 73 | err: 74 | clear(ctor, 1); 75 | free(ctor); 76 | return NULL; 77 | } 78 | 79 | if (!(ctor->elf = elf_begin(ctor->fd, ELF_C_WRITE_MMAP, elf))) 80 | goto err; 81 | 82 | gelf_newehdr(ctor->elf, gelf_getclass(elf)); 83 | gelf_update_ehdr(ctor->elf, ehdr); 84 | 85 | if (!(ctor->ehdr = gelf_getehdr(ctor->elf, &ctor->ehdr_mem))) 86 | goto err; 87 | 88 | return ctor; 89 | } 90 | 91 | static Elf_Scn *get_scn_by_type(ElfCreator *ctor, Elf64_Word sh_type) 92 | { 93 | Elf_Scn *scn = NULL; 94 | 95 | while ((scn = elf_nextscn(ctor->elf, scn)) != NULL) { 96 | GElf_Shdr *shdr, shdr_mem; 97 | 98 | shdr = gelf_getshdr(scn, &shdr_mem); 99 | if (shdr->sh_type == sh_type) 100 | return scn; 101 | } 102 | return NULL; 103 | } 104 | 105 | static void update_dyn_cache(ElfCreator *ctor) 106 | { 107 | ctor->dynscn = get_scn_by_type(ctor, SHT_DYNAMIC); 108 | if (ctor->dynscn == NULL) 109 | return; 110 | 111 | ctor->dynshdr = gelf_getshdr(ctor->dynscn, &ctor->dynshdr_mem); 112 | ctor->dyndata = elf_getdata(ctor->dynscn, NULL); 113 | } 114 | 115 | void elfcreator_copy_scn(ElfCreator *ctor, Elf *src, Elf_Scn *scn) 116 | { 117 | Elf_Scn *newscn; 118 | Elf_Data *indata, *outdata; 119 | GElf_Shdr *oldshdr, oldshdr_mem; 120 | GElf_Shdr *newshdr, newshdr_mem; 121 | 122 | newscn = elf_newscn(ctor->elf); 123 | newshdr = gelf_getshdr(newscn, &newshdr_mem); 124 | 125 | oldshdr = gelf_getshdr(scn, &oldshdr_mem); 126 | 127 | memmove(newshdr, oldshdr, sizeof(*newshdr)); 128 | gelf_update_shdr(newscn, newshdr); 129 | 130 | indata = NULL; 131 | while ((indata = elf_getdata(scn, indata)) != NULL) { 132 | outdata = elf_newdata(newscn); 133 | *outdata = *indata; 134 | } 135 | if (newshdr->sh_type == SHT_DYNAMIC) 136 | update_dyn_cache(ctor); 137 | } 138 | 139 | static GElf_Dyn *get_dyn_by_tag(ElfCreator *ctor, Elf64_Sxword d_tag, 140 | GElf_Dyn *mem, size_t *idx) 141 | { 142 | size_t cnt; 143 | 144 | if (!ctor->dyndata) 145 | return NULL; 146 | 147 | for (cnt = 1; cnt < ctor->dynshdr->sh_size / ctor->dynshdr->sh_entsize; 148 | cnt++) { 149 | GElf_Dyn *dyn; 150 | 151 | if ((dyn = gelf_getdyn(ctor->dyndata, cnt, mem)) == NULL) 152 | break; 153 | 154 | if (dyn->d_tag == d_tag) { 155 | *idx = cnt; 156 | return dyn; 157 | } 158 | } 159 | return NULL; 160 | } 161 | 162 | static void remove_dyn(ElfCreator *ctor, size_t idx) 163 | { 164 | size_t cnt; 165 | 166 | for (cnt = idx; cnt < ctor->dynshdr->sh_size/ctor->dynshdr->sh_entsize; 167 | cnt++) { 168 | GElf_Dyn *dyn, dyn_mem; 169 | 170 | if (cnt+1 == ctor->dynshdr->sh_size/ctor->dynshdr->sh_entsize) { 171 | memset(&dyn_mem, '\0', sizeof(dyn_mem)); 172 | gelf_update_dyn(ctor->dyndata, cnt, &dyn_mem); 173 | break; 174 | } 175 | 176 | dyn = gelf_getdyn(ctor->dyndata, cnt+1, &dyn_mem); 177 | gelf_update_dyn(ctor->dyndata, cnt, dyn); 178 | } 179 | ctor->dynshdr->sh_size--; 180 | gelf_update_shdr(ctor->dynscn, ctor->dynshdr); 181 | update_dyn_cache(ctor); 182 | } 183 | 184 | typedef void (*dyn_fixup_fn)(ElfCreator *ctor, Elf64_Sxword d_tag, Elf_Scn *scn); 185 | 186 | static void generic_dyn_fixup_fn(ElfCreator *ctor, Elf64_Sxword d_tag, Elf_Scn *scn) 187 | { 188 | GElf_Shdr *shdr, shdr_mem; 189 | GElf_Dyn *dyn, dyn_mem; 190 | size_t idx; 191 | 192 | dyn = get_dyn_by_tag(ctor, d_tag, &dyn_mem, &idx); 193 | shdr = gelf_getshdr(scn, &shdr_mem); 194 | if (shdr) { 195 | dyn->d_un.d_ptr = shdr->sh_addr; 196 | gelf_update_dyn(ctor->dyndata, idx, dyn); 197 | } else { 198 | remove_dyn(ctor, idx); 199 | } 200 | } 201 | 202 | static void rela_dyn_fixup_fn(ElfCreator *ctor, Elf64_Sxword d_tag, Elf_Scn *scn) 203 | { 204 | GElf_Shdr *shdr, shdr_mem; 205 | GElf_Dyn *dyn, dyn_mem; 206 | size_t idx; 207 | 208 | dyn = get_dyn_by_tag(ctor, d_tag, &dyn_mem, &idx); 209 | shdr = gelf_getshdr(scn, &shdr_mem); 210 | if (shdr) { 211 | dyn->d_un.d_ptr = shdr->sh_addr; 212 | gelf_update_dyn(ctor->dyndata, idx, dyn); 213 | } else { 214 | remove_dyn(ctor, idx); 215 | dyn = get_dyn_by_tag(ctor, DT_RELASZ, &dyn_mem, &idx); 216 | if (dyn) { 217 | dyn->d_un.d_val = 0; 218 | gelf_update_dyn(ctor->dyndata, idx, dyn); 219 | } 220 | } 221 | } 222 | 223 | static void rel_dyn_fixup_fn(ElfCreator *ctor, Elf64_Sxword d_tag, Elf_Scn *scn) 224 | { 225 | GElf_Shdr *shdr, shdr_mem; 226 | GElf_Dyn *dyn, dyn_mem; 227 | size_t idx; 228 | 229 | dyn = get_dyn_by_tag(ctor, d_tag, &dyn_mem, &idx); 230 | shdr = gelf_getshdr(scn, &shdr_mem); 231 | if (shdr) { 232 | dyn->d_un.d_ptr = shdr->sh_addr; 233 | gelf_update_dyn(ctor->dyndata, idx, dyn); 234 | } else { 235 | remove_dyn(ctor, idx); 236 | dyn = get_dyn_by_tag(ctor, DT_RELSZ, &dyn_mem, &idx); 237 | if (dyn) { 238 | dyn->d_un.d_val = 0; 239 | gelf_update_dyn(ctor->dyndata, idx, dyn); 240 | } 241 | } 242 | } 243 | 244 | static void fixup_dynamic(ElfCreator *ctor) 245 | { 246 | struct { 247 | Elf64_Sxword d_tag; 248 | Elf64_Word sh_type; 249 | dyn_fixup_fn fn; 250 | } fixups[] = { 251 | { DT_HASH, SHT_HASH, NULL }, 252 | { DT_STRTAB, SHT_STRTAB, NULL }, 253 | { DT_SYMTAB, SHT_SYMTAB, NULL }, 254 | { DT_RELA, SHT_RELA, rela_dyn_fixup_fn}, 255 | { DT_REL, SHT_REL, rel_dyn_fixup_fn}, 256 | { DT_GNU_HASH, SHT_GNU_HASH, NULL }, 257 | { DT_NULL, SHT_NULL, NULL } 258 | }; 259 | int i; 260 | 261 | for (i = 0; fixups[i].d_tag != DT_NULL; i++) { 262 | Elf_Scn *scn; 263 | 264 | scn = get_scn_by_type(ctor, fixups[i].sh_type); 265 | if (fixups[i].fn) 266 | fixups[i].fn(ctor, fixups[i].d_tag, scn); 267 | else 268 | generic_dyn_fixup_fn(ctor, fixups[i].d_tag, scn); 269 | } 270 | } 271 | 272 | void elfcreator_end(ElfCreator *ctor) 273 | { 274 | GElf_Phdr phdr_mem, *phdr; 275 | int m,n; 276 | 277 | for (m = 0; (phdr = gelf_getphdr(ctor->oldelf, m, &phdr_mem)) != NULL; m++) 278 | /* XXX this should check if an entry is needed */; 279 | 280 | gelf_newphdr(ctor->elf, m); 281 | elf_update(ctor->elf, ELF_C_NULL); 282 | update_dyn_cache(ctor); 283 | 284 | for (n = 0; n < m; n++) { 285 | /* XXX this should check if an entry is needed */ 286 | phdr = gelf_getphdr(ctor->oldelf, n, &phdr_mem); 287 | if (ctor->dynshdr && phdr->p_type == PT_DYNAMIC) 288 | phdr->p_offset = ctor->dynshdr->sh_offset; 289 | 290 | gelf_update_phdr(ctor->elf, n, phdr); 291 | } 292 | 293 | fixup_dynamic(ctor); 294 | 295 | clear(ctor, 0); 296 | free(ctor); 297 | } 298 | -------------------------------------------------------------------------------- /elfcreator.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2009 Red Hat, Inc. 3 | * 4 | * This program is free software; you can redistribute it and/or modify it 5 | * under the terms of version 2 of the GNU General Public License as 6 | * published by the Free Software Foundation. 7 | * 8 | * Author: Peter Jones 9 | */ 10 | #ifndef ELFCREATOR_H 11 | #define ELFCREATOR_H 1 12 | 13 | #include 14 | 15 | typedef struct elf_creator ElfCreator; 16 | extern ElfCreator *elfcreator_begin(char *path, Elf *elf); 17 | extern void elfcreator_copy_scn(ElfCreator *ctor, Elf *src, Elf_Scn *scn); 18 | extern void elfcreator_end(ElfCreator *ctor); 19 | 20 | #endif /* ELFCREATOR_H */ 21 | -------------------------------------------------------------------------------- /gobuffer.c: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (C) 2008 Arnaldo Carvalho de Melo 3 | 4 | Grow only buffer, add entries but never delete 5 | 6 | This program is free software; you can redistribute it and/or modify it 7 | under the terms of version 2 of the GNU General Public License as 8 | published by the Free Software Foundation. 9 | */ 10 | 11 | #include "gobuffer.h" 12 | 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | 21 | #include "dutil.h" 22 | 23 | #define GOBUFFER__BCHUNK (8 * 1024) 24 | #define GOBUFFER__ZCHUNK (8 * 1024) 25 | 26 | void gobuffer__init(struct gobuffer *gb) 27 | { 28 | gb->entries = NULL; 29 | gb->nr_entries = gb->allocated_size = 0; 30 | /* 0 == NULL */ 31 | gb->index = 1; 32 | } 33 | 34 | struct gobuffer *gobuffer__new(void) 35 | { 36 | struct gobuffer *gb = malloc(sizeof(*gb)); 37 | 38 | if (gb != NULL) 39 | gobuffer__init(gb); 40 | 41 | return gb; 42 | } 43 | 44 | void __gobuffer__delete(struct gobuffer *gb) 45 | { 46 | free(gb->entries); 47 | } 48 | 49 | void gobuffer__delete(struct gobuffer *gb) 50 | { 51 | __gobuffer__delete(gb); 52 | free(gb); 53 | } 54 | 55 | void *gobuffer__ptr(const struct gobuffer *gb, unsigned int s) 56 | { 57 | return s ? gb->entries + s : NULL; 58 | } 59 | 60 | int gobuffer__allocate(struct gobuffer *gb, unsigned int len) 61 | { 62 | const unsigned int rc = gb->index; 63 | const unsigned int index = gb->index + len; 64 | 65 | if (index >= gb->allocated_size) { 66 | unsigned int allocated_size = (gb->allocated_size + 67 | GOBUFFER__BCHUNK); 68 | if (allocated_size < index) 69 | allocated_size = index + GOBUFFER__BCHUNK; 70 | char *entries = realloc(gb->entries, allocated_size); 71 | 72 | if (entries == NULL) 73 | return -ENOMEM; 74 | 75 | gb->allocated_size = allocated_size; 76 | gb->entries = entries; 77 | } 78 | 79 | gb->index = index; 80 | return rc; 81 | } 82 | 83 | int gobuffer__add(struct gobuffer *gb, const void *s, unsigned int len) 84 | { 85 | const int rc = gobuffer__allocate(gb, len); 86 | 87 | if (rc >= 0) { 88 | ++gb->nr_entries; 89 | memcpy(gb->entries + rc, s, len); 90 | } 91 | return rc; 92 | } 93 | 94 | void gobuffer__copy(const struct gobuffer *gb, void *dest) 95 | { 96 | memcpy(dest, gb->entries, gobuffer__size(gb)); 97 | } 98 | 99 | const void *gobuffer__compress(struct gobuffer *gb, unsigned int *size) 100 | { 101 | z_stream z = { 102 | .zalloc = Z_NULL, 103 | .zfree = Z_NULL, 104 | .opaque = Z_NULL, 105 | .avail_in = gobuffer__size(gb), 106 | .next_in = (Bytef *)gobuffer__entries(gb), 107 | }; 108 | void *bf = NULL; 109 | unsigned int bf_size = 0; 110 | 111 | if (deflateInit(&z, Z_BEST_COMPRESSION) != Z_OK) 112 | goto out_free; 113 | 114 | do { 115 | const unsigned int new_bf_size = bf_size + GOBUFFER__ZCHUNK; 116 | void *nbf = realloc(bf, new_bf_size); 117 | 118 | if (nbf == NULL) 119 | goto out_close_and_free; 120 | 121 | bf = nbf; 122 | z.avail_out = GOBUFFER__ZCHUNK; 123 | z.next_out = (Bytef *)bf + bf_size; 124 | bf_size = new_bf_size; 125 | if (deflate(&z, Z_FINISH) == Z_STREAM_ERROR) 126 | goto out_close_and_free; 127 | } while (z.avail_out == 0); 128 | 129 | deflateEnd(&z); 130 | *size = bf_size - z.avail_out; 131 | out: 132 | return bf; 133 | 134 | out_close_and_free: 135 | deflateEnd(&z); 136 | out_free: 137 | free(bf); 138 | bf = NULL; 139 | goto out; 140 | } 141 | -------------------------------------------------------------------------------- /gobuffer.h: -------------------------------------------------------------------------------- 1 | #ifndef _GOBUFFER_H_ 2 | #define _GOBUFFER_H_ 1 3 | /* 4 | Copyright (C) 2008 Arnaldo Carvalho de Melo 5 | 6 | This program is free software; you can redistribute it and/or modify it 7 | under the terms of version 2 of the GNU General Public License as 8 | published by the Free Software Foundation. 9 | */ 10 | 11 | struct gobuffer { 12 | char *entries; 13 | unsigned int nr_entries; 14 | unsigned int index; 15 | unsigned int allocated_size; 16 | }; 17 | 18 | struct gobuffer *gobuffer__new(void); 19 | 20 | void gobuffer__init(struct gobuffer *self); 21 | void gobuffer__delete(struct gobuffer *self); 22 | void __gobuffer__delete(struct gobuffer *self); 23 | 24 | void gobuffer__copy(const struct gobuffer *self, void *dest); 25 | 26 | int gobuffer__add(struct gobuffer *self, const void *s, unsigned int len); 27 | int gobuffer__allocate(struct gobuffer *self, unsigned int len); 28 | 29 | static inline const void *gobuffer__entries(const struct gobuffer *self) 30 | { 31 | return self->entries; 32 | } 33 | 34 | static inline unsigned int gobuffer__nr_entries(const struct gobuffer *self) 35 | { 36 | return self->nr_entries; 37 | } 38 | 39 | static inline unsigned int gobuffer__size(const struct gobuffer *self) 40 | { 41 | return self->index; 42 | } 43 | 44 | void *gobuffer__ptr(const struct gobuffer *self, unsigned int s); 45 | 46 | const void *gobuffer__compress(struct gobuffer *self, unsigned int *size); 47 | 48 | #endif /* _GOBUFFER_H_ */ 49 | -------------------------------------------------------------------------------- /hash.h: -------------------------------------------------------------------------------- 1 | #ifndef _LINUX_HASH_H 2 | #define _LINUX_HASH_H 3 | /* Fast hashing routine for ints, longs and pointers. 4 | (C) 2002 William Lee Irwin III, IBM */ 5 | 6 | /* 7 | * Knuth recommends primes in approximately golden ratio to the maximum 8 | * integer representable by a machine word for multiplicative hashing. 9 | * Chuck Lever verified the effectiveness of this technique: 10 | * http://www.citi.umich.edu/techreports/reports/citi-tr-00-1.pdf 11 | * 12 | * These primes are chosen to be bit-sparse, that is operations on 13 | * them can use shifts and additions instead of multiplications for 14 | * machines where multiplications are slow. 15 | */ 16 | 17 | #include 18 | 19 | /* 2^31 + 2^29 - 2^25 + 2^22 - 2^19 - 2^16 + 1 */ 20 | #define GOLDEN_RATIO_PRIME_32 0x9e370001UL 21 | /* 2^63 + 2^61 - 2^57 + 2^54 - 2^51 - 2^18 + 1 */ 22 | #define GOLDEN_RATIO_PRIME_64 0x9e37fffffffc0001UL 23 | 24 | #if __WORDSIZE == 32 25 | #define GOLDEN_RATIO_PRIME GOLDEN_RATIO_PRIME_32 26 | #define hash_long(val, bits) hash_32(val, bits) 27 | #elif __WORDSIZE == 64 28 | #define hash_long(val, bits) hash_64(val, bits) 29 | #define GOLDEN_RATIO_PRIME GOLDEN_RATIO_PRIME_64 30 | #else 31 | #error Wordsize not 32 or 64 32 | #endif 33 | 34 | static inline uint64_t hash_64(const uint64_t val, const unsigned int bits) 35 | { 36 | uint64_t hash = val; 37 | 38 | /* Sigh, gcc can't optimise this alone like it does for 32 bits. */ 39 | uint64_t n = hash; 40 | n <<= 18; 41 | hash -= n; 42 | n <<= 33; 43 | hash -= n; 44 | n <<= 3; 45 | hash += n; 46 | n <<= 3; 47 | hash -= n; 48 | n <<= 4; 49 | hash += n; 50 | n <<= 2; 51 | hash += n; 52 | 53 | /* High bits are more random, so use them. */ 54 | return hash >> (64 - bits); 55 | } 56 | 57 | static inline uint32_t hash_32(uint32_t val, unsigned int bits) 58 | { 59 | /* On some cpus multiply is faster, on others gcc will do shifts */ 60 | uint32_t hash = val * GOLDEN_RATIO_PRIME_32; 61 | 62 | /* High bits are more random, so use them. */ 63 | return hash >> (32 - bits); 64 | } 65 | 66 | static inline unsigned long hash_ptr(void *ptr, unsigned int bits) 67 | { 68 | return hash_long((unsigned long)ptr, bits); 69 | } 70 | #endif /* _LINUX_HASH_H */ 71 | -------------------------------------------------------------------------------- /lib/Makefile: -------------------------------------------------------------------------------- 1 | obj-m := ctracer.o 2 | 3 | ctracer-y := ctracer_collector.o ctracer_relay.o 4 | 5 | # Files generated that shall be removed upon make clean 6 | clean-files := ctracer_collector.c 7 | 8 | CLASS=sock 9 | #KDIR := /home/acme/git/OUTPUT/qemu/linux-2.6/ 10 | KDIR := /lib/modules/$(shell uname -r)/build 11 | PWD := $(shell pwd) 12 | 13 | default: 14 | $(MAKE) -C $(KDIR) SUBDIRS=$(PWD) modules 15 | 16 | clean: 17 | rm -rf .*.mod.c .*o.cmd *.mod.c *.ko *.o \ 18 | ctracer_collector.c ctracer_methods.stp \ 19 | ctracer_classes.h \ 20 | Module.symvers .tmp_versions/ \ 21 | $(CLASS).{fields,functions} ctracer2ostra* 22 | 23 | $(src)/ctracer2ostra: ctracer_methods.stp 24 | $(CC) $@.c -o $@ 25 | 26 | cu_blacklist_file=/usr/share/dwarves/runtime/linux.blacklist.cu 27 | 28 | LOG=/tmp/ctracer.log 29 | callgraph: ctracer2ostra 30 | ./ctracer2ostra < $(LOG) > $(LOG).ostra ; \ 31 | rm -rf $(CLASS).callgraph ; \ 32 | PYTHONPATH=python/ ostra-cg $(CLASS) $(LOG).ostra 33 | 34 | $(obj)/ctracer_collector.o: ctracer_collector.c 35 | 36 | $(src)/ctracer_collector.c: 37 | ctracer --src_dir $(src) /usr/lib/debug/lib/modules/$(shell uname -r)/vmlinux \ 38 | --cu_blacklist $(cu_blacklist_file) $(CLASS) 39 | -------------------------------------------------------------------------------- /lib/ctracer_relay.c: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (C) 2007 Arnaldo Carvalho de Melo 3 | 4 | This program is free software; you can redistribute it and/or modify it 5 | under the terms of version 2 of the GNU General Public License as 6 | published by the Free Software Foundation. 7 | */ 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include "ctracer_relay.h" 17 | 18 | static struct rchan *ctracer__rchan; 19 | 20 | static int ctracer__subbuf_start_callback(struct rchan_buf *buf, void *subbuf, 21 | void *prev_subbuf, 22 | size_t prev_padding) 23 | { 24 | static int warned; 25 | if (!relay_buf_full(buf)) 26 | return 1; 27 | if (!warned) { 28 | warned = 1; 29 | printk("relay_buf_full!\n"); 30 | } 31 | return 0; 32 | } 33 | 34 | static struct dentry *ctracer__create_buf_file_callback(const char *filename, 35 | struct dentry *parent, 36 | int mode, 37 | struct rchan_buf *buf, 38 | int *is_global) 39 | { 40 | return debugfs_create_file(filename, mode, parent, buf, 41 | &relay_file_operations); 42 | } 43 | 44 | static int ctracer__remove_buf_file_callback(struct dentry *dentry) 45 | { 46 | debugfs_remove(dentry); 47 | return 0; 48 | } 49 | 50 | static struct rchan_callbacks ctracer__relay_callbacks = { 51 | .subbuf_start = ctracer__subbuf_start_callback, 52 | .create_buf_file = ctracer__create_buf_file_callback, 53 | .remove_buf_file = ctracer__remove_buf_file_callback, 54 | }; 55 | 56 | extern void ctracer__class_state(const void *from, void *to); 57 | 58 | void ctracer__method_hook(const unsigned long long now, 59 | const int probe_type, 60 | const unsigned long long function_id, 61 | const void *object, const int state_len) 62 | { 63 | if (object != NULL) { 64 | void *t = relay_reserve(ctracer__rchan, 65 | sizeof(struct trace_entry) + state_len); 66 | 67 | if (t != NULL) { 68 | struct trace_entry *entry = t; 69 | 70 | entry->nsec = now; 71 | entry->probe_type = probe_type; 72 | entry->object = object; 73 | entry->function_id = function_id; 74 | ctracer__class_state(object, t + sizeof(*entry)); 75 | } 76 | } 77 | } 78 | 79 | EXPORT_SYMBOL_GPL(ctracer__method_hook); 80 | 81 | static int __init ctracer__relay_init(void) 82 | { 83 | ctracer__rchan = relay_open("ctracer", NULL, 512 * 1024, 64, 84 | &ctracer__relay_callbacks, NULL); 85 | if (ctracer__rchan == NULL) { 86 | pr_info("ctracer: couldn't create the relay\n"); 87 | return -1; 88 | } 89 | return 0; 90 | } 91 | 92 | module_init(ctracer__relay_init); 93 | 94 | static void __exit ctracer__relay_exit(void) 95 | { 96 | relay_close(ctracer__rchan); 97 | } 98 | 99 | module_exit(ctracer__relay_exit); 100 | 101 | MODULE_LICENSE("GPL"); 102 | -------------------------------------------------------------------------------- /lib/ctracer_relay.h: -------------------------------------------------------------------------------- 1 | #ifndef _CTRACER_RELAY_H_ 2 | #define _CTRACER_RELAY_H_ 1 3 | /* 4 | Copyright (C) 2007 Arnaldo Carvalho de Melo 5 | 6 | This program is free software; you can redistribute it and/or modify it 7 | under the terms of version 2 of the GNU General Public License as 8 | published by the Free Software Foundation. 9 | */ 10 | 11 | struct trace_entry { 12 | unsigned long long nsec; 13 | unsigned long long probe_type:1; /* Entry or exit */ 14 | unsigned long long function_id:63; 15 | const void *object; 16 | }; 17 | 18 | void ctracer__method_hook(const unsigned long long now, 19 | const int probe_type, 20 | const unsigned long long function, 21 | const void *object, const int state_len); 22 | 23 | #endif 24 | -------------------------------------------------------------------------------- /lib/linux.blacklist.cu: -------------------------------------------------------------------------------- 1 | kernel/kprobes.c 2 | kernel/relay.c 3 | -------------------------------------------------------------------------------- /libctf.h: -------------------------------------------------------------------------------- 1 | #ifndef _LIBCTF_H 2 | #define _LIBCTF_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #include "gobuffer.h" 10 | #include "elf_symtab.h" 11 | 12 | struct ctf { 13 | void *buf; 14 | void *priv; 15 | Elf *elf; 16 | struct elf_symtab *symtab; 17 | GElf_Ehdr ehdr; 18 | struct gobuffer objects; /* data/variables */ 19 | struct gobuffer types; 20 | struct gobuffer funcs; 21 | struct gobuffer *strings; 22 | char *filename; 23 | size_t size; 24 | int swapped; 25 | int in_fd; 26 | uint8_t wordsize; 27 | unsigned int type_index; 28 | }; 29 | 30 | struct ctf *ctf__new(const char *filename, Elf *elf); 31 | void ctf__delete(struct ctf *ctf); 32 | 33 | bool ctf__ignore_symtab_function(const GElf_Sym *sym, const char *sym_name); 34 | bool ctf__ignore_symtab_object(const GElf_Sym *sym, const char *sym_name); 35 | 36 | int ctf__load(struct ctf *self); 37 | 38 | uint16_t ctf__get16(struct ctf *self, uint16_t *p); 39 | uint32_t ctf__get32(struct ctf *self, uint32_t *p); 40 | void ctf__put16(struct ctf *self, uint16_t *p, uint16_t val); 41 | void ctf__put32(struct ctf *self, uint32_t *p, uint32_t val); 42 | 43 | void *ctf__get_buffer(struct ctf *self); 44 | size_t ctf__get_size(struct ctf *self); 45 | 46 | int ctf__load_symtab(struct ctf *self); 47 | 48 | int ctf__add_base_type(struct ctf *self, uint32_t name, uint16_t size); 49 | int ctf__add_fwd_decl(struct ctf *self, uint32_t name); 50 | int ctf__add_short_type(struct ctf *self, uint16_t kind, uint16_t type, 51 | uint32_t name); 52 | void ctf__add_short_member(struct ctf *self, uint32_t name, uint16_t type, 53 | uint16_t offset, int64_t *position); 54 | void ctf__add_full_member(struct ctf *self, uint32_t name, uint16_t type, 55 | uint64_t offset, int64_t *position); 56 | int ctf__add_struct(struct ctf *self, uint16_t kind, uint32_t name, 57 | uint64_t size, uint16_t nr_members, int64_t *position); 58 | int ctf__add_array(struct ctf *self, uint16_t type, uint16_t index_type, 59 | uint32_t nelems); 60 | void ctf__add_parameter(struct ctf *self, uint16_t type, int64_t *position); 61 | int ctf__add_function_type(struct ctf *self, uint16_t type, 62 | uint16_t nr_parms, bool varargs, int64_t *position); 63 | int ctf__add_enumeration_type(struct ctf *self, uint32_t name, uint16_t size, 64 | uint16_t nr_entries, int64_t *position); 65 | void ctf__add_enumerator(struct ctf *self, uint32_t name, uint32_t value, 66 | int64_t *position); 67 | 68 | void ctf__add_function_parameter(struct ctf *self, uint16_t type, 69 | int64_t *position); 70 | int ctf__add_function(struct ctf *self, uint16_t type, uint16_t nr_parms, 71 | bool varargs, int64_t *position); 72 | 73 | int ctf__add_object(struct ctf *self, uint16_t type); 74 | 75 | void ctf__set_strings(struct ctf *self, struct gobuffer *strings); 76 | int ctf__encode(struct ctf *self, uint8_t flags); 77 | 78 | char *ctf__string(struct ctf *self, uint32_t ref); 79 | 80 | /** 81 | * ctf__for_each_symtab_function - iterate thru all the symtab functions 82 | * 83 | * @self: struct ctf instance to iterate 84 | * @index: uint32_t index 85 | * @sym: GElf_Sym iterator 86 | */ 87 | #define ctf__for_each_symtab_function(self, index, sym) \ 88 | elf_symtab__for_each_symbol(self->symtab, index, sym) \ 89 | if (ctf__ignore_symtab_function(&sym, \ 90 | elf_sym__name(&sym, \ 91 | self->symtab))) \ 92 | continue; \ 93 | else 94 | 95 | /** 96 | * ctf__for_each_symtab_object - iterate thru all the symtab objects 97 | * 98 | * @self: struct ctf instance to iterate 99 | * @index: uint32_t index 100 | * @sym: GElf_Sym iterator 101 | */ 102 | #define ctf__for_each_symtab_object(self, index, sym) \ 103 | elf_symtab__for_each_symbol(self->symtab, index, sym) \ 104 | if (ctf__ignore_symtab_object(&sym, \ 105 | elf_sym__name(&sym, \ 106 | self->symtab))) \ 107 | continue; \ 108 | else 109 | 110 | 111 | #endif /* _LIBCTF_H */ 112 | -------------------------------------------------------------------------------- /man-pages/pahole.1: -------------------------------------------------------------------------------- 1 | .\" Man page for pahole 2 | .\" Arnaldo Carvalho de Melo, 2009 3 | .\" Licensed under version 2 of the GNU General Public License. 4 | .TH pahole 1 "February 13, 2009" "dwarves" "dwarves" 5 | .\" 6 | .SH NAME 7 | pahole \- Shows and manipulates data structure layout. 8 | .SH SYNOPSIS 9 | \fBpahole\fR [\fIoptions\fR] \fIfiles\fR 10 | .SH DESCRIPTION 11 | .B pahole 12 | shows data structure layouts encoded in debugging information formats, 13 | DWARF and CTF being supported. 14 | 15 | This is useful for, among other things: optimizing important data structures by 16 | reducing its size, figuring out what is the field sitting at an offset from the 17 | start of a data structure, investigating ABI changes and more generally 18 | understanding a new codebase you have to work with. 19 | 20 | The files must have associated debugging information. This information may be 21 | inside the file itself, in ELF sections, or in another file. 22 | 23 | One way to have this information is to specify the \fB\-g\fR option to the 24 | compiler when building it. When this is done the information will be stored in 25 | an ELF section. For the DWARF debugging information format this, adds, among 26 | others, the \fB.debug_info\fR ELF section. For CTF it is found in just one 27 | ELF section, \fB.SUNW_ctf\fR. 28 | 29 | The \fBdebuginfo\fR packages available in most Linux distributions are also 30 | supported by \fBpahole\fR, where the debugging information is available in a 31 | separate file. 32 | 33 | By default, \fBpahole\fR shows the layout of all named structs in the files 34 | specified. 35 | 36 | .SH OPTIONS 37 | pahole supports the following options. 38 | 39 | .TP 40 | .B \-C, \-\-class_name=CLASS_NAMES 41 | Show just these classes. This can be a comma separated list of class names 42 | or file URLs (e.g.: file://class_list.txt) 43 | 44 | .TP 45 | .B \-c, \-\-cacheline_size=SIZE 46 | Set cacheline size to SIZE bytes. 47 | 48 | .TP 49 | .B \-E, \-\-expand_types 50 | Expand class members. Useful to find in what member of inner structs where an 51 | offset from the beginning of a struct is. 52 | 53 | .TP 54 | .B \-F, \-\-format_path 55 | Allows specifying a list of debugging formats to try, in order. Right now this 56 | includes "ctf" and "dwarf". The default format path used is equivalent to 57 | "-F dwarf,ctf". 58 | 59 | .TP 60 | .B \-r, \-\-rel_offset 61 | Show relative offsets of members in inner structs. 62 | 63 | .TP 64 | .B \-p, \-\-expand_pointers 65 | Expand class pointer members. 66 | 67 | .TP 68 | .B \-R, \-\-reorganize 69 | Reorganize struct, demoting and combining bitfields, moving members to remove 70 | alignment holes and padding. 71 | 72 | .TP 73 | .B \-S, \-\-show_reorg_steps 74 | Show the struct layout at each reorganization step. 75 | 76 | .TP 77 | .B \-i, \-\-contains=CLASS_NAME 78 | Show classes that contains CLASS_NAME. 79 | 80 | .TP 81 | .B \-a, \-\-anon_include 82 | Include anonymous classes. 83 | 84 | .TP 85 | .B \-A, \-\-nested_anon_include 86 | Include nested (inside other structs) anonymous classes. 87 | 88 | .TP 89 | .B \-B, \-\-bit_holes=NR_HOLES 90 | Show only structs at least NR_HOLES bit holes. 91 | 92 | .TP 93 | .B \-d, \-\-recursive 94 | Recursive mode, affects several other flags. 95 | 96 | .TP 97 | .B \-D, \-\-decl_exclude=PREFIX 98 | exclude classes declared in files with PREFIX. 99 | 100 | .TP 101 | .B \-f, \-\-find_pointers_to=CLASS_NAME 102 | Find pointers to CLASS_NAME. 103 | 104 | .TP 105 | .B \-H, \-\-holes=NR_HOLES 106 | Show only structs with at least NR_HOLES holes. 107 | 108 | .TP 109 | .B \-I, \-\-show_decl_info 110 | Show the file and line number where the tags were defined, if available in 111 | the debugging information. 112 | 113 | .TP 114 | .B \-l, \-\-show_first_biggest_size_base_type_member 115 | Show first biggest size base_type member. 116 | 117 | .TP 118 | .B \-m, \-\-nr_methods 119 | Show number of methods. 120 | 121 | .TP 122 | .B \-M, \-\-show_only_data_members 123 | Show only the members that use space in the class layout. C++ methods will be 124 | suppressed. 125 | 126 | .TP 127 | .B \-n, \-\-nr_members 128 | Show number of members. 129 | 130 | .TP 131 | .B \-N, \-\-class_name_len 132 | Show size of classes. 133 | 134 | .TP 135 | .B \-O, \-\-dwarf_offset=OFFSET 136 | Show tag with DWARF OFFSET. 137 | 138 | .TP 139 | .B \-P, \-\-packable 140 | Show only structs that has holes that can be packed if members are reorganized, 141 | for instance when using the \fB\-\-reorganize\fR option. 142 | 143 | .TP 144 | .B \-q, \-\-quiet 145 | Be quieter. 146 | 147 | .TP 148 | .B \-s, \-\-sizes 149 | Show size of classes. 150 | 151 | .TP 152 | .B \-t, \-\-separator=SEP 153 | Use SEP as the field separator. 154 | 155 | .TP 156 | .B \-T, \-\-nr_definitions 157 | Show how many times struct was defined. 158 | 159 | .TP 160 | .B \-u, \-\-defined_in 161 | Show CUs where CLASS_NAME (-C) is defined. 162 | 163 | .TP 164 | .B \-\-flat_arrays 165 | Flatten arrays, so that array[10][2] becomes array[20]. 166 | Useful when generating from both CTF and DWARF encodings 167 | for the same binary for testing purposes. 168 | 169 | .TP 170 | .B \-\-fixup_silly_bitfields 171 | Converts silly bitfields such as "int foo:32" to plain "int foo". 172 | 173 | .TP 174 | .B \-V, \-\-verbose 175 | be verbose 176 | 177 | .TP 178 | .B \-w, \-\-word_size=WORD_SIZE 179 | Change the arch word size to WORD_SIZE. 180 | 181 | .TP 182 | .B \-x, \-\-exclude=PREFIX 183 | Exclude PREFIXed classes. 184 | 185 | .TP 186 | .B \-X, \-\-cu_exclude=PREFIX 187 | Exclude PREFIXed compilation units. 188 | 189 | .TP 190 | .B \-y, \-\-prefix_filter=PREFIX 191 | Include PREFIXed classes. 192 | 193 | .TP 194 | .B \-z, \-\-hole_size_ge=HOLE_SIZE 195 | Show only structs with at least one hole greater or equal to HOLE_SIZE. 196 | 197 | .SH NOTES 198 | 199 | To enable the generation of debugging information in the Linux kernel build 200 | process select CONFIG_DEBUG_INFO. This can be done using make menuconfig by 201 | this path: "Kernel Hacking" -> "Kernel Debugging" -> "Compile the kernel with 202 | debug info". 203 | 204 | Many distributions also come with debuginfo packages, so just enable it in your 205 | package manager repository configuration and install the kernel-debuginfo, or 206 | any other userspace program written in a language that the compiler generates 207 | debuginfo (C, C++, for instance). 208 | 209 | .SH SEE ALSO 210 | \fIeu-readelf\fR(1), \fIreadelf\fR(1), \fIobjdump\fR(1). 211 | .P 212 | \fIhttp://oops.ghostprotocols.net:81/acme/7dwarves.pdf\fR. 213 | .SH AUTHOR 214 | \fBpahole\fR was written by Arnaldo Carvalho de Melo . 215 | 216 | Please send bug reports to . 217 | .P 218 | No\ subscription is required. 219 | -------------------------------------------------------------------------------- /ostra/ostra-cg: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | # ostra-cg - generate callgraphs from encoded trace 3 | # 4 | # Arnaldo Carvalho de Melo 5 | # 6 | # 7 | # Copyright (C) 2005, 2006, 2007 Arnaldo Carvalho de Melo 8 | # 9 | # This program is free software; you can redistribute it and/or modify it 10 | # under the terms of version 2 of the GNU General Public License as 11 | # published by the Free Software Foundation. 12 | 13 | import sys, datetime, os, ostra 14 | 15 | class_def = None 16 | 17 | ident = 0 18 | 19 | verbose = False 20 | valid_html = False 21 | print_exits = True 22 | print_exit_details = False 23 | print_function_times = True 24 | gen_html = True 25 | html_file_seq = 0 26 | nr_lines_per_page = 256 27 | output_file = None 28 | callgraph = None 29 | print_nr_exit_points = False 30 | first_table_row = True 31 | plot_min_samples = 4 32 | plot = False 33 | tab_space = 10 34 | my_object = None 35 | 36 | # @import url(file:///home/acme/git/ostra/ostra.css); 37 | html_style_import=''' 38 | 41 | ''' 42 | 43 | def emit_html_page_sequence_links(page): 44 | global output_file 45 | 46 | output_file.write("
") 47 | if page != 1: 48 | if page == 2: 49 | prev = "index" 50 | else: 51 | prev = str(page - 2) 52 | output_file.write("Index | ") 53 | output_file.write("Previous | " % prev) 54 | output_file.write("Next | " % page) 55 | output_file.write("Where fields changed | ") 56 | output_file.write("Methods statistics | ") 57 | output_file.write("Last\n") 58 | output_file.write("
") 59 | 60 | def close_callgraph_file(): 61 | if gen_html: 62 | output_file.write("\n") 63 | emit_html_page_sequence_links(html_file_seq) 64 | if valid_html: 65 | output_file.write(''' 66 |

67 | Valid HTML 4.01! 70 |

71 | ''') 72 | output_file.write("\n\n") 73 | 74 | output_file.close() 75 | 76 | def new_callgraph_file(traced_class): 77 | global html_file_seq, output_file, first_table_row 78 | 79 | if not gen_html: 80 | if output_file == None: 81 | output_file = file("%s.txt" % callgraph, "w") 82 | return 83 | 84 | first_table_row = True 85 | 86 | if html_file_seq == 0: 87 | os.mkdir(callgraph) 88 | if output_file != None: 89 | output_file.close() 90 | filename = "index" 91 | help = ''' 92 |

Tracing struct %s methods (functions with a struct %s * argument)

93 |

Click on the timestamps to see the object state

94 |

Click on the functions to go to its definition in LXR (http://lxr.linux.no/)

95 |

Red timestamps means the state changed

96 | ''' % (traced_class, traced_class) 97 | else: 98 | close_callgraph_file() 99 | filename = str(html_file_seq) 100 | help = " " 101 | 102 | output_file = file("%s/%s.html" % (callgraph, filename), "w") 103 | output_file.write(''' 104 | 106 | 107 | 108 | OSTRA Callgraph: %s, file %d 109 | %s 110 | 111 | 112 | ''' % (callgraph, html_file_seq, html_style_import)) 113 | 114 | html_file_seq += 1 115 | emit_html_page_sequence_links(html_file_seq) 116 | 117 | output_file.write("\n%s\n\n" % help) 118 | 119 | def trim_tstamp(tstamp): 120 | return str(tstamp).strip().lstrip('0').lstrip(':').lstrip('0').lstrip(':').lstrip('0').lstrip('.').lstrip('0') 121 | 122 | def object_state(): 123 | output = "
" 124 | state_changed = False 125 | for field in class_def.fields.values(): 126 | if not field.cg: 127 | continue 128 | value_changed_or_not_zero = False 129 | value = field.value 130 | if field.changed(): 131 | state_changed = True 132 | last_value = field.last_value 133 | if field.table and last_value and field.table.has_key(int(last_value)): 134 | last_value = field.table[int(last_value)] 135 | transition = "%s -> " % last_value 136 | color = " class=\"odd\"" 137 | value_changed_or_not_zero = True 138 | else: 139 | field_changed = False 140 | transition = "" 141 | color = "" 142 | if value != "0" and value != None: 143 | value_changed_or_not_zero = True 144 | 145 | if value_changed_or_not_zero: 146 | if field.table and value and field.table.has_key(int(value)): 147 | value = field.table[int(value)] 148 | output = output.strip() + "" % \ 149 | (color, field, transition, value) 150 | output += "
%s%s%s
" 151 | return (output, state_changed) 152 | 153 | total_lines = 0 154 | 155 | def tstamp_str(): 156 | global total_lines, first_table_row 157 | 158 | total_lines += 1 159 | 160 | if gen_html: 161 | state, changed = object_state() 162 | if changed: 163 | anchor = "%d.%d" % (class_def.tstamp.seconds, class_def.tstamp.microseconds) 164 | anchor_color = " class=\"red\"" 165 | else: 166 | anchor = "" 167 | anchor_color = "" 168 | if total_lines % 2 == 1: 169 | row_color = "odd" 170 | else: 171 | row_color = "evn" 172 | if first_table_row: 173 | close_last_tr = "" 174 | first_table_row = False 175 | else: 176 | close_last_tr = "\n" 177 | 178 | return "%s%04d.%06d%s" % \ 179 | (close_last_tr, row_color, anchor, anchor_color, 180 | class_def.tstamp.seconds, class_def.tstamp.microseconds, state) 181 | else: 182 | return "%06d.%06d" % (class_def.tstamp.seconds, class_def.tstamp.microseconds) 183 | 184 | def indent_str(indent, text): 185 | if gen_html: 186 | method = class_def.current_method() 187 | time_so_far = method.total_time.seconds * 10000 + method.total_time.microseconds 188 | tooltip = "%s: calls=%d, total time=%dus" % (method.name, method.calls, time_so_far) 189 | if class_def.fields["action"].value[0] == 'o': 190 | if class_def.fields.has_key("exit_point"): 191 | tooltip += ", exit point=%d" % (int(class_def.fields["exit_point"].value) + 1) 192 | else: 193 | text = "%s" % (method.name, text) 194 | 195 | return "%s%s" % (tooltip, " " * tab_space * indent, text) 196 | else: 197 | return "%s%s" % ("\t" * ident, text) 198 | 199 | def function_time_str(time): 200 | if gen_html: 201 | if class_def.current_method().print_return_value: 202 | ret_value = "%s" % class_def.fields["return_value"].value 203 | else: 204 | ret_value = "0" 205 | if ret_value == "0": 206 | ret_value = "" 207 | else: 208 | ret_value=" title=\"returned %s\"" % ret_value 209 | return "%sus" % (ret_value, time) 210 | else: 211 | return " %sus\n" % time 212 | 213 | previous_was_entry = False 214 | nr_lines = 0 215 | 216 | def process_record(): 217 | global ident, previous_was_entry, nr_lines 218 | 219 | if gen_html: 220 | nr_lines += 1 221 | if nr_lines > nr_lines_per_page: 222 | if ident == 0 or nr_lines > nr_lines_per_page * 5: 223 | new_callgraph_file(traced_class) 224 | nr_lines = 0 225 | 226 | method = class_def.current_method() 227 | 228 | if class_def.fields["action"].value[0] == 'i': 229 | output = "%s()" % method.name 230 | 231 | if print_exits and previous_was_entry: 232 | if gen_html: 233 | last_open = " { " 234 | else: 235 | last_open = " {\n" 236 | else: 237 | last_open = "" 238 | output_file.write("%s%s %s" % (last_open, tstamp_str(), indent_str(ident, output.strip()))) 239 | if not print_exits: 240 | output_file.write("\n") 241 | 242 | ident += 1 243 | 244 | method.calls += 1 245 | method.last_tstamp = class_def.tstamp 246 | previous_was_entry = True 247 | else: 248 | if not method.last_tstamp: 249 | method.last_tstamp = class_def.tstamp 250 | tstamp_delta = class_def.tstamp - method.last_tstamp 251 | if tstamp_delta < datetime.timedelta(): 252 | tstamp_delta = datetime.timedelta() 253 | method.total_time += tstamp_delta 254 | 255 | 256 | if ident > 0: 257 | ident -= 1 258 | if print_exits: 259 | if print_exit_details: 260 | exit_point = int(class_def.fields["exit_point"].value) + 1 261 | if class_def.last_method.name != method.name: 262 | output_file.write("%s %s" % (tstamp_str(), indent_str(ident, "}"))) 263 | if print_exit_details: 264 | output_file.write(" EXIT #%d (%s)" % (exit_point, method.name)) 265 | else: 266 | if print_exit_details: 267 | output_file.write("EXIT #%d" % exit_point) 268 | 269 | function_time = trim_tstamp(tstamp_delta) 270 | if len(function_time) == 0: 271 | function_time = "0" 272 | if print_exits: 273 | if print_function_times: 274 | output_file.write(function_time_str(function_time)) 275 | else: 276 | output_file.write("\n") 277 | 278 | if print_nr_exit_points: 279 | if method.exits.has_key(exit_point): 280 | method.exits[exit_point] += 1 281 | else: 282 | method.exits[exit_point] = 1 283 | 284 | previous_was_entry = False 285 | 286 | return html_file_seq - 1 287 | 288 | def print_where_fields_changed(): 289 | f = file("%s/changes.html" % callgraph, "w") 290 | f.write(''' 291 | 293 | 294 | 295 | OSTRA Callgraph: %s, Where the Fields Changed 296 | %s 297 | 298 | 299 |

Click on the values to go to where it was changed

300 |

Click on the field names to see a plotting of its value over time

301 | ''' % (callgraph, html_style_import)) 302 | output_file.write("
") 303 | f.write("Index\n") 304 | f.write("Last\n" % (html_file_seq - 1)) 305 | f.write("") 306 | 307 | max_samples = 50 308 | 309 | for key in class_def.fields.keys(): 310 | fields = class_def.fields[key] 311 | changes = fields.changes 312 | 313 | changes_str="" 314 | link_pre="" 315 | link_pos="" 316 | if len(changes) == 0: 317 | changes_str="Unchanged\n" 318 | elif plot and len(changes) >= plot_min_samples and fields.plot_fmt != "dev_null": 319 | link_pre="" % key 320 | link_pos="" 321 | 322 | f.write("\n") 342 | 343 | f.write("
%s%s%s%s" % (link_pre, key, link_pos, changes_str)) 323 | if len(changes) == 0: 324 | continue 325 | 326 | f.write("\n") 327 | nr_samples = 0 328 | for change in changes: 329 | nr_samples += 1 330 | if nr_samples <= max_samples: 331 | if change.seq == 0: 332 | filename="index" 333 | else: 334 | filename = str(change.seq) 335 | f.write("" % \ 336 | (filename, change.tstamp.seconds, change.tstamp.microseconds, change.value)) 337 | 338 | if nr_samples > max_samples: 339 | f.write("" % (max_samples, nr_samples)) 340 | 341 | f.write("
%s
Only %d samples out of %d were printed
\n
") 344 | output_file.write("
") 345 | f.write("\n\n") 346 | f.close() 347 | os.symlink("changes.html", "%s/%d.html" % (callgraph, html_file_seq)) 348 | os.symlink("%d.html" % (html_file_seq - 1), "%s/last.html" % callgraph) 349 | 350 | 351 | def method_stats(class_def, callgraph): 352 | os.mkdir("%s/methods" % callgraph) 353 | f = file("%s/methods/index.html" % callgraph, "w") 354 | f.write(''' 355 | 357 | 358 | 359 | OSTRA Callgraph: %s, Methods Statistics 360 | %s 361 | 362 | 363 |

Click on the methods names to see a plotting of the times for each call

364 | ''' % (callgraph, html_style_import)) 365 | 366 | if plot: 367 | class_def.plot_methods(callgraph) 368 | f.write("") 369 | for method in class_def.methods.values(): 370 | changes_str="" 371 | link_pre="" 372 | link_pos="" 373 | if len(method.times) < 4: 374 | changes_str="Less than 4 calls\n" 375 | else: 376 | if plot: 377 | link_pre="" % method.name 378 | link_pos="" 379 | changes_str="%d calls\n" % len(method.times) 380 | 381 | f.write("
%s%s%s%s" % \ 382 | (link_pre, method.name, link_pos, changes_str)) 383 | f.write("
") 384 | f.write("\n\n") 385 | f.close() 386 | 387 | if __name__ == '__main__': 388 | if len(sys.argv) not in [ 3, 4 ]: 389 | print "usage: ostra-cg [object]" 390 | sys.exit(1) 391 | 392 | gen_html = True 393 | traced_class = sys.argv[1] 394 | callgraph = "%s.callgraph" % traced_class 395 | encoded_trace = sys.argv[2] 396 | if len(sys.argv) == 4: 397 | my_object = sys.argv[3] 398 | if my_object == "none": 399 | my_object = None 400 | plot = True 401 | 402 | class_def = ostra.class_definition(class_def_file = "%s.fields" % traced_class, 403 | class_methods_file = "%s.functions" % traced_class) 404 | new_callgraph_file(traced_class) 405 | class_def.parse_file(encoded_trace, verbose = verbose, 406 | process_record = process_record, 407 | my_object = my_object) 408 | if gen_html: 409 | print_where_fields_changed() 410 | close_callgraph_file() 411 | method_stats(class_def, callgraph) 412 | if plot: 413 | ostra.plot(class_def, callgraph) 414 | -------------------------------------------------------------------------------- /ostra/python/ostra.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | # 3 | # Copyright (C) 2005, 2006, 2007 Arnaldo Carvalho de Melo 4 | # 5 | # This program is free software; you can redistribute it and/or modify it 6 | # under the terms of version 2 of the GNU General Public License as 7 | # published by the Free Software Foundation. 8 | 9 | from datetime import timedelta 10 | 11 | class trace_points: 12 | def __init__(self, hooks): 13 | self.entry = "entry" in hooks 14 | self.exit = "exit" in hooks 15 | 16 | def __repr__(self): 17 | return str(self.__dict__.values()) 18 | __str__ = __repr__ 19 | 20 | class change_point: 21 | def __init__(self, tstamp, value, seq): 22 | self.tstamp = tstamp 23 | self.value = value 24 | self.seq = seq 25 | 26 | class class_field: 27 | def __init__(self, line, class_def_file): 28 | field, self.name, cgtraced, self.grab_expr, \ 29 | self.collector_fmt, hooks, self.plot_fmt = line.strip().split(':') 30 | 31 | self.field = int(field) 32 | self.cg = cgtraced == "yes" 33 | self.hooks = trace_points(hooks.split(',')) 34 | self.value = None 35 | self.last_value = None 36 | self.changes = [] 37 | self._load_text_table(class_def_file) 38 | 39 | def _text_table_tokenizer(self, line): 40 | tokens = line.split(":") 41 | return int(tokens[0]), tokens[1][:-1] 42 | 43 | def _load_text_table(self, class_def_file): 44 | try: 45 | f = file("%s.%s.table" % (class_def_file, self.name)) 46 | except: 47 | self.table = {} 48 | return 49 | self.table = dict([self._text_table_tokenizer(line) for line in f.readlines()]) 50 | f.close() 51 | 52 | def set_last_value(self, tstamp, seq): 53 | if self.value != None: 54 | if self.cg and self.changed(): 55 | self.changes.append(change_point(tstamp, self.value, seq)) 56 | self.last_value = self.value 57 | 58 | def changed(self): 59 | return self.value != None and self.value != self.last_value 60 | 61 | def __repr__(self): 62 | return self.name 63 | __str__ = __repr__ 64 | 65 | class class_method: 66 | def __init__(self, line): 67 | fields = line.strip().split(':') 68 | self.function_id = fields[0] 69 | self.name = fields[1] 70 | self.print_return_value = fields[-1] 71 | self.function_id = int(self.function_id) 72 | self.print_return_value = self.print_return_value == "yes" 73 | self.calls = 0 74 | self.total_time = timedelta() 75 | self.last_tstamp = None 76 | self.times = [] 77 | self.exits = {} 78 | 79 | def begin(self, tstamp): 80 | self.calls += 1 81 | self.last_tstamp = tstamp 82 | 83 | def end(self, tstamp): 84 | tstamp_delta = tstamp - self.last_tstamp 85 | if tstamp_delta < timedelta(): 86 | tstamp_delta = timedelta() 87 | 88 | self.total_time += tstamp_delta 89 | self.times.append(tstamp_delta.seconds * 1000000 + tstamp_delta.microseconds) 90 | 91 | def plot(self, directory, entries, samples, nr_samples, verbose = False): 92 | from matplotlib import use as muse 93 | muse('Agg') 94 | from matplotlib.backends.backend_agg import FigureCanvasAgg as FigureCanvas 95 | from matplotlib.figure import Figure 96 | from matplotlib.ticker import FuncFormatter, FixedFormatter, LinearLocator 97 | from matplotlib.mlab import std as std_deviation 98 | from matplotlib.mlab import mean 99 | from time import asctime 100 | 101 | yfont = { 'fontname' : 'Bitstream Vera Sans', 102 | 'color' : 'r', 103 | 'fontsize' : 8 } 104 | 105 | xfont = { 'fontname' : 'Bitstream Vera Sans', 106 | 'color' : 'b', 107 | 'fontsize' : 8 } 108 | 109 | titlefont = { 'fontname' : 'Bitstream Vera Sans', 110 | 'color' : 'g', 111 | 'fontweight' : 'bold', 112 | 'fontsize' : 10 } 113 | 114 | inches = 0.00666667 115 | width = 950 * inches 116 | height = 680 * inches 117 | 118 | fig = Figure(figsize = (width, height)) 119 | canvas = FigureCanvas(fig) 120 | ax = fig.add_subplot(111) 121 | ax.grid(False) 122 | xtickfontsize = 5 123 | ytickfontsize = 5 124 | 125 | plot_type = 'b-' 126 | field_mean = mean(samples) 127 | yaxis_plot_fmt = FuncFormatter(pylab_formatter_ms) 128 | 129 | ax.plot(entries, samples, "b-") 130 | 131 | ax.set_xlabel("samples", xfont) 132 | ax.set_ylabel("time", yfont) 133 | 134 | for label in ax.get_xticklabels(): 135 | label.set(fontsize = xtickfontsize) 136 | for label in ax.get_yticklabels(): 137 | label.set(fontsize = ytickfontsize) 138 | 139 | ax.yaxis.set_major_formatter(yaxis_plot_fmt) 140 | ax.set_title("%d %s samples (%s)" % (nr_samples, self.name, asctime()), titlefont) 141 | canvas.print_figure("%s/methods/%s.png" % (directory, self.name)) 142 | del fig, canvas, ax 143 | 144 | class class_definition: 145 | def __init__(self, class_def_file = None, class_methods_file = None): 146 | self.fields = {} 147 | self.methods = {} 148 | self.tstamp = None 149 | self.last_tstamp = None 150 | self.last_method = None 151 | self.epoch = None 152 | 153 | if class_def_file: 154 | f = file(class_def_file) 155 | for line in f.readlines(): 156 | field = class_field(line, class_def_file) 157 | self.fields[field.name] = field 158 | f.close() 159 | 160 | if class_methods_file: 161 | f = file(class_methods_file) 162 | self.methods = dict([self._method_tokenizer(line) for line in f.readlines()]) 163 | f.close() 164 | 165 | def _method_tokenizer(self, line): 166 | method = class_method(line) 167 | return method.function_id, method 168 | 169 | def set_last_values(self, seq = 0): 170 | self.last_method = self.current_method() 171 | for field in self.fields.values(): 172 | field.set_last_value(self.tstamp, seq) 173 | self.last_tstamp = self.tstamp 174 | 175 | def parse_record(self, line): 176 | nsec, record = line[:-1].split(' ', 1) 177 | line_fields = record.split(':') 178 | 179 | self.tstamp = timedelta(microseconds = int(nsec) / 1000) 180 | if self.epoch == None: 181 | self.epoch = self.tstamp 182 | self.tstamp -= self.epoch 183 | 184 | action = line_fields[0][0] 185 | nr_fields = len(line_fields) 186 | for field in self.fields.values(): 187 | if field.field >= nr_fields or \ 188 | (action == 'i' and not field.hooks.entry) or \ 189 | (action == 'o' and not field.hooks.exit): 190 | field.value = None 191 | continue 192 | field.value = line_fields[field.field] 193 | 194 | def parse_file(self, filename, process_record = None, verbose = False, 195 | my_object = None): 196 | f = file(filename) 197 | current_object = None 198 | object_stack = [] 199 | 200 | if verbose: 201 | nr_lines = 0 202 | 203 | while True: 204 | line = f.readline() 205 | if not line: 206 | break 207 | if verbose: 208 | nr_lines += 1 209 | print "\r%d" % nr_lines, 210 | 211 | self.parse_record(line) 212 | 213 | method = self.current_method() 214 | # print method.name 215 | if my_object: 216 | if self.fields["action"].value[0] == 'i': 217 | current_object = self.fields["object"].value 218 | object_stack.append(current_object) 219 | else: 220 | current_object = object_stack.pop() 221 | 222 | if current_object != my_object: 223 | continue 224 | 225 | if self.fields["action"].value[0] == 'i': 226 | method.begin(self.tstamp) 227 | else: 228 | method.end(self.tstamp) 229 | seq = 0 230 | if process_record: 231 | seq = process_record() 232 | self.set_last_values(seq) 233 | 234 | f.close() 235 | if verbose: 236 | print 237 | 238 | def current_method(self): 239 | return self.methods[int(self.fields["function_id"].value)] 240 | 241 | def plot_methods(self, callgraph, verbose = False): 242 | for current_method in self.methods.values(): 243 | nr_samples = len(current_method.times) 244 | if nr_samples < 4: 245 | continue 246 | 247 | if verbose: 248 | print "plot_methods: plotting %s method (%d samples)" % \ 249 | (current_method.name, nr_samples) 250 | 251 | entries = [float("%d.0" % entry) for entry in range(nr_samples)] 252 | samples = current_method.times 253 | current_method.plot(callgraph, entries, samples, 254 | nr_samples, verbose) 255 | 256 | def pylab_formatter_kbps(x): 257 | mb = 1024 * 1024 258 | if x > mb: 259 | return "%d,%d Mbps" % (x / mb, x % mb) 260 | else: 261 | return "%d,%d Kbps" % (x / 1024, x % 1024) 262 | 263 | def pylab_formatter_ms(x, pos = 0): 264 | ms = x / 1000 265 | us = x % 1000 266 | s = "%d" % ms 267 | if us > 0: 268 | s += ".%03d" % us 269 | s = s.rstrip('0') 270 | s += "ms" 271 | 272 | return s 273 | 274 | def pylab_formatter(x, pos = 0): 275 | if current_plot_fmt == "kbps": 276 | return pylab_formatter_kbps(x) 277 | elif current_plot_fmt == "ms": 278 | return pylab_formatter_ms(x) 279 | else: 280 | return "%s" % str(int(x)) 281 | 282 | def plot_field(name, directory, tstamps, samples, nr_samples, plot_fmt = None, 283 | table = None, verbose = False): 284 | global current_plot_fmt 285 | 286 | from matplotlib import use as muse 287 | muse('Agg') 288 | from matplotlib.backends.backend_agg import FigureCanvasAgg as FigureCanvas 289 | from matplotlib.figure import Figure 290 | from matplotlib.ticker import FuncFormatter, FixedFormatter, LinearLocator 291 | from matplotlib.mlab import std as std_deviation 292 | from matplotlib.mlab import mean 293 | from time import asctime 294 | 295 | yfont = { 'fontname' : 'Bitstream Vera Sans', 296 | 'color' : 'r', 297 | 'fontsize' : 8 } 298 | 299 | xfont = { 'fontname' : 'Bitstream Vera Sans', 300 | 'color' : 'b', 301 | 'fontsize' : 8 } 302 | 303 | titlefont = { 'fontname' : 'Bitstream Vera Sans', 304 | 'color' : 'g', 305 | 'fontweight' : 'bold', 306 | 'fontsize' : 10 } 307 | 308 | inches = 0.00666667 309 | width = 950 * inches 310 | height = 680 * inches 311 | 312 | fig = Figure(figsize = (width, height)) 313 | canvas = FigureCanvas(fig) 314 | ax = fig.add_subplot(111) 315 | ax.grid(False) 316 | xtickfontsize = 5 317 | ytickfontsize = 5 318 | 319 | current_plot_fmt = plot_fmt 320 | field_mean = None 321 | 322 | plot_type = 'b-' 323 | if current_plot_fmt == "filter_dev": 324 | std = std_deviation(samples) * 2 325 | if verbose: 326 | print "filter_dev(%s) std=%d" % (name, std) 327 | for i in range(nr_samples): 328 | if samples[i] > std: 329 | if verbose: 330 | print "%s: filtering out %d" % (name, samples[i]) 331 | samples[i] = 0 332 | field_mean = mean(samples) 333 | yaxis_plot_fmt = FuncFormatter(pylab_formatter) 334 | elif current_plot_fmt == "table": 335 | ax.grid(True) 336 | plot_type = 'bo-' 337 | max_value = max(samples) 338 | without_zero = 1 339 | if table.has_key(0): 340 | without_zero = 0 341 | max_value += 1 342 | ax.yaxis.set_major_locator(LinearLocator(max_value)) 343 | tstamps = range(nr_samples) 344 | seq = [ " " ] * max_value 345 | for key in table.keys(): 346 | if key in samples: 347 | seq[key - without_zero] = "%s(%d)" % (table[key], key) 348 | ytickfontsize = 4 349 | yaxis_plot_fmt = FixedFormatter(seq) 350 | else: 351 | field_mean = mean(samples) 352 | yaxis_plot_fmt = FuncFormatter(pylab_formatter) 353 | 354 | ax.plot(tstamps, samples, plot_type) 355 | 356 | ax.set_xlabel("time", xfont) 357 | yname = name 358 | if field_mean: 359 | yname += " (mean=%s)" % pylab_formatter(field_mean) 360 | ax.set_ylabel(yname, yfont) 361 | 362 | for label in ax.get_xticklabels(): 363 | label.set(fontsize = xtickfontsize) 364 | for label in ax.get_yticklabels(): 365 | label.set(fontsize = ytickfontsize) 366 | 367 | ax.yaxis.set_major_formatter(yaxis_plot_fmt) 368 | ax.set_title("%d %s samples (%s)" % (nr_samples, name, asctime()), titlefont) 369 | canvas.print_figure("%s/%s.png" % (directory, name)) 370 | del fig, canvas, ax 371 | 372 | def plot(class_def, callgraph, verbose = False): 373 | for current_field in class_def.fields.values(): 374 | nr_samples = len(current_field.changes) 375 | if nr_samples < 4: 376 | continue 377 | 378 | if verbose: 379 | print "ostra-plot: plotting %s field (%d samples)" % (current_field.name, nr_samples) 380 | 381 | tstamps = [float("%d.%06d" % (entry.tstamp.seconds, entry.tstamp.microseconds)) \ 382 | for entry in current_field.changes] 383 | try: 384 | samples = [int(entry.value) for entry in current_field.changes] 385 | except: 386 | continue 387 | plot_field(current_field.name, callgraph, tstamps, samples, 388 | nr_samples, current_field.plot_fmt, 389 | current_field.table, verbose) 390 | 391 | if __name__ == '__main__': 392 | import sys 393 | c = class_definition(sys.argv[1], sys.argv[2]) 394 | for field in c.fields.values(): 395 | print "%s: %s" % (field, field.table) 396 | for method in c.methods.values(): 397 | print "%d: %s" % (method.function_id, method.name) 398 | -------------------------------------------------------------------------------- /pdwtags.c: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (C) 2007 Arnaldo Carvalho de Melo 3 | 4 | This program is free software; you can redistribute it and/or modify it 5 | under the terms of version 2 of the GNU General Public License as 6 | published by the Free Software Foundation. 7 | */ 8 | 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | #include "dwarves.h" 15 | #include "dutil.h" 16 | 17 | static struct conf_fprintf conf = { 18 | .emit_stats = 1, 19 | }; 20 | 21 | static void emit_tag(struct tag *tag, uint32_t tag_id, struct cu *cu) 22 | { 23 | printf("/* %d */\n", tag_id); 24 | 25 | if (tag->tag == DW_TAG_base_type) { 26 | char bf[64]; 27 | const char *name = base_type__name(tag__base_type(tag), cu, 28 | bf, sizeof(bf)); 29 | 30 | if (name == NULL) 31 | printf("anonymous base_type\n"); 32 | else 33 | puts(name); 34 | } else if (tag->tag == DW_TAG_pointer_type) 35 | printf(" /* pointer to %lld */\n", (unsigned long long)tag->type); 36 | else 37 | tag__fprintf(tag, cu, &conf, stdout); 38 | 39 | printf(" /* size: %zd */\n\n", tag__size(tag, cu)); 40 | } 41 | 42 | static int cu__emit_tags(struct cu *cu) 43 | { 44 | uint32_t i; 45 | struct tag *tag; 46 | 47 | puts("/* Types: */\n"); 48 | cu__for_each_type(cu, i, tag) 49 | emit_tag(tag, i, cu); 50 | 51 | puts("/* Functions: */\n"); 52 | conf.no_semicolon = true; 53 | struct function *function; 54 | cu__for_each_function(cu, i, function) { 55 | tag__fprintf(function__tag(function), cu, &conf, stdout); 56 | putchar('\n'); 57 | lexblock__fprintf(&function->lexblock, cu, function, 0, 58 | &conf, stdout); 59 | printf(" /* size: %zd */\n\n", 60 | tag__size(function__tag(function), cu)); 61 | } 62 | conf.no_semicolon = false; 63 | 64 | puts("\n\n/* Variables: */\n"); 65 | cu__for_each_variable(cu, i, tag) { 66 | tag__fprintf(tag, cu, NULL, stdout); 67 | printf(" /* size: %zd */\n\n", tag__size(tag, cu)); 68 | } 69 | 70 | 71 | return 0; 72 | } 73 | 74 | static enum load_steal_kind pdwtags_stealer(struct cu *cu, 75 | struct conf_load *conf_load __unused) 76 | { 77 | cu__emit_tags(cu); 78 | return LSK__DELETE; 79 | } 80 | 81 | static struct conf_load pdwtags_conf_load = { 82 | .steal = pdwtags_stealer, 83 | }; 84 | 85 | /* Name and version of program. */ 86 | ARGP_PROGRAM_VERSION_HOOK_DEF = dwarves_print_version; 87 | 88 | static const struct argp_option pdwtags__options[] = { 89 | { 90 | .name = "format_path", 91 | .key = 'F', 92 | .arg = "FORMAT_LIST", 93 | .doc = "List of debugging formats to try" 94 | }, 95 | { 96 | .key = 'V', 97 | .name = "verbose", 98 | .doc = "show details", 99 | }, 100 | { 101 | .name = NULL, 102 | } 103 | }; 104 | 105 | static error_t pdwtags__options_parser(int key, char *arg __unused, 106 | struct argp_state *state) 107 | { 108 | switch (key) { 109 | case ARGP_KEY_INIT: 110 | if (state->child_inputs != NULL) 111 | state->child_inputs[0] = state->input; 112 | break; 113 | case 'F': pdwtags_conf_load.format_path = arg; break; 114 | case 'V': conf.show_decl_info = 1; break; 115 | default: return ARGP_ERR_UNKNOWN; 116 | } 117 | return 0; 118 | } 119 | 120 | static const char pdwtags__args_doc[] = "FILE"; 121 | 122 | static struct argp pdwtags__argp = { 123 | .options = pdwtags__options, 124 | .parser = pdwtags__options_parser, 125 | .args_doc = pdwtags__args_doc, 126 | }; 127 | 128 | int main(int argc, char *argv[]) 129 | { 130 | int remaining, rc = EXIT_FAILURE; 131 | struct cus *cus = cus__new(); 132 | 133 | if (dwarves__init(0) || cus == NULL) { 134 | fputs("pwdtags: insufficient memory\n", stderr); 135 | goto out; 136 | } 137 | 138 | if (argp_parse(&pdwtags__argp, argc, argv, 0, &remaining, NULL) || 139 | remaining == argc) { 140 | argp_help(&pdwtags__argp, stderr, ARGP_HELP_SEE, argv[0]); 141 | goto out; 142 | } 143 | 144 | if (cus__load_files(cus, &pdwtags_conf_load, argv + remaining) == 0) 145 | rc = EXIT_SUCCESS; 146 | out: 147 | cus__delete(cus); 148 | dwarves__exit(); 149 | return rc; 150 | } 151 | -------------------------------------------------------------------------------- /pfunct.c: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (C) 2006 Mandriva Conectiva S.A. 3 | Copyright (C) 2006 Arnaldo Carvalho de Melo 4 | Copyright (C) 2007 Arnaldo Carvalho de Melo 5 | 6 | This program is free software; you can redistribute it and/or modify it 7 | under the terms of version 2 of the GNU General Public License as 8 | published by the Free Software Foundation. 9 | */ 10 | 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | 21 | #include "dwarves.h" 22 | #include "dwarves_emit.h" 23 | #include "dutil.h" 24 | #include "elf_symtab.h" 25 | 26 | static int verbose; 27 | static int show_inline_expansions; 28 | static int show_variables; 29 | static int show_externals; 30 | static int show_cc_inlined; 31 | static int show_cc_uninlined; 32 | static char *symtab_name; 33 | static bool show_prototypes; 34 | static bool expand_types; 35 | static struct type_emissions emissions; 36 | static uint64_t addr; 37 | 38 | static struct conf_fprintf conf; 39 | 40 | static struct conf_load conf_load; 41 | 42 | struct fn_stats { 43 | struct list_head node; 44 | struct tag *tag; 45 | const struct cu *cu; 46 | uint32_t nr_expansions; 47 | uint32_t size_expansions; 48 | uint32_t nr_files; 49 | }; 50 | 51 | static struct fn_stats *fn_stats__new(struct tag *tag, const struct cu *cu) 52 | { 53 | struct fn_stats *stats = malloc(sizeof(*stats)); 54 | 55 | if (stats != NULL) { 56 | const struct function *fn = tag__function(tag); 57 | 58 | stats->tag = tag; 59 | stats->cu = cu; 60 | stats->nr_files = 1; 61 | stats->nr_expansions = fn->cu_total_nr_inline_expansions; 62 | stats->size_expansions = fn->cu_total_size_inline_expansions; 63 | } 64 | 65 | return stats; 66 | } 67 | 68 | static void fn_stats__delete(struct fn_stats *stats) 69 | { 70 | free(stats); 71 | } 72 | 73 | static LIST_HEAD(fn_stats__list); 74 | 75 | static struct fn_stats *fn_stats__find(const char *name) 76 | { 77 | struct fn_stats *pos; 78 | 79 | list_for_each_entry(pos, &fn_stats__list, node) 80 | if (strcmp(function__name(tag__function(pos->tag), pos->cu), 81 | name) == 0) 82 | return pos; 83 | return NULL; 84 | } 85 | 86 | static void fn_stats__delete_list(void) 87 | { 88 | struct fn_stats *pos, *n; 89 | 90 | list_for_each_entry_safe(pos, n, &fn_stats__list, node) { 91 | list_del_init(&pos->node); 92 | fn_stats__delete(pos); 93 | } 94 | } 95 | 96 | static void fn_stats__add(struct tag *tag, const struct cu *cu) 97 | { 98 | struct fn_stats *fns = fn_stats__new(tag, cu); 99 | if (fns != NULL) 100 | list_add(&fns->node, &fn_stats__list); 101 | } 102 | 103 | static void fn_stats_inline_exps_fmtr(const struct fn_stats *stats) 104 | { 105 | struct function *fn = tag__function(stats->tag); 106 | if (fn->lexblock.nr_inline_expansions > 0) 107 | printf("%s: %u %d\n", function__name(fn, stats->cu), 108 | fn->lexblock.nr_inline_expansions, 109 | fn->lexblock.size_inline_expansions); 110 | } 111 | 112 | static void fn_stats_labels_fmtr(const struct fn_stats *stats) 113 | { 114 | struct function *fn = tag__function(stats->tag); 115 | if (fn->lexblock.nr_labels > 0) 116 | printf("%s: %u\n", function__name(fn, stats->cu), 117 | fn->lexblock.nr_labels); 118 | } 119 | 120 | static void fn_stats_variables_fmtr(const struct fn_stats *stats) 121 | { 122 | struct function *fn = tag__function(stats->tag); 123 | if (fn->lexblock.nr_variables > 0) 124 | printf("%s: %u\n", function__name(fn, stats->cu), 125 | fn->lexblock.nr_variables); 126 | } 127 | 128 | static void fn_stats_nr_parms_fmtr(const struct fn_stats *stats) 129 | { 130 | struct function *fn = tag__function(stats->tag); 131 | printf("%s: %u\n", function__name(fn, stats->cu), 132 | fn->proto.nr_parms); 133 | } 134 | 135 | static void fn_stats_name_len_fmtr(const struct fn_stats *stats) 136 | { 137 | struct function *fn = tag__function(stats->tag); 138 | const char *name = function__name(fn, stats->cu); 139 | printf("%s: %zd\n", name, strlen(name)); 140 | } 141 | 142 | static void fn_stats_size_fmtr(const struct fn_stats *stats) 143 | { 144 | struct function *fn = tag__function(stats->tag); 145 | const size_t size = function__size(fn); 146 | 147 | if (size != 0) 148 | printf("%s: %zd\n", function__name(fn, stats->cu), size); 149 | } 150 | 151 | static void fn_stats_fmtr(const struct fn_stats *stats) 152 | { 153 | if (verbose || show_prototypes) { 154 | tag__fprintf(stats->tag, stats->cu, &conf, stdout); 155 | putchar('\n'); 156 | if (show_prototypes) 157 | return; 158 | if (show_variables || show_inline_expansions) 159 | function__fprintf_stats(stats->tag, stats->cu, &conf, stdout); 160 | printf("/* definitions: %u */\n", stats->nr_files); 161 | putchar('\n'); 162 | } else { 163 | struct function *fn = tag__function(stats->tag); 164 | puts(function__name(fn, stats->cu)); 165 | } 166 | } 167 | 168 | static void print_fn_stats(void (*formatter)(const struct fn_stats *f)) 169 | { 170 | struct fn_stats *pos; 171 | 172 | list_for_each_entry(pos, &fn_stats__list, node) 173 | formatter(pos); 174 | } 175 | 176 | static void fn_stats_inline_stats_fmtr(const struct fn_stats *stats) 177 | { 178 | if (stats->nr_expansions > 1) 179 | printf("%-31.31s %6u %7u %6u %6u\n", 180 | function__name(tag__function(stats->tag), stats->cu), 181 | stats->size_expansions, stats->nr_expansions, 182 | stats->size_expansions / stats->nr_expansions, 183 | stats->nr_files); 184 | } 185 | 186 | static void print_total_inline_stats(void) 187 | { 188 | printf("%-32.32s %5.5s / %5.5s = %5.5s %s\n", 189 | "name", "totsz", "exp#", "avgsz", "src#"); 190 | print_fn_stats(fn_stats_inline_stats_fmtr); 191 | } 192 | 193 | static void fn_stats__dupmsg(struct function *func, 194 | const struct cu *func_cu, 195 | struct function *dup __unused, 196 | const struct cu *dup_cu, 197 | char *hdr, const char *fmt, ...) 198 | { 199 | va_list args; 200 | 201 | if (!*hdr) 202 | printf("function: %s\nfirst: %s\ncurrent: %s\n", 203 | function__name(func, func_cu), 204 | func_cu->name, 205 | dup_cu->name); 206 | 207 | va_start(args, fmt); 208 | vprintf(fmt, args); 209 | va_end(args); 210 | *hdr = 1; 211 | } 212 | 213 | static void fn_stats__chkdupdef(struct function *func, 214 | const struct cu *func_cu, 215 | struct function *dup, 216 | const struct cu *dup_cu) 217 | { 218 | char hdr = 0; 219 | const size_t func_size = function__size(func); 220 | const size_t dup_size = function__size(dup); 221 | 222 | if (func_size != dup_size) 223 | fn_stats__dupmsg(func, func_cu, dup, dup_cu, 224 | &hdr, "size: %zd != %zd\n", 225 | func_size, dup_size); 226 | 227 | if (func->proto.nr_parms != dup->proto.nr_parms) 228 | fn_stats__dupmsg(func, func_cu, dup, dup_cu, 229 | &hdr, "nr_parms: %u != %u\n", 230 | func->proto.nr_parms, dup->proto.nr_parms); 231 | 232 | /* XXX put more checks here: member types, member ordering, etc */ 233 | 234 | if (hdr) 235 | putchar('\n'); 236 | } 237 | 238 | static bool function__filter(struct function *function, struct cu *cu) 239 | { 240 | struct fn_stats *fstats; 241 | const char *name; 242 | 243 | if (!function__tag(function)->top_level) 244 | return true; 245 | 246 | /* 247 | * FIXME: remove this check and try to fix the parameter abstract 248 | * origin code someday... 249 | */ 250 | if (!function->name) 251 | return true; 252 | 253 | name = function__name(function, cu); 254 | if (show_externals && !function->external) 255 | return true; 256 | 257 | if (show_cc_uninlined && 258 | function->inlined != DW_INL_declared_not_inlined) 259 | return true; 260 | 261 | if (show_cc_inlined && function->inlined != DW_INL_inlined) 262 | return true; 263 | 264 | fstats = fn_stats__find(name); 265 | if (fstats != NULL) { 266 | struct function *fn = tag__function(fstats->tag); 267 | 268 | if (!fn->external) 269 | return false; 270 | 271 | if (verbose) 272 | fn_stats__chkdupdef(fn, fstats->cu, function, cu); 273 | fstats->nr_expansions += function->cu_total_nr_inline_expansions; 274 | fstats->size_expansions += function->cu_total_size_inline_expansions; 275 | fstats->nr_files++; 276 | return true; 277 | } 278 | 279 | return false; 280 | } 281 | 282 | static int cu_unique_iterator(struct cu *cu, void *cookie __unused) 283 | { 284 | cu__account_inline_expansions(cu); 285 | 286 | struct function *pos; 287 | uint32_t id; 288 | 289 | cu__for_each_function(cu, id, pos) 290 | if (!function__filter(pos, cu)) 291 | fn_stats__add(function__tag(pos), cu); 292 | return 0; 293 | } 294 | 295 | static int cu_class_iterator(struct cu *cu, void *cookie) 296 | { 297 | uint16_t target_id; 298 | struct tag *target = cu__find_struct_by_name(cu, cookie, 0, &target_id); 299 | 300 | if (target == NULL) 301 | return 0; 302 | 303 | struct function *pos; 304 | uint32_t id; 305 | 306 | cu__for_each_function(cu, id, pos) { 307 | if (pos->inlined || 308 | !ftype__has_parm_of_type(&pos->proto, target_id, cu)) 309 | continue; 310 | 311 | if (verbose) 312 | tag__fprintf(function__tag(pos), cu, &conf, stdout); 313 | else 314 | fputs(function__name(pos, cu), stdout); 315 | putchar('\n'); 316 | } 317 | 318 | return 0; 319 | } 320 | 321 | static int function__emit_type_definitions(struct function *func, 322 | struct cu *cu, FILE *fp) 323 | { 324 | struct parameter *pos; 325 | 326 | function__for_each_parameter(func, pos) { 327 | struct tag *type = cu__type(cu, pos->tag.type); 328 | try_again: 329 | if (type == NULL) 330 | continue; 331 | 332 | if (type->tag == DW_TAG_pointer_type) { 333 | type = cu__type(cu, type->type); 334 | goto try_again; 335 | } 336 | 337 | if (tag__is_type(type)) { 338 | type__emit_definitions(type, cu, &emissions, fp); 339 | type__emit(type, cu, NULL, NULL, fp); 340 | putchar('\n'); 341 | } 342 | } 343 | 344 | return 0; 345 | } 346 | 347 | static void function__show(struct function *func, struct cu *cu) 348 | { 349 | struct tag *tag = function__tag(func); 350 | 351 | if (expand_types) 352 | function__emit_type_definitions(func, cu, stdout); 353 | tag__fprintf(tag, cu, &conf, stdout); 354 | putchar('\n'); 355 | if (show_variables || show_inline_expansions) 356 | function__fprintf_stats(tag, cu, &conf, stdout); 357 | } 358 | 359 | static int cu_function_iterator(struct cu *cu, void *cookie) 360 | { 361 | struct function *function; 362 | uint32_t id; 363 | 364 | cu__for_each_function(cu, id, function) { 365 | if (strcmp(function__name(function, cu), cookie) != 0) 366 | continue; 367 | function__show(function, cu); 368 | return 1; 369 | } 370 | return 0; 371 | } 372 | 373 | int elf_symtab__show(char *filename) 374 | { 375 | int fd = open(filename, O_RDONLY), err = -1; 376 | if (fd < 0) 377 | return -1; 378 | 379 | if (elf_version(EV_CURRENT) == EV_NONE) { 380 | fprintf(stderr, "%s: cannot set libelf version.\n", __func__); 381 | goto out_close; 382 | } 383 | 384 | Elf *elf = elf_begin(fd, ELF_C_READ_MMAP, NULL); 385 | if (elf == NULL) { 386 | fprintf(stderr, "%s: cannot read %s ELF file.\n", 387 | __func__, filename); 388 | goto out_close; 389 | } 390 | 391 | GElf_Ehdr ehdr; 392 | if (gelf_getehdr(elf, &ehdr) == NULL) { 393 | fprintf(stderr, "%s: cannot get elf header.\n", __func__); 394 | goto out_elf_end; 395 | } 396 | 397 | struct elf_symtab *symtab = elf_symtab__new(symtab_name, elf, &ehdr); 398 | if (symtab == NULL) 399 | goto out_elf_end; 400 | 401 | GElf_Sym sym; 402 | uint32_t index; 403 | int longest_name = 0; 404 | elf_symtab__for_each_symbol(symtab, index, sym) { 405 | if (!elf_sym__is_local_function(&sym)) 406 | continue; 407 | int len = strlen(elf_sym__name(&sym, symtab)); 408 | if (len > longest_name) 409 | longest_name = len; 410 | } 411 | 412 | if (longest_name > 32) 413 | longest_name = 32; 414 | 415 | int index_spacing = 0; 416 | int nr = elf_symtab__nr_symbols(symtab); 417 | while (nr) { 418 | ++index_spacing; 419 | nr /= 10; 420 | } 421 | 422 | elf_symtab__for_each_symbol(symtab, index, sym) { 423 | if (!elf_sym__is_local_function(&sym)) 424 | continue; 425 | printf("%*d: %-*s %#llx %5u\n", 426 | index_spacing, index, longest_name, 427 | elf_sym__name(&sym, symtab), 428 | (unsigned long long)elf_sym__value(&sym), 429 | elf_sym__size(&sym)); 430 | } 431 | 432 | elf_symtab__delete(symtab); 433 | err = 0; 434 | out_elf_end: 435 | elf_end(elf); 436 | out_close: 437 | close(fd); 438 | return err; 439 | } 440 | 441 | int elf_symtabs__show(char *filenames[]) 442 | { 443 | int i = 0; 444 | 445 | while (filenames[i] != NULL) { 446 | if (elf_symtab__show(filenames[i])) 447 | return EXIT_FAILURE; 448 | ++i; 449 | } 450 | 451 | return EXIT_SUCCESS; 452 | } 453 | 454 | /* Name and version of program. */ 455 | ARGP_PROGRAM_VERSION_HOOK_DEF = dwarves_print_version; 456 | 457 | #define ARGP_symtab 300 458 | #define ARGP_no_parm_names 301 459 | 460 | static const struct argp_option pfunct__options[] = { 461 | { 462 | .key = 'a', 463 | .name = "addr", 464 | .arg = "ADDR", 465 | .doc = "show just the function that where ADDR is", 466 | }, 467 | { 468 | .key = 'b', 469 | .name = "expand_types", 470 | .doc = "Expand types needed by the prototype", 471 | }, 472 | { 473 | .key = 'c', 474 | .name = "class", 475 | .arg = "CLASS", 476 | .doc = "functions that have CLASS pointer parameters", 477 | }, 478 | { 479 | .key = 'E', 480 | .name = "externals", 481 | .doc = "show just external functions", 482 | }, 483 | { 484 | .key = 'f', 485 | .name = "function", 486 | .arg = "FUNCTION", 487 | .doc = "show just FUNCTION", 488 | }, 489 | { 490 | .name = "format_path", 491 | .key = 'F', 492 | .arg = "FORMAT_LIST", 493 | .doc = "List of debugging formats to try" 494 | }, 495 | { 496 | .key = 'g', 497 | .name = "goto_labels", 498 | .doc = "show number of goto labels", 499 | }, 500 | { 501 | .key = 'G', 502 | .name = "cc_uninlined", 503 | .doc = "declared inline, uninlined by compiler", 504 | }, 505 | { 506 | .key = 'H', 507 | .name = "cc_inlined", 508 | .doc = "not declared inline, inlined by compiler", 509 | }, 510 | { 511 | .key = 'i', 512 | .name = "inline_expansions", 513 | .doc = "show inline expansions", 514 | }, 515 | { 516 | .key = 'I', 517 | .name = "inline_expansions_stats", 518 | .doc = "show inline expansions stats", 519 | }, 520 | { 521 | .key = 'l', 522 | .name = "decl_info", 523 | .doc = "show source code info", 524 | }, 525 | { 526 | .key = 't', 527 | .name = "total_inline_stats", 528 | .doc = "show Multi-CU total inline expansions stats", 529 | }, 530 | { 531 | .key = 's', 532 | .name = "sizes", 533 | .doc = "show size of functions", 534 | }, 535 | { 536 | .key = 'N', 537 | .name = "function_name_len", 538 | .doc = "show size of functions names", 539 | }, 540 | { 541 | .key = 'p', 542 | .name = "nr_parms", 543 | .doc = "show number of parameters", 544 | }, 545 | { 546 | .key = 'P', 547 | .name = "prototypes", 548 | .doc = "show function prototypes", 549 | }, 550 | { 551 | .key = 'S', 552 | .name = "nr_variables", 553 | .doc = "show number of variables", 554 | }, 555 | { 556 | .key = 'T', 557 | .name = "variables", 558 | .doc = "show variables", 559 | }, 560 | { 561 | .key = 'V', 562 | .name = "verbose", 563 | .doc = "be verbose", 564 | }, 565 | { 566 | .name = "symtab", 567 | .key = ARGP_symtab, 568 | .arg = "NAME", 569 | .flags = OPTION_ARG_OPTIONAL, 570 | .doc = "show symbol table NAME (Default .symtab)", 571 | }, 572 | { 573 | .name = "no_parm_names", 574 | .key = ARGP_no_parm_names, 575 | .doc = "Don't show parameter names", 576 | }, 577 | { 578 | .name = NULL, 579 | } 580 | }; 581 | 582 | static void (*formatter)(const struct fn_stats *f) = fn_stats_fmtr; 583 | static char *class_name; 584 | static char *function_name; 585 | static int show_total_inline_expansion_stats; 586 | 587 | static error_t pfunct__options_parser(int key, char *arg, 588 | struct argp_state *state) 589 | { 590 | switch (key) { 591 | case ARGP_KEY_INIT: 592 | if (state->child_inputs != NULL) 593 | state->child_inputs[0] = state->input; 594 | break; 595 | case 'a': addr = strtoull(arg, NULL, 0); 596 | conf_load.get_addr_info = true; break; 597 | case 'b': expand_types = true; 598 | type_emissions__init(&emissions); break; 599 | case 'c': class_name = arg; break; 600 | case 'f': function_name = arg; break; 601 | case 'F': conf_load.format_path = arg; break; 602 | case 'E': show_externals = 1; break; 603 | case 's': formatter = fn_stats_size_fmtr; 604 | conf_load.get_addr_info = true; break; 605 | case 'S': formatter = fn_stats_variables_fmtr; break; 606 | case 'p': formatter = fn_stats_nr_parms_fmtr; break; 607 | case 'P': show_prototypes = true; break; 608 | case 'g': formatter = fn_stats_labels_fmtr; break; 609 | case 'G': show_cc_uninlined = 1; break; 610 | case 'H': show_cc_inlined = 1; break; 611 | case 'i': show_inline_expansions = verbose = 1; 612 | conf_load.extra_dbg_info = true; 613 | conf_load.get_addr_info = true; break; 614 | case 'I': formatter = fn_stats_inline_exps_fmtr; 615 | conf_load.get_addr_info = true; break; 616 | case 'l': conf.show_decl_info = 1; 617 | conf_load.extra_dbg_info = 1; break; 618 | case 't': show_total_inline_expansion_stats = true; 619 | conf_load.get_addr_info = true; break; 620 | case 'T': show_variables = 1; break; 621 | case 'N': formatter = fn_stats_name_len_fmtr; break; 622 | case 'V': verbose = 1; 623 | conf_load.extra_dbg_info = true; 624 | conf_load.get_addr_info = true; break; 625 | case ARGP_symtab: symtab_name = arg ?: ".symtab"; break; 626 | case ARGP_no_parm_names: conf.no_parm_names = 1; break; 627 | default: return ARGP_ERR_UNKNOWN; 628 | } 629 | 630 | return 0; 631 | } 632 | 633 | static const char pfunct__args_doc[] = "FILE"; 634 | 635 | static struct argp pfunct__argp = { 636 | .options = pfunct__options, 637 | .parser = pfunct__options_parser, 638 | .args_doc = pfunct__args_doc, 639 | }; 640 | 641 | int main(int argc, char *argv[]) 642 | { 643 | int err, remaining, rc = EXIT_FAILURE; 644 | 645 | if (argp_parse(&pfunct__argp, argc, argv, 0, &remaining, NULL) || 646 | remaining == argc) { 647 | argp_help(&pfunct__argp, stderr, ARGP_HELP_SEE, argv[0]); 648 | goto out; 649 | } 650 | 651 | if (symtab_name != NULL) 652 | return elf_symtabs__show(argv + remaining); 653 | 654 | if (dwarves__init(0)) { 655 | fputs("pfunct: insufficient memory\n", stderr); 656 | goto out; 657 | } 658 | 659 | struct cus *cus = cus__new(); 660 | if (cus == NULL) { 661 | fputs("pfunct: insufficient memory\n", stderr); 662 | goto out_dwarves_exit; 663 | } 664 | 665 | err = cus__load_files(cus, &conf_load, argv + remaining); 666 | if (err != 0) 667 | goto out_cus_delete; 668 | 669 | cus__for_each_cu(cus, cu_unique_iterator, NULL, NULL); 670 | 671 | if (addr) { 672 | struct cu *cu; 673 | struct function *f = cus__find_function_at_addr(cus, addr, &cu); 674 | 675 | if (f == NULL) { 676 | fprintf(stderr, "pfunct: No function found at %#llx!\n", 677 | (unsigned long long)addr); 678 | goto out_cus_delete; 679 | } 680 | function__show(f, cu); 681 | } else if (show_total_inline_expansion_stats) 682 | print_total_inline_stats(); 683 | else if (class_name != NULL) 684 | cus__for_each_cu(cus, cu_class_iterator, class_name, NULL); 685 | else if (function_name != NULL) 686 | cus__for_each_cu(cus, cu_function_iterator, 687 | function_name, NULL); 688 | else 689 | print_fn_stats(formatter); 690 | 691 | rc = EXIT_SUCCESS; 692 | out_cus_delete: 693 | cus__delete(cus); 694 | fn_stats__delete_list(); 695 | out_dwarves_exit: 696 | dwarves__exit(); 697 | out: 698 | return rc; 699 | } 700 | -------------------------------------------------------------------------------- /pglobal.c: -------------------------------------------------------------------------------- 1 | /* 2 | * 3 | * Copyright (C) 2007 Davi E. M. Arnaut 4 | * 5 | * This program is free software; you can redistribute it and/or modify it 6 | * under the terms of version 2 of the GNU General Public License as published 7 | * by the Free Software Foundation. 8 | */ 9 | 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | 18 | #include "dwarves.h" 19 | #include "dutil.h" 20 | 21 | static int verbose; 22 | 23 | struct extvar { 24 | struct extvar *next; 25 | const char *name; 26 | const struct variable *var; 27 | const struct cu *cu; 28 | }; 29 | 30 | struct extfun { 31 | struct extfun *next; 32 | const char *name; 33 | const struct function *fun; 34 | const struct cu *cu; 35 | }; 36 | 37 | static void *tree; 38 | 39 | static void oom(const char *msg) 40 | { 41 | fprintf(stderr, "pglobal: out of memory (%s)\n", msg); 42 | exit(EXIT_FAILURE); 43 | } 44 | 45 | static struct extvar *extvar__new(const struct variable *var, 46 | const struct cu *cu) 47 | { 48 | struct extvar *gvar = malloc(sizeof(*gvar)); 49 | 50 | if (gvar != NULL) { 51 | gvar->next = NULL; 52 | gvar->var = var; 53 | gvar->cu = cu; 54 | gvar->name = variable__name(var, cu); 55 | } 56 | 57 | return gvar; 58 | } 59 | 60 | static struct extfun *extfun__new(struct function *fun, 61 | const struct cu *cu) 62 | { 63 | struct extfun *gfun = malloc(sizeof(*gfun)); 64 | 65 | if (gfun != NULL) { 66 | gfun->next = NULL; 67 | gfun->fun = fun; 68 | gfun->cu = cu; 69 | gfun->name = function__name(fun, cu); 70 | } 71 | 72 | return gfun; 73 | } 74 | 75 | static int extvar__compare(const void *a, const void *b) 76 | { 77 | const struct extvar *ga = a, *gb = b; 78 | return strcmp(ga->name, gb->name); 79 | } 80 | 81 | static int extfun__compare(const void *a, const void *b) 82 | { 83 | const struct extfun *ga = a, *gb = b; 84 | return strcmp(ga->name, gb->name); 85 | } 86 | 87 | static void extvar__add(const struct variable *var, const struct cu *cu) 88 | { 89 | struct extvar **nodep, *gvar = extvar__new(var, cu); 90 | 91 | if (gvar != NULL) { 92 | nodep = tsearch(gvar, &tree, extvar__compare); 93 | if (nodep == NULL) 94 | oom("tsearch"); 95 | else if (*nodep != gvar) 96 | if (gvar->var->declaration) { 97 | gvar->next = (*nodep)->next; 98 | (*nodep)->next = gvar; 99 | } else { 100 | gvar->next = *nodep; 101 | *nodep = gvar; 102 | } 103 | } 104 | } 105 | 106 | static void extfun__add(struct function *fun, const struct cu *cu) 107 | { 108 | struct extfun **nodep, *gfun = extfun__new(fun, cu); 109 | 110 | if (gfun != NULL) { 111 | nodep = tsearch(gfun, &tree, extfun__compare); 112 | if (nodep == NULL) 113 | oom("tsearch"); 114 | else if (*nodep != gfun) { 115 | gfun->next = (*nodep)->next; 116 | (*nodep)->next = gfun; 117 | } 118 | } 119 | } 120 | 121 | static int cu_extvar_iterator(struct cu *cu, void *cookie __unused) 122 | { 123 | struct tag *pos; 124 | uint32_t id; 125 | 126 | cu__for_each_variable(cu, id, pos) { 127 | struct variable *var = tag__variable(pos); 128 | if (var->external) 129 | extvar__add(var, cu); 130 | } 131 | return 0; 132 | } 133 | 134 | static int cu_extfun_iterator(struct cu *cu, void *cookie __unused) 135 | { 136 | struct function *pos; 137 | uint32_t id; 138 | 139 | cu__for_each_function(cu, id, pos) 140 | if (pos->external) 141 | extfun__add(pos, cu); 142 | return 0; 143 | } 144 | 145 | static inline const struct extvar *node__variable(const void *nodep) 146 | { 147 | return *((const struct extvar **)nodep); 148 | } 149 | 150 | static inline const struct extfun *node__function(const void *nodep) 151 | { 152 | return *((const struct extfun **)nodep); 153 | } 154 | 155 | static inline struct tag *extvar__tag(const struct extvar *gvar) 156 | { 157 | return (struct tag *)gvar->var; 158 | } 159 | 160 | static inline struct tag *extfun__tag(const struct extfun *gfun) 161 | { 162 | return (struct tag *)gfun->fun; 163 | } 164 | 165 | static void declaration_action__walk(const void *nodep, const VISIT which, 166 | const int depth __unused) 167 | { 168 | uint32_t count = 0; 169 | struct tag *tag; 170 | const struct extvar *pos, *gvar = NULL; 171 | 172 | switch(which) { 173 | case preorder: 174 | break; 175 | case postorder: 176 | gvar = node__variable(nodep); 177 | break; 178 | case endorder: 179 | break; 180 | case leaf: 181 | gvar = node__variable(nodep); 182 | break; 183 | } 184 | 185 | if (gvar == NULL) 186 | return; 187 | 188 | tag = extvar__tag(gvar); 189 | 190 | tag__fprintf(tag, gvar->cu, NULL, stdout); 191 | 192 | for (pos = gvar->next; pos; pos = pos->next) 193 | count++; 194 | 195 | printf("; /* %u */\n\n", count); 196 | } 197 | 198 | static void function_action__walk(const void *nodep, const VISIT which, 199 | const int depth __unused) 200 | { 201 | struct tag *tag; 202 | const struct extfun *gfun = NULL; 203 | 204 | switch(which) { 205 | case preorder: 206 | break; 207 | case postorder: 208 | gfun = node__function(nodep); 209 | break; 210 | case endorder: 211 | break; 212 | case leaf: 213 | gfun = node__function(nodep); 214 | break; 215 | } 216 | 217 | if (gfun == NULL) 218 | return; 219 | 220 | tag = extfun__tag(gfun); 221 | 222 | tag__fprintf(tag, gfun->cu, NULL, stdout); 223 | 224 | fputs("\n\n", stdout); 225 | } 226 | 227 | static void free_node(void *nodep) 228 | { 229 | void **node = nodep; 230 | free(*node); 231 | } 232 | 233 | /* Name and version of program. */ 234 | ARGP_PROGRAM_VERSION_HOOK_DEF = dwarves_print_version; 235 | 236 | static const struct argp_option pglobal__options[] = { 237 | { 238 | .key = 'v', 239 | .name = "variables", 240 | .doc = "show global variables", 241 | }, 242 | { 243 | .key = 'f', 244 | .name = "functions", 245 | .doc = "show global functions", 246 | }, 247 | { 248 | .key = 'V', 249 | .name = "verbose", 250 | .doc = "be verbose", 251 | }, 252 | { 253 | .name = NULL, 254 | } 255 | }; 256 | 257 | static int walk_var, walk_fun; 258 | 259 | static error_t pglobal__options_parser(int key, char *arg __unused, 260 | struct argp_state *state) 261 | { 262 | switch (key) { 263 | case ARGP_KEY_INIT: 264 | if (state->child_inputs != NULL) 265 | state->child_inputs[0] = state->input; 266 | break; 267 | case 'v': walk_var = 1; break; 268 | case 'f': walk_fun = 1; break; 269 | case 'V': verbose = 1; break; 270 | default: return ARGP_ERR_UNKNOWN; 271 | } 272 | return 0; 273 | } 274 | 275 | static const char pglobal__args_doc[] = "FILE"; 276 | 277 | static struct argp pglobal__argp = { 278 | .options = pglobal__options, 279 | .parser = pglobal__options_parser, 280 | .args_doc = pglobal__args_doc, 281 | }; 282 | 283 | int main(int argc, char *argv[]) 284 | { 285 | int err, remaining, rc = EXIT_FAILURE; 286 | 287 | if (argp_parse(&pglobal__argp, argc, argv, 0, &remaining, NULL) || 288 | remaining == argc) { 289 | argp_help(&pglobal__argp, stderr, ARGP_HELP_SEE, argv[0]); 290 | goto out; 291 | } 292 | 293 | if (dwarves__init(0)) { 294 | fputs("pglobal: insufficient memory\n", stderr); 295 | goto out; 296 | } 297 | 298 | struct cus *cus = cus__new(); 299 | if (cus == NULL) { 300 | fputs("pglobal: insufficient memory\n", stderr); 301 | goto out_dwarves_exit; 302 | } 303 | 304 | err = cus__load_files(cus, NULL, argv + remaining); 305 | if (err != 0) 306 | goto out_cus_delete; 307 | 308 | if (walk_var) { 309 | cus__for_each_cu(cus, cu_extvar_iterator, NULL, NULL); 310 | twalk(tree, declaration_action__walk); 311 | } else if (walk_fun) { 312 | cus__for_each_cu(cus, cu_extfun_iterator, NULL, NULL); 313 | twalk(tree, function_action__walk); 314 | } 315 | 316 | tdestroy(tree, free_node); 317 | rc = EXIT_SUCCESS; 318 | out_cus_delete: 319 | cus__delete(cus); 320 | out_dwarves_exit: 321 | dwarves__exit(); 322 | out: 323 | return rc; 324 | } 325 | -------------------------------------------------------------------------------- /prefcnt.c: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (C) 2006 Mandriva Conectiva S.A. 3 | Copyright (C) 2006 Arnaldo Carvalho de Melo 4 | 5 | This program is free software; you can redistribute it and/or modify it 6 | under the terms of version 2 of the GNU General Public License as 7 | published by the Free Software Foundation. 8 | */ 9 | 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | 16 | #include "dwarves.h" 17 | #include "dutil.h" 18 | 19 | static void refcnt_tag(struct tag *tag, const struct cu *cu); 20 | 21 | static void refcnt_member(struct class_member *member, const struct cu *cu) 22 | { 23 | if (member->visited) 24 | return; 25 | member->visited = 1; 26 | if (member->tag.type != 0) { /* if not void */ 27 | struct tag *type = cu__type(cu, member->tag.type); 28 | if (type != NULL) 29 | refcnt_tag(type, cu); 30 | } 31 | } 32 | 33 | static void refcnt_parameter(const struct parameter *parameter, 34 | const struct cu *cu) 35 | { 36 | if (parameter->tag.type != 0) { /* if not void */ 37 | struct tag *type = cu__type(cu, parameter->tag.type); 38 | if (type != NULL) 39 | refcnt_tag(type, cu); 40 | } 41 | } 42 | 43 | static void refcnt_variable(const struct variable *variable, 44 | const struct cu *cu) 45 | { 46 | if (variable->ip.tag.type != 0) { /* if not void */ 47 | struct tag *type = cu__type(cu, variable->ip.tag.type); 48 | if (type != NULL) 49 | refcnt_tag(type, cu); 50 | } 51 | } 52 | 53 | static void refcnt_inline_expansion(const struct inline_expansion *exp, 54 | const struct cu *cu) 55 | { 56 | if (exp->ip.tag.type != 0) { /* if not void */ 57 | struct tag *type = cu__function(cu, exp->ip.tag.type); 58 | if (type != NULL) 59 | refcnt_tag(type, cu); 60 | } 61 | } 62 | 63 | static void refcnt_tag(struct tag *tag, const struct cu *cu) 64 | { 65 | struct class_member *member; 66 | 67 | tag->visited = 1; 68 | 69 | if (tag__is_struct(tag) || tag__is_union(tag)) 70 | type__for_each_member(tag__type(tag), member) 71 | refcnt_member(member, cu); 72 | } 73 | 74 | static void refcnt_lexblock(const struct lexblock *lexblock, const struct cu *cu) 75 | { 76 | struct tag *pos; 77 | 78 | list_for_each_entry(pos, &lexblock->tags, node) 79 | switch (pos->tag) { 80 | case DW_TAG_variable: 81 | refcnt_variable(tag__variable(pos), cu); 82 | break; 83 | case DW_TAG_inlined_subroutine: 84 | refcnt_inline_expansion(tag__inline_expansion(pos), cu); 85 | break; 86 | case DW_TAG_lexical_block: 87 | refcnt_lexblock(tag__lexblock(pos), cu); 88 | break; 89 | } 90 | } 91 | 92 | static void refcnt_function(struct function *function, const struct cu *cu) 93 | { 94 | struct parameter *parameter; 95 | 96 | function->proto.tag.visited = 1; 97 | 98 | if (function->proto.tag.type != 0) /* if not void */ { 99 | struct tag *type = cu__type(cu, function->proto.tag.type); 100 | if (type != NULL) 101 | refcnt_tag(type, cu); 102 | } 103 | 104 | list_for_each_entry(parameter, &function->proto.parms, tag.node) 105 | refcnt_parameter(parameter, cu); 106 | 107 | refcnt_lexblock(&function->lexblock, cu); 108 | } 109 | 110 | static int cu_refcnt_iterator(struct cu *cu, void *cookie __unused) 111 | { 112 | struct function *pos; 113 | uint32_t id; 114 | 115 | cu__for_each_function(cu, id, pos) 116 | refcnt_function(pos, cu); 117 | return 0; 118 | } 119 | 120 | static int lost_iterator(struct tag *tag, struct cu *cu, 121 | void *cookie __unused) 122 | { 123 | if (!tag->visited && tag__decl_file(tag, cu)) { 124 | tag__fprintf(tag, cu, NULL, stdout); 125 | puts(";\n"); 126 | } 127 | return 0; 128 | } 129 | 130 | static int cu_lost_iterator(struct cu *cu, void *cookie) 131 | { 132 | return cu__for_all_tags(cu, lost_iterator, cookie); 133 | } 134 | 135 | int main(int argc __unused, char *argv[]) 136 | { 137 | int err; 138 | struct cus *cus = cus__new(); 139 | 140 | if (dwarves__init(0) || cus == NULL) { 141 | fputs("prefcnt: insufficient memory\n", stderr); 142 | return EXIT_FAILURE; 143 | } 144 | 145 | err = cus__load_files(cus, NULL, argv + 1); 146 | if (err != 0) 147 | return EXIT_FAILURE; 148 | 149 | cus__for_each_cu(cus, cu_refcnt_iterator, NULL, NULL); 150 | cus__for_each_cu(cus, cu_lost_iterator, NULL, NULL); 151 | 152 | return EXIT_SUCCESS; 153 | } 154 | -------------------------------------------------------------------------------- /rbtree.c: -------------------------------------------------------------------------------- 1 | /* 2 | Red Black Trees 3 | (C) 1999 Andrea Arcangeli 4 | (C) 2002 David Woodhouse 5 | 6 | This program is free software; you can redistribute it and/or modify 7 | it under the terms of the GNU General Public License as published by 8 | the Free Software Foundation; either version 2 of the License, or 9 | (at your option) any later version. 10 | 11 | This program is distributed in the hope that it will be useful, 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | GNU General Public License for more details. 15 | 16 | You should have received a copy of the GNU General Public License 17 | along with this program; if not, write to the Free Software 18 | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 19 | 20 | linux/lib/rbtree.c 21 | */ 22 | 23 | #include "rbtree.h" 24 | 25 | static void __rb_rotate_left(struct rb_node *node, struct rb_root *root) 26 | { 27 | struct rb_node *right = node->rb_right; 28 | struct rb_node *parent = rb_parent(node); 29 | 30 | if ((node->rb_right = right->rb_left)) 31 | rb_set_parent(right->rb_left, node); 32 | right->rb_left = node; 33 | 34 | rb_set_parent(right, parent); 35 | 36 | if (parent) 37 | { 38 | if (node == parent->rb_left) 39 | parent->rb_left = right; 40 | else 41 | parent->rb_right = right; 42 | } 43 | else 44 | root->rb_node = right; 45 | rb_set_parent(node, right); 46 | } 47 | 48 | static void __rb_rotate_right(struct rb_node *node, struct rb_root *root) 49 | { 50 | struct rb_node *left = node->rb_left; 51 | struct rb_node *parent = rb_parent(node); 52 | 53 | if ((node->rb_left = left->rb_right)) 54 | rb_set_parent(left->rb_right, node); 55 | left->rb_right = node; 56 | 57 | rb_set_parent(left, parent); 58 | 59 | if (parent) 60 | { 61 | if (node == parent->rb_right) 62 | parent->rb_right = left; 63 | else 64 | parent->rb_left = left; 65 | } 66 | else 67 | root->rb_node = left; 68 | rb_set_parent(node, left); 69 | } 70 | 71 | void rb_insert_color(struct rb_node *node, struct rb_root *root) 72 | { 73 | struct rb_node *parent, *gparent; 74 | 75 | while ((parent = rb_parent(node)) && rb_is_red(parent)) 76 | { 77 | gparent = rb_parent(parent); 78 | 79 | if (parent == gparent->rb_left) 80 | { 81 | { 82 | register struct rb_node *uncle = gparent->rb_right; 83 | if (uncle && rb_is_red(uncle)) 84 | { 85 | rb_set_black(uncle); 86 | rb_set_black(parent); 87 | rb_set_red(gparent); 88 | node = gparent; 89 | continue; 90 | } 91 | } 92 | 93 | if (parent->rb_right == node) 94 | { 95 | register struct rb_node *tmp; 96 | __rb_rotate_left(parent, root); 97 | tmp = parent; 98 | parent = node; 99 | node = tmp; 100 | } 101 | 102 | rb_set_black(parent); 103 | rb_set_red(gparent); 104 | __rb_rotate_right(gparent, root); 105 | } else { 106 | { 107 | register struct rb_node *uncle = gparent->rb_left; 108 | if (uncle && rb_is_red(uncle)) 109 | { 110 | rb_set_black(uncle); 111 | rb_set_black(parent); 112 | rb_set_red(gparent); 113 | node = gparent; 114 | continue; 115 | } 116 | } 117 | 118 | if (parent->rb_left == node) 119 | { 120 | register struct rb_node *tmp; 121 | __rb_rotate_right(parent, root); 122 | tmp = parent; 123 | parent = node; 124 | node = tmp; 125 | } 126 | 127 | rb_set_black(parent); 128 | rb_set_red(gparent); 129 | __rb_rotate_left(gparent, root); 130 | } 131 | } 132 | 133 | rb_set_black(root->rb_node); 134 | } 135 | 136 | static void __rb_erase_color(struct rb_node *node, struct rb_node *parent, 137 | struct rb_root *root) 138 | { 139 | struct rb_node *other; 140 | 141 | while ((!node || rb_is_black(node)) && node != root->rb_node) 142 | { 143 | if (parent->rb_left == node) 144 | { 145 | other = parent->rb_right; 146 | if (rb_is_red(other)) 147 | { 148 | rb_set_black(other); 149 | rb_set_red(parent); 150 | __rb_rotate_left(parent, root); 151 | other = parent->rb_right; 152 | } 153 | if ((!other->rb_left || rb_is_black(other->rb_left)) && 154 | (!other->rb_right || rb_is_black(other->rb_right))) 155 | { 156 | rb_set_red(other); 157 | node = parent; 158 | parent = rb_parent(node); 159 | } 160 | else 161 | { 162 | if (!other->rb_right || rb_is_black(other->rb_right)) 163 | { 164 | rb_set_black(other->rb_left); 165 | rb_set_red(other); 166 | __rb_rotate_right(other, root); 167 | other = parent->rb_right; 168 | } 169 | rb_set_color(other, rb_color(parent)); 170 | rb_set_black(parent); 171 | rb_set_black(other->rb_right); 172 | __rb_rotate_left(parent, root); 173 | node = root->rb_node; 174 | break; 175 | } 176 | } 177 | else 178 | { 179 | other = parent->rb_left; 180 | if (rb_is_red(other)) 181 | { 182 | rb_set_black(other); 183 | rb_set_red(parent); 184 | __rb_rotate_right(parent, root); 185 | other = parent->rb_left; 186 | } 187 | if ((!other->rb_left || rb_is_black(other->rb_left)) && 188 | (!other->rb_right || rb_is_black(other->rb_right))) 189 | { 190 | rb_set_red(other); 191 | node = parent; 192 | parent = rb_parent(node); 193 | } 194 | else 195 | { 196 | if (!other->rb_left || rb_is_black(other->rb_left)) 197 | { 198 | rb_set_black(other->rb_right); 199 | rb_set_red(other); 200 | __rb_rotate_left(other, root); 201 | other = parent->rb_left; 202 | } 203 | rb_set_color(other, rb_color(parent)); 204 | rb_set_black(parent); 205 | rb_set_black(other->rb_left); 206 | __rb_rotate_right(parent, root); 207 | node = root->rb_node; 208 | break; 209 | } 210 | } 211 | } 212 | if (node) 213 | rb_set_black(node); 214 | } 215 | 216 | void rb_erase(struct rb_node *node, struct rb_root *root) 217 | { 218 | struct rb_node *child, *parent; 219 | int color; 220 | 221 | if (!node->rb_left) 222 | child = node->rb_right; 223 | else if (!node->rb_right) 224 | child = node->rb_left; 225 | else 226 | { 227 | struct rb_node *old = node, *left; 228 | 229 | node = node->rb_right; 230 | while ((left = node->rb_left) != NULL) 231 | node = left; 232 | child = node->rb_right; 233 | parent = rb_parent(node); 234 | color = rb_color(node); 235 | 236 | if (child) 237 | rb_set_parent(child, parent); 238 | if (parent == old) { 239 | parent->rb_right = child; 240 | parent = node; 241 | } else 242 | parent->rb_left = child; 243 | 244 | node->rb_parent_color = old->rb_parent_color; 245 | node->rb_right = old->rb_right; 246 | node->rb_left = old->rb_left; 247 | 248 | if (rb_parent(old)) 249 | { 250 | if (rb_parent(old)->rb_left == old) 251 | rb_parent(old)->rb_left = node; 252 | else 253 | rb_parent(old)->rb_right = node; 254 | } else 255 | root->rb_node = node; 256 | 257 | rb_set_parent(old->rb_left, node); 258 | if (old->rb_right) 259 | rb_set_parent(old->rb_right, node); 260 | goto color; 261 | } 262 | 263 | parent = rb_parent(node); 264 | color = rb_color(node); 265 | 266 | if (child) 267 | rb_set_parent(child, parent); 268 | if (parent) 269 | { 270 | if (parent->rb_left == node) 271 | parent->rb_left = child; 272 | else 273 | parent->rb_right = child; 274 | } 275 | else 276 | root->rb_node = child; 277 | 278 | color: 279 | if (color == RB_BLACK) 280 | __rb_erase_color(child, parent, root); 281 | } 282 | 283 | /* 284 | * This function returns the first node (in sort order) of the tree. 285 | */ 286 | struct rb_node *rb_first(const struct rb_root *root) 287 | { 288 | struct rb_node *n; 289 | 290 | n = root->rb_node; 291 | if (!n) 292 | return NULL; 293 | while (n->rb_left) 294 | n = n->rb_left; 295 | return n; 296 | } 297 | 298 | struct rb_node *rb_last(const struct rb_root *root) 299 | { 300 | struct rb_node *n; 301 | 302 | n = root->rb_node; 303 | if (!n) 304 | return NULL; 305 | while (n->rb_right) 306 | n = n->rb_right; 307 | return n; 308 | } 309 | 310 | struct rb_node *rb_next(const struct rb_node *node) 311 | { 312 | struct rb_node *parent; 313 | 314 | if (rb_parent(node) == node) 315 | return NULL; 316 | 317 | /* If we have a right-hand child, go down and then left as far 318 | as we can. */ 319 | if (node->rb_right) { 320 | node = node->rb_right; 321 | while (node->rb_left) 322 | node=node->rb_left; 323 | return (struct rb_node *)node; 324 | } 325 | 326 | /* No right-hand children. Everything down and left is 327 | smaller than us, so any 'next' node must be in the general 328 | direction of our parent. Go up the tree; any time the 329 | ancestor is a right-hand child of its parent, keep going 330 | up. First time it's a left-hand child of its parent, said 331 | parent is our 'next' node. */ 332 | while ((parent = rb_parent(node)) && node == parent->rb_right) 333 | node = parent; 334 | 335 | return parent; 336 | } 337 | 338 | struct rb_node *rb_prev(const struct rb_node *node) 339 | { 340 | struct rb_node *parent; 341 | 342 | if (rb_parent(node) == node) 343 | return NULL; 344 | 345 | /* If we have a left-hand child, go down and then right as far 346 | as we can. */ 347 | if (node->rb_left) { 348 | node = node->rb_left; 349 | while (node->rb_right) 350 | node=node->rb_right; 351 | return (struct rb_node *)node; 352 | } 353 | 354 | /* No left-hand children. Go up till we find an ancestor which 355 | is a right-hand child of its parent */ 356 | while ((parent = rb_parent(node)) && node == parent->rb_left) 357 | node = parent; 358 | 359 | return parent; 360 | } 361 | 362 | void rb_replace_node(struct rb_node *victim, struct rb_node *new, 363 | struct rb_root *root) 364 | { 365 | struct rb_node *parent = rb_parent(victim); 366 | 367 | /* Set the surrounding nodes to point to the replacement */ 368 | if (parent) { 369 | if (victim == parent->rb_left) 370 | parent->rb_left = new; 371 | else 372 | parent->rb_right = new; 373 | } else { 374 | root->rb_node = new; 375 | } 376 | if (victim->rb_left) 377 | rb_set_parent(victim->rb_left, new); 378 | if (victim->rb_right) 379 | rb_set_parent(victim->rb_right, new); 380 | 381 | /* Copy the pointers/colour from the victim to the replacement */ 382 | *new = *victim; 383 | } 384 | -------------------------------------------------------------------------------- /rbtree.h: -------------------------------------------------------------------------------- 1 | /* 2 | Red Black Trees 3 | (C) 1999 Andrea Arcangeli 4 | 5 | This program is free software; you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License as published by 7 | the Free Software Foundation; either version 2 of the License, or 8 | (at your option) any later version. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with this program; if not, write to the Free Software 17 | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 18 | 19 | linux/include/linux/rbtree.h 20 | 21 | To use rbtrees you'll have to implement your own insert and search cores. 22 | This will avoid us to use callbacks and to drop drammatically performances. 23 | I know it's not the cleaner way, but in C (not in C++) to get 24 | performances and genericity... 25 | 26 | Some example of insert and search follows here. The search is a plain 27 | normal search over an ordered tree. The insert instead must be implemented 28 | int two steps: as first thing the code must insert the element in 29 | order as a red leaf in the tree, then the support library function 30 | rb_insert_color() must be called. Such function will do the 31 | not trivial work to rebalance the rbtree if necessary. 32 | 33 | ----------------------------------------------------------------------- 34 | static inline struct page * rb_search_page_cache(struct inode * inode, 35 | unsigned long offset) 36 | { 37 | struct rb_node * n = inode->i_rb_page_cache.rb_node; 38 | struct page * page; 39 | 40 | while (n) 41 | { 42 | page = rb_entry(n, struct page, rb_page_cache); 43 | 44 | if (offset < page->offset) 45 | n = n->rb_left; 46 | else if (offset > page->offset) 47 | n = n->rb_right; 48 | else 49 | return page; 50 | } 51 | return NULL; 52 | } 53 | 54 | static inline struct page * __rb_insert_page_cache(struct inode * inode, 55 | unsigned long offset, 56 | struct rb_node * node) 57 | { 58 | struct rb_node ** p = &inode->i_rb_page_cache.rb_node; 59 | struct rb_node * parent = NULL; 60 | struct page * page; 61 | 62 | while (*p) 63 | { 64 | parent = *p; 65 | page = rb_entry(parent, struct page, rb_page_cache); 66 | 67 | if (offset < page->offset) 68 | p = &(*p)->rb_left; 69 | else if (offset > page->offset) 70 | p = &(*p)->rb_right; 71 | else 72 | return page; 73 | } 74 | 75 | rb_link_node(node, parent, p); 76 | 77 | return NULL; 78 | } 79 | 80 | static inline struct page * rb_insert_page_cache(struct inode * inode, 81 | unsigned long offset, 82 | struct rb_node * node) 83 | { 84 | struct page * ret; 85 | if ((ret = __rb_insert_page_cache(inode, offset, node))) 86 | goto out; 87 | rb_insert_color(node, &inode->i_rb_page_cache); 88 | out: 89 | return ret; 90 | } 91 | ----------------------------------------------------------------------- 92 | */ 93 | 94 | #ifndef _LINUX_RBTREE_H 95 | #define _LINUX_RBTREE_H 96 | 97 | #include 98 | 99 | /** 100 | * container_of - cast a member of a structure out to the containing structure 101 | * @ptr: the pointer to the member. 102 | * @type: the type of the container struct this is embedded in. 103 | * @member: the name of the member within the struct. 104 | * 105 | */ 106 | #define container_of(ptr, type, member) ({ \ 107 | const typeof( ((type *)0)->member ) *__mptr = (ptr); \ 108 | (type *)( (char *)__mptr - offsetof(type,member) );}) 109 | 110 | struct rb_node 111 | { 112 | unsigned long rb_parent_color; 113 | #define RB_RED 0 114 | #define RB_BLACK 1 115 | struct rb_node *rb_right; 116 | struct rb_node *rb_left; 117 | } __attribute__((aligned(sizeof(long)))); 118 | /* The alignment might seem pointless, but allegedly CRIS needs it */ 119 | 120 | struct rb_root 121 | { 122 | struct rb_node *rb_node; 123 | }; 124 | 125 | 126 | #define rb_parent(r) ((struct rb_node *)((r)->rb_parent_color & ~3)) 127 | #define rb_color(r) ((r)->rb_parent_color & 1) 128 | #define rb_is_red(r) (!rb_color(r)) 129 | #define rb_is_black(r) rb_color(r) 130 | #define rb_set_red(r) do { (r)->rb_parent_color &= ~1; } while (0) 131 | #define rb_set_black(r) do { (r)->rb_parent_color |= 1; } while (0) 132 | 133 | static inline void rb_set_parent(struct rb_node *rb, struct rb_node *p) 134 | { 135 | rb->rb_parent_color = (rb->rb_parent_color & 3) | (unsigned long)p; 136 | } 137 | static inline void rb_set_color(struct rb_node *rb, int color) 138 | { 139 | rb->rb_parent_color = (rb->rb_parent_color & ~1) | color; 140 | } 141 | 142 | #define RB_ROOT (struct rb_root) { NULL, } 143 | #define rb_entry(ptr, type, member) container_of(ptr, type, member) 144 | 145 | #define RB_EMPTY_ROOT(root) ((root)->rb_node == NULL) 146 | #define RB_EMPTY_NODE(node) (rb_parent(node) == node) 147 | #define RB_CLEAR_NODE(node) (rb_set_parent(node, node)) 148 | 149 | extern void rb_insert_color(struct rb_node *, struct rb_root *); 150 | extern void rb_erase(struct rb_node *, struct rb_root *); 151 | 152 | /* Find logical next and previous nodes in a tree */ 153 | extern struct rb_node *rb_next(const struct rb_node *); 154 | extern struct rb_node *rb_prev(const struct rb_node *); 155 | extern struct rb_node *rb_first(const struct rb_root *); 156 | extern struct rb_node *rb_last(const struct rb_root *); 157 | 158 | /* Fast replacement of a single node without remove/rebalance/add/rebalance */ 159 | extern void rb_replace_node(struct rb_node *victim, struct rb_node *new, 160 | struct rb_root *root); 161 | 162 | static inline void rb_link_node(struct rb_node * node, struct rb_node * parent, 163 | struct rb_node ** rb_link) 164 | { 165 | node->rb_parent_color = (unsigned long )parent; 166 | node->rb_left = node->rb_right = NULL; 167 | 168 | *rb_link = node; 169 | } 170 | 171 | #endif /* _LINUX_RBTREE_H */ 172 | -------------------------------------------------------------------------------- /regtest: -------------------------------------------------------------------------------- 1 | #! /usr/bin/python 2 | # -*- python -*- 3 | # -*- coding: utf-8 -*- 4 | # tuna - Application Tuning GUI 5 | # Copyright (C) 2009 Arnaldo Carvalho de Melo 6 | # Arnaldo Carvalho de Melo 7 | # 8 | # This application is free software; you can redistribute it and/or 9 | # modify it under the terms of the GNU General Public License 10 | # as published by the Free Software Foundation; version 2. 11 | # 12 | # This application is distributed in the hope that it will be useful, 13 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 | # General Public License for more details. 16 | 17 | import filecmp, getopt, os, posix, signal, sys, tempfile 18 | 19 | regtest_output_dir = "/media/tb/pahole/regtest/" 20 | regtest_obj_dir = "/media/tb/debuginfo/usr/lib/debug/" 21 | tools = {"pahole": { "dwarf": "--flat_arrays --show_private_classes --fixup_silly_bitfields --first_obj_only --classes_as_structs" }} 22 | all_formats = ("ctf", "dwarf") 23 | formats = all_formats 24 | len_debug_dir = len(regtest_obj_dir) 25 | verbose = 1 26 | 27 | # Turn this on when testing CTF generated files 28 | use_options = False 29 | 30 | def diff_file(from_filename, to_filename): 31 | fd, diff_filename = tempfile.mkstemp() 32 | command = 'diff -up "%s" "%s" > %s' % (from_filename, 33 | to_filename, diff_filename) 34 | if verbose > 1: 35 | print command 36 | try: 37 | os.system(command) 38 | os.system("vim %s" % diff_filename) 39 | finally: 40 | os.unlink(diff_filename) 41 | 42 | def dir_has_no_diffs(dirname): 43 | return os.access(os.path.join(dirname, ".no_diffs"), os.F_OK) 44 | 45 | def set_dir_has_no_diffs(dirname): 46 | f = file(os.path.join(dirname, ".no_diffs"), "w") 47 | f.close() 48 | 49 | def reset_dir_has_no_diffs(dirname): 50 | os.unlink(os.path.join(dirname, ".no_diffs")) 51 | 52 | def diff_dir(from_dir, to_dir, dir = None, recursive = True): 53 | if dir: 54 | from_dir = os.path.join(from_dir, dir) 55 | to_dir = os.path.join(to_dir, dir) 56 | print "\r%-130s" % from_dir 57 | sys.stdout.flush() 58 | diff = filecmp.dircmp(from_dir, to_dir) 59 | if not dir_has_no_diffs(to_dir): 60 | diff_files = diff.diff_files 61 | if diff_files: 62 | diff_files.sort() 63 | print "\n %s" % from_dir 64 | sys.stdout.flush() 65 | for f in diff_files: 66 | diff_file(os.path.join(from_dir, f), 67 | os.path.join(to_dir, f)) 68 | else: 69 | set_dir_has_no_diffs(to_dir) 70 | if not recursive: 71 | return 72 | common_dirs = diff.common_dirs 73 | if not common_dirs: 74 | return 75 | common_dirs.sort() 76 | for dir in common_dirs: 77 | diff_dir(from_dir, to_dir, dir) 78 | 79 | def do_diff_dwarfs2ctfs(): 80 | diff_dir(os.path.join(regtest_output_dir, "after", "pahole", "dwarf"), 81 | os.path.join(regtest_output_dir, "after", "pahole", "ctf")) 82 | 83 | def do_diff_dwarfs(): 84 | diff_dir(os.path.join(regtest_output_dir, "before", "pahole", "dwarf"), 85 | os.path.join(regtest_output_dir, "after", "pahole", "dwarf")) 86 | 87 | def do_tool(tool, before_after, format, dirname, fname, 88 | prepend_obj_dir = False): 89 | if prepend_obj_dir: 90 | fname += ".debug" 91 | fixed_dirname = dirname 92 | else: 93 | fixed_dirname = dirname[len_debug_dir:] 94 | tool_output_dir = os.path.join(regtest_output_dir, 95 | before_after, tool, format, 96 | fixed_dirname) 97 | obj_path = os.path.join(dirname, fname) 98 | if prepend_obj_dir: 99 | obj_path = os.path.join(regtest_obj_dir, obj_path) 100 | if os.path.islink(obj_path) or os.path.isdir(obj_path): 101 | return 102 | try: 103 | os.makedirs(tool_output_dir) 104 | except: 105 | pass 106 | if dir_has_no_diffs(tool_output_dir): 107 | reset_dir_has_no_diffs(tool_output_dir) 108 | output_file = os.path.join(tool_output_dir, fname[:-6]) 109 | if use_options and tools[tool].has_key(format): 110 | options = tools[tool][format] 111 | else: 112 | options = "" 113 | command = '%s -F %s %s %s > "%s"' % (tool, format, options, 114 | obj_path, output_file) 115 | if verbose > 1: 116 | print command 117 | sys.stdout.flush() 118 | elif verbose > 0: 119 | print "%s: %s" % (format, 120 | os.path.join(fixed_dirname, fname[:-6])) 121 | os.system(command) 122 | 123 | def do_tool_on_files(arg, dirname, fnames, prepend_obj_dir = False): 124 | if dirname.find("/.") >= 0: 125 | return 126 | tool, before_after = arg 127 | for fname in fnames: 128 | if not prepend_obj_dir and fname[-6:] != ".debug": 129 | continue 130 | 131 | for format in formats: 132 | do_tool(tool, before_after, format, dirname, fname, 133 | prepend_obj_dir) 134 | 135 | def do_tools(before_after): 136 | for tool in tools.keys(): 137 | os.path.walk(regtest_obj_dir, do_tool_on_files, (tool, before_after)) 138 | 139 | def do_ctf(dirname, fname, prepend_obj_dir = False): 140 | if prepend_obj_dir: 141 | fname += ".debug" 142 | fixed_dirname = dirname 143 | else: 144 | fixed_dirname = dirname[len_debug_dir:] 145 | obj_path = os.path.join(dirname, fname) 146 | if prepend_obj_dir: 147 | obj_path = os.path.join(regtest_obj_dir, obj_path) 148 | 149 | if os.path.islink(obj_path) or os.path.isdir(obj_path): 150 | return 151 | command = 'pahole -Z "%s" 2> /dev/null' % obj_path 152 | if verbose > 1: 153 | print command 154 | elif verbose > 0: 155 | print os.path.join(fixed_dirname, fname[:-6]) 156 | os.system(command) 157 | 158 | def do_ctf_on_files(arg, dirname, fnames, prepend_obj_dir = False): 159 | if dirname.find("/.") >= 0: 160 | return 161 | for fname in fnames: 162 | if not prepend_obj_dir and fname[-6:] != ".debug": 163 | continue 164 | 165 | do_ctf(dirname, fname, prepend_obj_dir) 166 | 167 | def do_ctfs(): 168 | os.path.walk(regtest_obj_dir, do_ctf_on_files, None) 169 | 170 | def sig_exit(sig_number, stack_frame): 171 | sys.exit(1) 172 | 173 | def listdebugs(dirname): 174 | fnames = [] 175 | for fname in os.listdir(os.path.join(regtest_obj_dir, dirname)): 176 | if fname[-6:] != ".debug": 177 | continue 178 | obj_path = os.path.join(regtest_obj_dir, dirname, fname) 179 | if os.path.islink(obj_path) or os.path.isdir(obj_path): 180 | continue 181 | fnames.append(fname[:-6]) 182 | return fnames 183 | 184 | def usage(): 185 | print 'Usage: regtest [OPTIONS]' 186 | fmt = '\t%-20s %s' 187 | print fmt % ('-h, --help', 'Give this help list') 188 | print fmt % ('-a, --after', 'Generate new output') 189 | print fmt % ('-b, --before', 'Generate old output') 190 | print fmt % ('-c, --ctf_diff', 'Diff between DWARF and CTF for new output') 191 | print fmt % ('-C, --ctf_encode', 'Encode CTF into object files') 192 | print fmt % ('-d, --diff', 'Diff between old and new output') 193 | print fmt % ('-f, --formats', 'formats used (default: %s)' ','.join(formats)) 194 | 195 | def main(argv): 196 | global formats 197 | 198 | for sig in (signal.SIGHUP, signal.SIGINT, signal.SIGTERM): 199 | signal.signal(sig, sig_exit) 200 | 201 | try: 202 | short = "habcCdf:" 203 | long = ("help", "after", "before", "ctf_diff", "ctf_encode", 204 | "diff", "formats") 205 | opts, args = getopt.getopt(sys.argv[1:], short, long) 206 | except getopt.GetoptError, err: 207 | usage() 208 | print str(err) 209 | sys.exit(2) 210 | 211 | for o, a in opts: 212 | if o in ("-h", "--help"): 213 | usage() 214 | return 215 | elif o in ("-f", "--formats"): 216 | formats = a.split(',') 217 | elif o in ("-a", "--after", 218 | "-b", "--before", 219 | "-c", "--ctf_diff", 220 | "-C", "--ctf_encode", 221 | "-d", "--diff"): 222 | 223 | if len(args) > 0: 224 | dirname = args[0] 225 | if len(args) > 1: 226 | fnames = args[1:] 227 | elif o in ('-a', '--after', 228 | '-b', '--before', 229 | '-C', '--ctf_encode'): 230 | fnames = listdebugs(dirname) 231 | 232 | if o in ('-b', '--before', '-a', '--after'): 233 | if o in ('-b', '--before'): 234 | when = 'before' 235 | else: 236 | when = 'after' 237 | if len(args) > 0: 238 | for tool in tools.keys(): 239 | arg = (tool, when) 240 | do_tool_on_files(arg, dirname, fnames, True) 241 | else: 242 | do_tools(when) 243 | elif o in ('-d', '--diff'): 244 | if len(args) > 0: 245 | from_dir = os.path.join(regtest_output_dir, 246 | "before", "pahole", 247 | "dwarf", dirname) 248 | to_dir = os.path.join(regtest_output_dir, 249 | "after", "pahole", 250 | "dwarf", dirname) 251 | if len(args) > 1: 252 | for fname in fnames: 253 | diff_file(os.path.join(from_dir, fname), 254 | os.path.join(to_dir, fname)) 255 | else: 256 | diff_dir(from_dir, to_dir, recursive = False) 257 | else: 258 | do_diff_dwarfs() 259 | elif o in ('-C', 'ctf'): 260 | if len(args) > 0: 261 | do_ctf_on_files(None, dirname, fnames, True) 262 | else: 263 | do_ctfs() 264 | elif o in ('-c', 'ctf_diff'): 265 | if len(args) > 0: 266 | from_dir = os.path.join(regtest_output_dir, 267 | "after", "pahole", 268 | "dwarf", dirname) 269 | to_dir = os.path.join(regtest_output_dir, 270 | "after", "pahole", 271 | "ctf", dirname) 272 | if len(args) > 1: 273 | for fname in fnames: 274 | diff_file(os.path.join(from_dir, fname), 275 | os.path.join(to_dir, fname)) 276 | else: 277 | diff_dir(from_dir, to_dir, recursive = False) 278 | else: 279 | do_diff_dwarfs2ctfs() 280 | 281 | if __name__ == '__main__': 282 | main(sys.argv) 283 | -------------------------------------------------------------------------------- /rpm/SPECS/dwarves.spec: -------------------------------------------------------------------------------- 1 | %define libname libdwarves 2 | %define libver 1 3 | 4 | Name: dwarves 5 | Version: 1.10 6 | Release: 1%{?dist} 7 | License: GPLv2 8 | Summary: Debugging Information Manipulation Tools 9 | Group: Development/Tools 10 | URL: http://acmel.wordpress.com 11 | Source: http://fedorapeople.org/~acme/dwarves/%{name}-%{version}.tar.bz2 12 | BuildRequires: cmake 13 | BuildRequires: zlib-devel 14 | BuildRequires: elfutils-devel >= 0.130 15 | BuildRoot: %(mktemp -ud %{_tmppath}/%{name}-%{version}-%{release}-XXXXXX) 16 | 17 | %description 18 | dwarves is a set of tools that use the debugging information inserted in 19 | ELF binaries by compilers such as GCC, used by well known debuggers such as 20 | GDB, and more recent ones such as systemtap. 21 | 22 | Utilities in the dwarves suite include pahole, that can be used to find 23 | alignment holes in structs and classes in languages such as C, C++, but not 24 | limited to these. 25 | 26 | It also extracts other information such as CPU cacheline alignment, helping 27 | pack those structures to achieve more cache hits. 28 | 29 | A diff like tool, codiff can be used to compare the effects changes in source 30 | code generate on the resulting binaries. 31 | 32 | Another tool is pfunct, that can be used to find all sorts of information about 33 | functions, inlines, decisions made by the compiler about inlining, etc. 34 | 35 | %package -n %{libname}%{libver} 36 | Summary: Debugging information processing library 37 | Group: Development/Libraries 38 | 39 | %description -n %{libname}%{libver} 40 | Debugging information processing library. 41 | 42 | %package -n %{libname}%{libver}-devel 43 | Summary: Debugging information library development files 44 | Group: Development/Libraries 45 | Requires: %{libname}%{libver} = %{version}-%{release} 46 | 47 | %description -n %{libname}%{libver}-devel 48 | Debugging information processing library development files. 49 | 50 | %prep 51 | %setup -q -c -n %{name}-%{version} 52 | 53 | %build 54 | %cmake . 55 | make VERBOSE=1 %{?_smp_mflags} 56 | 57 | %install 58 | rm -Rf %{buildroot} 59 | make install DESTDIR=%{buildroot} 60 | 61 | %post -n %{libname}%{libver} -p /sbin/ldconfig 62 | 63 | %postun -n %{libname}%{libver} -p /sbin/ldconfig 64 | 65 | %clean 66 | rm -rf %{buildroot} 67 | 68 | %files 69 | %defattr(0644,root,root,0755) 70 | %doc README.ctracer 71 | %doc NEWS 72 | %defattr(0755,root,root,0755) 73 | %{_bindir}/codiff 74 | %{_bindir}/ctracer 75 | %{_bindir}/dtagnames 76 | %{_bindir}/pahole 77 | %{_bindir}/pdwtags 78 | %{_bindir}/pfunct 79 | %{_bindir}/pglobal 80 | %{_bindir}/prefcnt 81 | %{_bindir}/scncopy 82 | %{_bindir}/syscse 83 | %{_bindir}/ostra-cg 84 | %dir %{_datadir}/dwarves/ 85 | %dir %{_datadir}/dwarves/runtime/ 86 | %dir %{_datadir}/dwarves/runtime/python/ 87 | %defattr(0644,root,root,0755) 88 | %{_mandir}/man1/pahole.1* 89 | %{_datadir}/dwarves/runtime/Makefile 90 | %{_datadir}/dwarves/runtime/linux.blacklist.cu 91 | %{_datadir}/dwarves/runtime/ctracer_relay.c 92 | %{_datadir}/dwarves/runtime/ctracer_relay.h 93 | %attr(0755,root,root) %{_datadir}/dwarves/runtime/python/ostra.py* 94 | 95 | %files -n %{libname}%{libver} 96 | %defattr(0644,root,root,0755) 97 | %{_libdir}/%{libname}.so.* 98 | %{_libdir}/%{libname}_emit.so.* 99 | %{_libdir}/%{libname}_reorganize.so.* 100 | 101 | %files -n %{libname}%{libver}-devel 102 | %defattr(0644,root,root,0755) 103 | %doc MANIFEST README 104 | %{_includedir}/dwarves/dwarves.h 105 | %{_includedir}/dwarves/dwarves_emit.h 106 | %{_includedir}/dwarves/dwarves_reorganize.h 107 | %{_includedir}/dwarves/dutil.h 108 | %{_includedir}/dwarves/gobuffer.h 109 | %{_includedir}/dwarves/list.h 110 | %{_includedir}/dwarves/rbtree.h 111 | %{_includedir}/dwarves/strings.h 112 | %{_libdir}/%{libname}.so 113 | %{_libdir}/%{libname}_emit.so 114 | %{_libdir}/%{libname}_reorganize.so 115 | 116 | %changelog 117 | * Wed May 30 2012 Arnaldo Carvalho de Melo - 1.10-1 118 | - New release 119 | 120 | * Sat Nov 20 2010 Arnaldo Carvalho de Melo - 1.9-1 121 | - New release 122 | 123 | * Fri Dec 4 2009 Arnaldo Carvalho de Melo - 1.8-1 124 | - New release 125 | 126 | * Fri Feb 13 2009 Arnaldo Carvalho de Melo - 1.7-2 127 | - Own /usr/share/dwarves, fixes #473645 128 | 129 | * Fri Feb 13 2009 Arnaldo Carvalho de Melo - 1.7-1 130 | - A CTF decoder based on work done by David S. Miller 131 | - Handle DW_TAG_class_type, 132 | - Add support for showing classes with a prefix 133 | - Add support to DW_TAG_ptr_to_member_type 134 | - Handle typedef definitions in functions 135 | - Print the number of members in a struct/class 136 | - Handle the empty base optimization trick (Zero sized C++ class) 137 | - codiff detect changes in the prototype even when function size doesn't change 138 | - pfunct: Implement --expand_types 139 | - Reduce memory consumption by using a strings table 140 | - Speed up struct search by name 141 | - Several minor bug fixes and infrastructure improvements. 142 | - Initial man page for pahole 143 | 144 | * Mon Feb 11 2008 Arnaldo Carvalho de Melo - 1.6-1 145 | - c83d935a4fd561a3807f520c126c2a61ae1f4d83 146 | - [DWARVES]: Use a hash table for the tags in a CU 147 | 148 | * Thu Feb 7 2008 Arnaldo Carvalho de Melo - 1.5-1 149 | - c4e49add9e48ff08a8ba4187ea43d795af995136 150 | - PAHOLE: Introduce --defined_in 151 | - DWARVES: Another fix for DW_TAG_base_type entries without DW_AT_name 152 | - PAHOLE: Cope with DW_TAG_basic_type entries without DW_AT_name 153 | - CODIFF: Allow passing /dev/null as one of the files to compare 154 | - DWARVES: Allow passing NULL as self to cu__find_ 155 | - DWARVES: Fixup usage messages 156 | - DWARVES: Find holes in inner, nameless structs 157 | - DWARVES: Adopt tag__follow_typedef from pahole 158 | - DWARVES: Add some destructors: tag, cu, namespace 159 | - CODIFF: Check if the objects are the same when we have build-id 160 | - DWARVES: Introduce cu__same_build_id 161 | - DWARVES_REORGANIZE: Proper tail padding fixup 162 | - DWARVES: Don't search in empty structs 163 | - DWARVES: Follow const and volatile tags to its ultimate types 164 | - PAHOLE: Add a newline after the --class_dwarf_offset output 165 | - PAHOLE: Expose type__find_first_biggest_size_base_type_member 166 | - DWARVES: Introduce type__find_first_biggest_size_base_type_member 167 | - PAHOLE: Account arrays properly when changing word-size 168 | - PAHOLE: Follow typedefs too when resizing unions 169 | - PAHOLE: Follow typedefs to find if they are resized structs/unions 170 | - PAHOLE: Check if types of struct and union members were already resized 171 | - DWARVES_REORGANIZE: Fixup class__fixup_alingment 172 | - PAHOLE: Allow changing the architecture word-size 173 | - DWARVES_REORGANIZE: Adopt class__add_offsets_from and class__fixup_alignment from ctracer 174 | - DWARVES: build id support requires a recent elfutils package 175 | 176 | * Sat Jan 5 2008 Arnaldo Carvalho de Melo - 1.4-1 177 | - 8e099cf5d1f204e9ea1a9c8c0f1a09a43458d9d3 178 | - codiff fixes 179 | 180 | * Sun Dec 9 2007 Arnaldo Carvalho de Melo - 1.3-2 181 | - c6c71398cd2481e219ea3ef63f32c6479ba4f08f 182 | - SPEC file adjustments to follow http://fedoraproject.org/wiki/Packaging/cmake 183 | 184 | * Sat Dec 8 2007 Arnaldo Carvalho de Melo - 1.3-1 185 | - c4ee21aa122f51f2601893b2118b7f7902d2f410 186 | - Fixed bitfield byte offset handling, now there are no 187 | more BRAIN FART alerts on a x86_64 linux kernel and on 188 | an old openbsd kernel image. 189 | 190 | * Thu Dec 6 2007 Arnaldo Carvalho de Melo - 1.2-1 191 | - 07e0974f2c3798acb8e9a2d06f6b2ece7a01c508 192 | - Fix a patological bitfield case 193 | 194 | * Thu Dec 6 2007 Arnaldo Carvalho de Melo - 1.1-1 195 | - 2c01420b51e889196b42a204910b46811ab22f1a 196 | - ctracer now generates systemtap scripts 197 | - Lots of other fixes, see git changelog. 198 | 199 | * Tue May 8 2007 Arnaldo Carvalho de Melo - 1.0-1 200 | - 161c6712f4ae1b7e2ea50df3a0d5c28310905cec 201 | - handle --help, -? --usage on with_executable_option() 202 | 203 | * Tue May 8 2007 Arnaldo Carvalho de Melo 204 | - b8eb5eb214f3897ea6faa3272879baa8bf2573c0 205 | - Fix cus__loadfl detection of --executable 206 | 207 | * Sun May 6 2007 Arnaldo Carvalho de Melo 208 | - 05351ece16e5203717dd21a6fc1ad2e6ff87c203 209 | - libdwarves_emit 210 | 211 | * Tue Apr 3 2007 Arnaldo Carvalho de Melo 212 | - f3c4f527f70053e39b402005107ead6cb10e0b4a 213 | - Fix some --reorganize bugs 214 | 215 | * Mon Apr 2 2007 Arnaldo Carvalho de Melo 216 | - 1ec66565a12ce7f197cd40e3901ed6be84935781 217 | - --reorganize improvements 218 | - --packable uses --reorganize code to show structs that can be packed by 219 | reorganization done with --reorganize. 220 | 221 | * Fri Mar 30 2007 Arnaldo Carvalho de Melo 222 | - fd3542317508d04e8178c5d391385d2aa50d6fb7 223 | - Use libdwfl in all tools that handle just one file, codiff and ctracer 224 | still need work and are still using plain libdw. 225 | 226 | * Sun Feb 25 2007 Arnaldo Carvalho de Melo 227 | - 3c148cd84b74b89663febdefab23356952906502 228 | - _snprintf routines changed to _fprintf 229 | - codiff shows diffs in number and total size of inline expansions 230 | - codiff shows diffs in the number of lexblocks 231 | - better alignment in the --expand_types case 232 | - CMake improvements 233 | 234 | * Fri Feb 2 2007 Arnaldo Carvalho de Melo 235 | - d37f41df58c375412badf827e24dfc346cea2ff2 236 | - ostra-cg 237 | - relay/debugfs 238 | - mini-structs 239 | - ctracer2ostra 240 | - All this in the Makefile 241 | 242 | * Fri Feb 2 2007 Arnaldo Carvalho de Melo 243 | - b7cad1782d683571ffb2601b429ab151bddad5d7 244 | - pglobal, by Davi Arnaut 245 | - pahole --show_reorg_steps 246 | - Reorganize bitfields in pahole --reorganize 247 | 248 | * Tue Jan 30 2007 Arnaldo Carvalho de Melo 249 | - 8e236f4ca37b8a3d2057f4ede5a14ab1fa99f73c 250 | - x86-64 lib install fixes 251 | 252 | * Tue Jan 30 2007 Arnaldo Carvalho de Melo 253 | - 4a4b75e75a6d7f34215d320cc4a9f669b6ba4075 254 | - pahole --reorganize 255 | 256 | * Mon Jan 29 2007 Arnaldo Carvalho de Melo 257 | - 2de67fcaf401ac1e20feca5fa88dfc63fbc4203e 258 | - Type expansion! 259 | 260 | * Sat Jan 27 2007 Arnaldo Carvalho de Melo 261 | - 6bf2d2d7707b65e7ca21a13706d8d07824cd6f2f 262 | - ctracer improvements, /usr/lib/ctracer/, etc 263 | 264 | * Fri Jan 26 2007 Arnaldo Carvalho de Melo 265 | - c49f2c963425d5c09c429370e10d9af3d7d7fe32 266 | - Emit typedefs of typedef arrays 267 | - Detect typedef loops 268 | - Fix emission of arrays of structs, unions, etc 269 | - use sysconf for the default cacheline size 270 | 271 | * Wed Jan 18 2007 Arnaldo Carvalho de Melo 272 | - fab0db03ea9046893ca110bb2b7d71b764f61033 273 | - pdwtags added 274 | 275 | * Wed Jan 17 2007 Arnaldo Carvalho de Melo 276 | - e3786105c007a39ff3dbfb36a3037e786021e0c6 277 | - First Fedora native build 278 | - struct, enum, enum, void typedefs 279 | 280 | * Sat Jan 13 2007 Arnaldo Carvalho de Melo 281 | - 9a413e60a3875980d99817722bf019cba3a24573 282 | - pahole --nr_methods, improvements in tag__print, better support for unions 283 | 284 | * Fri Jan 12 2007 Arnaldo Carvalho de Melo 285 | - a1f5422656a91568a8b4edbcebaae9c1837b5cbd 286 | - Support a DW_TAG_reference_type 287 | 288 | * Fri Jan 12 2007 Arnaldo Carvalho de Melo 289 | - 0ad467a32187e1929c14054a0fc7326bc4d235c8 290 | - Added a description 291 | 292 | * Thu Jan 11 2007 Arnaldo Carvalho de Melo 293 | - new release with type not found asserts replaced by error messages 294 | 295 | * Thu Jan 11 2007 Arnaldo Carvalho de Melo 296 | - package created 297 | -------------------------------------------------------------------------------- /scncopy.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2009 Red Hat, Inc. 3 | * 4 | * This program is free software; you can redistribute it and/or modify it 5 | * under the terms of version 2 of the GNU General Public License as 6 | * published by the Free Software Foundation. 7 | * 8 | * Author: Peter Jones 9 | */ 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | 18 | #include "elfcreator.h" 19 | #include "dutil.h" 20 | 21 | static int should_copy_scn(Elf *elf, GElf_Shdr *shdr, struct strlist *scns) 22 | { 23 | char *name; 24 | size_t shstrndx; 25 | 26 | if (elf_getshdrstrndx(elf, &shstrndx) < 0) 27 | return 0; 28 | name = elf_strptr(elf, shstrndx, shdr->sh_name); 29 | if (name == NULL) 30 | return 0; 31 | 32 | if (strlist__has_entry(scns, name)) 33 | return 1; 34 | return 0; 35 | } 36 | 37 | int main(int argc, char *argv[]) 38 | { 39 | int n; 40 | struct strlist *sections; 41 | char *infile = NULL, *outfile = NULL; 42 | int fd; 43 | Elf *elf; 44 | Elf_Scn *scn; 45 | int copy_all_sections = 0; 46 | ElfCreator *ctor; 47 | 48 | sections = strlist__new(false); 49 | for (n = 1; n < argc; n++) { 50 | if (!strcmp(argv[n], "-a")) { 51 | copy_all_sections = 1; 52 | } else if (!strcmp(argv[n], "-s")) { 53 | if (n == argc-1) { 54 | fprintf(stderr, "Missing argument to -s\n"); 55 | return -1; 56 | } 57 | n++; 58 | strlist__add(sections, argv[n]); 59 | continue; 60 | } else if (!strcmp(argv[n], "-o")) { 61 | if (n == argc-1) { 62 | fprintf(stderr, "Missing argument to -o\n"); 63 | return -1; 64 | } 65 | n++; 66 | outfile = argv[n]; 67 | continue; 68 | } else if (!strcmp(argv[n], "-?") || 69 | !strcmp(argv[n], "--help") || 70 | !strcmp(argv[n], "--usage")) { 71 | printf("usage: scncopy [-s section0 [[-s section1] ... -s sectionN] | -a ] -o outfile infile\n"); 72 | return 0; 73 | } else if (n == argc-1) { 74 | infile = argv[n]; 75 | } else { 76 | fprintf(stderr, "usage: pjoc -s section 0 [[-s section1] ... -s sectionN] -o outfile infile\n"); 77 | return 1; 78 | } 79 | } 80 | if (!infile || !outfile) { 81 | fprintf(stderr, "usage: pjoc -s section 0 [[-s section1] ... -s sectionN] -o outfile infile\n"); 82 | return 1; 83 | } 84 | 85 | if (!(fd = open(infile, O_RDONLY))) { 86 | fprintf(stderr, "Could not open \"%s\" for reading: %m\n", infile); 87 | return 1; 88 | } 89 | 90 | elf_version(EV_CURRENT); 91 | 92 | if ((elf = elf_begin(fd, ELF_C_READ_MMAP_PRIVATE, NULL)) == NULL) { 93 | fprintf(stderr, "cannot get elf descriptor for \"%s\": %s\n", 94 | infile, elf_errmsg(-1)); 95 | close(fd); 96 | return 1; 97 | } 98 | 99 | if (elf_kind(elf) != ELF_K_ELF) { 100 | fprintf(stderr, "\"%s\" is not an ELF file\n", infile); 101 | err: 102 | elf_end(elf); 103 | close(fd); 104 | return 1; 105 | } 106 | 107 | if ((ctor = elfcreator_begin(outfile, elf)) == NULL) { 108 | fprintf(stderr, "could not initialize ELF creator\n"); 109 | goto err; 110 | } 111 | 112 | scn = NULL; 113 | while ((scn = elf_nextscn(elf, scn)) != NULL) { 114 | GElf_Shdr shdr_mem, *shdr; 115 | 116 | shdr = gelf_getshdr(scn, &shdr_mem); 117 | if (shdr == NULL) 118 | continue; 119 | 120 | if (!should_copy_scn(elf, shdr, sections) && !copy_all_sections) 121 | continue; 122 | 123 | elfcreator_copy_scn(ctor, elf, scn); 124 | } 125 | elfcreator_end(ctor); 126 | return 0; 127 | } 128 | -------------------------------------------------------------------------------- /strings.c: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (C) 2008 Arnaldo Carvalho de Melo 3 | 4 | This program is free software; you can redistribute it and/or modify it 5 | under the terms of version 2 of the GNU General Public License as 6 | published by the Free Software Foundation. 7 | */ 8 | 9 | #include "strings.h" 10 | #include "gobuffer.h" 11 | 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | 19 | #include "dutil.h" 20 | 21 | struct strings *strings__new(void) 22 | { 23 | struct strings *strs = malloc(sizeof(*strs)); 24 | 25 | if (strs != NULL) { 26 | strs->tree = NULL; 27 | gobuffer__init(&strs->gb); 28 | } 29 | 30 | return strs; 31 | 32 | } 33 | 34 | static void do_nothing(void *ptr __unused) 35 | { 36 | } 37 | 38 | void strings__delete(struct strings *strs) 39 | { 40 | if (strs == NULL) 41 | return; 42 | tdestroy(strs->tree, do_nothing); 43 | __gobuffer__delete(&strs->gb); 44 | free(strs); 45 | } 46 | 47 | static strings_t strings__insert(struct strings *strs, const char *s) 48 | { 49 | return gobuffer__add(&strs->gb, s, strlen(s) + 1); 50 | } 51 | 52 | struct search_key { 53 | struct strings *strs; 54 | const char *str; 55 | }; 56 | 57 | static int strings__compare(const void *a, const void *b) 58 | { 59 | const struct search_key *key = a; 60 | 61 | return strcmp(key->str, key->strs->gb.entries + (unsigned long)b); 62 | } 63 | 64 | strings_t strings__add(struct strings *strs, const char *str) 65 | { 66 | unsigned long *s; 67 | strings_t index; 68 | struct search_key key = { 69 | .strs = strs, 70 | .str = str, 71 | }; 72 | 73 | if (str == NULL) 74 | return 0; 75 | 76 | s = tsearch(&key, &strs->tree, strings__compare); 77 | if (s != NULL) { 78 | if (*(struct search_key **)s == (void *)&key) { /* Not found, replace with the right key */ 79 | index = strings__insert(strs, str); 80 | if (index != 0) 81 | *s = (unsigned long)index; 82 | else { 83 | tdelete(&key, &strs->tree, strings__compare); 84 | return 0; 85 | } 86 | } else /* Found! */ 87 | index = *s; 88 | } else 89 | return 0; 90 | 91 | return index; 92 | } 93 | 94 | strings_t strings__find(struct strings *strs, const char *str) 95 | { 96 | strings_t *s; 97 | struct search_key key = { 98 | .strs = strs, 99 | .str = str, 100 | }; 101 | 102 | if (str == NULL) 103 | return 0; 104 | 105 | s = tfind(&key, &strs->tree, strings__compare); 106 | return s ? *s : 0; 107 | } 108 | 109 | int strings__cmp(const struct strings *strs, strings_t a, strings_t b) 110 | { 111 | return a == b ? 0 : strcmp(strings__ptr(strs, a), 112 | strings__ptr(strs, b)); 113 | } 114 | -------------------------------------------------------------------------------- /strings.h: -------------------------------------------------------------------------------- 1 | #ifndef _STRINGS_H_ 2 | #define _STRINGS_H_ 1 3 | /* 4 | Copyright (C) 2008 Arnaldo Carvalho de Melo 5 | 6 | This program is free software; you can redistribute it and/or modify it 7 | under the terms of version 2 of the GNU General Public License as 8 | published by the Free Software Foundation. 9 | */ 10 | 11 | #include "gobuffer.h" 12 | 13 | typedef unsigned int strings_t; 14 | 15 | struct strings { 16 | void *tree; 17 | struct gobuffer gb; 18 | }; 19 | 20 | struct strings *strings__new(void); 21 | 22 | void strings__delete(struct strings *self); 23 | 24 | strings_t strings__add(struct strings *self, const char *str); 25 | strings_t strings__find(struct strings *self, const char *str); 26 | 27 | int strings__cmp(const struct strings *self, strings_t a, strings_t b); 28 | 29 | static inline const char *strings__ptr(const struct strings *self, strings_t s) 30 | { 31 | return gobuffer__ptr(&self->gb, s); 32 | } 33 | 34 | static inline const char *strings__entries(const struct strings *self) 35 | { 36 | return gobuffer__entries(&self->gb); 37 | } 38 | 39 | static inline unsigned int strings__nr_entries(const struct strings *self) 40 | { 41 | return gobuffer__nr_entries(&self->gb); 42 | } 43 | 44 | static inline strings_t strings__size(const struct strings *self) 45 | { 46 | return gobuffer__size(&self->gb); 47 | } 48 | 49 | static inline const char *strings__compress(struct strings *self, 50 | unsigned int *size) 51 | { 52 | return gobuffer__compress(&self->gb, size); 53 | } 54 | 55 | #endif /* _STRINGS_H_ */ 56 | -------------------------------------------------------------------------------- /syscse.c: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (C) 2007 Arnaldo Carvalho de Melo 3 | 4 | System call sign extender 5 | 6 | This program is free software; you can redistribute it and/or modify it 7 | under the terms of version 2 of the GNU General Public License as 8 | published by the Free Software Foundation. 9 | */ 10 | 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | 17 | #include "dwarves.h" 18 | #include "dutil.h" 19 | 20 | static const char *prefix = "sys_"; 21 | static size_t prefix_len = 4; 22 | 23 | static bool filter(struct function *f, struct cu *cu) 24 | { 25 | if (f->proto.nr_parms != 0) { 26 | const char *name = function__name(f, cu); 27 | 28 | if (strlen(name) > prefix_len && 29 | memcmp(name, prefix, prefix_len) == 0) 30 | return false; 31 | } 32 | return true; 33 | } 34 | 35 | static void zero_extend(const int regparm, const struct base_type *bt, 36 | struct cu *cu, const char *parm) 37 | { 38 | const char *instr = "INVALID"; 39 | 40 | switch (bt->bit_size) { 41 | case 32: 42 | instr = "sll"; 43 | break; 44 | case 16: 45 | instr = "slw"; 46 | break; 47 | case 8: 48 | instr = "slb"; 49 | break; 50 | } 51 | 52 | char bf[64]; 53 | printf("\t%s\t$a%d, $a%d, 0" 54 | "\t/* zero extend $a%d(%s %s) from %d to 64-bit */\n", 55 | instr, regparm, regparm, regparm, 56 | base_type__name(bt, cu, bf, sizeof(bf)), 57 | parm, bt->bit_size); 58 | } 59 | 60 | static void emit_wrapper(struct function *f, struct cu *cu) 61 | { 62 | struct parameter *parm; 63 | const char *name = function__name(f, cu); 64 | int regparm = 0, needs_wrapper = 0; 65 | 66 | function__for_each_parameter(f, parm) { 67 | const uint16_t type_id = parm->tag.type; 68 | struct tag *type = cu__type(cu, type_id); 69 | 70 | tag__assert_search_result(type); 71 | if (type->tag == DW_TAG_base_type) { 72 | struct base_type *bt = tag__base_type(type); 73 | char bf[64]; 74 | 75 | if (bt->bit_size < 64 && 76 | strncmp(base_type__name(bt, cu, bf, sizeof(bf)), 77 | "unsigned", 8) == 0) { 78 | if (!needs_wrapper) { 79 | printf("wrap_%s:\n", name); 80 | needs_wrapper = 1; 81 | } 82 | zero_extend(regparm, bt, cu, 83 | parameter__name(parm, cu)); 84 | } 85 | } 86 | ++regparm; 87 | } 88 | 89 | if (needs_wrapper) 90 | printf("\tj\t%s\n\n", name); 91 | } 92 | 93 | static int cu__emit_wrapper(struct cu *cu, void *cookie __unused) 94 | { 95 | struct function *pos; 96 | uint32_t id; 97 | 98 | cu__for_each_function(cu, id, pos) 99 | if (!filter(pos, cu)) 100 | emit_wrapper(pos, cu); 101 | return 0; 102 | } 103 | 104 | static void cus__emit_wrapper(struct cus *cu) 105 | { 106 | cus__for_each_cu(cu, cu__emit_wrapper, NULL, NULL); 107 | } 108 | 109 | /* Name and version of program. */ 110 | ARGP_PROGRAM_VERSION_HOOK_DEF = dwarves_print_version; 111 | 112 | static const struct argp_option options[] = { 113 | { 114 | .key = 'p', 115 | .name = "prefix", 116 | .arg = "PREFIX", 117 | .doc = "function prefix", 118 | }, 119 | { 120 | .name = NULL, 121 | } 122 | }; 123 | 124 | static error_t options_parser(int key, char *arg, struct argp_state *state) 125 | { 126 | switch (key) { 127 | case ARGP_KEY_INIT: 128 | if (state->child_inputs != NULL) 129 | state->child_inputs[0] = state->input; 130 | break; 131 | case 'p': 132 | prefix = arg; 133 | prefix_len = strlen(prefix); 134 | break; 135 | default: 136 | return ARGP_ERR_UNKNOWN; 137 | } 138 | return 0; 139 | } 140 | 141 | static const char args_doc[] = "FILE"; 142 | 143 | static struct argp argp = { 144 | .options = options, 145 | .parser = options_parser, 146 | .args_doc = args_doc, 147 | }; 148 | 149 | int main(int argc, char *argv[]) 150 | { 151 | int err, remaining; 152 | struct cus *cus = cus__new(); 153 | 154 | if (cus == NULL) { 155 | fprintf(stderr, "%s: insufficient memory\n", argv[0]); 156 | return EXIT_FAILURE; 157 | } 158 | 159 | if (argp_parse(&argp, argc, argv, 0, &remaining, NULL) || 160 | remaining == argc) { 161 | argp_help(&argp, stderr, ARGP_HELP_SEE, argv[0]); 162 | return EXIT_FAILURE; 163 | } 164 | err = cus__load_files(cus, NULL, argv + remaining); 165 | if (err != 0) 166 | return EXIT_FAILURE; 167 | 168 | cus__emit_wrapper(cus); 169 | return EXIT_SUCCESS; 170 | } 171 | --------------------------------------------------------------------------------