diff options
67 files changed, 10475 insertions, 3165 deletions
@@ -46,19 +46,14 @@ po/remove-potcdate.sin po/stamp-po po/stamp-it py-compile -scripts/*.bt src/applet/abrt-applet src/applet/abrt-applet.desktop src/cli/abrt-cli -src/utils/abrt-backtrace -lib/utils/backtrace_parser.c -lib/utils/backtrace_parser.output src/daemon/abrtd src/gui/abrt.desktop src/hooks/abrt_exception_handler.py src/hooks/dumpoops src/hooks/abrt-hook-ccpp -scripts/abrt-rate-backtrace stamp-h1 x86_64/ *.pyc diff --git a/Makefile.am b/Makefile.am index 6303e738..09d00544 100644 --- a/Makefile.am +++ b/Makefile.am @@ -1,5 +1,5 @@ ACLOCAL_AMFLAGS = -I m4 -SUBDIRS = lib src inc po icons +SUBDIRS = btparser lib src inc po icons DISTCHECK_CONFIGURE_FLAGS = \ --with-systemdsystemunitdir=$$dc_install_base/$(systemdsystemunitdir) @@ -355,7 +355,6 @@ fi %{_bindir}/abrt-action-bugzilla %{_bindir}/abrt-action-install-debuginfo %{_bindir}/%{name}-handle-upload -%{_bindir}/%{name}-backtrace %config(noreplace) %{_sysconfdir}/%{name}/%{name}.conf %config(noreplace) %{_sysconfdir}/%{name}/gpg_keys %config(noreplace) %{_sysconfdir}/dbus-1/system.d/dbus-%{name}.conf @@ -368,7 +367,6 @@ fi %dir %{_sysconfdir}/%{name} %dir %{_sysconfdir}/%{name}/plugins %dir %{_libdir}/%{name} -%{_mandir}/man1/%{name}-backtrace.1.gz %{_mandir}/man8/abrtd.8.gz %{_mandir}/man5/%{name}.conf.5.gz #%{_mandir}/man5/pyhook.conf.5.gz diff --git a/btparser/COPYING b/btparser/COPYING new file mode 100644 index 00000000..d511905c --- /dev/null +++ b/btparser/COPYING @@ -0,0 +1,339 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Lesser General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + <one line to give the program's name and a brief idea of what it does.> + Copyright (C) <year> <name of author> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + <signature of Ty Coon>, 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. diff --git a/btparser/ChangeLog b/btparser/ChangeLog new file mode 100644 index 00000000..b2e36bbf --- /dev/null +++ b/btparser/ChangeLog @@ -0,0 +1,544 @@ +2010-10-14 Karel Klíč <kklic@redhat.com> + + * configure.ac: Increase version to 0.7. + + * tests/strbuf.at: New file, includes tests for + btp_strbuf_append_char and btp_strbuf_append_str. + + * README: Fixed a typo. + + * TODO: Updated. Includes list of functions which need a test in + the testsuite. + + * lib/Makefile.am (libbtparser_la_LDFLAGS): Increase current + interface version. + + * lib/utils.c (btp_file_to_string): Use open, lseek, read, close + instead of fopen, fseek, fread, fclose. + + * lib/normalize_dbus.c (btp_normalize_dbus_thread): + * lib/normalize_gdk.c (btp_normalize_gdk_thread): + * lib/normalize_glib.c (btp_normalize_glib_thread): + * lib/normalize_glibc.c (btp_normalize_glibc_thread): + * lib/normalize_libstdcpp.c (btp_normalize_libstdcpp_thread): + * lib/normalize_linux.c (btp_normalize_linux_thread): + * lib/normalize_xorg.c (btp_normalize_xorg_thread): Store + next_frame at the beginning of block to simplify the code a + bit. + +2010-09-23 Karel Klíč <kklic@redhat.com> + + * Makefile.am (EXTRA_DIST): Added autogen.sh. + +2010-09-22 Karel Klíč <kklic@redhat.com> + + * Released as btparser-0.6. + + * NEWS (Changes): Document recent changes. + + * lib/frame.h, lib/frame.c (btp_frame_parse_header): Simplified + the function interface. Now it returns a pointer to frame or NULL + in the case of failure. The frame argument was removed. + * lib/frame.c (btp_frame_parse): + * tests/frame.at (btp_frame_parse_header): Keep up with the + btp_frame_parse_header interface change. + + * lib/backtrace.h, lib/backtrace.c (btp_backtrace_parse): + Simplified the function interface. Now it returns a pointer to + backtrace or NULL in the case of failure. The backtrace argument + was removed. + * btparser.c (main): + * tests/backtrace.at (btp_backtrace_find_crash_thread) + (btp_backtrace_limit_frame_depth, btp_backtrace_quality_complex): + Keep up with the btp_backtrace_parse interface change. + + * lib/thread.h, lib/thread.c (btp_thread_parse): Simplified the + function interface. Now it returns a pointer to thread or NULL in + the case of failure. The thread argument was removed. + * tests/thread.at (btp_thread_parse, btp_thread_parse-locations): + * lib/backtrace.c (btp_backtrace_parse): Keep up with the + btp_thread_parse interface change. + + * tests/frame.at (btp_frame_parse): Check whether the expected_frame is + NULL when the frame is also NULL. + +2010-09-21 Karel Klíč <kklic@redhat.com> + + * lib/frame.h, lib/frame.c (btp_frame_parse): Simplified the + function interface. Now it returns a pointer to frame or NULL in + the case of failure. The frame argument was removed. + * tests/frame.at (btp_frame_parse): + * lib/backtrace.c (btp_backtrace_parse_header): + * lib/thread.c (btp_thread_parse): Keep up with the + btp_frame_parse interface change. + + * lib/utils.h, lib/utils.c: Removed unused function + btp_parse_regexp. + + * tests/utils.at: Removed a test for btp_parser_regexp. + +2010-09-20 Karel Klíč <kklic@redhat.com> + + * lib/normalize_dbus.h, lib/normalize_gdk.h, normalize_glib.h: + * normalize_glibc.h, normalize_libstdcpp.h, normalize_linux.h: + * normalize_xorg.h: Function definitions were moved to + normalize.h, and these header files were removed. + + * lib/Makefile.am, lib/backtrace.c, lib/normalize.c: + * lib/normalize.h, lib/normalize_dbus.c, lib/normalize_gdk.c: + * lib/normalize_glib.c, lib/normalize_glibc.c: + * lib/normalize_libstdcpp.c, lib/normalize_libstdcpp.c: + * lib/normalize_xorg.c: Keep up with the normalize_*.h removal. + + * lib/normalize_glib.c (btp_normalize_glib_thread): Optimized and + simplified the IA__ prefix removal code. + + * lib/normalize_glibc.c (btp_normalize_glibc_thread): Used strcpy + instead of free and strdup functions in the + NORMALIZE_ARCH_SPECIFIC macro. + + * tests/backtrace.at (btp_backtrace_remove_threads_except_one): + Include required stdlib.h header. + + * lib/backtrace.h, lib/frame.h, lib/thread.h, lib/utils.h: Moved includes + section out of extern "C" section. + + * lib/backtrace.h, lib/frame.h, lib/normalize.h: + * lib/normalize_dbus.h, lib/normalize_gdk.h, lib/normalize_glib.h: + * lib/normalize_glibc.h, lib/normalize_libstdcpp.h: + * lib/normalize_linux.h, lib/normalize_xorg.h, lib/thread.h: + Removed /* Declarations */ comment. + + * lib/backtrace.h, lib/frame.h, lib/thread.h: Removed superfluous + stdio.h include. + + * lib/backtrace.c, lib/frame.c: Include required header stdio.h. + + * NEWS: Document recent changes. + + * lib/backtrace.h, lib/backtrace.c (btp_backtrace_dup): + * lib/frame.h, lib/frame.c (btp_frame_dup): + * lib/thread.h, lib/thread.c (btp_thread_dup): Remove the shallow + parameter to simplify the interface. + + * tests/frame.at (btp_frame_dup): + * lib/backtrace.c (btp_backtrace_quality_complex) + (btp_backtrace_get_crash_frame) + (btp_backtrace_get_duplication_hash, btp_backtrace_parse): + * lib/frame.c (btp_frame_parse_header): + * lib/thread.c (btp_thread_parse): Keep up with the shallow + parameter removal. + + * configure.ac: Increase version to 0.6. + + * lib/frame.h, lib/frame.c: Function btp_frame_eq0 was renamed to + btp_frame_calls_func, btp_frame_eq1 was renamed to + btp_frame_calls_func_in_file, btp_frame_eq2 was renamed to + btp_frame_calls_func_in_file2, btp_frame_eq3 was renamed to + btp_frame_calls_func_in_file3, btp_frame_eq4 was renamed to + btp_frame_calls_func_in_file4. + + * lib/normalize_dbus.c, lib/normalize_gdk.c, lib/normalize_glib.c: + Keep up with the renames. + * lib/normalize_glibc.c, lib/normalize_libstdcpp.c: Likewise. + * lib/normalize_linux.c, lib/normalize_xorg.c: Likewise. + +2010-09-02 Nikola Pajkovský <npajkovsk@redhat.com> + + * lib/utils.c (btp_file_to_string): Use %zd instead of %d in a + fprintf call to allow compilation on 64-bit architectures. + +2010-08-31 Karel Klíč <kklic@redhat.com> + + * Released as btparser-0.5. + + * NEWS: Document the fix of rhbz#592523. + + * configure.ac: Changed version to 0.5. + + * lib/normalize.c (btp_normalize_thread): If the last frame has + address 0x0000 and its name is '??', remove it. This frame is not + really invalid, and it affects backtrace quality rating. See Red + Hat Bugzilla bug #592523. + +2010-08-30 Karel Klíč <kklic@redhat.com> + + * Released as btparser-0.4. + + * NEWS: RPM spec news. + + * Makefile.am: Added 'rpm' and 'srpm' targets. + + * btparser.spec.in: Newly created RPM spec file. + + * Released as btparser-0.3. + + * configure.ac, Makefile.am: Generate and distribute btparser.pc. + + * btparser.pc.in: New file - template for pkg-config metadata file + btparser.pc. + + * tests/Makefile.am (package.m4): Do not depend on configure.ac, + but depend on the Makefile.in directly. Removed $srcdir prefix as + it's superfluous. + + * tests/frame.at: Added a test for btp_frame_dup function. + + * README: Added a "what is btparser" section. + + * lib/frame.h: Added documentation to functions btp_frame_eq0, + btp_frame_eq1, btp_frame_eq2, and btp_frame_eq3. + + * configure.ac: Increase version to 0.3. + +2010-08-28 Karel Klíč <kklic@redhat.com> + + * Released as btparser-0.2. + + * tests/Makefile.am (EXTRA_DIST): Added backtrace subdirectory to + EXTRA_DIST, as it should be a part of the distribution. + +2010-08-27 Karel Klíč <kklic@redhat.com> + + * NEWS: Add duplication hash quality comparison of various + versions of btparser. Add parser precision comparison with + abrt-backtrace utility. + + * README: Removed older parser precision comparison. + + * TODO: Remove finished tasks. + + * btparser.1: Synchronize with btparser interface changes. Old + options removed, new options documented. + + * btparser.c: --debug short option changed from -p to -d. + Fixed a typo in an error message. + + * lib/backtrace.c + (btp_backtrace_find_crash_thread_from_crash_frame): Display + debugging information when btp_debug_parser is enabled. + (btp_backtrace_quality_complex): Use btp_normalize_backtrace so + that the quality is measured on the normalized backtrace. The + quality near the crash frame now includes the top 5 frames of the + normalized thread. + (btp_backtrace_get_crash_frame): Use btp_normalize_backtrace to + find the crash frame. A disadvantage of backtrace normalization is + that the frame returned is a duplicate and must be released by the + function caller. + (btp_backtrace_get_duplication_hash): Use btp_normalize_backtrace, + and the limit the frame depth to 3 frames to get the duplication + hash. + + * lib/backtrace.h ( btp_backtrace_get_crash_frame): Document the + need to release the returned frame by btp_frame_free(). + + * lib/frame.c, lib/frame.h: New functions btp_frame_eq0, + btp_frame_eq1, btp_frame_eq2, btp_frame_eq3, and btp_frame_eq4. + + * lib/normalize.c, lib/normalize.h: New functions + btp_normalize_thread and btp_normalize_backtrace. + + * lib/ops.c: Renamed to normalize.c. + * lib/ops.h: Renamed to normalize.h. + * lib/ops-dbus.h, lib/ops-dbus.c, lib/ops-gdk.c, + lib/ops-gdk.h:Renamed to normalize_xxx.[ch]. + * lib/ops-glib.c, lib/ops-glib.h, lib/ops-glibc.c: Likewise. + * lib/ops-glibc.h, lib/ops-libstdcpp.c, lib/ops-libstdcpp.h: + Likewise. + * lib/ops-linux.c, lib/ops-linux.h, lib/ops-xorg.c: Likewise. + * lib/ops-xorg.h: Likewise. + + * lib/Makefile.am: Synchronize with the file renaming. + + * scripts/btparser-bz-downloader: Rewritten to get the search + results first, then sort the bugs depending on last update time, + then fetch the data. Added more progress logging output. + + * scripts/btparser-cache-dupchecker: Simplified data + structures. Added more logging, and change existing output to be + clearer. Only include Fedora bugs in dupclosecount. + + * scripts/btparser-cache-improvetips: Use the new btparser command + line interface instead of the now-defunct old one. + +2010-08-25 Karel Klíč <kklic@redhat.com> + + * lib/ops-glibc.c (btp_glibc_frame_is_exit): raise() might be in + libpthread.so. + + * btparser.c (main): Fixed a typo in an error message. + + * scripts/btparser-compare: Removed. + + * scripts/btparser-compare-all: Renamed to btparser-cache-compare. + + * lib/frame.c (btp_frame_parse_file_location): Added an underscore + to supported file name characters. + (btp_frame_parseadd_operator): Do not modify the parameter target + unless the operator is really detected. + + * lib/frame.h (btp_frame_parseadd_operator): Mention that the + target buffer is not modified if no operator is found. + + * tests/frame.at: Several tests were extended to catch more cases. + + * scripts/btparser-cache-dupchecker: Adapted to the new btparser + command line interface. + * scripts/btparser-cache-improvetips: Likewise. + + * scripts/btparser-compare-all: Read the backtraces from the cache + subdirectory, where they usually resides, not from the current + directory. + + * TODO: New file. + + * configure.ac: Increase version to 0.2. + + * tests/backtrace.at: New file. Added tests of + btp_backtrace_remove_threads_except_one, + btp_backtrace_find_crash_thread, btp_backtrace_limit_frame_depth, + btp_backtrace_quality_complex. + + * lib/backtrace.c (btp_backtrace_get_duplication_hash): Do not + free the backtrace before creating a textual representation of it. + + * lib/frame.c (btp_frame_dup): Fix the duplication crash when run + with siblings parameter set to true. + + * lib/thread.c (btp_thread_dup): Fix the duplication crash when + run with siblings parameter set to true. + (btp_thread_get_frame_count): Rename variable 'f' to 'frame' to + improve code readability. + +2010-08-24 Karel Klíč <kklic@redhat.com> + + * btparser.c: Rewritten to use the new functions + btp_backtrace_quality_complex, btp_backtrace_get_crash_frame, + btp_backtrace_get_duplication_hash. New user interface. + + * lib/backtrace.h: Extended the documentation of most + functions. Fixed the documentation alignment. Removed extern + keyword from function declarations. + + * lib/backtrace.h, lib/backtrace.c: Renamed function + btp_backtrace_quality to btp_backtrace_quality_simple. Implemented + new functions btp_backtrace_quality_complex, + btp_backtrace_get_crash_frame, btp_backtrace_get_duplication_hash. + + * lib/backtrace.c (btp_backtrace_limit_frame_depth): Reimplemented + using the new function btp_thread_remove_frames_below_n. + (btp_backtrace_find_crash_thread_from_crash_frame): Marked as + 'static'. Made the code more readable. + (btp_backtrace_remove_threads_except_one): Renamed parameter 'one' + to 'thread'. Renamed 'rm' to 'delete_thread'. + + * lib/ops.h, lib/ops.c: Implement new functions + btp_ops_backtrace_remove_redundant_frames and + btp_ops_frame_is_redundant. + (tp_ops_thread_remove_redundant_frames): Use + btp_ops_frame_is_redundant. + + * tests/thread.at (btp_thread_parse-locations) + (btp_thread_remove_frames_below_n, btp_thread_remove_frames_above) + (btp_thread_remove_frame): New tests. + + * lib/thread.h: Removed extern keyword from function + declarations. Extended the documentation of all functions. + + * lib/thread.h, lib/thread.c: Renamed the function + btp_thread_rating to btp_thread_quality_counts. Implemented new + functions btp_thread_quality, btp_thread_remove_frame, + btp_thread_remove_frames_above, btp_thread_remove_frames_below_n. + + * lib/thread.c (btp_thread_append_to_str): More precise error + messages. Fixed adding a line to the location for the just-parsed + thread header line. + + * lib/frame.c (btp_frame_add_sibling): Do not return a value. + (btp_frame_parse_frame_start): Do not modify input if the parsing + failed and the function is returning 0. Calculate the returned + value more efficiently in the case of parsing success. + + * lib/frame.h: Massively extended documentation of all functions. + Removed extern keyword from function declarations. + + * lib/ops-gdk.h, lib/ops-glib.h, lib/ops-libstdcpp.h: Remove + extern keyword from function declarations. + * lib/ops-linux.h, lib/ops-xorg.h, lib/location.h: Likewise. + * lib/ops-glibc.h: Likewise. Plus the documentation has been + extended. + + * lib/utils.h: Remove extern keyword from function + declarations. Fix the documentation indentation. + + * lib/strbuf.c (btp_strbuf_free): Do not crash if the provided + pointer is NULL. + + * lib/strbuf.h: Properly document all functions and the struct + strbuf. + + * tests/local.at (AT_TESTFUN): Autotest ignores the stdout and + stderr of the testing C program. + + * tests/frame.at (btp_frame_parseadd_operator): Check the parsed + length. Output helper data to stdout. Added a check for an + invalid operator. + (btp_frame_parse_function_name, btp_frame_parse_function_call): + Output helper data to stdout. + +2010-08-23 Karel Klíč <kklic@redhat.com> + + * lib/frame.h: Small documentation fixes. + + * lib/location.h (btp_location_add, btp_location_add_ext) + (btp_location): Add a documentation. + (btp_location_eat_char, btp_location_eat_char_ext): Fixed the + documentation grammar, and extended. + +2010-08-20 Karel Klíč <kklic@redhat.com> + + * lib/location.h, lib/location.c (btp_location_eat_char): New + function. + + * lib/frame.c (btp_frame_parseadd_operator) + (btp_frame_parse_function_name_chunk) + (btp_frame_parse_function_name_braces) + (btp_frame_parse_function_name_template): Return an integer + representing the number of parsed characters, instead of a boolean + indicating success. + (btp_frame_parse_function_name) + (btp_frame_skip_function_args): Added a location parameter, and + implemented the location support. + + * lib/frame.h (btp_frame_parseadd_operator) + (btp_frame_parse_function_name) + (btp_frame_parse_function_name_template) + (btp_frame_parse_function_name_braces) + (btp_frame_parse_function_name_chunk): Added documentation. + + * tests/frame.at (btp_frame_parse_frame_start): Added comments and + made the code more readable. + (btp_frame_parseadd_operator): Update the test to check for the + returned integer value. + (btp_frame_parse_function_name, btp_frame_skip_function_args): + Update the test to use location parameter. The value returned in + this parameter is not checked for correctness yet. + +2010-08-16 Karel Klíč <kklic@redhat.com> + + * tests/frame.at, tests/thread.at: Keep up with the function + interface changes. + + * tests/utils.at: Keep up with interface changes. Added new tests + for functions btp_strspn_location, btp_skip_char, + btp_skip_char_limited, btp_skip_char_sequence, btp_skip_char_span, + btp_skip_char_span_location, btp_parse_char_span, btp_skip_string, + btp_skip_unsigned_integer, btp_parse_unsigned_integer. + + * lib/utils.h: New functions btp_strspn_location and + btp_skip_char_span_location. Functions btp_skip_char_sequence, + btp_skip_char_span, btp_parse_char_span, btp_skip_string, + btp_skip_unsigned_integer, btp_parse_unsigned_integer, + btp_skip_hexadecimal_number, and btp_parse_hexadecimal_number + return an integer (indicating the number of characters processed) + instead of a boolean (indicating success/failure). This change is + neccessary for implementing proper error reporting with + line/column error location. + + * lib/thread.c (btp_thread_parse): Added the location parameter, + and implemented its usage. + + * lib/thread.h: Added the location parameter to the function + btp_thread_parse. + + * lib/frame.c (btp_frame_parse, btp_frame_parse_function_call): + Added the location parameter, but the location feature has not + been fully implemented yet. + (btp_frame_parse_frame_start): Returns the number of characters + parsed from input. + (btp_frame_parseadd_operator, btp_frame_parse_function_name): + Adapted to the changes of other functions. + (btp_frame_parse_address_in_function) + (btp_frame_parse_file_location, btp_frame_parse_header): Added the + location parameter, and implemented its usage. + + * lib/frame.h: Add the location parameter to functions + btp_frame_parse, btp_frame_parse_function_call, + btp_frame_parse_address_in_function, + btp_frame_parse_file_location, btp_frame_parse_header. Function + btp_frame_parse_frame_start returns int instead of bool. It + returns the number of characters parsed from input. + + * lib/backtrace.c (btp_backtrace_parse): Use the newly added + location parameter of btp_thread_parse and btp_frame_parse + functions. + +2010-08-05 Karel Klíč <kklic@redhat.com> + + * tests/utils.at: Added btp_strcmp0, btp_strchr_location, and + btp_strstr_location tests. + + * lib/utils.c (btp_strcmp0): Changed it so that NULL value is + considered to be "less" than an existing string. + + * tests/utils.at: Renamed parser_elements.at to utils.at. + + * tests/frame.at: Renamed parser_frame.at to frame.at. + + * tests/thread.at: Renamed parser_thread.at to thread.at. + + * lib/utils.h: Extended the interface documentation. Added new + functions btp_strchr_location and btp_strstr_location. + + * lib/utils.c: Implemented new functions added to lib/utils.h. + + * lib/backtrace.h: Extended the interface documentation. Added + location parameter to functions btp_backtrace_parse and + btp_backtrace_parse_header. + + * lib/backtrace.c (btp_backtrace_parse) + (btp_backtrace_parse_header): Added location support. + + * btparser.c: Updated to use the new location feature. + + * lib/location.h, lib/location.c: New struct btp_location and + associated helper functions. + + * lib/Makefile.am (libbtparser_la_SOURCES): Added location.h and + location.c. + (pkginclude_HEADERS): Added location.h. + + * scripts/btparser-bz-downloader: Skip bug downloading when + bug.info file already exists. Ask server for component owner only + if it's not already available. + (getbug): New method, repeats Bugzilla XML/RPC request if Bugzilla + fails to answer. + + * scripts/btparser-cache-dupchecker: Put back --verbose option. + Fixed an exception when adding a bug to component-bugs hash. + + * btparser.c (main): Added a newline to an error message. + +2010-07-29 Karel Klíč <kklic@redhat.com> + + * scripts/btparser-bz-downloader: Properly serialize duplicates. + + * scripts/btparser-bz-improvetips: btparser trims the backtrace + output like ABRT does. Properly deserialize duplicates from the + input file. + +2010-07-28 Karel Klíč <kklic@redhat.com> + + * scripts/btparser-bz-improvetips: New script. It checks that the + bugs marked as duplicates in Bugzilla are recognized as duplicates + by btparser. + + * scripts/btparser-bz-downloader: New script. Downloads + ABRT-reported backtraces from Bugzilla. + + * scripts/btparser-compare-all: Added some comments. + +2010-06-21 Karel Klíč <kklic@redhat.com> + + * configure.ac: Added AM_MAINTAINER_MODE. + * Makefile.am: Add 'upload' target to .PHONY. diff --git a/btparser/Makefile.am b/btparser/Makefile.am new file mode 100644 index 00000000..dae5e137 --- /dev/null +++ b/btparser/Makefile.am @@ -0,0 +1,38 @@ +SUBDIRS = lib tests + +bin_PROGRAMS = btparser +btparser_CFLAGS = -Wall -Werror +btparser_SOURCES = btparser.c +btparser_LDADD = lib/libbtparser.la + +man_MANS = btparser.1 +EXTRA_DIST = $(man_MANS) + +pkgconfigdir = $(libdir)/pkgconfig +pkgconfig_DATA = btparser.pc +DISTCLEANFILES = $(pkgconfig_DATA) +EXTRA_DIST += btparser.pc.in + +EXTRA_DIST += autogen.sh + +UPLOAD_URI = klic.name:/home/karel/public_html/ftp.klic.name/public/btparser +.PHONY: upload +upload: + make dist-gzip + scp $(distdir).tar.gz $(UPLOAD_URI) + make dist-zip + scp $(distdir).zip $(UPLOAD_URI) + make dist-xz + scp $(distdir).tar.xz $(UPLOAD_URI) + +RPM_DIRS = --define "_sourcedir `pwd`" \ + --define "_rpmdir `pwd`" \ + --define "_specdir `pwd`" \ + --define "_builddir `pwd`" \ + --define "_srcrpmdir `pwd`" + +EXTRA_DIST += btparser.spec.in +rpm: dist-xz btparser.spec + rpmbuild $(RPM_DIRS) -ba btparser.spec +srpm: dist-xz btparser.spec + rpmbuild $(RPM_DIRS) -bs btparser.spec diff --git a/btparser/NEWS b/btparser/NEWS new file mode 100644 index 00000000..21f76d31 --- /dev/null +++ b/btparser/NEWS @@ -0,0 +1,120 @@ +== btparser 0.7 + +What's new: +- Small code cleanups +- Two tests were added + +== btparser 0.6 +Released 2010-09-23. + +Changes: +- Functions btp_frame_eq* were renamed to provide cleaner interface. +- Parameter `shallow` in functions btp_backtrace_dup, btp_thread_dup, + btp_frame_dup has been removed to simplify the interface. +- Interfaces of parser functions were modified to return + structures/NULL instead of bool. + +Bugs fixed: +- A compilation issue on 64-bit architecture with a fprintf + call using %d instead of %zd. + +See the ChangeLog file for more details. + +== btparser 0.5 +Released 2010-08-31. + +What's new: +- If the last frame has address 0x0000 and its name is '??', its + remove during backtrace normalization. This fixes rhbz#592523. + +== btparser 0.4 +Released 2010-08-30. + +What's new: +- RPM spec file has been added +- 'make rpm' and 'make srpm' works for testing purposes + +== btparser 0.3 +Released 2010-08-30. + +What's new: +- the interface documentation has been extended +- a proper README file was created +- a pkg-config metadata file support has been added +- some autotest code was added + +== btparser 0.2 +Released 2010-08-27. + +What's new: +- the API has been extensively reworked and simplified; user can call + the function btp_backtrace_quality_complex to get the quality of + the backtrace, function btp_backtrace_get_duplication_hash to get + the hash, and function btp_backtrace_get_crash_frame to get the + place where the program crashed +- location support: in the case of failure, the backtrace parser + reports line and column of the input string where the failure + occurred and a message describing what input was expected +- the command line options of the btparser utitity has been reduced + and simplified; you can now run `btparser file.bt --duplicate-hash` + to get the hash +- the normalization code was significantly improved; this results in + better backtrace hash quality + +=== Duplication hash quality +The hash quality has been significantly improved since btparser 0.1: + +./btparser-bz-improvetips: 3092 duplicates out of total 8051 +duplicates were _not_ recognized by btparser + +=== Parser precision +When compared to abrt-backtrace utility, the btparser's parser +provides better results. In a test comparing the parser results on +25685 backtraces, btparser was "better" in 726 cases. + +=== Parser speed +The btparser's parser is slightly slower than abrt-backtrace's parser. + +Measurement of how long it takes to parse 25685 backtraces: + btparser took 192.070000 seconds + abrt-backtrace took 181.230000 seconds + +== btparser 0.1 +Released 2010-06-15. + +Here is how btparser's hand-written parser became as good as +abrt-backtrace's bison parser on 2010-05-28: + +initial + -> parser quality: 1540 regressions out of 9015 + +newline allowed after function name in frame header + -> parser quality: 1391 regressions out of 9015 + +nonrecursive braces (with spaces) allowed in function name + -> parser quality: 1216 regressions out of 9015 + +recursive templates and braces, skip Python backtraces + -> parser quality: 336 regressions out of 9015 + +manually marking backtraces where the difference is caused by better +parser btparser + -> parser quality: 98 regressions out of 9015, 164 times was btparser + better + +support for operator> and similar + -> parser quality: 65 regressions out of 9015, 185 times was btparser + better + +support for type before function name and some more backtrace marking + -> parser quality: 59 regressions out of 9015, 191 times was btparser + better + +various small fixes of corner cases + -> parser quality: 0 regressions out of 9015, 241 times was btparser better + +btparser took 101.650000 seconds, abrt-backtrace took 105.260000 seconds + +=== Duplication hash quality +./btparser-bz-improvetips: 3976 duplicates out of total 7668 +duplicates were not recognized by btparser. diff --git a/btparser/README b/btparser/README new file mode 100644 index 00000000..b2ed1bb3 --- /dev/null +++ b/btparser/README @@ -0,0 +1,38 @@ +What is btparser? + +btparser is a backtrace parser and analyzer, which works with +backtraces produced by the GNU Project Debugger. It can parse a text +file with a backtrace to a tree of C structures, allowing to analyze +the threads and frames of the backtrace and work with them. + +btparser also contains some backtrace manipulation and extraction +routines: +- it can find a frame in the crash-time backtrace where the program + most likely crashed (a chance is that the function described in that + frame is buggy) +- it can produce a duplication hash of the backtrace, which helps to + discover that two crash-time backtraces are duplicates, triggered by + the same flaw of the code +- it can "rate" the backtrace quality, which depends on the number of + frames with and without the function name known (missing function + name is caused by missing debugging symbols) + +== Speed measurement + +For speed measurment the best backtrace is 547367.bt. +Valgrind is very useful to see where the time is spent: +$ valgrind --tool=callgrind btparser 547367.bt +$ kcachegrind callgrind.out.11555 + +=== Do not use regexps! +$ time btparser --debug 547367.bt + +With single regexp in btp_frame_parse_file_location: +real 5m41.857s +user 5m29.894s +sys 0m0.573s + +Without it: +real 0m7.753s +user 0m0.761s +sys 0m0.173s diff --git a/btparser/TODO b/btparser/TODO new file mode 100644 index 00000000..eac098ab --- /dev/null +++ b/btparser/TODO @@ -0,0 +1,19 @@ +Write tests for more functions: +- btp_thread_dup +- btp_thread_cmp +- btp_thread_add_sibling +- btp_thread_get_frame_count +- btp_thread_quality_counts +- btp_thread_quality +- btp_backtrace_dup +- btp_backtrace_get_thread_count +- btp_backtrace_quality_simple +- btp_backtrace_to_text +- btp_backtrace_get_crash_frame +- btp_backtrace_get_duplication_hash +- btp_backtrace_parse +- btp_backtrace_parse_header + +Start writing a manual. + +Investigate more duplicates to find more normalization procedures. diff --git a/btparser/autogen.sh b/btparser/autogen.sh new file mode 100755 index 00000000..9a3daccf --- /dev/null +++ b/btparser/autogen.sh @@ -0,0 +1 @@ +autoreconf --install --force diff --git a/btparser/btparser.1 b/btparser/btparser.1 new file mode 100644 index 00000000..a9ca0412 --- /dev/null +++ b/btparser/btparser.1 @@ -0,0 +1,40 @@ +.TH btparser "1" "24 May 2010" "" +.SH NAME +btparser \- a backtrace analyzer +.SH SYNOPSIS +.B btparser +[option]... [FILE] +.SH DESCRIPTION +.I btparser +is a command line tool that analyzes backtraces produced by +GDB and provides their textual representation useful for +crash duplication detection. + +By default, btparser prints the backtrace tree created by +parsing the input file. + +.SH OPTIONS +.B Basic startup options +.IP "\-V, \-\-version" +Displays version of btparser. +.IP "\-?, \-\-help" +Print a help message describing all of btparser’s command-line options. + +.PP +.B Actions +.IP "\-r, \-\-rate" +Print a float number between 0 and 1, representing the quality of the +backtrace. +.IP "\-c, \-\-crash\-function" +Print the name of the function where the program crashed, if it's +successfully detected. +.IP "\-h, \-\-duplicate\-hash" +Print a short, textual representation of the backtrace, useful for +detecting the backtrace duplicates. + +.PP +.B Additional options +.IP "\-d, \-\-debug" +Prints debug information when scanning/parsing the backtrace. +.IP "\-v, \-\-verbose" +Print more output than usual. diff --git a/btparser/btparser.c b/btparser/btparser.c new file mode 100644 index 00000000..a15354ae --- /dev/null +++ b/btparser/btparser.c @@ -0,0 +1,189 @@ +/* + btparser.c - backtrace parsing tool + + Copyright (C) 2010 Red Hat, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ +#include "lib/backtrace.h" +#include "lib/thread.h" +#include "lib/frame.h" +#include "lib/utils.h" +#include "lib/location.h" +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <argp.h> +#include <sysexits.h> +#include <assert.h> + +const char *argp_program_version = "btparser " VERSION; +const char *argp_program_bug_address = "<kklic@redhat.com>"; + +static char doc[] = "btparser -- backtrace parser"; + +/* A description of the arguments we accept. */ +static char args_doc[] = "FILE"; + +static struct argp_option options[] = { + {"rate" , 'r', 0, 0, "Prints the backtrace rating from 0 to 1"}, + {"crash-function" , 'c', 0, 0, "Prints crash function"}, + {"duplication-hash", 'h', 0, 0, "Prints normalized string useful for hash calculation"}, + {"debug" , 'd', 0, 0, "Prints parser debug information"}, + {"verbose" , 'v', 0, 0, "Prints human-friendly superfluous output."}, + { 0 } +}; + +enum what_to_output +{ + BACKTRACE, + RATE, + CRASH_FUNCTION, + DUPLICATION_HASH +}; + +struct arguments +{ + enum what_to_output output; + bool debug; + bool verbose; + char *filename; +}; + +static error_t +parse_opt (int key, char *arg, struct argp_state *state) +{ + /* Get the input argument from argp_parse, which we + know is a pointer to our arguments structure. */ + struct arguments *arguments = (struct arguments*)state->input; + + switch (key) + { + case 'r': arguments->output = RATE; break; + case 'c': arguments->output = CRASH_FUNCTION; break; + case 'h': arguments->output = DUPLICATION_HASH; break; + case 'd': arguments->debug = true; break; + case 'v': arguments->verbose = true; break; + case ARGP_KEY_ARG: + if (arguments->filename) + { + /* Too many arguments. */ + argp_usage(state); + exit(EX_USAGE); /* Invalid argument */ + } + arguments->filename = arg; + break; + case ARGP_KEY_END: + if (!arguments->filename) + { + /* Argument required */ + argp_usage(state); + exit(EX_USAGE); /* Invalid argument */ + } + break; + default: + return ARGP_ERR_UNKNOWN; + } + return 0; +} + +/** Our argp parser. */ +static struct argp argp = { options, parse_opt, args_doc, doc }; + +int main(int argc, char **argv) +{ + /* Set options default values and parse program command line. */ + struct arguments arguments; + arguments.output = BACKTRACE; + arguments.debug = false; + arguments.verbose = false; + arguments.filename = 0; + argp_parse(&argp, argc, argv, 0, 0, &arguments); + + if (arguments.debug) + btp_debug_parser = true; + + /* Load the input file to a string. */ + char *text = btp_file_to_string(arguments.filename); + if (!text) + { + fprintf(stderr, "Failed to read the input file.\n"); + exit(1); + } + + /* Parse the input string. */ + char *ptr = text; + struct btp_location location; + btp_location_init(&location); + struct btp_backtrace *backtrace = btp_backtrace_parse(&ptr, &location); + if (!backtrace) + { + fprintf(stderr, + "Failed to parse the backtrace.\n Line %d, column %d: %s\n", + location.line, + location.column, + location.message); + exit(1); + } + free(text); + + switch (arguments.output) + { + case BACKTRACE: + { + char *text_parsed = btp_backtrace_to_text(backtrace, false); + puts(text_parsed); + free(text_parsed); + break; + } + case RATE: + { + float q = btp_backtrace_quality_complex(backtrace); + printf("%.2f", q); + break; + } + case CRASH_FUNCTION: + { + struct btp_frame *frame = btp_backtrace_get_crash_frame(backtrace); + if (!frame) + { + fprintf(stderr, "Failed to find the crash function."); + exit(1); + } + if (frame->function_name) + puts(frame->function_name); + else + { + assert(frame->signal_handler_called); + puts("signal handler"); + } + btp_frame_free(frame); + break; + } + case DUPLICATION_HASH: + { + char *hash = btp_backtrace_get_duplication_hash(backtrace); + puts(hash); + free(hash); + break; + } + default: + fprintf(stderr, "Unexpected operation."); + exit(1); + } + + btp_backtrace_free(backtrace); + return 0; +} diff --git a/btparser/btparser.pc.in b/btparser/btparser.pc.in new file mode 100644 index 00000000..de3de378 --- /dev/null +++ b/btparser/btparser.pc.in @@ -0,0 +1,10 @@ +prefix=@prefix@ +exec_prefix=@exec_prefix@ +libdir=@libdir@ +includedir=@includedir@ + +Name: btparser +Description: Library to parse and analyze backtraces produced by the GNU Project Debugger +Version: @PACKAGE_VERSION@ +Libs: -L${libdir} -lbtparser +Cflags: -I${includedir}
\ No newline at end of file diff --git a/btparser/btparser.spec.in b/btparser/btparser.spec.in new file mode 100644 index 00000000..79e176a1 --- /dev/null +++ b/btparser/btparser.spec.in @@ -0,0 +1,68 @@ +Name: btparser +Version: @PACKAGE_VERSION@ +Release: 1%{?dist} +Summary: Backtrace parser and analyzer for backtraces produced by GDB +Group: Development/Libraries +License: GPLv2+ +URL: none +Source0: btparser-%{version}.tar.xz + +%description +btparser is a backtrace parser and analyzer, which works with +backtraces produced by The GNU Project Debugger. It can parse a text +file with a backtrace to a tree of C structures, allowing to analyze +the threads and frames of the backtrace and work with them. + +btparser also contains some backtrace manipulation and extraction +routines: +- it can find a frame in the crash-time backtrace where the program + most likely crashed (a chance is that the function described in that + frame is buggy) +- it can produce a duplication hash of the backtrace, which helps to + discover that two crash-time backtraces are duplicates, triggered by + the same flaw of the code +- it can "rate" the backtrace quality, which depends on the number of + frames with and without the function name known (missing function + name is caused by missing debugging symbols) + +%package devel +Summary: Development libraries for %{name} +Group: Development/Libraries +Requires: %{name} = %{version}-%{release} + +%description devel +Development libraries and headers for %{name}. + +%prep +%setup -q + +%build +%configure --disable-static +make %{?_smp_mflags} + +%install +rm -rf $RPM_BUILD_ROOT +make install DESTDIR=$RPM_BUILD_ROOT + +# Remove all libtool archives (*.la) from modules directory. +find $RPM_BUILD_ROOT -regex ".*\.la$" | xargs rm -f -- + +%check +make check + +%files +%defattr(-,root,root,-) +%doc README NEWS COPYING TODO ChangeLog +%{_bindir}/%{name} +%{_mandir}/man1/%{name}.1.gz +%{_libdir}/lib*.so.* + +%files devel +%defattr(-,root,root,-) +%{_includedir}/* +%{_libdir}/lib*.so +%{_libdir}/pkgconfig/* + +%changelog +* Mon Aug 30 2010 Karel Klic <kklic@redhat.com> @PACKAGE_VERSION@-1 +- Initial packing diff --git a/btparser/configure.ac b/btparser/configure.ac new file mode 100644 index 00000000..bb08c16b --- /dev/null +++ b/btparser/configure.ac @@ -0,0 +1,24 @@ +AC_INIT([btparser], [0.7], [kklic@redhat.com]) + +AM_INIT_AUTOMAKE([-Wall -Werror foreign]) +AM_MAINTAINER_MODE + +AC_DISABLE_STATIC +AC_PROG_LIBTOOL +AC_PROG_CC + +# Initialize the test suite. +AC_CONFIG_TESTDIR(tests) +AC_CONFIG_FILES([tests/Makefile tests/atlocal]) +AM_MISSING_PROG([AUTOM4TE], [autom4te]) +# Needed by tests/atlocal.in. +AC_SUBST([O0CFLAGS], [`echo $CFLAGS | sed 's/-O[[0-9]] *//'`]) + +AC_CONFIG_FILES([ + btparser.spec + btparser.pc + Makefile + lib/Makefile +]) + +AC_OUTPUT diff --git a/btparser/lib/Makefile.am b/btparser/lib/Makefile.am new file mode 100644 index 00000000..38d3dd26 --- /dev/null +++ b/btparser/lib/Makefile.am @@ -0,0 +1,53 @@ +pkginclude_HEADERS = \ + backtrace.h \ + frame.h \ + location.h + normalize.h \ + strbuf.h \ + thread.h \ + utils.h + +lib_LTLIBRARIES = libbtparser.la +libbtparser_la_SOURCES = \ + backtrace.h backtrace.c \ + frame.h frame.c \ + location.h location.c \ + normalize.h normalize.c \ + normalize_dbus.c \ + normalize_gdk.c \ + normalize_glib.c \ + normalize_glibc.c \ + normalize_libstdcpp.c \ + normalize_linux.c \ + normalize_xorg.c \ + strbuf.h strbuf.c \ + thread.h thread.c \ + utils.h utils.c +libbtparser_la_CFLAGS = -Wall -Werror -D_GNU_SOURCE +libbtparser_la_LDFLAGS = -version-info 1:1:0 + +# From http://www.seul.org/docs/autotut/ +# Version consists 3 numbers: CURRENT, REVISION, AGE. +# CURRENT is the version of the interface the library implements. +# Whenever a new function is added, or its name changed, or +# the number or type of its parameters (the prototype -- in +# libraries we call this the function signature), this number +# goes up. And it goes up exactly by one. +# +# REVISION is the revision of the implementation of this +# interface, i.e., when you change the library by only modifying +# code inside the functions (fixing bugs, optimizing internal +# behavior, or adding/removing/changing signatures of functions +# that are private to the library -- used only internally) you +# raise the revision number only. +# +# Age is the difference between the newest and oldest interface +# the library currently implements. Let's say you had 8 versions +# of your library's interface, 0 through 7. You are now on +# the 4th revision of the 8th interface, that is, 7:3:X (remember +# we start counting on zero). And when you had to make choices +# for what old interfaces you would keep support -- for backward +# compatibility purposes, you chose to keep support for +# interfaces 5, 6 and (obviously) the current, 7. The libtool +# version of your library would be 7:3:2 , because the Age +# is 7-5 = 2. diff --git a/btparser/lib/backtrace.c b/btparser/lib/backtrace.c new file mode 100644 index 00000000..576c1776 --- /dev/null +++ b/btparser/lib/backtrace.c @@ -0,0 +1,445 @@ +/* + backtrace.c + + Copyright (C) 2010 Red Hat, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ +#include "backtrace.h" +#include "thread.h" +#include "frame.h" +#include "utils.h" +#include "strbuf.h" +#include "location.h" +#include "normalize.h" +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <assert.h> + +struct btp_backtrace * +btp_backtrace_new() +{ + struct btp_backtrace *backtrace = btp_malloc(sizeof(struct btp_backtrace)); + btp_backtrace_init(backtrace); + return backtrace; +} + +void +btp_backtrace_init(struct btp_backtrace *backtrace) +{ + backtrace->threads = NULL; + backtrace->crash = NULL; +} + +void +btp_backtrace_free(struct btp_backtrace *backtrace) +{ + if (!backtrace) + return; + + while (backtrace->threads) + { + struct btp_thread *rm = backtrace->threads; + backtrace->threads = rm->next; + btp_thread_free(rm); + } + + if (backtrace->crash) + btp_frame_free(backtrace->crash); + + free(backtrace); +} + +struct btp_backtrace * +btp_backtrace_dup(struct btp_backtrace *backtrace) +{ + struct btp_backtrace *result = btp_backtrace_new(); + memcpy(result, backtrace, sizeof(struct btp_backtrace)); + + if (backtrace->crash) + backtrace->crash = btp_frame_dup(backtrace->crash, false); + if (backtrace->threads) + backtrace->threads = btp_thread_dup(backtrace->threads, true); + + return result; +} + +int +btp_backtrace_get_thread_count(struct btp_backtrace *backtrace) +{ + struct btp_thread *thread = backtrace->threads; + int count = 0; + while (thread) + { + thread = thread->next; + ++count; + } + return count; +} + +void +btp_backtrace_remove_threads_except_one(struct btp_backtrace *backtrace, + struct btp_thread *thread) +{ + while (backtrace->threads) + { + struct btp_thread *delete_thread = backtrace->threads; + backtrace->threads = delete_thread->next; + if (delete_thread != thread) + btp_thread_free(delete_thread); + } + + thread->next = NULL; + backtrace->threads = thread; +} + +/** + * Loop through all threads and if a single one contains the crash + * frame on the top, return it. Otherwise, return NULL. + * + * If require_abort is true, it is also required that the thread + * containing the crash frame contains some known "abort" function. In + * this case there can be multiple threads with the crash frame on the + * top, but only one of them might contain the abort function to + * succeed. + */ +static struct btp_thread * +btp_backtrace_find_crash_thread_from_crash_frame(struct btp_backtrace *backtrace, + bool require_abort) +{ + if (btp_debug_parser) + printf("%s(backtrace, %s)\n", __FUNCTION__, require_abort ? "true" : "false"); + + assert(backtrace->threads); /* checked by the caller */ + if (!backtrace->crash || !backtrace->crash->function_name) + return NULL; + + struct btp_thread *result = NULL; + struct btp_thread *thread = backtrace->threads; + while (thread) + { + struct btp_frame *top_frame = thread->frames; + bool same_name = top_frame && + top_frame->function_name && + 0 == strcmp(top_frame->function_name, backtrace->crash->function_name); + bool abort_requirement_satisfied = !require_abort || + btp_glibc_thread_find_exit_frame(thread); + if (btp_debug_parser) + { + printf(" - thread #%d: same_name %s, abort_satisfied %s\n", + thread->number, + same_name ? "true" : "false", + abort_requirement_satisfied ? "true" : "false"); + } + + if (same_name && abort_requirement_satisfied) + { + if (NULL == result) + result = thread; + else + { + /* Second frame with the same function. Failure. */ + return NULL; + } + } + + thread = thread->next; + } + + return result; +} + +struct btp_thread * +btp_backtrace_find_crash_thread(struct btp_backtrace *backtrace) +{ + /* If there is no thread, be silent and report NULL. */ + if (!backtrace->threads) + return NULL; + + /* If there is just one thread, it is simple. */ + if (!backtrace->threads->next) + return backtrace->threads; + + /* If we have a crash frame *and* there is just one thread which has + * this frame on the top, it is also simple. + */ + struct btp_thread *thread; + thread = btp_backtrace_find_crash_thread_from_crash_frame(backtrace, false); + if (thread) + return thread; + + /* There are multiple threads with a frame indistinguishable from + * the crash frame on the top of stack. + * Try to search for known abort functions. + */ + thread = btp_backtrace_find_crash_thread_from_crash_frame(backtrace, true); + + /* We might want to search a thread with known abort function, and + * without the crash frame here. However, it hasn't been needed so + * far. + */ + return thread; /* result or null */ +} + + +void +btp_backtrace_limit_frame_depth(struct btp_backtrace *backtrace, + int depth) +{ + assert(depth > 0); + struct btp_thread *thread = backtrace->threads; + while (thread) + { + btp_thread_remove_frames_below_n(thread, depth); + thread = thread->next; + } +} + +float +btp_backtrace_quality_simple(struct btp_backtrace *backtrace) +{ + int ok_count = 0, all_count = 0; + struct btp_thread *thread = backtrace->threads; + while (thread) + { + btp_thread_quality_counts(thread, &ok_count, &all_count); + thread = thread->next; + } + + if (all_count == 0) + return 0; + + return ok_count / (float)all_count; +} + +float +btp_backtrace_quality_complex(struct btp_backtrace *backtrace) +{ + backtrace = btp_backtrace_dup(backtrace); + + /* Find the crash thread, and then normalize the backtrace. It is + * not possible to find the crash thread after the backtrace has + * been normalized. + */ + struct btp_thread *crash_thread = btp_backtrace_find_crash_thread(backtrace); + btp_normalize_backtrace(backtrace); + + /* Get the quality q1 of the full backtrace. */ + float q1 = btp_backtrace_quality_simple(backtrace); + + if (!crash_thread) + { + btp_backtrace_free(backtrace); + return q1; + } + + /* Get the quality q2 of the crash thread. */ + float q2 = btp_thread_quality(crash_thread); + + /* Get the quality q3 of the frames around the crash. First, + * duplicate the crash thread so we can cut it. Then find an exit + * frame, and remove it and everything above it + * (__run_exit_handlers and such). Then remove all the redundant + * frames (assert calls etc.) Then limit the frame count to 5. + */ + btp_thread_remove_frames_below_n(crash_thread, 5); + float q3 = btp_thread_quality(crash_thread); + + btp_backtrace_free(backtrace); + + /* Compute and return the final backtrace quality q. */ + return 0.25f * q1 + 0.35f * q2 + 0.4f * q3; +} + +char * +btp_backtrace_to_text(struct btp_backtrace *backtrace, bool verbose) +{ + struct btp_strbuf *str = btp_strbuf_new(); + if (verbose) + { + btp_strbuf_append_strf(str, "Thread count: %d\n", + btp_backtrace_get_thread_count(backtrace)); + } + + if (backtrace->crash && verbose) + { + btp_strbuf_append_str(str, "Crash frame: "); + btp_frame_append_to_str(backtrace->crash, str, verbose); + } + + struct btp_thread *thread = backtrace->threads; + while (thread) + { + btp_thread_append_to_str(thread, str, verbose); + thread = thread->next; + } + + return btp_strbuf_free_nobuf(str); +} + +struct btp_frame * +btp_backtrace_get_crash_frame(struct btp_backtrace *backtrace) +{ + backtrace = btp_backtrace_dup(backtrace); + + struct btp_thread *crash_thread = btp_backtrace_find_crash_thread(backtrace); + if (!crash_thread) + { + btp_backtrace_free(backtrace); + return NULL; + } + + btp_normalize_backtrace(backtrace); + struct btp_frame *crash_frame = crash_thread->frames; + crash_frame = btp_frame_dup(crash_frame, false); + btp_backtrace_free(backtrace); + return crash_frame; +} + +char * +btp_backtrace_get_duplication_hash(struct btp_backtrace *backtrace) +{ + backtrace = btp_backtrace_dup(backtrace); + struct btp_thread *crash_thread = btp_backtrace_find_crash_thread(backtrace); + if (crash_thread) + btp_backtrace_remove_threads_except_one(backtrace, crash_thread); + + btp_normalize_backtrace(backtrace); + btp_backtrace_limit_frame_depth(backtrace, 3); + char *hash = btp_backtrace_to_text(backtrace, false); + btp_backtrace_free(backtrace); + return hash; +} + +struct btp_backtrace * +btp_backtrace_parse(char **input, + struct btp_location *location) +{ + char *local_input = *input; + struct btp_backtrace *imbacktrace = btp_backtrace_new(); /* im - intermediate */ + + /* The header is mandatory, but it might contain no frame header, + * in some broken backtraces. In that case, backtrace.crash value + * is kept as NULL. + */ + if (!btp_backtrace_parse_header(&local_input, + &imbacktrace->crash, + location)) + { + btp_backtrace_free(imbacktrace); + return NULL; + } + + struct btp_thread *thread, *prevthread = NULL; + while ((thread = btp_thread_parse(&local_input, location))) + { + if (prevthread) + { + btp_thread_add_sibling(prevthread, thread); + prevthread = thread; + } + else + imbacktrace->threads = prevthread = thread; + } + if (!imbacktrace->threads) + { + btp_backtrace_free(imbacktrace); + return NULL; + } + + *input = local_input; + return imbacktrace; +} + +bool +btp_backtrace_parse_header(char **input, + struct btp_frame **frame, + struct btp_location *location) +{ + int first_thread_line, first_thread_column; + char *first_thread = btp_strstr_location(*input, + "\nThread ", + &first_thread_line, + &first_thread_column); + + /* Skip the newline. */ + if (first_thread) + { + ++first_thread; + first_thread_line += 1; + first_thread_column = 0; + } + + int first_frame_line, first_frame_column; + char *first_frame = btp_strstr_location(*input, + "\n#", + &first_frame_line, + &first_frame_column); + + /* Skip the newline. */ + if (first_frame) + { + ++first_frame; + first_frame_line += 1; + first_frame_column = 0; + } + + if (first_thread) + { + if (first_frame && first_frame < first_thread) + { + /* Common case. The crash frame is present in the input + * before the list of threads begins. + */ + *input = first_frame; + btp_location_add(location, first_frame_line, first_frame_column); + } + else + { + /* Uncommon case (caused by some kernel bug) where the + * frame is missing from the header. The backtrace + * contains just threads. We silently skip the header and + * return true. + */ + *input = first_thread; + btp_location_add(location, + first_thread_line, + first_thread_column); + *frame = NULL; + return true; + } + } + else if (first_frame) + { + /* Degenerate case when the backtrace contains no thread, but + * the frame is there. + */ + *input = first_frame; + btp_location_add(location, first_frame_line, first_frame_column); + } + else + { + /* Degenerate case where the input is empty or completely + * meaningless. Report a failure. + */ + location->message = "No frame and no thread found."; + return false; + } + + /* Parse the frame header. */ + *frame = btp_frame_parse(input, location); + return *frame; +} diff --git a/btparser/lib/backtrace.h b/btparser/lib/backtrace.h new file mode 100644 index 00000000..d5de3ff3 --- /dev/null +++ b/btparser/lib/backtrace.h @@ -0,0 +1,269 @@ +/* + backtrace.h + + Copyright (C) 2010 Red Hat, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ +#ifndef BTPARSER_BACKTRACE_H +#define BTPARSER_BACKTRACE_H + +#include <stdbool.h> + +#ifdef __cplusplus +extern "C" { +#endif + +struct btp_thread; +struct btp_frame; +struct btp_location; + +/** + * A backtrace obtained at the time of a program crash, consisting of + * several threads which contains frames. + */ +struct btp_backtrace +{ + struct btp_thread *threads; + /** + * The frame where the crash happened according to debugger. It + * might be that we can not tell to which thread this frame + * belongs, because some threads end with mutually + * indistinguishable frames. + */ + struct btp_frame *crash; +}; + +/** + * Creates and initializes a new backtrace structure. + * @returns + * It never returns NULL. The returned pointer must be released by + * calling the function btp_backtrace_free(). + */ +struct btp_backtrace * +btp_backtrace_new(); + +/** + * Initializes all members of the backtrace structure to their default + * values. No memory is released, members are simply overwritten. + * This is useful for initializing a backtrace structure placed on the + * stack. + */ +void +btp_backtrace_init(struct btp_backtrace *backtrace); + +/** + * Releases the memory held by the backtrace, its threads and frames. + * @param backtrace + * If the backtrace is NULL, no operation is performed. + */ +void +btp_backtrace_free(struct btp_backtrace *backtrace); + +/** + * Creates a duplicate of the backtrace. + * @param backtrace + * The backtrace to be copied. It's not modified by this function. + * @returns + * This function never returns NULL. If the returned duplicate is not + * shallow, it must be released by calling the function + * btp_backtrace_free(). + */ +struct btp_backtrace * +btp_backtrace_dup(struct btp_backtrace *backtrace); + +/** + * Returns a number of threads in the backtrace. + * @param backtrace + * It's not modified by calling this function. + */ +int +btp_backtrace_get_thread_count(struct btp_backtrace *backtrace); + +/** + * Removes all threads from the backtrace and deletes them, except the + * one provided as a parameter. + * @param thread + * This function does not check whether the thread is a member of the backtrace. + * If it's not, all threads are removed from the backtrace and then deleted. + */ +void +btp_backtrace_remove_threads_except_one(struct btp_backtrace *backtrace, + struct btp_thread *thread); + +/** + * Search all threads and tries to find the one that caused the crash. + * It might return NULL if the thread cannot be determined. + * @param backtrace + * It must be non-NULL pointer. It's not modified by calling this + * function. + */ +struct btp_thread * +btp_backtrace_find_crash_thread(struct btp_backtrace *backtrace); + +/** + * Remove frames from the bottom of threads in the backtrace, until + * all threads have at most 'depth' frames. + * @param backtrace + * Must be non-NULL pointer. + */ +void +btp_backtrace_limit_frame_depth(struct btp_backtrace *backtrace, + int depth); + +/** + * Evaluates the quality of the backtrace. The quality is the ratio of + * the number of frames with function name fully known to the number + * of all frames. This function does not take into account that some + * frames are more important than others. + * @param backtrace + * It must be non-NULL pointer. It's not modified by calling this + * function. + * @returns + * A number between 0 and 1. 0 means the lowest quality, 1 means full + * backtrace is known. + */ +float +btp_backtrace_quality_simple(struct btp_backtrace *backtrace); + +/** + * Evaluates the quality of the backtrace. The quality is determined + * depending on the ratio of frames with function name fully known to + * all frames. + * @param backtrace + * It must be non-NULL pointer. It's not modified by calling this + * function. + * @returns + * A number between 0 and 1. 0 means the lowest quality, 1 means full + * backtrace is known. The returned value takes into account that the + * thread which caused the crash is more important than the other + * threads, and the frames around the crash frame are more important + * than distant frames. + */ +float +btp_backtrace_quality_complex(struct btp_backtrace *backtrace); + +/** + * Returns textual representation of the backtrace. + * @param backtrace + * It must be non-NULL pointer. It's not modified by calling this + * function. + * @returns + * This function never returns NULL. The caller is responsible for + * releasing the returned memory using function free(). + */ +char * +btp_backtrace_to_text(struct btp_backtrace *backtrace, + bool verbose); + +/** + * Analyzes the backtrace to get the frame where a crash occurred. + * @param backtrace + * It must be non-NULL pointer. It's not modified by calling this + * function. + * @returns + * The returned value must be released by calling btp_frame_free(), + * when it's no longer needed. NULL is returned if the crash frame is + * not found. + */ +struct btp_frame * +btp_backtrace_get_crash_frame(struct btp_backtrace *backtrace); + +/** + * Calculates the duplication hash string of the backtrace. + * @param backtrace + * It must be non-NULL pointer. It's not modified by calling this + * function. + * @returns + * This function never returns NULL. The caller is responsible for + * releasing the returned memory using function free(). + */ +char * +btp_backtrace_get_duplication_hash(struct btp_backtrace *backtrace); + +/** + * Parses a textual backtrace and puts it into a structure. If + * parsing fails, the input parameter is not changed and NULL is + * returned. + * @code + * struct btp_location location; + * btp_location_init(&location); + * char *input = "..."; + * struct btp_backtrace *backtrace = btp_backtrace_parse(input, location; + * if (!backtrace) + * { + * fprintf(stderr, + * "Failed to parse the backtrace.\n" + * "Line %d, column %d: %s\n", + * location.line, + * location.column, + * location.message); + * exit(-1); + * } + * btp_backtrace_free(backtrace); + * @endcode + * @param input + * Pointer to the string with the backtrace. If this function returns + * true, this pointer is modified to point after the backtrace that + * was just parsed. + * @param location + * The caller must provide a pointer to an instance of btp_location + * here. The line and column members of the location are gradually + * increased as the parser handles the input, so the location should + * be initialized before calling this function to get reasonable + * values. When this function returns false (an error occurred), the + * structure will contain the error line, column, and message. + * @returns + * A newly allocated backtrace structure or NULL. A backtrace struct + * is returned when at least one thread was parsed from the input and + * no error occurred. The returned structure should be released by + * btp_backtrace_free(). + */ +struct btp_backtrace * +btp_backtrace_parse(char **input, + struct btp_location *location); + +/** + * Parse backtrace header if it is available in the backtrace. The + * header usually contains frame where the program crashed. + * @param input + * Pointer moved to point behind the header if the header is + * successfully detected and parsed. + * @param frame + * If this function succeeds and returns true, *frame contains the + * crash frame that is usually a part of the header. If no frame is + * detected in the header, *frame is set to NULL. + * @code + * [New Thread 11919] + * [New Thread 11917] + * Core was generated by `evince file:///tmp/Factura04-05-2010.pdf'. + * Program terminated with signal 8, Arithmetic exception. + * #0 0x000000322a2362b9 in repeat (image=<value optimized out>, + * mask=<value optimized out>, mask_bits=<value optimized out>) + * at pixman-bits-image.c:145 + * 145 pixman-bits-image.c: No such file or directory. + * in pixman-bits-image.c + * @endcode + */ +bool +btp_backtrace_parse_header(char **input, + struct btp_frame **frame, + struct btp_location *location); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/btparser/lib/frame.c b/btparser/lib/frame.c new file mode 100644 index 00000000..83680910 --- /dev/null +++ b/btparser/lib/frame.c @@ -0,0 +1,1027 @@ +/* + frame.c + + Copyright (C) 2010 Red Hat, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ +#include "frame.h" +#include "strbuf.h" +#include "utils.h" +#include "location.h" +#include <stdlib.h> +#include <stdio.h> +#include <string.h> + +struct btp_frame * +btp_frame_new() +{ + struct btp_frame *frame = btp_malloc(sizeof(struct btp_frame)); + btp_frame_init(frame); + return frame; +} + +void +btp_frame_init(struct btp_frame *frame) +{ + frame->function_name = NULL; + frame->function_type = NULL; + frame->number = 0; + frame->source_file = NULL; + frame->source_line = -1; + frame->signal_handler_called = false; + frame->address = -1; + frame->next = NULL; +} + +void +btp_frame_free(struct btp_frame *frame) +{ + if (!frame) + return; + free(frame->function_name); + free(frame->function_type); + free(frame->source_file); + free(frame); +} + +struct btp_frame * +btp_frame_dup(struct btp_frame *frame, bool siblings) +{ + struct btp_frame *result = btp_frame_new(); + memcpy(result, frame, sizeof(struct btp_frame)); + + /* Handle siblings. */ + if (siblings) + { + if (result->next) + result->next = btp_frame_dup(result->next, true); + } + else + result->next = NULL; /* Do not copy that. */ + + /* Duplicate all strings if the copy is not shallow. */ + if (result->function_name) + result->function_name = btp_strdup(result->function_name); + if (result->function_type) + result->function_type = btp_strdup(result->function_type); + if (result->source_file) + result->source_file = btp_strdup(result->source_file); + + return result; +} + +bool +btp_frame_calls_func(struct btp_frame *frame, + const char *function_name) +{ + return frame->function_name && + 0 == strcmp(frame->function_name, function_name); +} + +bool +btp_frame_calls_func_in_file(struct btp_frame *frame, + const char *function_name, + const char *source_file) +{ + return frame->function_name && + 0 == strcmp(frame->function_name, function_name) && + frame->source_file && + NULL != strstr(frame->source_file, source_file); +} + +bool +btp_frame_calls_func_in_file2(struct btp_frame *frame, + const char *function_name, + const char *source_file0, + const char *source_file1) +{ + return frame->function_name && + 0 == strcmp(frame->function_name, function_name) && + frame->source_file && + (NULL != strstr(frame->source_file, source_file0) || + NULL != strstr(frame->source_file, source_file1)); +} + +bool +btp_frame_calls_func_in_file3(struct btp_frame *frame, + const char *function_name, + const char *source_file0, + const char *source_file1, + const char *source_file2) +{ + return frame->function_name && + 0 == strcmp(frame->function_name, function_name) && + frame->source_file && + (NULL != strstr(frame->source_file, source_file0) || + NULL != strstr(frame->source_file, source_file1) || + NULL != strstr(frame->source_file, source_file2)); +} + +bool +btp_frame_calls_func_in_file4(struct btp_frame *frame, + const char *function_name, + const char *source_file0, + const char *source_file1, + const char *source_file2, + const char *source_file3) +{ + return frame->function_name && + 0 == strcmp(frame->function_name, function_name) && + frame->source_file && + (NULL != strstr(frame->source_file, source_file0) || + NULL != strstr(frame->source_file, source_file1) || + NULL != strstr(frame->source_file, source_file2) || + NULL != strstr(frame->source_file, source_file3)); +} + +int +btp_frame_cmp(struct btp_frame *f1, + struct btp_frame *f2, + bool compare_number) +{ + /* Singnal handler. */ + if (f1->signal_handler_called) + { + if (!f2->signal_handler_called) + return 1; + + /* Both contain signal handler called. */ + return 0; + } + else + { + if (f2->signal_handler_called) + return -1; + /* No signal handler called, continue. */ + } + + /* Function. */ + int function_name = btp_strcmp0(f1->function_name, f2->function_name); + if (function_name != 0) + return function_name; + int function_type = btp_strcmp0(f1->function_type, f2->function_type); + if (function_type != 0) + return function_type; + + /* Sourcefile. */ + int source_file = btp_strcmp0(f1->source_file, f2->source_file); + if (source_file != 0) + return source_file; + + /* Sourceline. */ + int source_line = f1->source_line - f2->source_line; + if (source_line != 0) + return source_line; + + /* Frame number. */ + if (compare_number) + { + int number = f1->number - f2->number; + if (number != 0) + return number; + } + + return 0; +} + +void +btp_frame_add_sibling(struct btp_frame *a, struct btp_frame *b) +{ + struct btp_frame *aa = a; + while (aa->next) + aa = aa->next; + + aa->next = b; +} + +void +btp_frame_append_to_str(struct btp_frame *frame, + struct btp_strbuf *str, + bool verbose) +{ + if (verbose) + btp_strbuf_append_strf(str, " #%d", frame->number); + else + btp_strbuf_append_str(str, " "); + + if (frame->function_type) + btp_strbuf_append_strf(str, " %s", frame->function_type); + if (frame->function_name) + btp_strbuf_append_strf(str, " %s", frame->function_name); + if (verbose && frame->source_file) + { + if (frame->function_name) + btp_strbuf_append_str(str, " at"); + btp_strbuf_append_strf(str, " %s", frame->source_file); + } + + if (frame->signal_handler_called) + btp_strbuf_append_str(str, " <signal handler called>"); + + btp_strbuf_append_str(str, "\n"); +} + +/** + * Find string a or b in input, whatever comes first. + * If no string is found, return the \0 character at the end of input. + */ +static char * +findfirstabnul(char *input, const char *a, const char *b) +{ + size_t alen = strlen(a); + size_t blen = strlen(b); + char *p = input; + while (*p) + { + if (strncmp(p, a, alen) == 0) + return p; + if (strncmp(p, b, blen) == 0) + return p; + ++p; + } + return p; +} + +struct btp_frame * +btp_frame_parse(char **input, + struct btp_location *location) +{ + char *local_input = *input; + struct btp_frame *header = btp_frame_parse_header(input, location); + if (!header) + return NULL; + + /* Skip the variables section for now. */ + /* Todo: speedup by implementing strstrnul. */ + local_input = findfirstabnul(local_input, "\n#", "\nThread"); + if (*local_input != '\0') + ++local_input; /* ++ skips the newline */ + + if (btp_debug_parser) + { + printf("frame #%u %s\n", + header->number, + header->function_name ? header->function_name : "signal handler called"); + } + + *input = local_input; + return header; +} + +int +btp_frame_parse_frame_start(char **input, unsigned *number) +{ + char *local_input = *input; + + /* Read the hash sign. */ + if (!btp_skip_char(&local_input, '#')) + return 0; + int count = 1; + + /* Read the frame position. */ + int digits = btp_parse_unsigned_integer(&local_input, number); + count += digits; + if (0 == digits) + return 0; + + /* Read all the spaces after the positon. */ + int spaces = btp_skip_char_sequence(&local_input, ' '); + count += spaces; + if (0 == spaces) + return 0; + + *input = local_input; + return count; +} + +int +btp_frame_parseadd_operator(char **input, struct btp_strbuf *target) +{ + char *local_input = *input; + if (0 == btp_skip_string(&local_input, "operator")) + return 0; + +#define OP(x) \ + if (0 < btp_skip_string(&local_input, x)) \ + { \ + btp_strbuf_append_str(target, "operator"); \ + btp_strbuf_append_str(target, x); \ + int length = local_input - *input; \ + *input = local_input; \ + return length; \ + } + + OP(">>=")OP(">>")OP(">=")OP(">"); + OP("<<=")OP("<<")OP("<=")OP("<"); + OP("->*")OP("->")OP("-"); + OP("==")OP("="); + OP("&&")OP("&=")OP("&"); + OP("||")OP("|=")OP("|"); + OP("++")OP("+=")OP("+"); + OP("--")OP("-=")OP("-"); + OP("/=")OP("/"); + OP("*=")OP("*"); + OP("%=")OP("%"); + OP("!=")OP("!"); + OP("~"); + OP("()"); + OP("[]"); + OP(","); + OP("^=")OP("^"); + OP(" new[]")OP(" new"); + OP(" delete[]")OP(" delete"); + /* User defined operators are not parsed. + Should they be? */ +#undef OP + return 0; +} + +#define FUNCTION_NAME_CHARS BTP_alnum "@.:=!*+-[]~&/%^|,_" + +int +btp_frame_parse_function_name_chunk(char **input, + bool space_allowed, + char **target) +{ + char *local_input = *input; + struct btp_strbuf *buf = btp_strbuf_new(); + while (*local_input) + { + if (0 < btp_frame_parseadd_operator(&local_input, buf)) + { + /* Space is allowed after operator even when it + is not normally allowed. */ + if (btp_skip_char(&local_input, ' ')) + { + /* ...but if ( follows, it is not allowed. */ + if (btp_skip_char(&local_input, '(')) + { + /* Return back both the space and (. */ + local_input -= 2; + } + else + btp_strbuf_append_char(buf, ' '); + } + } + + if (strchr(FUNCTION_NAME_CHARS, *local_input) == NULL) + { + if (!space_allowed || strchr(" ", *local_input) == NULL) + break; + } + + btp_strbuf_append_char(buf, *local_input); + ++local_input; + } + + if (buf->len == 0) + { + btp_strbuf_free(buf); + return 0; + } + + *target = btp_strbuf_free_nobuf(buf); + int total_char_count = local_input - *input; + *input = local_input; + return total_char_count; +} + +int +btp_frame_parse_function_name_braces(char **input, char **target) +{ + char *local_input = *input; + if (!btp_skip_char(&local_input, '(')) + return 0; + + struct btp_strbuf *buf = btp_strbuf_new(); + btp_strbuf_append_char(buf, '('); + while (true) + { + char *namechunk = NULL; + if (0 < btp_frame_parse_function_name_chunk(&local_input, true, &namechunk) || + 0 < btp_frame_parse_function_name_braces(&local_input, &namechunk) || + 0 < btp_frame_parse_function_name_template(&local_input, &namechunk)) + { + btp_strbuf_append_str(buf, namechunk); + free(namechunk); + } + else + break; + } + + if (!btp_skip_char(&local_input, ')')) + { + btp_strbuf_free(buf); + return 0; + } + + btp_strbuf_append_char(buf, ')'); + *target = btp_strbuf_free_nobuf(buf); + int total_char_count = local_input - *input; + *input = local_input; + return total_char_count; +} + +int +btp_frame_parse_function_name_template(char **input, char **target) +{ + char *local_input = *input; + if (!btp_skip_char(&local_input, '<')) + return 0; + + struct btp_strbuf *buf = btp_strbuf_new(); + btp_strbuf_append_char(buf, '<'); + while (true) + { + char *namechunk = NULL; + if (0 < btp_frame_parse_function_name_chunk(&local_input, true, &namechunk) || + 0 < btp_frame_parse_function_name_braces(&local_input, &namechunk) || + 0 < btp_frame_parse_function_name_template(&local_input, &namechunk)) + { + btp_strbuf_append_str(buf, namechunk); + free(namechunk); + } + else + break; + } + + if (!btp_skip_char(&local_input, '>')) + { + btp_strbuf_free(buf); + return 0; + } + + btp_strbuf_append_char(buf, '>'); + *target = btp_strbuf_free_nobuf(buf); + int total_char_count = local_input - *input; + *input = local_input; + return total_char_count; +} + +bool +btp_frame_parse_function_name(char **input, + char **function_name, + char **function_type, + struct btp_location *location) +{ + /* Handle unknown function name, represended by double question + mark. */ + if (btp_parse_string(input, "??", function_name)) + { + *function_type = NULL; + location->column += 2; + return true; + } + + char *local_input = *input; + /* Up to three parts of function name. */ + struct btp_strbuf *buf0 = btp_strbuf_new(), *buf1 = NULL; + + /* First character: + '~' for destructor + '*' for ???? + '_a-zA-Z' for mangled/nonmangled function name + '(' to start "(anonymous namespace)::" or something + */ + char first; + char *namechunk; + if (btp_parse_char_limited(&local_input, "~*_" BTP_alpha, &first)) + { + /* If it's a start of 'o'perator, put the 'o' back! */ + if (first == 'o') + --local_input; + else + { + btp_strbuf_append_char(buf0, first); + ++location->column; + } + } + else + { + int chars = btp_frame_parse_function_name_braces(&local_input, + &namechunk); + if (0 < chars) + { + btp_strbuf_append_str(buf0, namechunk); + free(namechunk); + location->column += chars; + } + else + { + location->message = "Expected function name."; + btp_strbuf_free(buf0); + return false; + } + } + + /* The rest consists of function name, braces, templates...*/ + while (true) + { + char *namechunk = NULL; + int chars = btp_frame_parse_function_name_chunk(&local_input, + false, + &namechunk); + + if (0 == chars) + { + chars = btp_frame_parse_function_name_braces(&local_input, + &namechunk); + } + + if (0 == chars) + { + chars = btp_frame_parse_function_name_template(&local_input, + &namechunk); + } + + if (0 == chars) + break; + + btp_strbuf_append_str(buf0, namechunk); + free(namechunk); + location->column += chars; + } + + /* Function name MUST be ended by empty space. */ + char space; + if (!btp_parse_char_limited(&local_input, BTP_space, &space)) + { + btp_strbuf_free(buf0); + location->message = "Space or newline expected after function name."; + return false; + } + + /* Some C++ function names and function types might contain suffix + " const". */ + int chars = btp_skip_string(&local_input, "const"); + if (0 < chars) + { + btp_strbuf_append_char(buf0, space); + btp_location_eat_char(location, space); + btp_strbuf_append_str(buf0, "const"); + location->column += chars; + + /* Check the empty space after function name again.*/ + if (!btp_parse_char_limited(&local_input, BTP_space, &space)) + { + /* Function name MUST be ended by empty space. */ + btp_strbuf_free(buf0); + location->message = "Space or newline expected after function name."; + return false; + } + } + + /* Maybe the first series was just a type of the function, and now + the real function follows. Now, we know it must not start with + '(', nor with '<'. */ + chars = btp_frame_parse_function_name_chunk(&local_input, + false, + &namechunk); + if (0 < chars) + { + /* Eat the space separator first. */ + btp_location_eat_char(location, space); + + buf1 = btp_strbuf_new(); + btp_strbuf_append_str(buf1, namechunk); + free(namechunk); + location->column += chars; + + /* The rest consists of a function name parts, braces, templates...*/ + while (true) + { + char *namechunk = NULL; + chars = btp_frame_parse_function_name_chunk(&local_input, + false, + &namechunk); + if (0 == chars) + { + chars = btp_frame_parse_function_name_braces(&local_input, + &namechunk); + } + if (0 == chars) + { + chars = btp_frame_parse_function_name_template(&local_input, + &namechunk); + } + if (0 == chars) + break; + + btp_strbuf_append_str(buf1, namechunk); + free(namechunk); + location->column += chars; + } + + /* Function name MUST be ended by empty space. */ + if (!btp_parse_char_limited(&local_input, BTP_space, &space)) + { + btp_strbuf_free(buf0); + btp_strbuf_free(buf1); + location->message = "Space or newline expected after function name."; + return false; + } + } + + /* Again, some C++ function names might contain suffix " const" */ + chars = btp_skip_string(&local_input, "const"); + if (0 < chars) + { + struct btp_strbuf *buf = buf1 ? buf1 : buf0; + btp_strbuf_append_char(buf, space); + btp_location_eat_char(location, space); + btp_strbuf_append_str(buf, "const"); + location->column += chars; + + /* Check the empty space after function name again.*/ + if (!btp_skip_char_limited(&local_input, BTP_space)) + { + /* Function name MUST be ended by empty space. */ + btp_strbuf_free(buf0); + btp_strbuf_free(buf1); + location->message = "Space or newline expected after function name."; + return false; + } + } + + /* Return back to the empty space. */ + --local_input; + + if (buf1) + { + *function_name = btp_strbuf_free_nobuf(buf1); + *function_type = btp_strbuf_free_nobuf(buf0); + } + else + { + *function_name = btp_strbuf_free_nobuf(buf0); + *function_type = NULL; + } + + *input = local_input; + return true; +} + +bool +btp_frame_skip_function_args(char **input, struct btp_location *location) +{ + char *local_input = *input; + if (!btp_skip_char(&local_input, '(')) + { + location->message = "Expected '(' to start function argument list."; + return false; + } + location->column += 1; + + int depth = 0; + bool string = false; + bool escape = false; + do + { + if (string) + { + if (escape) + escape = false; + else if (*local_input == '\\') + escape = true; + else if (*local_input == '"') + string = false; + } + else + { + if (*local_input == '"') + string = true; + else if (*local_input == '(') + ++depth; + else if (*local_input == ')') + { + if (depth > 0) + --depth; + else + break; + } + } + btp_location_eat_char(location, *local_input); + ++local_input; + } + while (*local_input); + + if (depth != 0 || string || escape) + { + location->message = "Unbalanced function parameter list."; + return false; + } + + if (!btp_skip_char(&local_input, ')')) + { + location->message = "Expected ')' to close the function parameter list."; + return false; + } + location->column += 1; + + *input = local_input; + return true; +} + +bool +btp_frame_parse_function_call(char **input, + char **function_name, + char **function_type, + struct btp_location *location) +{ + char *local_input = *input; + char *name = NULL, *type = NULL; + if (!btp_frame_parse_function_name(&local_input, + &name, + &type, + location)) + { + /* The location message is set by the function returning + * false, no need to update it here. */ + return false; + } + + int line, column; + if (0 == btp_skip_char_span_location(&local_input, + " \n", + &line, + &column)) + { + free(name); + free(type); + location->message = "Expected a space or newline after the function name."; + return false; + } + btp_location_add(location, line, column); + + if (!btp_frame_skip_function_args(&local_input, location)) + { + free(name); + free(type); + /* The location message is set by the function returning + * false, no need to update it here. */ + return false; + } + + *function_name = name; + *function_type = type; + *input = local_input; + return true; +} + +bool +btp_frame_parse_address_in_function(char **input, + uint64_t *address, + char **function_name, + char **function_type, + struct btp_location *location) +{ + char *local_input = *input; + + /* Read memory address in hexadecimal format. */ + int digits = btp_parse_hexadecimal_number(&local_input, address); + location->column += digits; + if (0 == digits) + { + location->message = "Hexadecimal number representing memory address expected."; + return false; + } + + /* Skip spaces. */ + int chars = btp_skip_char_sequence(&local_input, ' '); + location->column += chars; + if (0 == chars) + { + location->message = "Space expected after memory address."; + return false; + } + + /* Skip keyword "in". */ + chars = btp_skip_string(&local_input, "in"); + location->column += chars; + if (0 == chars) + { + location->message = "Keyword \"in\" expected after memory address."; + return false; + } + + /* Skip spaces. */ + chars = btp_skip_char_sequence(&local_input, ' '); + location->column += chars; + if (0 == chars) + { + location->message = "Space expected after 'in'."; + return false; + } + + /* C++ specific case for "0xfafa in vtable for function ()" */ + chars = btp_skip_string(&local_input, "vtable"); + location->column += chars; + if (0 < chars) + { + chars = btp_skip_char_sequence(&local_input, ' '); + location->column += chars; + if (0 == chars) + { + location->message = "Space expected after 'vtable'."; + return false; + } + + chars = btp_skip_string(&local_input, "for"); + location->column += chars; + if (0 == chars) + { + location->message = "Keyword \"for\" expected."; + return false; + } + + chars = btp_skip_char_sequence(&local_input, ' '); + location->column += chars; + if (0 == chars) + { + location->message = "Space expected after 'for'."; + return false; + } + } + + if (!btp_frame_parse_function_call(&local_input, + function_name, + function_type, + location)) + { + /* Do not update location here, it has been modified by the + called function. */ + return false; + } + + *input = local_input; + return true; +} + +bool +btp_frame_parse_file_location(char **input, + char **file, + unsigned *fileline, + struct btp_location *location) +{ + char *local_input = *input; + int line, column; + if (0 == btp_skip_char_span_location(&local_input, " \n", &line, &column)) + { + location->message = "Expected a space or a newline."; + return false; + } + btp_location_add(location, line, column); + + int chars = btp_skip_string(&local_input, "at"); + if (0 == chars) + { + chars = btp_skip_string(&local_input, "from"); + if (0 == chars) + { + location->message = "Expected 'at' or 'from'."; + return false; + } + } + location->column += chars; + + int spaces = btp_skip_char_sequence(&local_input, ' '); + location->column += spaces; + if (0 == spaces) + { + location->message = "Expected a space before file location."; + return false; + } + + char *file_name; + chars = btp_parse_char_span(&local_input, BTP_alnum "_/\\+.-", &file_name); + location->column += chars; + if (0 == chars) + { + location->message = "Expected a file name."; + return false; + } + + if (btp_skip_char(&local_input, ':')) + { + location->column += 1; + int digits = btp_parse_unsigned_integer(&local_input, fileline); + location->column += digits; + if (0 == digits) + { + free(file_name); + location->message = "Expected a line number."; + return false; + } + } + else + *fileline = -1; + + *file = file_name; + *input = local_input; + return true; +} + +struct btp_frame * +btp_frame_parse_header(char **input, + struct btp_location *location) +{ + char *local_input = *input; + struct btp_frame *imframe = btp_frame_new(); /* im - intermediate */ + int chars = btp_frame_parse_frame_start(&local_input, + &imframe->number); + + location->column += chars; + if (0 == chars) + { + location->message = "Frame start sequence expected."; + btp_frame_free(imframe); + return NULL; + } + + struct btp_location internal_location; + btp_location_init(&internal_location); + if (btp_frame_parse_address_in_function(&local_input, + &imframe->address, + &imframe->function_name, + &imframe->function_type, + &internal_location)) + { + btp_location_add(location, + internal_location.line, + internal_location.column); + + /* Optional section " from file.c:65" */ + /* Optional section " at file.c:65" */ + btp_location_init(&internal_location); + if (btp_frame_parse_file_location(&local_input, + &imframe->source_file, + &imframe->source_line, + &internal_location)) + { + btp_location_add(location, + internal_location.line, + internal_location.column); + } + } + else + { + btp_location_init(&internal_location); + if (btp_frame_parse_function_call(&local_input, + &imframe->function_name, + &imframe->function_type, + &internal_location)) + { + btp_location_add(location, + internal_location.line, + internal_location.column); + + /* Mandatory section " at file.c:65" */ + btp_location_init(&internal_location); + if (!btp_frame_parse_file_location(&local_input, + &imframe->source_file, + &imframe->source_line, + &internal_location)) + { + location->message = "Function call in the frame header " + "misses mandatory \"at file.c:xy\" section"; + btp_frame_free(imframe); + return NULL; + } + + btp_location_add(location, + internal_location.line, + internal_location.column); + } + else + { + int chars = btp_skip_string(&local_input, "<signal handler called>"); + if (0 < chars) + { + location->column += chars; + imframe->signal_handler_called = true; + } + else + { + location->message = "Frame header variant not recognized."; + btp_frame_free(imframe); + return NULL; + } + } + } + + *input = local_input; + return imframe; +} diff --git a/btparser/lib/frame.h b/btparser/lib/frame.h new file mode 100644 index 00000000..3cc19c3c --- /dev/null +++ b/btparser/lib/frame.h @@ -0,0 +1,470 @@ +/* + frame.h + + Copyright (C) 2010 Red Hat, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ +#ifndef BTPARSER_FRAME_H +#define BTPARSER_FRAME_H + +#include <stdbool.h> +#include <stdint.h> + +#ifdef __cplusplus +extern "C" { +#endif + +struct btp_strbuf; +struct btp_location; + +/** + * A frame representing a function call or a signal handler on a call + * stack of a thread. + */ +struct btp_frame +{ + /** + * A function name or NULL. If it's NULL, signal_handler_called is + * true. + */ + char *function_name; + /** + * A function type, or NULL if it isn't present. + */ + char *function_type; + /** + * A frame number in a thread. It does not necessarily show the + * actual position in the thread, as this number is set by the + * parser and never updated. + */ + unsigned number; + /** + * The name of the source file containing the function definition, + * or the name of the binary file (.so) with the binary code of + * the function, or NULL. + */ + char *source_file; + /** + * A line number in the source file, determining the position of + * the function definition, or -1 when unknown. + */ + unsigned source_line; + /** + * Signal handler was called on this frame. + */ + bool signal_handler_called; + /** + * The function address in the computer memory, or -1 when the + * address is unknown. + */ + uint64_t address; + /** + * A sibling frame residing below this one, or NULL if this is the + * last frame in the parent thread. + */ + struct btp_frame *next; +}; + +/** + * Creates and initializes a new frame structure. + * @returns + * It never returns NULL. The returned pointer must be released by + * calling the function btp_frame_free(). + */ +struct btp_frame * +btp_frame_new(); + +/** + * Initializes all members of the frame structure to their default + * values. No memory is released, members are simply overwritten. + * This is useful for initializing a frame structure placed on the + * stack. + */ +void +btp_frame_init(struct btp_frame *frame); + +/** + * Releases the memory held by the frame. The frame siblings are not + * released. + * @param frame + * If the frame is NULL, no operation is performed. + */ +void +btp_frame_free(struct btp_frame *frame); + +/** + * Creates a duplicate of the frame. + * @param frame + * It must be non-NULL pointer. The frame is not modified by calling + * this function. + * @param siblings + * Whether to duplicate also siblings referenced by frame->next. If + * false, frame->next is not duplicated for the new frame, but it is + * set to NULL. + * @returns + * This function never returns NULL. If the returned duplicate is not + * shallow, it must be released by calling the function + * btp_frame_free(). + */ +struct btp_frame * +btp_frame_dup(struct btp_frame *frame, + bool siblings); + +/** + * Checks whether the frame represents a call of function with certain + * function name. + */ +bool +btp_frame_calls_func(struct btp_frame *frame, + const char *function_name); + +/** + * Checks whether the frame represents a call of function with certain + * function name, which resides in a source file. + * @param source_file + * The frame's source_file is searched for the source_file as a + * substring. + */ +bool +btp_frame_calls_func_in_file(struct btp_frame *frame, + const char *function_name, + const char *source_file); + +/** + * Checks whether the frame represents a call of function with certain + * function name, which resides in one of the source files. + * @param source_file0 + * The frame's source_file is searched for the source_file0 as a + * substring. + * @returns + * True if the frame corresponds to a function with function_name, + * residing in the source_file0, or source_file1. + */ +bool +btp_frame_calls_func_in_file2(struct btp_frame *frame, + const char *function_name, + const char *source_file0, + const char *source_file1); + +/** + * Checks whether the frame represents a call of function with certain + * function name, which resides in one of the source files. + * @param source_file0 + * The frame's source_file is searched for the source_file0 as a + * substring. + * @returns + * True if the frame corresponds to a function with function_name, + * residing in the source_file0, source_file1, or source_file2. + */ +bool +btp_frame_calls_func_in_file3(struct btp_frame *frame, + const char *function_name, + const char *source_file0, + const char *source_file1, + const char *source_file2); + +/** + * Checks whether the frame represents a call of function with certain + * function name, which resides in one of the source files. + * @param source_file0 + * The frame's source_file is searched for the source_file0 as a + * substring. + * @returns + * True if the frame corresponds to a function with function_name, + * residing in the source_file0, source_file1, source_file2, or + * source_file3. + */ +bool +btp_frame_calls_func_in_file4(struct btp_frame *frame, + const char *function_name, + const char *source_file0, + const char *source_file1, + const char *source_file2, + const char *source_file3); + +/** + * Compares two frames. + * @param f1 + * It must be non-NULL pointer. It's not modified by calling this + * function. + * @param f2 + * It must be non-NULL pointer. It's not modified by calling this + * function. + * @param compare_number + * Indicates whether to include the frame numbers in the + * comparsion. If set to false, the frame numbers are ignored. + * @returns + * Returns 0 if the frames are same. Returns negative number if f1 is + * found to be 'less' than f2. Returns positive number if f1 is found + * to be 'greater' than f2. + */ +int +btp_frame_cmp(struct btp_frame *f1, + struct btp_frame *f2, + bool compare_number); + +/** + * Puts the frame 'b' to the bottom of the stack 'a'. In other words, + * it finds the last sibling of the frame 'a', and appends the frame + * 'b' to this last sibling. + */ +void +btp_frame_add_sibling(struct btp_frame *a, + struct btp_frame *b); + +/** + * Appends the textual representation of the frame to the string + * buffer. + * @param frame + * It must be non-NULL pointer. It's not modified by calling this + * function. + */ +void +btp_frame_append_to_str(struct btp_frame *frame, + struct btp_strbuf *str, + bool verbose); + +/** + * If the input contains a complete frame, this function parses the + * frame text, returns it in a structure, and moves the input pointer + * after the frame. If the input does not contain proper, complete + * frame, the function does not modify input and returns NULL. + * @returns + * Allocated pointer with a frame structure. The pointer should be + * released by btp_frame_free(). + * @param location + * The caller must provide a pointer to an instance of btp_location + * here. When this function returns NULL, the structure will contain + * the error line, column, and message. The line and column members + * of the location are gradually increased as the parser handles the + * input, so the location should be initialized before calling this + * function to get reasonable values. + */ +struct btp_frame * +btp_frame_parse(char **input, + struct btp_location *location); + +/** + * If the input contains a proper frame start section, parse the frame + * number, and move the input pointer after this section. Otherwise do + * not modify input. + * @returns + * The number of characters parsed from input. 0 if the input does not + * contain a frame start. + * @code + * "#1 " + * "#255 " + * @endcode + */ +int +btp_frame_parse_frame_start(char **input, unsigned *number); + +/** + * Parses C++ operator on input. + * Supports even 'operator new[]' and 'operator delete[]'. + * @param target + * The parsed operator name is appened to the string buffer provided, + * if an operator is found. Otherwise the string buffer is not + * changed. + * @returns + * The number of characters parsed from input. 0 if the input does not + * contain operator. + */ +int +btp_frame_parseadd_operator(char **input, + struct btp_strbuf *target); + +/** + * Parses a part of function name from the input. + * @param target + * Pointer to a non-allocated pointer. This function will set + * the pointer to newly allocated memory containing the name chunk, + * if it returns positive, nonzero value. + * @returns + * The number of characters parsed from input. 0 if the input does not + * contain a part of function name. + */ +int +btp_frame_parse_function_name_chunk(char **input, + bool space_allowed, + char **target); + +/** + * If the input buffer contains part of function name containing braces, + * for example "(anonymous namespace)", parse it, append the contents + * to target and move input after the braces. + * Otherwise do not modify niether the input nor the target. + * @returns + * The number of characters parsed from input. 0 if the input does not + * contain a braced part of function name. + */ +int +btp_frame_parse_function_name_braces(char **input, + char **target); + +/** + * @returns + * The number of characters parsed from input. 0 if the input does not + * contain a template part of function name. + */ +int +btp_frame_parse_function_name_template(char **input, + char **target); + +/** + * Parses the function name, which is a part of the frame header, from + * the input. If the frame header contains also the function type, + * it's also parsed. + * @param function_name + * A pointer pointing to an uninitialized pointer. This function + * allocates a string and sets the pointer to it if it parses the + * function name from the input successfully. The memory returned + * this way must be released by the caller using the function free(). + * If this function returns true, this pointer is guaranteed to be + * non-NULL. + * @param location + * The caller must provide a pointer to an instance of btp_location + * here. The line and column members of the location are gradually + * increased as the parser handles the input, so the location should + * be initialized before calling this function to get reasonable + * values. When this function returns false (an error occurred), the + * structure will contain the error line, column, and message. + * @returns + * True if the input stream contained a function name, which has been + * parsed. False otherwise. + */ +bool +btp_frame_parse_function_name(char **input, + char **function_name, + char **function_type, + struct btp_location *location); + +/** + * Skips function arguments which are a part of the frame header, in + * the input stream. + * @param location + * The caller must provide a pointer to an instance of btp_location + * here. The line and column members of the location are gradually + * increased as the parser handles the input, so the location should + * be initialized before calling this function to get reasonable + * values. When this function returns false (an error occurred), the + * structure will contain the error line, column, and message. + */ +bool +btp_frame_skip_function_args(char **input, + struct btp_location *location); + +/** + * If the input contains proper function call, parse the function + * name and store it to result, move the input pointer after whole + * function call, and return true. Otherwise do not modify the input + * and return false. + * + * If this function returns true, the caller is responsible to free + * the the function_name. + * @todo + * Parse and return the function call arguments. + * @param location + * The caller must provide a pointer to an instance of btp_location + * here. The line and column members of the location are gradually + * increased as the parser handles the input, so the location should + * be initialized before calling this function to get reasonable + * values. When this function returns false (an error occurred), the + * structure will contain the error line, column, and message. + */ +bool +btp_frame_parse_function_call(char **input, + char **function_name, + char **function_type, + struct btp_location *location); + +/** + * If the input contains address and function call, parse them, move + * the input pointer after this sequence, and return true. + * Otherwise do not modify the input and return false. + * + * If this function returns true, the caller is responsible to free + * the parameter function. + * + * @code + * 0x000000322160e7fd in fsync () + * 0x000000322222987a in write_to_temp_file ( + * filename=0x18971b0 "/home/jfclere/.recently-used.xbel", + * contents=<value optimized out>, length=29917, error=0x7fff3cbe4110) + * @endcode + * @param location + * The caller must provide a pointer to an instance of btp_location + * here. The line and column members of the location are gradually + * increased as the parser handles the input, so the location should + * be initialized before calling this function to get reasonable + * values. When this function returns false (an error occurred), the + * structure will contain the error line, column, and message. + */ +bool +btp_frame_parse_address_in_function(char **input, + uint64_t *address, + char **function_name, + char **function_type, + struct btp_location *location); + +/** + * If the input contains sequence "from path/to/file:fileline" or "at + * path/to/file:fileline", parse it, move the input pointer after this + * sequence and return true. Otherwise do not modify the input and + * return false. + * + * The ':' followed by line number is optional. If it is not present, + * the fileline is set to -1. + * @param location + * The caller must provide a pointer to an instance of btp_location + * here. The line and column members of the location are gradually + * increased as the parser handles the input, so the location should + * be initialized before calling this function to get reasonable + * values. When this function returns false (an error occurred), the + * structure will contain the error line, column, and message. + */ +bool +btp_frame_parse_file_location(char **input, + char **file, + unsigned *fileline, + struct btp_location *location); + +/** + * If the input contains proper frame header, this function + * parses the frame header text, moves the input pointer + * after the frame header, and returns a frame struct. + * If the input does not contain proper frame header, this function + * returns NULL and does not modify input. + * @param location + * The caller must provide a pointer to an instance of btp_location + * here. The line and column members of the location are gradually + * increased as the parser handles the input, so the location should + * be initialized before calling this function to get reasonable + * values. When this function returns false (an error occurred), the + * structure will contain the error line, column, and message. + * @returns + * Newly created frame struct or NULL. The returned frame struct + * should be released by btp_frame_free(). + */ +struct btp_frame * +btp_frame_parse_header(char **input, + struct btp_location *location); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/btparser/lib/location.c b/btparser/lib/location.c new file mode 100644 index 00000000..ade706f2 --- /dev/null +++ b/btparser/lib/location.c @@ -0,0 +1,78 @@ +/* + location.c + + Copyright (C) 2010 Red Hat, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ +#include "location.h" +#include <stdlib.h> /* contains NULL */ + +void +btp_location_init(struct btp_location *location) +{ + location->line = 1; + location->column = 0; + location->message = NULL; +} + +void +btp_location_add(struct btp_location *location, + int add_line, + int add_column) +{ + btp_location_add_ext(&location->line, + &location->column, + add_line, + add_column); +} + +void +btp_location_add_ext(int *line, + int *column, + int add_line, + int add_column) +{ + if (add_line > 1) + { + *line += add_line - 1; + *column = add_column; + } + else + *column += add_column; +} + +void +btp_location_eat_char(struct btp_location *location, + char c) +{ + btp_location_eat_char_ext(&location->line, + &location->column, + c); +} + +void +btp_location_eat_char_ext(int *line, + int *column, + char c) +{ + if (c == '\n') + { + *line += 1; + *column = 0; + } + else + *column += 1; +} diff --git a/btparser/lib/location.h b/btparser/lib/location.h new file mode 100644 index 00000000..0d620205 --- /dev/null +++ b/btparser/lib/location.h @@ -0,0 +1,118 @@ +/* + location.h + + Copyright (C) 2010 Red Hat, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ +#ifndef BTPARSER_LOCATION_H +#define BTPARSER_LOCATION_H + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * A location in the backtrace file with an attached message. + * It's used for error reporting: the line and the column points to + * the place where a parser error occurred, and the message explains + * what the parser expected and didn't find on that place. + */ +struct btp_location +{ + /** Starts from 1. */ + int line; + /** Starts from 0. */ + int column; + /** + * Error message related to the line and column. Do not release + * the memory this pointer points to. + */ + const char *message; +}; + +/** + * Initializes all members of the location struct to their default + * values. No memory is allocated or released by this function. + */ +void +btp_location_init(struct btp_location *location); + +/** + * Adds a line and a column to specific location. + * @note + * If the line is not 1 (meaning the first line), the column in the + * location structure is overwritten by the provided add_column value. + * Otherwise the add_column value is added to the column member of the + * location structure. + * @param location + * The structure to be modified. It must be a valid pointer. + * @param add_line + * Starts from 1. It means that if add_line is 1, the line member of the + * location structure is not changed. + * @param add_column + * Starts from 0. + */ +void +btp_location_add(struct btp_location *location, + int add_line, + int add_column); + +/** + * Adds a line column pair to another line column pair. + * @note + * If the add_line is not 1 (meaning the frist line), the column is + * overwritten by the provided add_column value. Otherwise the + * add_column value is added to the column. + * @param add_line + * Starts from 1. It means that if add_line is 1, the line is not + * changed. + * @param add_column + * Starts from 0. + */ +void +btp_location_add_ext(int *line, + int *column, + int add_line, + int add_column); + +/** + * Updates the line and column of the location by moving "after" the + * char c. If c is a newline character, the line number is increased + * and the column is set to 0. Otherwise the column is increased by 1. + */ +void +btp_location_eat_char(struct btp_location *location, + char c); + +/** + * Updates the line and the column by moving "after" the char c. If c + * is a newline character, the line number is increased and the column + * is set to 0. Otherwise the column is increased. + * @param line + * Must be a valid pointer. + * @param column + * Must be a valid pointer. + */ +void +btp_location_eat_char_ext(int *line, + int *column, + char c); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/btparser/lib/normalize.c b/btparser/lib/normalize.c new file mode 100644 index 00000000..4bbee99c --- /dev/null +++ b/btparser/lib/normalize.c @@ -0,0 +1,68 @@ +/* + normalize.c + + Copyright (C) 2010 Red Hat, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ +#include "normalize.h" +#include "frame.h" +#include "thread.h" +#include "backtrace.h" +#include <string.h> + +void +btp_normalize_thread(struct btp_thread *thread) +{ + btp_normalize_dbus_thread(thread); + btp_normalize_gdk_thread(thread); + btp_normalize_glib_thread(thread); + btp_normalize_glibc_thread(thread); + btp_normalize_libstdcpp_thread(thread); + btp_normalize_linux_thread(thread); + btp_normalize_xorg_thread(thread); + + /* If the last frame has address 0x0000 and its name is '??', + * remove it. This frame is not really invalid, and it affects + * backtrace quality rating. See Red Hat Bugzilla bug #592523. + * @code + * #2 0x00007f4dcebbd62d in clone () + * at ../sysdeps/unix/sysv/linux/x86_64/clone.S:112 + * No locals. + * #3 0x0000000000000000 in ?? () + * @endcode + */ + struct btp_frame *last = thread->frames; + while (last && last->next) + last = last->next; + if (last && + last->address == 0x0000 && + last->function_name && + 0 == strcmp(last->function_name, "??")) + { + btp_thread_remove_frame(thread, last); + } +} + +void +btp_normalize_backtrace(struct btp_backtrace *backtrace) +{ + struct btp_thread *thread = backtrace->threads; + while (thread) + { + btp_normalize_thread(thread); + thread = thread->next; + } +} diff --git a/btparser/lib/normalize.h b/btparser/lib/normalize.h new file mode 100644 index 00000000..35fd2836 --- /dev/null +++ b/btparser/lib/normalize.h @@ -0,0 +1,74 @@ +/* + normalize.h + + Copyright (C) 2010 Red Hat, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ +#ifndef BTPARSER_NORMALIZE_H +#define BTPARSER_NORMALIZE_H + +#ifdef __cplusplus +extern "C" { +#endif + +struct btp_thread; +struct btp_backtrace; + +void +btp_normalize_thread(struct btp_thread *thread); + +void +btp_normalize_backtrace(struct btp_backtrace *backtrace); + +/** + */ +void +btp_normalize_dbus_thread(struct btp_thread *thread); + +void +btp_normalize_gdk_thread(struct btp_thread *thread); + +void +btp_normalize_glib_thread(struct btp_thread *thread); + +/** + * Checks whether the thread it contains some function used to exit + * application. If a frame with the function is found, it is + * returned. If there are multiple frames with abort function, the + * lowest one is returned. + * @returns + * Returns NULL if such a frame is not found. + */ +struct btp_frame * +btp_glibc_thread_find_exit_frame(struct btp_thread *thread); + +void +btp_normalize_glibc_thread(struct btp_thread *thread); + +void +btp_normalize_libstdcpp_thread(struct btp_thread *thread); + +void +btp_normalize_linux_thread(struct btp_thread *thread); + +void +btp_normalize_xorg_thread(struct btp_thread *thread); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/btparser/lib/normalize_dbus.c b/btparser/lib/normalize_dbus.c new file mode 100644 index 00000000..d3d6a13a --- /dev/null +++ b/btparser/lib/normalize_dbus.c @@ -0,0 +1,44 @@ +/* + normalize_dbus.c + + Copyright (C) 2010 Red Hat, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ +#include "normalize.h" +#include "frame.h" +#include "thread.h" +#include <stdbool.h> + +void +btp_normalize_dbus_thread(struct btp_thread *thread) +{ + struct btp_frame *frame = thread->frames; + while (frame) + { + struct btp_frame *next_frame = frame->next; + + /* Remove frames which are not a cause of the crash. */ + bool removable = + btp_frame_calls_func_in_file(frame, "gerror_to_dbus_error_message", "dbus-gobject.c") || + btp_frame_calls_func_in_file(frame, "dbus_g_method_return_error", "dbus-gobject.c"); + if (removable) + { + btp_thread_remove_frame(thread, frame); + } + + frame = next_frame; + } +} diff --git a/btparser/lib/normalize_gdk.c b/btparser/lib/normalize_gdk.c new file mode 100644 index 00000000..e9c4ef6a --- /dev/null +++ b/btparser/lib/normalize_gdk.c @@ -0,0 +1,44 @@ +/* + normalize_gdk.c + + Copyright (C) 2010 Red Hat, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ +#include "normalize.h" +#include "frame.h" +#include "thread.h" +#include <stdbool.h> + +void +btp_normalize_gdk_thread(struct btp_thread *thread) +{ + struct btp_frame *frame = thread->frames; + while (frame) + { + struct btp_frame *next_frame = frame->next; + + /* Remove frames which are not a cause of the crash. */ + bool removable = + btp_frame_calls_func_in_file(frame, "gdk_x_error", "gdkmain-x11.c"); + + if (removable) + { + btp_thread_remove_frame(thread, frame); + } + + frame = next_frame; + } +} diff --git a/btparser/lib/normalize_glib.c b/btparser/lib/normalize_glib.c new file mode 100644 index 00000000..b5c12b60 --- /dev/null +++ b/btparser/lib/normalize_glib.c @@ -0,0 +1,60 @@ +/* + normalize_glib.c + + Copyright (C) 2010 Red Hat, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ +#include "normalize.h" +#include "frame.h" +#include "thread.h" +#include "utils.h" +#include <stdbool.h> +#include <string.h> + +void +btp_normalize_glib_thread(struct btp_thread *thread) +{ + struct btp_frame *frame = thread->frames; + while (frame) + { + struct btp_frame *next_frame = frame->next; + + /* Normalize frame names. */ + if (frame->function_name && + 0 == strncmp(frame->function_name, "IA__g_", strlen("IA__g_"))) + { + /* Remove the IA__ prefix. The strcpy function cannot be + * used for that because the source and destination + * pointers overlap. */ + char *p = frame->function_name; + while ((*p = p[4]) != '\0') + ++p; + } + + /* Remove frames which are not a cause of the crash. */ + bool removable = + btp_frame_calls_func_in_file2(frame, "g_log", "gmessages.c", "libglib") || + btp_frame_calls_func_in_file2(frame, "g_logv", "gmessages.c", "libglib") || + btp_frame_calls_func_in_file2(frame, "g_assertion_message", "gtestutils.c", "libglib") || + btp_frame_calls_func_in_file2(frame, "g_assertion_message_expr", "gtestutils.c", "libglib"); + if (removable) + { + btp_thread_remove_frame(thread, frame); + } + + frame = next_frame; + } +} diff --git a/btparser/lib/normalize_glibc.c b/btparser/lib/normalize_glibc.c new file mode 100644 index 00000000..ea40ba9d --- /dev/null +++ b/btparser/lib/normalize_glibc.c @@ -0,0 +1,120 @@ +/* + normalize_glibc.c + + Copyright (C) 2010 Red Hat, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ +#include "normalize.h" +#include "frame.h" +#include "thread.h" +#include "utils.h" +#include <string.h> +#include <stdlib.h> +#include <assert.h> + +struct btp_frame * +btp_glibc_thread_find_exit_frame(struct btp_thread *thread) +{ + struct btp_frame *frame = thread->frames; + struct btp_frame *result = NULL; + while (frame) + { + bool is_exit_frame = + btp_frame_calls_func_in_file(frame, "__run_exit_handlers", "exit.c") || + btp_frame_calls_func_in_file4(frame, "raise", "pt-raise.c", "libc.so", "libc-", "libpthread.so") || + btp_frame_calls_func_in_file(frame, "exit", "exit.c") || + btp_frame_calls_func_in_file3(frame, "abort", "abort.c", "libc.so", "libc-") || + /* Terminates a function in case of buffer overflow. */ + btp_frame_calls_func_in_file2(frame, "__chk_fail", "chk_fail.c", "libc.so"); + + if (is_exit_frame) + result = frame; + + frame = frame->next; + } + + return result; +} + + +void +btp_normalize_glibc_thread(struct btp_thread *thread) +{ + /* Find the exit frame and remove everything above it. */ + struct btp_frame *exit_frame = btp_glibc_thread_find_exit_frame(thread); + if (exit_frame) + { + bool success = btp_thread_remove_frames_above(thread, exit_frame); + assert(success); /* if this fails, some code become broken */ + success = btp_thread_remove_frame(thread, exit_frame); + assert(success); /* if this fails, some code become broken */ + } + + /* Standard function filtering loop. */ + struct btp_frame *frame = thread->frames; + while (frame) + { + struct btp_frame *next_frame = frame->next; + + /* Normalize frame names. */ +#define NORMALIZE_ARCH_SPECIFIC(func) \ + if (btp_frame_calls_func_in_file2(frame, "__" func "_sse2", func ".S", "libc.so") || \ + btp_frame_calls_func_in_file2(frame, "__" func "_ssse3", func ".S", "libc.so") || \ + btp_frame_calls_func_in_file2(frame, "__" func "_ia32", func ".S", "libc.so")) \ + { \ + strcpy(frame->function_name, func); \ + } + + NORMALIZE_ARCH_SPECIFIC("memchr"); + NORMALIZE_ARCH_SPECIFIC("memcmp"); + NORMALIZE_ARCH_SPECIFIC("memcpy"); + NORMALIZE_ARCH_SPECIFIC("memset"); + NORMALIZE_ARCH_SPECIFIC("rawmemchr"); + NORMALIZE_ARCH_SPECIFIC("strcat"); + NORMALIZE_ARCH_SPECIFIC("strchr"); + NORMALIZE_ARCH_SPECIFIC("strchrnul"); + NORMALIZE_ARCH_SPECIFIC("strcmp"); + NORMALIZE_ARCH_SPECIFIC("strcpy"); + NORMALIZE_ARCH_SPECIFIC("strcspn"); + NORMALIZE_ARCH_SPECIFIC("strlen"); + NORMALIZE_ARCH_SPECIFIC("strncmp"); + NORMALIZE_ARCH_SPECIFIC("strpbrk"); + NORMALIZE_ARCH_SPECIFIC("strrchr"); + NORMALIZE_ARCH_SPECIFIC("strspn"); + NORMALIZE_ARCH_SPECIFIC("strtok"); + + /* Remove frames which are not a cause of the crash. */ + bool removable = + btp_frame_calls_func(frame, "__assert_fail") || + btp_frame_calls_func(frame, "__strcat_chk") || + btp_frame_calls_func(frame, "__strcpy_chk") || + btp_frame_calls_func(frame, "__strncpy_chk") || + btp_frame_calls_func(frame, "__vsnprintf_chk") || + btp_frame_calls_func(frame, "___vsnprintf_chk") || + btp_frame_calls_func(frame, "__snprintf_chk") || + btp_frame_calls_func(frame, "___snprintf_chk") || + btp_frame_calls_func(frame, "__vasprintf_chk"); + if (removable) + { + bool success = btp_thread_remove_frames_above(thread, frame); + assert(success); + success = btp_thread_remove_frame(thread, frame); + assert(success); + } + + frame = next_frame; + } +} diff --git a/btparser/lib/normalize_libstdcpp.c b/btparser/lib/normalize_libstdcpp.c new file mode 100644 index 00000000..1f833ded --- /dev/null +++ b/btparser/lib/normalize_libstdcpp.c @@ -0,0 +1,46 @@ +/* + normalize_libstdcpp.c + + Copyright (C) 2010 Red Hat, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ +#include "normalize.h" +#include "frame.h" +#include "thread.h" +#include <stdbool.h> + +void +btp_normalize_libstdcpp_thread(struct btp_thread *thread) +{ + struct btp_frame *frame = thread->frames; + while (frame) + { + struct btp_frame *next_frame = frame->next; + + /* Remove frames which are not a cause of the crash. */ + bool removable = + btp_frame_calls_func_in_file(frame, "__gnu_cxx::__verbose_terminate_handler", "vterminate.cc") || + btp_frame_calls_func_in_file(frame, "__cxxabiv1::__terminate", "eh_terminate.cc") || + btp_frame_calls_func_in_file(frame, "std::terminate", "eh_terminate.cc") || + btp_frame_calls_func_in_file(frame, "__cxxabiv1::__cxa_throw", "eh_throw.cc"); + if (removable) + { + btp_thread_remove_frame(thread, frame); + } + + frame = next_frame; + } +} diff --git a/btparser/lib/normalize_linux.c b/btparser/lib/normalize_linux.c new file mode 100644 index 00000000..8df9f9c2 --- /dev/null +++ b/btparser/lib/normalize_linux.c @@ -0,0 +1,41 @@ +/* + normalize_linux.c + + Copyright (C) 2010 Red Hat, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ +#include "normalize.h" +#include "utils.h" +#include "frame.h" +#include "thread.h" +#include <stdbool.h> + +void +btp_normalize_linux_thread(struct btp_thread *thread) +{ + struct btp_frame *frame = thread->frames; + while (frame) + { + struct btp_frame *next_frame = frame->next; + + /* Remove frames which are not a cause of the crash. */ + bool removable = btp_frame_calls_func(frame, "__kernel_vsyscall"); + if (removable) + btp_thread_remove_frame(thread, frame); + + frame = next_frame; + } +} diff --git a/btparser/lib/normalize_xorg.c b/btparser/lib/normalize_xorg.c new file mode 100644 index 00000000..11e8d624 --- /dev/null +++ b/btparser/lib/normalize_xorg.c @@ -0,0 +1,46 @@ +/* + normalize_xorg.c + + Copyright (C) 2010 Red Hat, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ +#include "normalize.h" +#include "frame.h" +#include "thread.h" +#include <stdbool.h> + +void +btp_normalize_xorg_thread(struct btp_thread *thread) +{ + struct btp_frame *frame = thread->frames; + while (frame) + { + struct btp_frame *next_frame = frame->next; + + /* Remove frames which are not a cause of the crash. */ + bool removable = + btp_frame_calls_func_in_file(frame, "_XReply", "xcb_io.c") || + btp_frame_calls_func_in_file(frame, "_XError", "XlibInt.c") || + btp_frame_calls_func_in_file(frame, "XSync", "Sync.c") || + btp_frame_calls_func_in_file(frame, "process_responses", "xcb_io.c"); + if (removable) + { + btp_thread_remove_frame(thread, frame); + } + + frame = next_frame; + } +} diff --git a/btparser/lib/strbuf.c b/btparser/lib/strbuf.c new file mode 100644 index 00000000..43d834fd --- /dev/null +++ b/btparser/lib/strbuf.c @@ -0,0 +1,151 @@ +/* + strbuf.c - string buffer + + Copyright (C) 2010 Red Hat, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ +#include "strbuf.h" +#include "utils.h" +#include <stdlib.h> +#include <stdio.h> +#include <assert.h> +#include <string.h> +#include <stdarg.h> + +struct btp_strbuf * +btp_strbuf_new() +{ + struct btp_strbuf *buf = btp_malloc(sizeof(struct btp_strbuf)); + buf->alloc = 8; + buf->len = 0; + buf->buf = btp_malloc(buf->alloc); + buf->buf[buf->len] = '\0'; + return buf; +} + +void +btp_strbuf_free(struct btp_strbuf *strbuf) +{ + if (!strbuf) + return; + + free(strbuf->buf); + free(strbuf); +} + +char * +btp_strbuf_free_nobuf(struct btp_strbuf *strbuf) +{ + char *buf = strbuf->buf; + free(strbuf); + return buf; +} + + +void +btp_strbuf_clear(struct btp_strbuf *strbuf) +{ + assert(strbuf->alloc > 0); + strbuf->len = 0; + strbuf->buf[0] = '\0'; +} + +/* Ensures that the buffer can be extended by num characters + * without touching malloc/realloc. + */ +void +btp_strbuf_grow(struct btp_strbuf *strbuf, int num) +{ + if (strbuf->len + num + 1 > strbuf->alloc) + { + while (strbuf->len + num + 1 > strbuf->alloc) + strbuf->alloc *= 2; /* huge grow = infinite loop */ + + strbuf->buf = realloc(strbuf->buf, strbuf->alloc); + if (!strbuf->buf) + { + puts("Error while allocating memory for string buffer."); + exit(5); + } + } +} + +struct btp_strbuf * +btp_strbuf_append_char(struct btp_strbuf *strbuf, + char c) +{ + btp_strbuf_grow(strbuf, 1); + strbuf->buf[strbuf->len++] = c; + strbuf->buf[strbuf->len] = '\0'; + return strbuf; +} + +struct btp_strbuf * +btp_strbuf_append_str(struct btp_strbuf *strbuf, + const char *str) +{ + int len = strlen(str); + btp_strbuf_grow(strbuf, len); + assert(strbuf->len + len < strbuf->alloc); + strcpy(strbuf->buf + strbuf->len, str); + strbuf->len += len; + return strbuf; +} + +struct btp_strbuf * +btp_strbuf_prepend_str(struct btp_strbuf *strbuf, + const char *str) +{ + int len = strlen(str); + btp_strbuf_grow(strbuf, len); + assert(strbuf->len + len < strbuf->alloc); + memmove(strbuf->buf + len, strbuf->buf, strbuf->len + 1); + memcpy(strbuf->buf, str, len); + strbuf->len += len; + return strbuf; +} + +struct btp_strbuf * +btp_strbuf_append_strf(struct btp_strbuf *strbuf, + const char *format, ...) +{ + va_list p; + char *string_ptr; + + va_start(p, format); + string_ptr = btp_vasprintf(format, p); + va_end(p); + + btp_strbuf_append_str(strbuf, string_ptr); + free(string_ptr); + return strbuf; +} + +struct btp_strbuf * +btp_strbuf_prepend_strf(struct btp_strbuf *strbuf, + const char *format, ...) +{ + va_list p; + char *string_ptr; + + va_start(p, format); + string_ptr = btp_vasprintf(format, p); + va_end(p); + + btp_strbuf_prepend_str(strbuf, string_ptr); + free(string_ptr); + return strbuf; +} diff --git a/btparser/lib/strbuf.h b/btparser/lib/strbuf.h new file mode 100644 index 00000000..d8503e02 --- /dev/null +++ b/btparser/lib/strbuf.h @@ -0,0 +1,124 @@ +/* + strbuf.h - a string buffer + + Copyright (C) 2010 Red Hat, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ +#ifndef BTPARSER_STRBUF_H +#define BTPARSER_STRBUF_H + +#ifdef __cplusplus +extern "C" { +#endif + +struct btp_strbuf +{ + /** + * Size of the allocated buffer. Always > 0. + */ + int alloc; + /** + * Length of the string, without the ending \0. + */ + int len; + char *buf; +}; + +/** + * Creates and initializes a new string buffer. + * @returns + * It never returns NULL. The returned pointer must be released by + * calling the function btp_strbuf_free(). + */ +struct btp_strbuf * +btp_strbuf_new(); + +/** + * Releases the memory held by the string buffer. + * @param strbuf + * If the strbuf is NULL, no operation is performed. + */ +void +btp_strbuf_free(struct btp_strbuf *strbuf); + +/** + * Releases the strbuf, but not the internal buffer. The internal + * string buffer is returned. Caller is responsible to release the + * returned memory using free(). + */ +char * +btp_strbuf_free_nobuf(struct btp_strbuf *strbuf); + +/** + * The string content is set to an empty string, erasing any previous + * content and leaving its length at 0 characters. + */ +void +btp_strbuf_clear(struct btp_strbuf *strbuf); + +/** + * Ensures that the buffer can be extended by num characters + * without dealing with malloc/realloc. + */ +void +btp_strbuf_grow(struct btp_strbuf *strbuf, int num); + +/** + * The current content of the string buffer is extended by adding a + * character c at its end. + */ +struct btp_strbuf * +btp_strbuf_append_char(struct btp_strbuf *strbuf, + char c); + +/** + * The current content of the string buffer is extended by adding a + * string str at its end. + */ +struct btp_strbuf * +btp_strbuf_append_str(struct btp_strbuf *strbuf, + const char *str); + +/** + * The current content of the string buffer is extended by inserting a + * string str at its beginning. + */ +struct btp_strbuf * +btp_strbuf_prepend_str(struct btp_strbuf *strbuf, + const char *str); + +/** + * The current content of the string buffer is extended by adding a + * sequence of data formatted as the format argument specifies. + */ +struct btp_strbuf * +btp_strbuf_append_strf(struct btp_strbuf *strbuf, + const char *format, ...); + +/** + * The current content of the string buffer is extended by inserting a + * sequence of data formatted as the format argument specifies at the + * buffer beginning. + */ +struct btp_strbuf * +btp_strbuf_prepend_strf(struct btp_strbuf *strbuf, + const char *format, ...); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/btparser/lib/thread.c b/btparser/lib/thread.c new file mode 100644 index 00000000..1a7f715e --- /dev/null +++ b/btparser/lib/thread.c @@ -0,0 +1,364 @@ +/* + thread.c + + Copyright (C) 2010 Red Hat, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ +#include "thread.h" +#include "frame.h" +#include "strbuf.h" +#include "utils.h" +#include "location.h" +#include <stdlib.h> +#include <string.h> +#include <assert.h> + +struct btp_thread * +btp_thread_new() +{ + struct btp_thread *thread = btp_malloc(sizeof(struct btp_thread)); + btp_thread_init(thread); + return thread; +} + +void +btp_thread_init(struct btp_thread *thread) +{ + thread->number = -1; + thread->frames = NULL; + thread->next = NULL; +} + +void +btp_thread_free(struct btp_thread *thread) +{ + if (!thread) + return; + + while (thread->frames) + { + struct btp_frame *rm = thread->frames; + thread->frames = rm->next; + btp_frame_free(rm); + } + + free(thread); +} + +struct btp_thread * +btp_thread_dup(struct btp_thread *thread, bool siblings) +{ + struct btp_thread *result = btp_thread_new(); + memcpy(result, thread, sizeof(struct btp_thread)); + + /* Handle siblings. */ + if (siblings) + { + if (result->next) + result->next = btp_thread_dup(result->next, true); + } + else + result->next = NULL; /* Do not copy that. */ + + result->frames = btp_frame_dup(result->frames, true); + + return result; +} + +int +btp_thread_cmp(struct btp_thread *t1, struct btp_thread *t2) +{ + int number = t1->number - t2->number; + if (number != 0) + return number; + struct btp_frame *f1 = t1->frames, *f2 = t2->frames; + do { + if (f1 && !f2) + return 1; + else if (f2 && !f1) + return -1; + else if (f1 && f2) + { + int frames = btp_frame_cmp(f1, f2, true); + if (frames != 0) + return frames; + f1 = f1->next; + f2 = f2->next; + } + } while (f1 || f2); + + return 0; +} + +struct btp_thread * +btp_thread_add_sibling(struct btp_thread *a, struct btp_thread *b) +{ + struct btp_thread *aa = a; + while (aa->next) + aa = aa->next; + + aa->next = b; + return a; +} + +int +btp_thread_get_frame_count(struct btp_thread *thread) +{ + struct btp_frame *frame = thread->frames; + int count = 0; + while (frame) + { + frame = frame->next; + ++count; + } + return count; +} + +void +btp_thread_quality_counts(struct btp_thread *thread, + int *ok_count, + int *all_count) +{ + struct btp_frame *frame = thread->frames; + while (frame) + { + *all_count += 1; + if (frame->signal_handler_called || + (frame->function_name + && 0 != strcmp(frame->function_name, "??"))) + { + *ok_count += 1; + } + frame = frame->next; + } +} + +float +btp_thread_quality(struct btp_thread *thread) +{ + int ok_count = 0, all_count = 0; + btp_thread_quality_counts(thread, &ok_count, &all_count); + if (0 == all_count) + return 1; + return ok_count/(float)all_count; +} + +bool +btp_thread_remove_frame(struct btp_thread *thread, + struct btp_frame *frame) +{ + struct btp_frame *loop_frame = thread->frames, *prev_frame = NULL; + while (loop_frame) + { + if (loop_frame == frame) + { + if (prev_frame) + prev_frame->next = loop_frame->next; + else + thread->frames = loop_frame->next; + + btp_frame_free(loop_frame); + return true; + } + prev_frame = loop_frame; + loop_frame = loop_frame->next; + } + return false; +} + +bool +btp_thread_remove_frames_above(struct btp_thread *thread, + struct btp_frame *frame) +{ + /* Check that the frame is present in the thread. */ + struct btp_frame *loop_frame = thread->frames; + while (loop_frame) + { + if (loop_frame == frame) + break; + loop_frame = loop_frame->next; + } + + if (!loop_frame) + return false; + + /* Delete all the frames up to the frame. */ + while (thread->frames != frame) + { + loop_frame = thread->frames->next; + btp_frame_free(thread->frames); + thread->frames = loop_frame; + } + + return true; +} + +void +btp_thread_remove_frames_below_n(struct btp_thread *thread, + int n) +{ + assert(n >= 0); + + /* Skip some frames to get the required stack depth. */ + int i = n; + struct btp_frame *frame = thread->frames, *last_frame = NULL; + while (frame && i) + { + last_frame = frame; + frame = frame->next; + --i; + } + + /* Delete the remaining frames. */ + if (last_frame) + last_frame->next = NULL; + else + thread->frames = NULL; + + while (frame) + { + struct btp_frame *delete_frame = frame; + frame = frame->next; + btp_frame_free(delete_frame); + } +} + +void +btp_thread_append_to_str(struct btp_thread *thread, + struct btp_strbuf *str, + bool verbose) +{ + int framecount = btp_thread_get_frame_count(thread); + if (verbose) + { + btp_strbuf_append_strf(str, "Thread no. %d (%d frames)\n", + thread->number, framecount); + } + else + btp_strbuf_append_str(str, "Thread\n"); + + struct btp_frame *frame = thread->frames; + while (frame) + { + btp_frame_append_to_str(frame, str, verbose); + frame = frame->next; + } +} + +struct btp_thread * +btp_thread_parse(char **input, + struct btp_location *location) +{ + char *local_input = *input; + + /* Read the Thread keyword, which is mandatory. */ + int chars = btp_skip_string(&local_input, "Thread"); + location->column += chars; + if (0 == chars) + { + location->message = "\"Thread\" header expected"; + return NULL; + } + + /* Skip spaces, at least one space is mandatory. */ + int spaces = btp_skip_char_sequence(&local_input, ' '); + location->column += spaces; + if (0 == spaces) + { + location->message = "Space expected after the \"Thread\" keyword."; + return NULL; + } + + /* Read thread number. */ + struct btp_thread *imthread = btp_thread_new(); + int digits = btp_parse_unsigned_integer(&local_input, &imthread->number); + location->column += digits; + if (0 == digits) + { + location->message = "Thread number expected."; + btp_thread_free(imthread); + return NULL; + } + + /* Skip spaces after the thread number and before the parenthesis. */ + spaces = btp_skip_char_sequence(&local_input, ' '); + location->column += spaces; + if (0 == spaces) + { + location->message = "Space expected after the thread number."; + btp_thread_free(imthread); + return NULL; + } + + /* Read the Thread keyword in parenthesis, which is mandatory. */ + chars = btp_skip_string(&local_input, "(Thread "); + location->column += chars; + if (0 == chars) + { + location->message = "Thread keyword in the parenthesis expected in the form '(Thread '."; + btp_thread_free(imthread); + return NULL; + } + + /* Read the thread identification number. */ + digits = btp_skip_unsigned_integer(&local_input); + location->column += digits; + if (0 == digits) + { + location->message = "The thread identification number expected."; + btp_thread_free(imthread); + return NULL; + } + + /* Read the end of the parenthesis. */ + chars = btp_skip_string(&local_input, "):\n"); + if (0 == chars) + { + location->message = "The end of the parenthesis expected in the form of '):\\n'."; + btp_thread_free(imthread); + return NULL; + } + /* Add the newline from the last btp_skip_string. */ + btp_location_add(location, 2, 0); + + /* Read the frames. */ + struct btp_frame *frame, *prevframe = NULL; + struct btp_location frame_location; + btp_location_init(&frame_location); + while ((frame = btp_frame_parse(&local_input, &frame_location))) + { + if (prevframe) + { + btp_frame_add_sibling(prevframe, frame); + prevframe = frame; + } + else + imthread->frames = prevframe = frame; + + btp_location_add(location, + frame_location.line, + frame_location.column); + } + if (!imthread->frames) + { + location->message = frame_location.message; + btp_thread_free(imthread); + return NULL; + } + + *input = local_input; + return imthread; +} diff --git a/btparser/lib/thread.h b/btparser/lib/thread.h new file mode 100644 index 00000000..b9f0973d --- /dev/null +++ b/btparser/lib/thread.h @@ -0,0 +1,204 @@ +/* + thread.h + + Copyright (C) 2010 Red Hat, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ +#ifndef BTPARSER_THREAD_H +#define BTPARSER_THREAD_H + +#include <stdbool.h> + +#ifdef __cplusplus +extern "C" { +#endif + +struct btp_frame; +struct btp_strbuf; +struct btp_location; + +/** + * Represents a thread containing frames. + */ +struct btp_thread +{ + unsigned number; + /** + * Thread's frames, starting from the top of the stack. + */ + struct btp_frame *frames; + /** + * A sibling thread, or NULL if this is the last thread in a backtrace. + */ + struct btp_thread *next; +}; + +/** + * Creates and initializes a new frame structure. + * @returns + * It never returns NULL. The returned pointer must be released by + * calling the function btp_thread_free(). + */ +struct btp_thread * +btp_thread_new(); + +/** + * Initializes all members of the thread to default values. + * No memory is released, members are simply overwritten. + * This is useful for initializing a thread structure placed on the + * stack. + */ +void +btp_thread_init(struct btp_thread *thread); + +/** + * Releases the memory held by the thread. The thread siblings are not + * released. + * @param thread + * If thread is NULL, no operation is performed. + */ +void +btp_thread_free(struct btp_thread *thread); + +/** + * Creates a duplicate of the thread. + * @param thread + * It must be non-NULL pointer. The thread is not modified by calling + * this function. + * @param siblings + * Whether to duplicate also siblings referenced by thread->next. If + * false, thread->next is not duplicated for the new frame, but it is + * set to NULL. + */ +struct btp_thread * +btp_thread_dup(struct btp_thread *thread, + bool siblings); + +/** + * Compares two threads. When comparing the threads, it compares also + * their frames, including the frame numbers. + * @returns + * Returns 0 if the threads are same. Returns negative number if t1 + * is found to be 'less' than t2. Returns positive number if t1 is + * found to be 'greater' than t2. + */ +int +btp_thread_cmp(struct btp_thread *t1, struct btp_thread *t2); + +/** + * Puts the thread 'b' to the bottom of the stack 'a'. In other words, + * it finds the last sibling of the thread 'a', and appends the thread + * 'b' to this last sibling. + */ +struct btp_thread * +btp_thread_add_sibling(struct btp_thread *a, struct btp_thread *b); + +/** + * Returns the number of frames of the thread. + */ +int +btp_thread_get_frame_count(struct btp_thread *thread); + +/** + * Counts the number of 'good' frames and the number of all frames in + * a thread. Good means that the function name is known (so it's not + * just '??'). + * @param ok_count + * @param all_count + * Not zeroed. This function just adds the numbers to ok_count and + * all_count. + */ +void +btp_thread_quality_counts(struct btp_thread *thread, + int *ok_count, + int *all_count); + +/** + * Returns the quality of the thread. The quality is the ratio of the + * number of frames with function name fully known to the number of + * all frames. This function does not take into account that some + * frames are more important than others. + * @param thread + * Must be a non-NULL pointer. It's not modified in this function. + * @returns + * A number between 0 and 1. 0 means the lowest quality, 1 means full + * thread backtrace is known. If the thread contains no frames, this + * function returns 1. + */ +float +btp_thread_quality(struct btp_thread *thread); + +/** + * Removes the frame from the thread and then deletes it. + * @returns + * True if the frame was found in the thread and removed and deleted. + * False if the frame was not found in the thread. + */ +bool +btp_thread_remove_frame(struct btp_thread *thread, + struct btp_frame *frame); + +/** + * Removes all the frames from the thread that are above certain + * frame. + * @returns + * True if the frame was found, and all the frames that were above the + * frame in the thread were removed from the thread and then deleted. + * False if the frame was not found in the thread. + */ +bool +btp_thread_remove_frames_above(struct btp_thread *thread, + struct btp_frame *frame); + +/** + * Keeps only the top n frames in the thread. + */ +void +btp_thread_remove_frames_below_n(struct btp_thread *thread, + int n); + +/** + * Appends a textual representation of 'thread' to the 'str'. + */ +void +btp_thread_append_to_str(struct btp_thread *thread, + struct btp_strbuf *str, + bool verbose); + +/** + * If the input contains proper thread with frames, parse the thread, + * move the input pointer after the thread, and return a structure + * representing the thread. Otherwise to not modify the input pointer + * and return NULL. + * @param location + * The caller must provide a pointer to struct btp_location here. The + * line and column members are gradually increased as the parser + * handles the input, keep this in mind to get reasonable values. + * When this function returns NULL (an error occurred), the structure + * will contain the error line, column, and message. + * @returns + * NULL or newly allocated structure, which should be released by + * calling btp_thread_free(). + */ +struct btp_thread * +btp_thread_parse(char **input, + struct btp_location *location); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/btparser/lib/utils.c b/btparser/lib/utils.c new file mode 100644 index 00000000..1de329a7 --- /dev/null +++ b/btparser/lib/utils.c @@ -0,0 +1,423 @@ +/* + utils.c + + Copyright (C) 2010 Red Hat, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ +#include "utils.h" +#include "location.h" +#include <stdio.h> +#include <string.h> +#include <errno.h> +#include <regex.h> +#include <limits.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <unistd.h> +#include <fcntl.h> + +bool btp_debug_parser = false; + +void * +btp_malloc(size_t size) +{ + void *ptr = malloc(size); + if (ptr == NULL) + { + fprintf(stderr, "btp: out of memory"); + exit(1); + } + return ptr; +} + +char * +btp_vasprintf(const char *format, va_list p) +{ + int r; + char *string_ptr; + +#if 1 + // GNU extension + r = vasprintf(&string_ptr, format, p); +#else + // Bloat for systems that haven't got the GNU extension. + va_list p2; + va_copy(p2, p); + r = vsnprintf(NULL, 0, format, p); + string_ptr = xmalloc(r+1); + r = vsnprintf(string_ptr, r+1, format, p2); + va_end(p2); +#endif + + if (r < 0) + { + fprintf(stderr, "btp: out of memory"); + exit(1); + } + + return string_ptr; +} + +char * +btp_strdup(const char *s) +{ + return btp_strndup(s, strlen(s)); +} + +char * +btp_strndup(const char *s, size_t n) +{ + char *result = strndup(s, n); + if (result == NULL) + { + fprintf(stderr, "btp: out of memory"); + exit(1); + } + return result; +} + +int +btp_strcmp0(const char *s1, const char *s2) +{ + if (!s1) + { + if (s2) + return -1; + return 0; + } + else + { + if (!s2) + return 1; + /* Both are non-null. */ + return strcmp(s1, s2); + } +} + +char * +btp_strchr_location(const char *s, int c, int *line, int *column) +{ + *line = 1; + *column = 0; + + /* Scan s for the character. When this loop is finished, + s will either point to the end of the string or the + character we were looking for. */ + while (*s != '\0' && *s != (char)c) + { + btp_location_eat_char_ext(line, column, *s); + ++s; + } + return ((*s == c) ? (char*)s : NULL); +} + +char * +btp_strstr_location(const char *haystack, + const char *needle, + int *line, + int *column) +{ + *line = 1; + *column = 0; + size_t needlelen; + + /* Check for the null needle case. */ + if (*needle == '\0') + return (char*)haystack; + + needlelen = strlen(needle); + int chrline, chrcolumn; + for (;(haystack = btp_strchr_location(haystack, *needle, &chrline, &chrcolumn)) != NULL; ++haystack) + { + btp_location_add_ext(line, column, chrline, chrcolumn); + + if (strncmp(haystack, needle, needlelen) == 0) + return (char*)haystack; + + btp_location_eat_char_ext(line, column, *haystack); + } + return NULL; +} + +size_t +btp_strspn_location(const char *s, + const char *accept, + int *line, + int *column) +{ + *line = 1; + *column = 0; + const char *sc; + for (sc = s; *sc != '\0'; ++sc) + { + if (strchr(accept, *sc) == NULL) + return (sc - s); + + btp_location_eat_char_ext(line, column, *sc); + } + return sc - s; /* terminating nulls don't match */ +} + +char * +btp_file_to_string(const char *filename) +{ + /* Open input file, and parse it. */ + int fd = open(filename, O_RDONLY | O_LARGEFILE); + if (fd < 0) + { + fprintf(stderr, "Unable to open '%s': %s.\n", + filename, strerror(errno)); + return NULL; + } + + off_t size = lseek(fd, 0, SEEK_END); + if (size < 0) /* EOVERFLOW? */ + { + fprintf(stderr, "Unable to seek in '%s': %s.\n", + filename, strerror(errno)); + } + + lseek(fd, 0, SEEK_SET); /* No reason to fail. */ + + static const size_t FILE_SIZE_LIMIT = 20000000; /* ~ 20 MB */ + if (size > FILE_SIZE_LIMIT) + { + fprintf(stderr, "Input file too big (%lld). Maximum size is %zd.\n", + (long long)size, FILE_SIZE_LIMIT); + close(fd); + return NULL; + } + + char *contents = btp_malloc(size + 1); + if (size != read(fd, contents, size)) + { + fprintf(stderr, "Unable to read from '%s'.\n", filename); + close(fd); + free(contents); + return NULL; + } + + /* Just reading, so no need to check the returned value. */ + close(fd); + + contents[size] = '\0'; + return contents; +} + +bool +btp_skip_char(char **input, char c) +{ + if (**input != c) + return false; + ++*input; + return true; +} + +bool +btp_skip_char_limited(char **input, const char *allowed) +{ + if (strchr(allowed, **input) == NULL) + return false; + ++*input; + return true; +} + +bool +btp_parse_char_limited(char **input, const char *allowed, char *result) +{ + if (**input == '\0') + return false; + if (strchr(allowed, **input) == NULL) + return false; + *result = **input; + ++*input; + return true; +} + +int +btp_skip_char_sequence(char **input, char c) +{ + int count = 0; + + /* Skip all the occurences of c. */ + while (btp_skip_char(input, c)) + ++count; + + return count; +} + +int +btp_skip_char_span(char **input, const char *chars) +{ + size_t count = strspn(*input, chars); + if (0 == count) + return count; + *input += count; + return count; +} + +int +btp_skip_char_span_location(char **input, + const char *chars, + int *line, + int *column) +{ + size_t count = btp_strspn_location(*input, chars, line, column); + if (0 == count) + return count; + *input += count; + return count; +} + +int +btp_parse_char_span(char **input, const char *accept, char **result) +{ + size_t count = strspn(*input, accept); + if (count == 0) + return 0; + *result = btp_strndup(*input, count); + *input += count; + return count; +} + +bool +btp_parse_char_cspan(char **input, const char *reject, char **result) +{ + size_t count = strcspn(*input, reject); + if (count == 0) + return false; + *result = btp_strndup(*input, count); + *input += count; + return true; +} + +int +btp_skip_string(char **input, const char *string) +{ + char *local_input = *input; + const char *local_string = string; + while (*local_string && *local_input && *local_input == *local_string) + { + ++local_input; + ++local_string; + } + if (*local_string != '\0') + return 0; + int count = local_input - *input; + *input = local_input; + return count; +} + +bool +btp_parse_string(char **input, const char *string, char **result) +{ + char *local_input = *input; + const char *local_string = string; + while (*local_string && *local_input && *local_input == *local_string) + { + ++local_input; + ++local_string; + } + if (*local_string != '\0') + return false; + *result = btp_strndup(string, local_input - *input); + *input = local_input; + return true; +} + +char +btp_parse_digit(char **input) +{ + char digit = **input; + if (digit < '0' || digit > '9') + return '\0'; + ++*input; + return digit; +} + +int +btp_skip_unsigned_integer(char **input) +{ + return btp_skip_char_span(input, "0123456789"); +} + +int +btp_parse_unsigned_integer(char **input, unsigned *result) +{ + char *local_input = *input; + char *numstr; + int length = btp_parse_char_span(&local_input, + "0123456789", + &numstr); + if (0 == length) + return 0; + + char *endptr; + errno = 0; + unsigned long r = strtoul(numstr, &endptr, 10); + bool failure = (errno || numstr == endptr || *endptr != '\0' + || r > UINT_MAX); + free(numstr); + if (failure) /* number too big or some other error */ + return 0; + *result = r; + *input = local_input; + return length; +} + +int +btp_skip_hexadecimal_number(char **input) +{ + char *local_input = *input; + if (!btp_skip_char(&local_input, '0')) + return 0; + if (!btp_skip_char(&local_input, 'x')) + return 0; + int count = 2; + count += btp_skip_char_span(&local_input, "abcdef0123456789"); + if (2 == count) /* btp_skip_char_span returned 0 */ + return 0; + *input = local_input; + return count; +} + +int +btp_parse_hexadecimal_number(char **input, uint64_t *result) +{ + char *local_input = *input; + if (!btp_skip_char(&local_input, '0')) + return 0; + if (!btp_skip_char(&local_input, 'x')) + return 0; + int count = 2; + char *numstr; + count += btp_parse_char_span(&local_input, + "abcdef0123456789", + &numstr); + + if (2 == count) /* btp_parse_char_span returned 0 */ + return 0; + char *endptr; + errno = 0; + unsigned long long r = strtoull(numstr, &endptr, 16); + bool failure = (errno || numstr == endptr || *endptr != '\0'); + free(numstr); + if (failure) /* number too big or some other error */ + return 0; + *result = r; + *input = local_input; + return count; +} diff --git a/btparser/lib/utils.h b/btparser/lib/utils.h new file mode 100644 index 00000000..680e67e0 --- /dev/null +++ b/btparser/lib/utils.h @@ -0,0 +1,284 @@ +/* + utils.h + + Copyright (C) 2010 Red Hat, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ +#ifndef BTPARSER_UTILS_H +#define BTPARSER_UTILS_H + +#include <stdlib.h> +#include <stdarg.h> +#include <stdbool.h> +#include <stdint.h> + +#ifdef __cplusplus +extern "C" { +#endif + +#define BTP_lower "abcdefghijklmnopqrstuvwxyz" +#define BTP_upper "ABCDEFGHIJKLMNOPQRSTUVWXYZ" +#define BTP_alpha BTP_lower BTP_upper +#define BTP_space " \t\r\n\v\f" +#define BTP_digit "0123456789" +#define BTP_alnum BTP_alpha BTP_digit + +/** + * Debugging output to stdout while parsing. + * Default value is false. + */ +extern bool +btp_debug_parser; + +/** + * Never returns NULL. + */ +void * +btp_malloc(size_t size); + +/** + * Never returns NULL. + */ +char * +btp_vasprintf(const char *format, va_list p); + +/** + * Never returns NULL. + */ +char * +btp_strdup(const char *s); + +/** + * Never returns NULL. + */ +char * +btp_strndup(const char *s, size_t n); + +/** + * A strcmp() variant that works also with NULL parameters. NULL is + * considered to be less than a string. + */ +int +btp_strcmp0(const char *s1, const char *s2); + +/** + * A strchr() variant providing line and column in the string s + * indicating where the char c was found. + * @param line + * Starts from 1. Its value is valid only when this function does not + * return NULL. + * @param column + * Starts from 0. Its value is valid only when this function does not + * return NULL. + */ +char * +btp_strchr_location(const char *s, int c, int *line, int *column); + +/** + * A strstr() variant providing line and column of the haystick + * indicating where the needle was found. + * @param line + * Starts from 1. Its value is valid only when this function does not + * return NULL. + * @param column + * Starts from 0. Its value is valid only when this function does not + * return NULL. + */ +char * +btp_strstr_location(const char *haystack, + const char *needle, + int *line, + int *column); + +/** + * A strspn() variant providing line and column of the string s which + * corresponds to the returned length. + * @param line + * Starts from 1. + * @param column + * Starts from 0. + */ +size_t +btp_strspn_location(const char *s, + const char *accept, + int *line, + int *column); + +/** + * Loads file contents to a string. + * @returns + * File contents. If file opening/reading fails, NULL is returned. + */ +char * +btp_file_to_string(const char *filename); + +/** + * If the input contains character c in the current positon, move the + * input pointer after the character, and return true. Otherwise do + * not modify the input and return false. + */ +bool +btp_skip_char(char **input, char c); + +/** + * If the input contains one of allowed characters, move + * the input pointer after that character, and return true. + * Otherwise do not modify the input and return false. + */ +bool +btp_skip_char_limited(char **input, const char *allowed); + +/** + * If the input contains one of allowed characters, store + * the character to the result, move the input pointer after + * that character, and return true. Otherwise do not modify + * the input and return false. + */ +bool +btp_parse_char_limited(char **input, const char *allowed, char *result); + +/** + * If the input contains the character c one or more times, update it + * so that the characters are skipped. Returns the number of characters + * skipped, thus zero if **input does not contain c. + */ +int +btp_skip_char_sequence(char **input, char c); + +/** + * If the input contains one or more characters from string chars, + * move the input pointer after the sequence. Otherwise do not modify + * the input. + * @returns + * The number of characters skipped. + */ +int +btp_skip_char_span(char **input, const char *chars); + +/** + * If the input contains one or more characters from string chars, + * move the input pointer after the sequence. Otherwise do not modify + * the input. + * @param line + * Starts from 1. Corresponds to the returned number. + * @param column + * Starts from 0. Corresponds to the returned number. + * @returns + * The number of characters skipped. + */ +int +btp_skip_char_span_location(char **input, + const char *chars, + int *line, + int *column); + +/** + * If the input contains one or more characters from string accept, + * create a string from this sequence and store it to the result, move + * the input pointer after the sequence, and return the lenght of the + * sequence. Otherwise do not modify the input and return 0. + * + * If this function returns nonzero value, the caller is responsible + * to free the result. + */ +int +btp_parse_char_span(char **input, const char *accept, char **result); + +/** + * If the input contains characters which are not in string reject, + * create a string from this sequence and store it to the result, + * move the input pointer after the sequence, and return true. + * Otherwise do not modify the input and return false. + * + * If this function returns true, the caller is responsible to + * free the result. + */ +bool +btp_parse_char_cspan(char **input, const char *reject, char **result); + +/** + * If the input contains the string, move the input pointer after + * the sequence. Otherwise do not modify the input. + * @returns + * Number of characters skipped. 0 if the input does not contain the + * string. + */ +int +btp_skip_string(char **input, const char *string); + +/** + * If the input contains the string, copy the string to result, + * move the input pointer after the string, and return true. + * Otherwise do not modify the input and return false. + * + * If this function returns true, the caller is responsible to free + * the result. + */ +bool +btp_parse_string(char **input, const char *string, char **result); + +/** + * If the input contains digit 0-9, return it as a character + * and move the input pointer after it. Otherwise return + * '\0' and do not modify the input. + */ +char +btp_parse_digit(char **input); + +/** + * If the input contains [0-9]+, move the input pointer + * after the number. + * @returns + * The number of skipped characters. 0 if input does not start with a + * digit. + */ +int +btp_skip_unsigned_integer(char **input); + +/** + * If the input contains [0-9]+, parse it, move the input pointer + * after the number. + * @returns + * Number of parsed characters. 0 if input does not contain a number. + */ +int +btp_parse_unsigned_integer(char **input, unsigned *result); + +/** + * If the input contains 0x[0-9a-f]+, move the input pointer + * after that. + * @returns + * The number of characters processed from input. 0 if the input does + * not contain a hexadecimal number. + */ +int +btp_skip_hexadecimal_number(char **input); + +/** + * If the input contains 0x[0-9a-f]+, parse the number, and move the + * input pointer after it. Otherwise do not modify the input. + * @returns + * The number of characters read from input. 0 if the input does not + * contain a hexadecimal number. + */ +int +btp_parse_hexadecimal_number(char **input, uint64_t *result); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/btparser/tests/Makefile.am b/btparser/tests/Makefile.am new file mode 100644 index 00000000..bc8be638 --- /dev/null +++ b/btparser/tests/Makefile.am @@ -0,0 +1,60 @@ +EXTRA_DIST = backtraces + +## ------------ ## +## package.m4. ## +## ------------ ## + +package.m4: Makefile.in + { \ + echo '# Signature of the current package.' && \ + echo 'm4_define([AT_PACKAGE_NAME],' && \ + echo ' [@PACKAGE_NAME@])' && \ + echo 'm4_define([AT_PACKAGE_TARNAME],' && \ + echo ' [@PACKAGE_TARNAME@])' && \ + echo 'm4_define([AT_PACKAGE_VERSION],' && \ + echo ' [@PACKAGE_VERSION@])' && \ + echo 'm4_define([AT_PACKAGE_STRING],' && \ + echo ' [@PACKAGE_STRING@])' && \ + echo 'm4_define([AT_PACKAGE_BUGREPORT],' && \ + echo ' [@PACKAGE_BUGREPORT@])'; \ + echo 'm4_define([AT_PACKAGE_URL],' && \ + echo ' [@PACKAGE_URL@])'; \ + } >'package.m4' +EXTRA_DIST += package.m4 + +## ------------ ## +## Test suite. ## +## ------------ ## + +TESTSUITE_AT = \ + local.at \ + testsuite.at \ + utils.at \ + strbuf.at \ + frame.at \ + thread.at \ + backtrace.at + +EXTRA_DIST += $(TESTSUITE_AT) +TESTSUITE = $(srcdir)/testsuite +MAINTAINERCLEANFILES = Makefile.in $(TESTSUITE) +check_DATA = atconfig atlocal $(TESTSUITE) +DISTCLEANFILES = atconfig +EXTRA_DIST += atlocal.in + +atconfig: $(top_builddir)/config.status + (cd ${top_builddir} && ./config.status ${subdir}/atconfig) + +check-local: $(check_DATA) + $(SHELL) '$(TESTSUITE)' $(TESTSUITEFLAGS) ||: + +installcheck-local: $(check_DATA) + $(SHELL) '$(TESTSUITE)' AUTOTEST_PATH='$(bindir)' $(TESTSUITEFLAGS) ||: + +clean-local: + test ! -f '$(TESTSUITE)' || $(SHELL) '$(TESTSUITE)' --clean + +AUTOTEST = $(AUTOM4TE) --language=autotest +$(TESTSUITE): $(TESTSUITE_AT) $(srcdir)/package.m4 + $(AUTOTEST) -I '$(srcdir)' -o $@.tmp $@.at + mv $@.tmp $@ diff --git a/btparser/tests/atlocal.in b/btparser/tests/atlocal.in new file mode 100644 index 00000000..856e5fec --- /dev/null +++ b/btparser/tests/atlocal.in @@ -0,0 +1,15 @@ +# @configure_input@ -*- shell-script -*- +# Configurable variable values for btparser test suite. + +# We need a C compiler. +CC='@CC@' +LIBTOOL="$abs_top_builddir/libtool" + +# We want no optimization. +CFLAGS="@O0CFLAGS@ -I$abs_top_builddir -D_GNU_SOURCE" + +# Are special link options needed? +LDFLAGS="@LDFLAGS@ $abs_top_builddir/lib/libbtparser.la" + +# Are special libraries needed? +LIBS="@LIBS@" diff --git a/btparser/tests/backtrace.at b/btparser/tests/backtrace.at new file mode 100644 index 00000000..057d2e63 --- /dev/null +++ b/btparser/tests/backtrace.at @@ -0,0 +1,152 @@ +# Checking the btparser. -*- Autotest -*- + +AT_BANNER([Backtraces]) + +## --------------------------------------- ## +## btp_backtrace_remove_threads_except_one ## +## --------------------------------------- ## +AT_TESTFUN([btp_backtrace_remove_threads_except_one], +[[ +#include <lib/backtrace.h> +#include <lib/thread.h> +#include <assert.h> +#include <stdlib.h> + +int main(void) +{ + /* Delete the thread except the middle one. */ + struct btp_thread *thread2 = btp_thread_new(); + struct btp_thread *thread1 = btp_thread_new(); + thread1->next = thread2; + struct btp_thread *thread0 = btp_thread_new(); + thread0->next = thread1; + struct btp_backtrace *backtrace = btp_backtrace_new(); + backtrace->threads = thread0; + btp_backtrace_remove_threads_except_one(backtrace, thread1); + assert(backtrace->threads == thread1); + assert(NULL == backtrace->threads->next); + + /* Delete all threads except one when there is only one. */ + btp_backtrace_remove_threads_except_one(backtrace, thread1); + assert(backtrace->threads == thread1); + assert(NULL == backtrace->threads->next); + + /* Delete all threads except the first one. */ + thread0 = btp_thread_new(); + backtrace->threads = thread0; + thread0->next = thread1; // already exists + thread2 = btp_thread_new(); + thread1->next = thread2; + btp_backtrace_remove_threads_except_one(backtrace, thread0); + assert(backtrace->threads == thread0); + assert(NULL == backtrace->threads->next); + + /* Delete all threads except the last one. */ + thread1 = btp_thread_new(); + thread0->next = thread1; + thread2 = btp_thread_new(); + thread1->next = thread2; + btp_backtrace_remove_threads_except_one(backtrace, thread2); + assert(backtrace->threads == thread2); + assert(NULL == backtrace->threads->next); + + btp_backtrace_free(backtrace); + return 0; +} +]]) + +## ------------------------------- ## +## btp_backtrace_find_crash_thread ## +## ------------------------------- ## +AT_TESTFUN([btp_backtrace_find_crash_thread], +[ +#include <lib/backtrace.h> +#include <lib/thread.h> +#include <lib/frame.h> +#include <lib/location.h> +#include <lib/utils.h> +#include <assert.h> + +int main(void) +{ + /* Load the backtrace from Red Hat Bugzilla bug #621492. */ + struct btp_location location; + btp_location_init(&location); + char *full_input = btp_file_to_string("../../backtraces/621492.bt"); + assert(full_input); + char *input = full_input; + struct btp_backtrace *backtrace = btp_backtrace_parse(&input, &location); + assert(backtrace); + + /* Check that the crash thread is found. */ + struct btp_thread *crash_thread = btp_backtrace_find_crash_thread(backtrace); + assert(crash_thread); + assert(0 == strcmp(crash_thread->frames->function_name, "raise")); + btp_backtrace_free(backtrace); + return 0; +} +]) + +## ------------------------------- ## +## btp_backtrace_limit_frame_depth ## +## ------------------------------- ## +AT_TESTFUN([btp_backtrace_limit_frame_depth], +[[ +#include <lib/backtrace.h> +#include <lib/thread.h> +#include <lib/location.h> +#include <lib/utils.h> +#include <assert.h> + +int main(void) +{ + /* Load the backtrace from Red Hat Bugzilla bug #621492. */ + struct btp_location location; + btp_location_init(&location); + char *full_input = btp_file_to_string("../../backtraces/621492.bt"); + assert(full_input); + char *input = full_input; + struct btp_backtrace *backtrace = btp_backtrace_parse(&input, &location); + assert(backtrace); + + /* Check the frame depth limit. */ + btp_backtrace_limit_frame_depth(backtrace, 5); + assert(11 == btp_backtrace_get_thread_count(backtrace)); + struct btp_thread *thread = backtrace->threads; + while (thread) + { + assert(5 == btp_thread_get_frame_count(thread)); + thread = thread->next; + } + + btp_backtrace_free(backtrace); + return 0; +} +]]) + +## ----------------------------- ## +## btp_backtrace_quality_complex ## +## ----------------------------- ## +AT_TESTFUN([btp_backtrace_quality_complex], +[[ +#include <lib/backtrace.h> +#include <lib/thread.h> +#include <lib/location.h> +#include <lib/utils.h> +#include <assert.h> + +int main(void) +{ + /* Load the backtrace from Red Hat Bugzilla bug #621492. */ + struct btp_location location; + btp_location_init(&location); + char *full_input = btp_file_to_string("../../backtraces/621492.bt"); + assert(full_input); + char *input = full_input; + struct btp_backtrace *backtrace = btp_backtrace_parse(&input, &location); + assert(backtrace); + assert(1.0f == btp_backtrace_quality_complex(backtrace)); + btp_backtrace_free(backtrace); + return 0; +} +]]) diff --git a/btparser/tests/backtraces/621492.bt b/btparser/tests/backtraces/621492.bt new file mode 100644 index 00000000..f1e5404e --- /dev/null +++ b/btparser/tests/backtraces/621492.bt @@ -0,0 +1,2668 @@ +[New Thread 19947] +[New Thread 19948] +[New Thread 19949] +[New Thread 19955] +[New Thread 19962] +[New Thread 19963] +[New Thread 21889] +[New Thread 19950] +[New Thread 19951] +[New Thread 19961] +[New Thread 19965] +Core was generated by `/usr/lib64/thunderbird-3.1/thunderbird-bin'. +Program terminated with signal 11, Segmentation fault. +#0 0x0000003848c0f30b in raise (sig=<value optimized out>) + at ../nptl/sysdeps/unix/sysv/linux/pt-raise.c:42 +42 ../nptl/sysdeps/unix/sysv/linux/pt-raise.c: No such file or directory. + in ../nptl/sysdeps/unix/sysv/linux/pt-raise.c + +Thread 11 (Thread 19965): +#0 0x00000038484d7de3 in __poll (fds=<value optimized out>, + nfds=<value optimized out>, timeout=<value optimized out>) + at ../sysdeps/unix/sysv/linux/poll.c:87 + __arg2 = 2 + _a3 = -1 + _a1 = 140258994637568 + resultvar = <value optimized out> + __arg3 = 72197854784913407 + __arg1 = 140258994637568 + _a2 = 2 + resultvar = <value optimized out> + oldtype = 0 + result = <value optimized out> +#1 0x00007f90879e4c0f in poll_func (ufds=0x7f90978d4b00, nfds=2, timeout=-1, + userdata=0x7f908807ec70) at pulse/thread-mainloop.c:75 + mutex = 0x7f908807ec70 + r = -1752347904 + __func__ = "poll_func" + __PRETTY_FUNCTION__ = "poll_func" +#2 0x00007f90879d4ae6 in pa_mainloop_poll (m=0x7f9088088200) + at pulse/mainloop.c:879 + __func__ = "pa_mainloop_poll" + __PRETTY_FUNCTION__ = "pa_mainloop_poll" +#3 0x00007f90879d5ec9 in pa_mainloop_iterate (m=0x7f9088088200, + block=<value optimized out>, retval=0x0) at pulse/mainloop.c:961 + r = 0 + __func__ = "pa_mainloop_iterate" + __PRETTY_FUNCTION__ = "pa_mainloop_iterate" +#4 0x00007f90879d5f80 in pa_mainloop_run (m=0x7f9088088200, retval=0x0) + at pulse/mainloop.c:979 + r = <value optimized out> +#5 0x00007f90879e4a0b in thread (userdata=0x7f908807ec10) + at pulse/thread-mainloop.c:94 + mask = {__val = {18446744067267100671, + 18446744073709551615 <repeats 15 times>}} +#6 0x00007f90877a1878 in internal_thread_func (userdata=0x7f9088049380) + at pulsecore/thread-posix.c:72 + t = 0x7f9088049380 + __func__ = "internal_thread_func" + __PRETTY_FUNCTION__ = "internal_thread_func" +#7 0x0000003848c07761 in start_thread (arg=0x7f9082edf710) + at pthread_create.c:301 + __res = <value optimized out> + pd = 0x7f9082edf710 + now = <value optimized out> + unwind_buf = {cancel_jmp_buf = {{jmp_buf = {140258648651536, + -555364893392092215, 241738781088, 140258648652240, 0, 3, + 534792876637569993, -560026272429489207}, + mask_was_saved = 0}}, priv = {pad = {0x0, 0x0, 0x0, 0x0}, + data = {prev = 0x0, cleanup = 0x0, canceltype = 0}}} + not_first_call = <value optimized out> + sp = <value optimized out> + freesize = <value optimized out> +#8 0x00000038484e14ed in clone () + at ../sysdeps/unix/sysv/linux/x86_64/clone.S:115 +No locals. + +Thread 10 (Thread 19961): +#0 pthread_cond_wait@@GLIBC_2.3.2 () + at ../nptl/sysdeps/unix/sysv/linux/x86_64/pthread_cond_wait.S:162 +No locals. +#1 0x0000003858c23cce in PR_WaitCondVar (cvar=0x7f9097c6f600, + timeout=4294967295) + at ../../../mozilla/nsprpub/pr/src/pthreads/ptsynch.c:417 + rv = <value optimized out> + thred = 0x7f908baa5780 +#2 0x00007f908aa93fd5 in nsSSLThread::Run (this=0x7f9097c6f5c0) + at /usr/src/debug/thunderbird-3.1.1/comm-1.9.2/mozilla/security/manager/ssl/src/nsSSLThread.cpp:980 + threadLock = {<nsAutoLockBase> = {<No data fields>}, + mLock = 0x7f9097c80a80, mLocked = 1} + pending_work = 0 + busy_socket_ssl_state = <value optimized out> + needToSetPollableEvent = <value optimized out> + socketToDestroy = 0x0 +#3 0x0000003858c29843 in _pt_root (arg=0x7f908baa5780) + at ../../../mozilla/nsprpub/pr/src/pthreads/ptthread.c:228 + thred = 0x7f908baa5780 + detached = 0 +#4 0x0000003848c07761 in start_thread (arg=0x7f909932a710) + at pthread_create.c:301 + __res = <value optimized out> + pd = 0x7f909932a710 + now = <value optimized out> + unwind_buf = {cancel_jmp_buf = {{jmp_buf = {140259022251792, + -555364893392092215, 140734046858640, 140259022252496, 0, 3, + 534733149211739081, -560026272429489207}, + mask_was_saved = 0}}, priv = {pad = {0x0, 0x0, 0x0, 0x0}, + data = {prev = 0x0, cleanup = 0x0, canceltype = 0}}} + not_first_call = <value optimized out> + sp = <value optimized out> + freesize = <value optimized out> +#5 0x00000038484e14ed in clone () + at ../sysdeps/unix/sysv/linux/x86_64/clone.S:115 +No locals. + +Thread 9 (Thread 19951): +#0 pthread_cond_timedwait@@GLIBC_2.3.2 () + at ../nptl/sysdeps/unix/sysv/linux/x86_64/pthread_cond_timedwait.S:212 +No locals. +#1 0x0000003858c23049 in pt_TimedWait (cv=0x7f90a82fbd88, ml=0x7f90a82f7320, + timeout=658) at ../../../mozilla/nsprpub/pr/src/pthreads/ptsynch.c:292 + rv = <value optimized out> + now = {tv_sec = 1281000337, tv_usec = 584686} + tmo = {tv_sec = 1281000338, tv_nsec = 242686000} + ticks = <value optimized out> +#2 0x0000003858c23c2c in PR_WaitCondVar (cvar=0x7f90a82fbd80, timeout=658) + at ../../../mozilla/nsprpub/pr/src/pthreads/ptsynch.c:419 + rv = <value optimized out> + thred = 0x7f90a8212360 +#3 0x0000003139a6fbea in TimerThread::Run (this=0x7f90a8222440) + at /usr/src/debug/thunderbird-3.1.1/comm-1.9.2/mozilla/xpcom/threads/TimerThread.cpp:344 + waitFor = <value optimized out> + lock = {<nsAutoLockBase> = {<No data fields>}, + mLock = 0x7f90a82f7320, mLocked = 1} +#4 0x0000003139a6c765 in nsThread::ProcessNextEvent (this=0x7f90a0a9caa0, + mayWait=1, result=0x7f909bbfebdc) + at /usr/src/debug/thunderbird-3.1.1/comm-1.9.2/mozilla/xpcom/threads/nsThread.cpp:527 + event = {<nsCOMPtr_base> = { + mRawPtr = 0x7f90a8222440}, <No data fields>} + notifyGlobalObserver = 1 + obs = {<nsCOMPtr_base> = {mRawPtr = 0x0}, <No data fields>} + rv = 0 +#5 0x0000003139a3db88 in NS_ProcessNextEvent_P ( + thread=<value optimized out>, mayWait=<value optimized out>) + at nsThreadUtils.cpp:250 + val = 1 +#6 0x0000003139a6ce3b in nsThread::ThreadFunc (arg=0x7f90a0a9caa0) + at /usr/src/debug/thunderbird-3.1.1/comm-1.9.2/mozilla/xpcom/threads/nsThread.cpp:254 + self = 0x7f90a0a9caa0 + event = {<nsCOMPtr_base> = {mRawPtr = 0x0}, <No data fields>} +#7 0x0000003858c29843 in _pt_root (arg=0x7f90a8212360) + at ../../../mozilla/nsprpub/pr/src/pthreads/ptthread.c:228 + thred = 0x7f90a8212360 + detached = 0 +#8 0x0000003848c07761 in start_thread (arg=0x7f909bbff710) + at pthread_create.c:301 + __res = <value optimized out> + pd = 0x7f909bbff710 + now = <value optimized out> + unwind_buf = {cancel_jmp_buf = {{jmp_buf = {140259065067280, + -555364893392092215, 140734046875760, 140259065067984, 0, 3, + 534738605430817737, -560026272429489207}, + mask_was_saved = 0}}, priv = {pad = {0x0, 0x0, 0x0, 0x0}, + data = {prev = 0x0, cleanup = 0x0, canceltype = 0}}} + not_first_call = <value optimized out> + sp = <value optimized out> + freesize = <value optimized out> +#9 0x00000038484e14ed in clone () + at ../sysdeps/unix/sysv/linux/x86_64/clone.S:115 +No locals. + +Thread 8 (Thread 19950): +#0 pthread_cond_timedwait@@GLIBC_2.3.2 () + at ../nptl/sysdeps/unix/sysv/linux/x86_64/pthread_cond_timedwait.S:212 +No locals. +#1 0x0000003858c23049 in pt_TimedWait (cv=0x7f90a0ef59c8, ml=0x7f90a0a16e20, + timeout=0) at ../../../mozilla/nsprpub/pr/src/pthreads/ptsynch.c:292 + rv = <value optimized out> + now = {tv_sec = 1281000336, tv_usec = 939599} + tmo = {tv_sec = 1281000337, tv_nsec = 939599000} + ticks = <value optimized out> +#2 0x0000003858c23c2c in PR_WaitCondVar (cvar=0x7f90a0ef59c0, timeout=1000) + at ../../../mozilla/nsprpub/pr/src/pthreads/ptsynch.c:419 + rv = <value optimized out> + thred = 0x7f90a8211ae0 +#3 0x00007f909e7f6657 in XPCJSRuntime::WatchdogMain (arg=0x7f90a0a2ac00) + at /usr/src/debug/thunderbird-3.1.1/comm-1.9.2/mozilla/js/src/xpconnect/src/xpcjsruntime.cpp:808 + cx = <value optimized out> + self = 0x7f90a0a2ac00 + lock = {mJSRuntime = 0x7f90a0ee0000} +#4 0x0000003858c29843 in _pt_root (arg=0x7f90a8211ae0) + at ../../../mozilla/nsprpub/pr/src/pthreads/ptthread.c:228 + thred = 0x7f90a8211ae0 + detached = 1 +#5 0x0000003848c07761 in start_thread (arg=0x7f909ddbd710) + at pthread_create.c:301 + __res = <value optimized out> + pd = 0x7f909ddbd710 + now = <value optimized out> + unwind_buf = {cancel_jmp_buf = {{jmp_buf = {140259100448528, + -555364893392092215, 140734046874544, 140259100449232, 0, 3, + 534742145557611465, -560026272429489207}, + mask_was_saved = 0}}, priv = {pad = {0x0, 0x0, 0x0, 0x0}, + data = {prev = 0x0, cleanup = 0x0, canceltype = 0}}} + not_first_call = <value optimized out> + sp = <value optimized out> + freesize = <value optimized out> +#6 0x00000038484e14ed in clone () + at ../sysdeps/unix/sysv/linux/x86_64/clone.S:115 +No locals. + +Thread 7 (Thread 21889): +#0 pthread_cond_timedwait@@GLIBC_2.3.2 () + at ../nptl/sysdeps/unix/sysv/linux/x86_64/pthread_cond_timedwait.S:212 +No locals. +#1 0x0000003858c23049 in pt_TimedWait (cv=0x7f90a0e68e88, ml=0x7f90a0a168a0, + timeout=0) at ../../../mozilla/nsprpub/pr/src/pthreads/ptsynch.c:292 + rv = <value optimized out> + now = {tv_sec = 1281000208, tv_usec = 213698} + tmo = {tv_sec = 1281000508, tv_nsec = 213698000} + ticks = <value optimized out> +#2 0x0000003858c23c2c in PR_WaitCondVar (cvar=0x7f90a0e68e80, timeout=300000) + at ../../../mozilla/nsprpub/pr/src/pthreads/ptsynch.c:419 + rv = <value optimized out> + thred = 0x7f9081cd1040 +#3 0x00007f909fd4f15f in nsHostResolver::GetHostToLookup ( + this=0x7f90a0e67700, result=0x7f9089ad3bf8) + at /usr/src/debug/thunderbird-3.1.1/comm-1.9.2/mozilla/netwerk/dns/src/nsHostResolver.cpp:773 + epoch = 1099954005 + timeout = 300000 + timedOut = <value optimized out> + now = <value optimized out> + lock = {<nsAutoLockBase> = {<No data fields>}, + mLock = 0x7f90a0a168a0, mLocked = 1} +#4 0x00007f909fd4fa24 in nsHostResolver::ThreadFunc (arg=0x7f90a0e67700) + at /usr/src/debug/thunderbird-3.1.1/comm-1.9.2/mozilla/netwerk/dns/src/nsHostResolver.cpp:877 + rs = {mLastReset = 1099039833} + resolver = 0x7f90a0e67700 + rec = 0x7f9088b50f00 + ai = <value optimized out> +#5 0x0000003858c29843 in _pt_root (arg=0x7f9081cd1040) + at ../../../mozilla/nsprpub/pr/src/pthreads/ptthread.c:228 + thred = 0x7f9081cd1040 + detached = 1 +#6 0x0000003848c07761 in start_thread (arg=0x7f9089ad4710) + at pthread_create.c:301 + __res = <value optimized out> + pd = 0x7f9089ad4710 + now = <value optimized out> + unwind_buf = {cancel_jmp_buf = {{jmp_buf = {140258761852688, + -555364893392092215, 140259133114112, 140258761853392, 0, 3, + 534769230158250953, -560026272429489207}, + mask_was_saved = 0}}, priv = {pad = {0x0, 0x0, 0x0, 0x0}, + data = {prev = 0x0, cleanup = 0x0, canceltype = 0}}} + not_first_call = <value optimized out> + sp = <value optimized out> + freesize = <value optimized out> +#7 0x00000038484e14ed in clone () + at ../sysdeps/unix/sysv/linux/x86_64/clone.S:115 +No locals. + +Thread 6 (Thread 19963): +#0 pthread_cond_wait@@GLIBC_2.3.2 () + at ../nptl/sysdeps/unix/sysv/linux/x86_64/pthread_cond_wait.S:162 +No locals. +#1 0x0000003858c23cce in PR_WaitCondVar (cvar=0x7f9097c6f680, + timeout=4294967295) + at ../../../mozilla/nsprpub/pr/src/pthreads/ptsynch.c:417 + rv = <value optimized out> + thred = 0x7f908baa59a0 +#2 0x0000003858c23d46 in PR_Wait (mon=0x7f908ba8f570, + timeout=<value optimized out>) + at ../../../mozilla/nsprpub/pr/src/pthreads/ptsynch.c:601 + rv = -512 + saved_entries = 1 + saved_owner = 140258929596176 +#3 0x0000003139a6bb17 in Wait (this=0x7f908af9b980, mayWait=1, + result=0x7f9093accb70) at ../../dist/include/nsAutoLock.h:340 +No locals. +#4 nsEventQueue::GetEvent (this=0x7f908af9b980, mayWait=1, + result=0x7f9093accb70) + at /usr/src/debug/thunderbird-3.1.1/comm-1.9.2/mozilla/xpcom/threads/nsEventQueue.cpp:85 + mon = {<nsAutoLockBase> = {<No data fields>}, + mMonitor = 0x7f908ba8f570, mLockCount = 1} +#5 0x0000003139a6c748 in GetEvent (this=0x7f908af9b940, mayWait=1, + result=0x7f9093accbdc) + at /usr/src/debug/thunderbird-3.1.1/comm-1.9.2/mozilla/xpcom/threads/nsThread.h:112 +No locals. +#6 nsThread::ProcessNextEvent (this=0x7f908af9b940, mayWait=1, + result=0x7f9093accbdc) + at /usr/src/debug/thunderbird-3.1.1/comm-1.9.2/mozilla/xpcom/threads/nsThread.cpp:521 + event = {<nsCOMPtr_base> = {mRawPtr = 0x0}, <No data fields>} + notifyGlobalObserver = 1 + obs = {<nsCOMPtr_base> = {mRawPtr = 0x0}, <No data fields>} + rv = 0 +#7 0x0000003139a3db88 in NS_ProcessNextEvent_P ( + thread=<value optimized out>, mayWait=<value optimized out>) + at nsThreadUtils.cpp:250 + val = 1 +#8 0x0000003139a6ce3b in nsThread::ThreadFunc (arg=0x7f908af9b940) + at /usr/src/debug/thunderbird-3.1.1/comm-1.9.2/mozilla/xpcom/threads/nsThread.cpp:254 + self = 0x7f908af9b940 + event = {<nsCOMPtr_base> = {mRawPtr = 0x0}, <No data fields>} +#9 0x0000003858c29843 in _pt_root (arg=0x7f908baa59a0) + at ../../../mozilla/nsprpub/pr/src/pthreads/ptthread.c:228 + thred = 0x7f908baa59a0 + detached = 0 +#10 0x0000003848c07761 in start_thread (arg=0x7f9093acd710) + at pthread_create.c:301 + __res = <value optimized out> + pd = 0x7f9093acd710 + now = <value optimized out> + unwind_buf = {cancel_jmp_buf = {{jmp_buf = {140258929596176, + -555364893392092215, 140734046859216, 140258929596880, 0, 3, + 534756052661715913, -560026272429489207}, + mask_was_saved = 0}}, priv = {pad = {0x0, 0x0, 0x0, 0x0}, + data = {prev = 0x0, cleanup = 0x0, canceltype = 0}}} + not_first_call = <value optimized out> + sp = <value optimized out> + freesize = <value optimized out> +#11 0x00000038484e14ed in clone () + at ../sysdeps/unix/sysv/linux/x86_64/clone.S:115 +No locals. + +Thread 5 (Thread 19962): +#0 pthread_cond_wait@@GLIBC_2.3.2 () + at ../nptl/sysdeps/unix/sysv/linux/x86_64/pthread_cond_wait.S:162 +No locals. +#1 0x0000003858c23cce in PR_WaitCondVar (cvar=0x7f9097c6f640, + timeout=4294967295) + at ../../../mozilla/nsprpub/pr/src/pthreads/ptsynch.c:417 + rv = <value optimized out> + thred = 0x7f908baa5890 +#2 0x00007f908aa94de2 in nsCertVerificationThread::Run (this=0x7f908af9b8b0) + at /usr/src/debug/thunderbird-3.1.1/comm-1.9.2/mozilla/security/manager/ssl/src/nsCertVerificationThread.cpp:138 + threadLock = {<nsAutoLockBase> = {<No data fields>}, + mLock = 0x7f9097c80b30, mLocked = 1} + job = 0x0 +#3 0x0000003858c29843 in _pt_root (arg=0x7f908baa5890) + at ../../../mozilla/nsprpub/pr/src/pthreads/ptthread.c:228 + thred = 0x7f908baa5890 + detached = 0 +#4 0x0000003848c07761 in start_thread (arg=0x7f90926cb710) + at pthread_create.c:301 + __res = <value optimized out> + pd = 0x7f90926cb710 + now = <value optimized out> + unwind_buf = {cancel_jmp_buf = {{jmp_buf = {140258908616464, + -555364893392092215, 140734046858640, 140258908617168, 0, 3, + 534756599196304329, -560026272429489207}, + mask_was_saved = 0}}, priv = {pad = {0x0, 0x0, 0x0, 0x0}, + data = {prev = 0x0, cleanup = 0x0, canceltype = 0}}} + not_first_call = <value optimized out> + sp = <value optimized out> + freesize = <value optimized out> +#5 0x00000038484e14ed in clone () + at ../sysdeps/unix/sysv/linux/x86_64/clone.S:115 +No locals. + +Thread 4 (Thread 19955): +#0 pthread_cond_wait@@GLIBC_2.3.2 () + at ../nptl/sysdeps/unix/sysv/linux/x86_64/pthread_cond_wait.S:162 +No locals. +#1 0x0000003858c23cce in PR_WaitCondVar (cvar=0x7f90983d9b40, + timeout=4294967295) + at ../../../mozilla/nsprpub/pr/src/pthreads/ptsynch.c:417 + rv = <value optimized out> + thred = 0x7f9098866120 +#2 0x0000003858c23d46 in PR_Wait (mon=0x7f9097d48de0, + timeout=<value optimized out>) + at ../../../mozilla/nsprpub/pr/src/pthreads/ptsynch.c:601 + rv = -512 + saved_entries = 1 + saved_owner = 140258919106320 +#3 0x0000003139a6bb17 in Wait (this=0x7f9097b69420, mayWait=1, + result=0x7f90930cbb70) at ../../dist/include/nsAutoLock.h:340 +No locals. +#4 nsEventQueue::GetEvent (this=0x7f9097b69420, mayWait=1, + result=0x7f90930cbb70) + at /usr/src/debug/thunderbird-3.1.1/comm-1.9.2/mozilla/xpcom/threads/nsEventQueue.cpp:85 + mon = {<nsAutoLockBase> = {<No data fields>}, + mMonitor = 0x7f9097d48de0, mLockCount = 1} +#5 0x0000003139a6c748 in GetEvent (this=0x7f9097b693e0, mayWait=1, + result=0x7f90930cbbdc) + at /usr/src/debug/thunderbird-3.1.1/comm-1.9.2/mozilla/xpcom/threads/nsThread.h:112 +No locals. +#6 nsThread::ProcessNextEvent (this=0x7f9097b693e0, mayWait=1, + result=0x7f90930cbbdc) + at /usr/src/debug/thunderbird-3.1.1/comm-1.9.2/mozilla/xpcom/threads/nsThread.cpp:521 + event = {<nsCOMPtr_base> = {mRawPtr = 0x0}, <No data fields>} + notifyGlobalObserver = 1 + obs = {<nsCOMPtr_base> = {mRawPtr = 0x0}, <No data fields>} + rv = 0 +#7 0x0000003139a3db88 in NS_ProcessNextEvent_P ( + thread=<value optimized out>, mayWait=<value optimized out>) + at nsThreadUtils.cpp:250 + val = 1 +#8 0x0000003139a6ce3b in nsThread::ThreadFunc (arg=0x7f9097b693e0) + at /usr/src/debug/thunderbird-3.1.1/comm-1.9.2/mozilla/xpcom/threads/nsThread.cpp:254 + self = 0x7f9097b693e0 + event = {<nsCOMPtr_base> = {mRawPtr = 0x0}, <No data fields>} +#9 0x0000003858c29843 in _pt_root (arg=0x7f9098866120) + at ../../../mozilla/nsprpub/pr/src/pthreads/ptthread.c:228 + thred = 0x7f9098866120 + detached = 0 +#10 0x0000003848c07761 in start_thread (arg=0x7f90930cc710) + at pthread_create.c:301 + __res = <value optimized out> + pd = 0x7f90930cc710 + now = <value optimized out> + unwind_buf = {cancel_jmp_buf = {{jmp_buf = {140258919106320, + -555364893392092215, 140734046849712, 140258919107024, 0, 3, + 534754674514084809, -560026272429489207}, + mask_was_saved = 0}}, priv = {pad = {0x0, 0x0, 0x0, 0x0}, + data = {prev = 0x0, cleanup = 0x0, canceltype = 0}}} + not_first_call = <value optimized out> + sp = <value optimized out> + freesize = <value optimized out> +#11 0x00000038484e14ed in clone () + at ../sysdeps/unix/sysv/linux/x86_64/clone.S:115 +No locals. + +Thread 3 (Thread 19949): +#0 pthread_cond_wait@@GLIBC_2.3.2 () + at ../nptl/sysdeps/unix/sysv/linux/x86_64/pthread_cond_wait.S:162 +No locals. +#1 0x0000003858c23cce in PR_WaitCondVar (cvar=0x7f90a0ef5980, + timeout=4294967295) + at ../../../mozilla/nsprpub/pr/src/pthreads/ptsynch.c:417 + rv = <value optimized out> + thred = 0x7f90a82118c0 +#2 0x0000003b8ae92582 in JSBackgroundThread::work (this=0x7f90a0efb490) + at /usr/src/debug/thunderbird-3.1.1/comm-1.9.2/mozilla/js/src/jstask.cpp:91 + t = <value optimized out> +#3 0x0000003858c29843 in _pt_root (arg=0x7f90a82118c0) + at ../../../mozilla/nsprpub/pr/src/pthreads/ptthread.c:228 + thred = 0x7f90a82118c0 + detached = 0 +#4 0x0000003848c07761 in start_thread (arg=0x7f909e7be710) + at pthread_create.c:301 + __res = <value optimized out> + pd = 0x7f909e7be710 + now = <value optimized out> + unwind_buf = {cancel_jmp_buf = {{jmp_buf = {140259110938384, + -555364893392092215, 140734046874480, 140259110939088, 0, 3, + 534747917456786377, -560026272429489207}, + mask_was_saved = 0}}, priv = {pad = {0x0, 0x0, 0x0, 0x0}, + data = {prev = 0x0, cleanup = 0x0, canceltype = 0}}} + not_first_call = <value optimized out> + sp = <value optimized out> + freesize = <value optimized out> +#5 0x00000038484e14ed in clone () + at ../sysdeps/unix/sysv/linux/x86_64/clone.S:115 +No locals. + +Thread 2 (Thread 19948): +#0 0x00000038484d7de3 in __poll (fds=<value optimized out>, + nfds=<value optimized out>, timeout=<value optimized out>) + at ../sysdeps/unix/sysv/linux/poll.c:87 + __arg2 = 1 + _a3 = -1 + _a1 = 140259133114288 + resultvar = <value optimized out> + __arg3 = 244813135871 + __arg1 = 140259133114288 + _a2 = 1 + resultvar = <value optimized out> + oldtype = 0 + result = <value optimized out> +#1 0x0000003858c256ef in _pr_poll_with_poll (pds=0x7f90a0e929c0, + npds=<value optimized out>, timeout=<value optimized out>) + at ../../../mozilla/nsprpub/pr/src/pthreads/ptio.c:3915 + stack_syspoll = {{fd = 12, events = 1, revents = 0}, {fd = 4217387, + events = 0, revents = 0}, {fd = 2144215040, events = 32656, + revents = 0}, {fd = 2, events = 0, revents = 0}, { + fd = 2144215040, events = 32656, revents = 0}, {fd = 2256, + events = 0, revents = 0}, {fd = 2106593272, events = 32656, + revents = 0}, {fd = -1472524016, events = 32656, revents = 0}, { + fd = -1979709176, events = 32656, revents = 0}, {fd = 1489124226, + events = 56, revents = 0}, {fd = 1, events = 0, revents = 0}, { + fd = -1748911488, events = 32656, revents = 0}, {fd = -1, + events = 0, revents = 0}, {fd = 0, events = 0, + revents = 0} <repeats 11 times>, {fd = -1963357272, + events = 32656, revents = 0}, {fd = 2106664992, events = 32656, + revents = 0}, {fd = 2121073600, events = 32656, revents = 0}, { + fd = 967017730, events = 49, revents = 0}, {fd = 0, events = 0, + revents = 0}, {fd = 4217387, events = 28, revents = 0}, { + fd = -1968406804, events = 32656, revents = 0}, {fd = 1489124803, + events = 2, revents = 0}, {fd = -1963357168, events = 32656, + revents = 0}, {fd = -1963357216, events = 32656, revents = 0}, { + fd = 105462118, events = 0, revents = 0}, {fd = 967016693, + events = 49, revents = 0}, {fd = -1750069088, events = 32656, + revents = 0}, {fd = -1472521960, events = 32656, revents = 0}, { + fd = -1770357160, events = 32656, revents = 0}, {fd = 967018203, + events = 49, revents = 0}, {fd = 0, events = 0, revents = 0}, { + fd = 4217387, events = 0, revents = 0}, {fd = 2121073600, + events = 32656, revents = 0}, {fd = 1489124812, events = 56, + revents = 0}, {fd = 0, events = 0, revents = 0}, { + fd = -1951811472, events = 32656, revents = 0}, { + fd = -1770357248, events = 32656, revents = 0}, { + fd = -1968544452, events = 32656, revents = 0}, {fd = 0, + events = 0, revents = 0}, {fd = 4217387, events = 0, + revents = 0}, {fd = 1, events = 0, revents = 0}, {fd = 4217387, + events = 0, revents = 0}, {fd = 0, events = 0, revents = 0}, { + fd = 1489124812, events = 56, revents = 0}, {fd = 3, events = 0, + revents = 0}, {fd = -1474197528, events = 32656, revents = 0}, { + fd = -1613870704, events = 32656, revents = 0}, {fd = 853538836, + events = 32767, revents = 0}, {fd = -1613870688, events = 32656, + revents = 0}, {fd = 853538836, events = 32767, revents = 0}, { + fd = -1613870624, events = 32656, revents = 0}, {fd = 0, + events = 0, revents = 0}, {fd = -1613870656, events = 32656, + revents = 0}, {fd = 853539004, events = 32767, revents = 0}} + syspoll = <value optimized out> + index = <value optimized out> + msecs = -1 + ready = <value optimized out> + start = <value optimized out> + elapsed = <value optimized out> + remaining = <value optimized out> +#2 0x00007f909fd45bbd in nsSocketTransportService::Poll ( + this=<value optimized out>, wait=<value optimized out>, + interval=0x7f909fce4a4c) + at /usr/src/debug/thunderbird-3.1.1/comm-1.9.2/mozilla/netwerk/base/src/nsSocketTransportService2.cpp:355 + rv = <value optimized out> + pollList = 0x7f90a0e929c0 + pollCount = 1 + pollTimeout = 4294967295 + ts = 1100069864 + passedInterval = <value optimized out> +#3 0x00007f909fd46078 in nsSocketTransportService::DoPollIteration ( + this=0x7f90a0e92000, wait=1) + at /usr/src/debug/thunderbird-3.1.1/comm-1.9.2/mozilla/netwerk/base/src/nsSocketTransportService2.cpp:660 + i = -1 + count = <value optimized out> + pollInterval = 32656 + n = <value optimized out> +#4 0x00007f909fd4628a in nsSocketTransportService::OnProcessNextEvent ( + this=0x7f90a0e92000, thread=0x7f90a8243af0, + mayWait=<value optimized out>, depth=<value optimized out>) + at /usr/src/debug/thunderbird-3.1.1/comm-1.9.2/mozilla/netwerk/base/src/nsSocketTransportService2.cpp:539 + val = 0 +#5 0x0000003139a6c712 in nsThread::ProcessNextEvent (this=0x7f90a8243af0, + mayWait=1, result=0x7f909fce4b1c) + at /usr/src/debug/thunderbird-3.1.1/comm-1.9.2/mozilla/xpcom/threads/nsThread.cpp:508 + notifyGlobalObserver = 1 + obs = {<nsCOMPtr_base> = {mRawPtr = 0x7f90a0e92010}, <No data fields>} + rv = <value optimized out> +#6 0x0000003139a3db88 in NS_ProcessNextEvent_P ( + thread=<value optimized out>, mayWait=<value optimized out>) + at nsThreadUtils.cpp:250 + val = 32656 +#7 0x00007f909fd45dce in nsSocketTransportService::Run (this=0x7f90a0e92000) + at /usr/src/debug/thunderbird-3.1.1/comm-1.9.2/mozilla/netwerk/base/src/nsSocketTransportService2.cpp:581 + thread = 0x7f90a8243af0 + threadInt = {<nsCOMPtr_base> = { + mRawPtr = 0x7f90a8243af0}, <No data fields>} + i = <value optimized out> +#8 0x0000003139a6c765 in nsThread::ProcessNextEvent (this=0x7f90a8243af0, + mayWait=1, result=0x7f909fce4bdc) + at /usr/src/debug/thunderbird-3.1.1/comm-1.9.2/mozilla/xpcom/threads/nsThread.cpp:527 + event = {<nsCOMPtr_base> = { + mRawPtr = 0x7f90a0e92018}, <No data fields>} + notifyGlobalObserver = 0 + obs = {<nsCOMPtr_base> = {mRawPtr = 0x0}, <No data fields>} + rv = 0 +#9 0x0000003139a3db88 in NS_ProcessNextEvent_P ( + thread=<value optimized out>, mayWait=<value optimized out>) + at nsThreadUtils.cpp:250 + val = 1 +#10 0x0000003139a6ce3b in nsThread::ThreadFunc (arg=0x7f90a8243af0) + at /usr/src/debug/thunderbird-3.1.1/comm-1.9.2/mozilla/xpcom/threads/nsThread.cpp:254 + self = 0x7f90a8243af0 + event = {<nsCOMPtr_base> = {mRawPtr = 0x0}, <No data fields>} +#11 0x0000003858c29843 in _pt_root (arg=0x7f90a82117b0) + at ../../../mozilla/nsprpub/pr/src/pthreads/ptthread.c:228 + thred = 0x7f90a82117b0 + detached = 0 +#12 0x0000003848c07761 in start_thread (arg=0x7f909fce5710) + at pthread_create.c:301 + __res = <value optimized out> + pd = 0x7f909fce5710 + now = <value optimized out> + unwind_buf = {cancel_jmp_buf = {{jmp_buf = {140259133118224, + -555364893392092215, 140734046876304, 140259133118928, 0, 3, + 534746444819874761, -560026272429489207}, + mask_was_saved = 0}}, priv = {pad = {0x0, 0x0, 0x0, 0x0}, + data = {prev = 0x0, cleanup = 0x0, canceltype = 0}}} + not_first_call = <value optimized out> + sp = <value optimized out> + freesize = <value optimized out> +#13 0x00000038484e14ed in clone () + at ../sysdeps/unix/sysv/linux/x86_64/clone.S:115 +No locals. + +Thread 1 (Thread 19947): +#0 0x0000003848c0f30b in raise (sig=<value optimized out>) + at ../nptl/sysdeps/unix/sysv/linux/pt-raise.c:42 + resultvar = 0 + pid = <value optimized out> +#1 0x0000003139e1f34e in nsProfileLock::FatalSignalHandler (signo=11, + info=<value optimized out>, context=<value optimized out>) + at nsProfileLock.cpp:213 + unblock_sigs = {__val = {1024, 0 <repeats 15 times>}} + oldact = <value optimized out> +#2 <signal handler called> +No symbol table info available. +#3 0x00007f909544e763 in nsTreeBodyFrame::PrefillPropertyArray ( + this=0x7f909108c8a8, aRowIndex=-1, aCol=0x7f908861f760) + at /usr/src/debug/thunderbird-3.1.1/comm-1.9.2/mozilla/layout/xul/base/src/tree/src/nsTreeBodyFrame.cpp:2055 + sorted = 0 +#4 0x00007f909544ebef in nsTreeBodyFrame::PaintColumn (this=0x7f909108c8a8, + aColumn=0x7f908861f760, aColumnRect=..., aPresContext=0x7f9097882000, + aRenderingContext=..., aDirtyRect=<value optimized out>) + at /usr/src/debug/thunderbird-3.1.1/comm-1.9.2/mozilla/layout/xul/base/src/tree/src/nsTreeBodyFrame.cpp:2915 + colContext = <value optimized out> + colRect = {x = -1860605664, y = 32656, width = -1861695320, + height = 32656} + colMargin = {top = 0, right = 0, bottom = 15060, left = 0} +#5 0x00007f909545064b in nsTreeBodyFrame::PaintTreeBody ( + this=0x7f909108c8a8, aRenderingContext=..., aDirtyRect=..., aPt=...) + at /usr/src/debug/thunderbird-3.1.1/comm-1.9.2/mozilla/layout/xul/base/src/tree/src/nsTreeBodyFrame.cpp:2873 + dirtyRect = {x = 60, y = 7140, width = 15060, height = 48300} + colRect = {x = 60, y = 7140, width = 15060, height = 48300} + rv = <value optimized out> + currCol = 0x7f908861f760 + oldPageCount = <value optimized out> +#6 0x00007f909545094d in PaintTreeBody (aFrame=<value optimized out>, + aCtx=<value optimized out>, aDirtyRect=<value optimized out>, + aPt=<value optimized out>) + at /usr/src/debug/thunderbird-3.1.1/comm-1.9.2/mozilla/layout/xul/base/src/tree/src/nsTreeBodyFrame.cpp:2811 +No locals. +#7 0x00007f90950bb986 in nsDisplayGeneric::Paint (this=0x7f907fab5938, + aBuilder=<value optimized out>, aCtx=0x7f907d912a60) + at /usr/src/debug/thunderbird-3.1.1/comm-1.9.2/mozilla/layout/base/nsDisplayList.h:968 +No locals. +#8 0x00007f9095082ffe in nsDisplayList::Paint (this=<value optimized out>, + aBuilder=0x7fff32dee530, aCtx=0x7f907d912a60) + at /usr/src/debug/thunderbird-3.1.1/comm-1.9.2/mozilla/layout/base/nsDisplayList.cpp:405 + i = 0x7f907fab5938 +#9 0x00007f9095083150 in Paint (this=0x7f907fab59f0, + aBuilder=0x7fff32dee530, aCtx=0x7f907d912a60) + at /usr/src/debug/thunderbird-3.1.1/comm-1.9.2/mozilla/layout/base/nsDisplayList.cpp:1007 +No locals. +#10 nsDisplayClip::Paint (this=0x7f907fab59f0, aBuilder=0x7fff32dee530, + aCtx=0x7f907d912a60) + at /usr/src/debug/thunderbird-3.1.1/comm-1.9.2/mozilla/layout/base/nsDisplayList.cpp:1203 +No locals. +#11 0x00007f9095082ffe in nsDisplayList::Paint (this=<value optimized out>, + aBuilder=0x7fff32dee530, aCtx=0x7f907d912a60) + at /usr/src/debug/thunderbird-3.1.1/comm-1.9.2/mozilla/layout/base/nsDisplayList.cpp:405 + i = 0x7f907fab59f0 +#12 0x00007f9095096400 in nsLayoutUtils::PaintFrame ( + aRenderingContext=0x7f907d912a60, aFrame=0x7f9096786110, + aDirtyRegion=..., aBackstop=4294967295, aFlags=<value optimized out>) + at /usr/src/debug/thunderbird-3.1.1/comm-1.9.2/mozilla/layout/base/nsLayoutUtils.cpp:1161 + builder = {mReferenceFrame = 0x7f9096786110, mMovingFrame = 0x0, + mSaveVisibleRegionOfMovingContent = 0x0, mIgnoreScrollFrame = 0x0, + mMoveDelta = {x = 0, y = 118}, mPool = {first = { + next = 0x7f907fab5800, base = 140734046856568, + limit = 140734046856568, avail = 140734046856568}, + current = 0x7f907fab5800, arenasize = 1024, mask = 7}, + mBoundingSelection = {<nsCOMPtr_base> = { + mRawPtr = 0x0}, <No data fields>}, + mPresShellStates = {<nsTArray<nsDisplayListBuilder::PresShellState>> = {<nsTArray_base> = {static sEmptyHdr = {mLength = 0, mCapacity = 0, + mIsAutoArray = 0}, + mHdr = 0x7fff32dee5a0}, <No data fields>}, + mAutoBuf = "\000\000\000\000\b\000\000\200\000\070\210\227\220\177", '\000' <repeats 14 times>"\377, \177\000\000v\000\000\000\377\177\000\000\000\000\000\000\377\177\000\000v\000\000\000\377\177\000\000\375\000\000\000\070\000\000\000'\003\000\000\000\000\000\000 \347\336\062\377\177\000\000\270\212c\210\220\177\000\000\001g@\000\000\000\000\000\360\346\336\062\377\177\000\000\270\212c\210\220\177\000\000\235\003", '\000' <repeats 38 times>, " U$K8", '\000' <repeats 11 times>, "<\035\001K8\000\000\000\000|\227}\220\177\000\000\001g@\000\000\000\000\000L\347\336\062\377\177\000"}, + mFramesMarkedForDisplay = {<nsTArray<nsIFrame*>> = {<nsTArray_base> = {static sEmptyHdr = {mLength = 0, mCapacity = 0, mIsAutoArray = 0}, + mHdr = 0x7fff32dee670}, <No data fields>}, + mAutoBuf = "\000\000\000\000d\000\000\200\020\347\336\062\377\177\000\000\240)\221}\220\177\000\000>j@\000\000\000\000\000\001\000\000\000\220\177\000\000\200\332'\250\220\177\000\000\000\000\000\000\220\177\000\000\000\000\000\000\000\000\000\000\340\353\336\062\377\177\000\000\000\000\000\000\000\000\000\000\340\353\336\062\377\177\000\000\316\372\202S8\000\000\000\000\373\000\000\000\000\000\000\000\373\000\000\000%\003", '\000' <repeats 14 times>, "%\003\000\340u\227}\220\177\000\000\267\327\201S8\000\000\000@\307\224}\220\177\000\000=\277\202S8", '\000' <repeats 11 times>"\232, \231\231\231\231\231\271?\000\000\000\000\000\000\000\000+Z@", '\000' <repeats 14 times>, "\005\000\000\265\003\000\000@\210\222}\220\177\000\000\375\000\000\000\004\000\000\000\000\000\000\000v\000\000\000\200\200\020\210\220\177\000\000\001\000\000\000\000\000\000\000\060\253/\250\220\177\000\000\000\000\000\000\000\000\000\000\300\330'\250"...}, mCurrentTableItem = 0x0, mBuildCaret = 1 '\001', + mEventDelivery = 0 '\000', mIsBackgroundOnly = 0 '\000', + mIsAtRootOfPseudoStackingContext = 0 '\000', + mPaintAllFrames = 0 '\000', mAccurateVisibleRegions = 0 '\000', + mInTransform = 0 '\000'} + list = {mSentinel = {mAbove = 0x7f907fab59f0}, mTop = 0x7f907fab59f8} + rv = 0 + frameType = <value optimized out> + disableAssert = {mOldValue = 0} + dirtyRect = {x = 60, y = 7140, width = 15060, height = 48300} + visibleRegion = {mRectCount = 0, mCurRect = 0x7fff32dee4a0, + mRectListHead = {<nsRegion::nsRectFast> = {<nsRect> = {x = 0, + y = 0, width = 0, height = 0}, <No data fields>}, + prev = 0x7fff32dee4a0, next = 0x7fff32dee4a0}, + mBoundRect = {<nsRect> = {x = 0, y = 0, width = 0, + height = 0}, <No data fields>}} +#13 0x00007f909509f128 in PresShell::Paint (this=0x7f9097883800, + aView=0x7f9099d40500, aRenderingContext=0x7f907d912a60, aDirtyRegion=...) + at /usr/src/debug/thunderbird-3.1.1/comm-1.9.2/mozilla/layout/base/nsPresShell.cpp:5844 + bgcolor = <value optimized out> + frame = <value optimized out> +#14 0x00007f9095311ac9 in nsViewManager::RenderViews (this=0x7f9099d40280, + aView=<value optimized out>, aRC=..., aRegion=<value optimized out>) + at /usr/src/debug/thunderbird-3.1.1/comm-1.9.2/mozilla/view/src/nsViewManager.cpp:533 + offsetToRoot = {x = 60, y = 7140} + damageRegion = {mRectCount = 1, mCurRect = 0x7f908868d5c8, + mRectListHead = {<nsRegion::nsRectFast> = {<nsRect> = {x = 0, + y = 0, width = 0, height = 0}, <No data fields>}, + prev = 0x7f908868d5c8, next = 0x7f908868d5c8}, + mBoundRect = {<nsRect> = {x = 60, y = 7140, width = 15060, + height = 48300}, <No data fields>}} + displayRoot = 0x7f9099d40500 + displayRootVM = <value optimized out> +#15 0x00007f9095312a10 in nsViewManager::Refresh (this=0x7f9099d40280, + aView=0x7f909116e680, aContext=0x7f907d912a60, + aRegion=<value optimized out>, aUpdateFlags=1) + at /usr/src/debug/thunderbird-3.1.1/comm-1.9.2/mozilla/view/src/nsViewManager.cpp:492 + localcx = {<nsCOMPtr_base> = { + mRawPtr = 0x7f907d912a60}, <No data fields>} + p2a = 60 + ctx = {mRawPtr = 0x7f907d914f20} + viewRect = warning: bits 64-128 in computed object were optimized out; replacing with zeroes +{x = 0, y = 0, width = 0, height = 0} + vtowoffset = {x = 0, y = 0} + damageRegion = {mRectCount = 1, mCurRect = 0x7f90a0a7d448, + mRectListHead = {<nsRegion::nsRectFast> = {<nsRect> = {x = 0, + y = 0, width = 0, height = 0}, <No data fields>}, + prev = 0x7f90a0a7d448, next = 0x7f90a0a7d448}, + mBoundRect = {<nsRect> = {x = 0, y = 0, width = 15060, + height = 48300}, <No data fields>}} +#16 0x00007f9095312f8f in nsViewManager::DispatchEvent (this=0x7f9099d40280, + aEvent=0x7fff32deed40, aView=<value optimized out>, + aStatus=<value optimized out>) + at /usr/src/debug/thunderbird-3.1.1/comm-1.9.2/mozilla/view/src/nsViewManager.cpp:1008 + rootVM = {mRawPtr = 0x7f9099d40280} + widget = {<nsCOMPtr_base> = { + mRawPtr = 0x7f9097878500}, <No data fields>} + transparentWindow = <value optimized out> + view = 0x7f909116e680 + didResize = 0 + event = 0x7fff32deed40 + region = {<nsCOMPtr_base> = { + mRawPtr = 0x7f907d933600}, <No data fields>} +#17 0x00007f909530deaa in HandleEvent (aEvent=0x7fff32deed40) + at /usr/src/debug/thunderbird-3.1.1/comm-1.9.2/mozilla/view/src/nsView.cpp:167 + vm = {<nsCOMPtr_base> = {mRawPtr = 0x7f9099d40280}, <No data fields>} + result = nsEventStatus_eConsumeNoDefault + view = 0x7f909116e680 +#18 0x00007f909d169999 in nsWindow::DispatchEvent (this=0x7f90a8292b50, + aEvent=<value optimized out>, aStatus=@0x7fff32deeeb8) + at /usr/src/debug/thunderbird-3.1.1/comm-1.9.2/mozilla/widget/src/gtk2/nsWindow.cpp:626 +No locals. +#19 0x00007f909d172912 in nsWindow::OnExposeEvent (this=0x7f90a8292b50, + aWidget=<value optimized out>, aEvent=0x7fff32def450) + at /usr/src/debug/thunderbird-3.1.1/comm-1.9.2/mozilla/widget/src/gtk2/nsWindow.cpp:2614 + translucent = 0 + updateRegion = {<nsCOMPtr_base> = { + mRawPtr = 0x7f907d933600}, <No data fields>} + nrects = 1 + r = <value optimized out> + r_end = 0x7f907d918500 + rc = {<nsCOMPtr_base> = {mRawPtr = 0x7f907d912a60}, <No data fields>} + boundsRect = {x = 0, y = 0, width = 251, height = 805} + bufferPixmap = 0x7f907d92f310 + event = {<nsGUIEvent> = {<nsEvent> = {eventStructType = 6 '\006', + message = 130, refPoint = {x = 0, y = 0}, time = 0, flags = 1, + userType = {<nsCOMPtr_base> = { + mRawPtr = 0x0}, <No data fields>}, + target = {<nsCOMPtr_base> = {mRawPtr = 0x0}, <No data fields>}, + currentTarget = {<nsCOMPtr_base> = { + mRawPtr = 0x0}, <No data fields>}, + originalTarget = {<nsCOMPtr_base> = { + mRawPtr = 0x0}, <No data fields>}}, + widget = {<nsCOMPtr_base> = { + mRawPtr = 0x7f90a8292b50}, <No data fields>}, + nativeMsg = 0x0}, renderingContext = 0x7f907d912a60, region = + 0x7f907d933600, rect = 0x0} + rects = 0x7f907d9184f0 + bufferPixmapSize = <value optimized out> + ctx = {mRawPtr = 0x7f907d914ec0} + status = <value optimized out> + kRegionCID = {m0 = 3777450736, m1 = 61082, m2 = 4561, + m3 = "\250*\000@\225\232(\311"} + bufferPixmapSurface = {mRawPtr = 0x7f907d913f40} +#20 0x00007f909d172d68 in expose_event_cb (widget=0x7f9097d03700, + event=0x7fff32def450) + at /usr/src/debug/thunderbird-3.1.1/comm-1.9.2/mozilla/widget/src/gtk2/nsWindow.cpp:5828 + window = {mRawPtr = 0x7f90a8292b50} +#21 0x0000003138b51003 in _gtk_marshal_BOOLEAN__BOXED ( + closure=0x7f90977a4c70, return_value=0x7fff32def110, + n_param_values=<value optimized out>, param_values=0x7f907d92f280, + invocation_hint=<value optimized out>, marshal_data=<value optimized out>) + at gtkmarshalers.c:84 + callback = 0x7f909d172d34 <expose_event_cb(GtkWidget*, GdkEventExpose*)> + cc = 0x7f90977a4c70 + data1 = 0x7f9097d03700 + data2 = 0x0 + v_return = <value optimized out> + __PRETTY_FUNCTION__ = "_gtk_marshal_BOOLEAN__BOXED" +#22 0x000000384b00b98e in IA__g_closure_invoke (closure=0x7f90977a4c70, + return_value=0x7fff32def110, n_param_values=2, + param_values=0x7f907d92f280, invocation_hint=0x7fff32def0d0) + at gclosure.c:767 + marshal = <value optimized out> + marshal_data = <value optimized out> + in_marshal = <value optimized out> + __PRETTY_FUNCTION__ = "IA__g_closure_invoke" +#23 0x000000384b01f947 in signal_emit_unlocked_R (node=<value optimized out>, + detail=0, instance=0x7f9097d03700, emission_return=0x7fff32def260, + instance_and_params=0x7f907d92f280) at gsignal.c:3248 + tmp = <value optimized out> + handler = 0x7f90977a4bb0 + accumulator = 0x7f90a82a0df0 + emission = {next = 0x7fff32df3460, instance = 0x7f9097d03700, + ihint = {signal_id = 41, detail = 0, + run_type = G_SIGNAL_RUN_FIRST}, state = EMISSION_RUN, + chain_type = 4} + class_closure = 0x7f90a8289100 + handler_list = 0x7f90977a4bb0 + return_accu = 0x7fff32def110 + accu = {g_type = 20, data = {{v_int = 0, v_uint = 0, v_long = 0, + v_ulong = 0, v_int64 = 0, v_uint64 = 0, v_float = 0, + v_double = 0, v_pointer = 0x0}, {v_int = 0, v_uint = 0, + v_long = 0, v_ulong = 0, v_int64 = 0, v_uint64 = 0, + v_float = 0, v_double = 0, v_pointer = 0x0}}} + signal_id = 41 + max_sequential_handler_number = 1552 + return_value_altered = 0 +#24 0x000000384b020c29 in IA__g_signal_emit_valist ( + instance=<value optimized out>, signal_id=<value optimized out>, + detail=<value optimized out>, var_args=0x7fff32def2c0) at gsignal.c:2991 + return_value = {g_type = 20, data = {{v_int = 0, v_uint = 0, + v_long = 0, v_ulong = 0, v_int64 = 0, v_uint64 = 0, + v_float = 0, v_double = 0, v_pointer = 0x0}, {v_int = 0, + v_uint = 0, v_long = 0, v_ulong = 0, v_int64 = 0, v_uint64 = 0, + v_float = 0, v_double = 0, v_pointer = 0x0}}} + error = 0x0 + rtype = 20 + static_scope = 0 + instance_and_params = 0x7f907d92f280 + signal_return_type = 20 + param_values = 0x7f907d92f298 + node = 0x7f90a82882e0 + i = <value optimized out> + n_params = 1 + __PRETTY_FUNCTION__ = "IA__g_signal_emit_valist" +#25 0x000000384b0213a3 in IA__g_signal_emit (instance=<value optimized out>, + signal_id=<value optimized out>, detail=<value optimized out>) + at gsignal.c:3038 + var_args = {{gp_offset = 32, fp_offset = 48, + overflow_arg_area = 0x7fff32def3a0, + reg_save_area = 0x7fff32def2e0}} +#26 0x0000003138c8190f in gtk_widget_event_internal (widget=0x7f9097d03700, + event=0x7fff32def450) at gtkwidget.c:4958 + signal_num = <value optimized out> + return_val = 0 +#27 0x0000003138b4909e in IA__gtk_main_do_event (event=0x7fff32def450) + at gtkmain.c:1583 + event_widget = 0x7f9097d03700 + grab_widget = 0x7f9097d03700 + window_group = 0x7f90975dbd20 + rewritten_event = <value optimized out> + tmp_list = <value optimized out> + __PRETTY_FUNCTION__ = "IA__gtk_main_do_event" +#28 0x000000313924340a in _gdk_window_process_updates_recurse ( + window=0x7f909100a9d0, expose_region=0x7f907d92f250) at gdkwindow.c:5181 + event = {type = GDK_EXPOSE, any = {type = GDK_EXPOSE, + window = 0x7f909100a9d0, send_event = 0 '\000'}, expose = { + type = GDK_EXPOSE, window = 0x7f909100a9d0, + send_event = 0 '\000', area = {x = 0, y = 0, width = 251, + height = 805}, region = 0x7f907d92f250, count = 0}, + no_expose = {type = GDK_EXPOSE, window = 0x7f909100a9d0, + send_event = 0 '\000'}, visibility = {type = GDK_EXPOSE, + window = 0x7f909100a9d0, send_event = 0 '\000', + state = GDK_VISIBILITY_UNOBSCURED}, motion = {type = GDK_EXPOSE, + window = 0x7f909100a9d0, send_event = 0 '\000', time = 0, + x = 5.3262094353228335e-312, y = 6.9295894550159656e-310, + axes = 0x7f907d92f250, state = 0, is_hint = 32656, + device = 0x7f909100a9d0, x_root = 6.9296935438300264e-310, + y_root = 6.9296935367154811e-310}, button = {type = GDK_EXPOSE, + window = 0x7f909100a9d0, send_event = 0 '\000', time = 0, + x = 5.3262094353228335e-312, y = 6.9295894550159656e-310, + axes = 0x7f907d92f250, state = 0, button = 32656, + device = 0x7f909100a9d0, x_root = 6.9296935438300264e-310, + y_root = 6.9296935367154811e-310}, scroll = {type = GDK_EXPOSE, + window = 0x7f909100a9d0, send_event = 0 '\000', time = 0, + x = 5.3262094353228335e-312, y = 6.9295894550159656e-310, + state = 2106782288, direction = 32656, device = 0x7f9000000000, + x_root = 6.9297096482918431e-310, + y_root = 6.9296935438300264e-310}, key = {type = GDK_EXPOSE, + window = 0x7f909100a9d0, send_event = 0 '\000', time = 0, + state = 0, keyval = 251, length = 805, + string = 0x7f907d92f250 "\001", hardware_keycode = 0, + group = 0 '\000', is_modifier = 0}, crossing = { + type = GDK_EXPOSE, window = 0x7f909100a9d0, + send_event = 0 '\000', subwindow = 0xfb00000000, time = 805, + x = 6.92969354385137e-310, y = 6.9295894549761933e-310, + x_root = 6.9297096482918431e-310, + y_root = 6.9296935438300264e-310, mode = 2106637856, + detail = 32656, focus = 0, state = 0}, focus_change = { + type = GDK_EXPOSE, window = 0x7f909100a9d0, + send_event = 0 '\000', in = -22495}, configure = { + type = GDK_EXPOSE, window = 0x7f909100a9d0, + send_event = 0 '\000', x = 0, y = 0, width = 251, height = 805}, + property = {type = GDK_EXPOSE, window = 0x7f909100a9d0, + send_event = 0 '\000', atom = 0xfb00000000, time = 805, + state = 32656}, selection = {type = GDK_EXPOSE, + window = 0x7f909100a9d0, send_event = 0 '\000', + selection = 0xfb00000000, target = 0x7f9000000325, + property = 0x7f907d92f250, time = 0, requestor = 32656}, + owner_change = {type = GDK_EXPOSE, window = 0x7f909100a9d0, + send_event = 0 '\000', owner = 0, + reason = GDK_OWNER_CHANGE_NEW_OWNER, selection = 0x7f9000000325, + time = 2106782288, selection_time = 32656}, proximity = { + type = GDK_EXPOSE, window = 0x7f909100a9d0, + send_event = 0 '\000', time = 0, device = 0xfb00000000}, + client = {type = GDK_EXPOSE, window = 0x7f909100a9d0, + send_event = 0 '\000', message_type = 0xfb00000000, + data_format = 805, data = { + b = "P\362\222}\220\177\000\000\000\000\000\000\220\177\000\000\320\251\000\221", s = {-3504, 32146, 32656, 0, 0, 0, 32656, 0, -22064, + -28416}, l = {140258558800464, 140256452018176, + 140258884757968, 140258558800032, 140258558656032}}}, dnd = { + type = GDK_EXPOSE, window = 0x7f909100a9d0, + send_event = 0 '\000', context = 0xfb00000000, time = 805, + x_root = 32656, y_root = 0}, window_state = {type = GDK_EXPOSE, + window = 0x7f909100a9d0, send_event = 0 '\000', changed_mask = 0, + new_window_state = 0}, setting = {type = GDK_EXPOSE, + window = 0x7f909100a9d0, send_event = 0 '\000', + action = GDK_SETTING_ACTION_NEW, + name = 0xfb00000000 <Address 0xfb00000000 out of bounds>}, + grab_broken = {type = GDK_EXPOSE, window = 0x7f909100a9d0, + send_event = 0 '\000', keyboard = 0, implicit = 0, + grab_window = 0x7f9000000325}} + private = 0x7f909100a9d0 + child = <value optimized out> + child_region = <value optimized out> + r = {x = 2106781904, y = 32656, width = -1862227504, height = 32656} + l = <value optimized out> + children = 0x0 +#29 0x000000313923fecb in gdk_window_process_updates_internal ( + window=0x7f909100a9d0) at gdkwindow.c:5340 + expose_region = 0x7f907d92f250 + update_area = 0x7f907d92f0a0 + private = 0x7f909100a9d0 + impl_iface = <value optimized out> + save_region = 0 + clip_box = {x = 0, y = 0, width = 251, height = 805} +#30 0x0000003139244a41 in IA__gdk_window_process_all_updates () + at gdkwindow.c:5448 + private = 0x7f909100a9d0 + old_update_windows = 0x7f907d918480 + tmp_list = 0x7f907d918160 + in_process_all_updates = 1 + got_recursive_update = 1 +#31 0x0000003139244aa9 in gdk_window_update_idle (data=<value optimized out>) + at gdkwindow.c:5074 +No locals. +#32 0x000000313921d606 in gdk_threads_dispatch (data=0x7f907d9145a0) + at gdk.c:512 + dispatch = 0x7f907d9145a0 + ret = 0 +#33 0x0000003849c3bd02 in g_main_dispatch (context=0x7f90a82177a0) + at gmain.c:1960 + dispatch = 0x3849c39d70 <g_idle_dispatch> + was_in_call = 0 + user_data = 0x7f907d9145a0 + callback = 0x313921d5b0 <gdk_threads_dispatch> + cb_funcs = 0x3849efad30 + cb_data = 0x7f907d914760 + current_source_link = {data = 0x7f907d9126a0, next = 0x7fff32df3850} + need_destroy = <value optimized out> + source = 0x7f907d9126a0 + current = 0x7f9099d609d0 + i = <value optimized out> +#34 IA__g_main_context_dispatch (context=0x7f90a82177a0) at gmain.c:2513 +No locals. +#35 0x0000003849c3fae8 in g_main_context_iterate (context=0x7f90a82177a0, + block=1, dispatch=1, self=<value optimized out>) at gmain.c:2591 + max_priority = 120 + timeout = 0 + some_ready = 1 + nfds = 14 + allocated_nfds = <value optimized out> + fds = <value optimized out> + __PRETTY_FUNCTION__ = "g_main_context_iterate" +#36 0x0000003849c3fff5 in IA__g_main_loop_run (loop=0x7f907d921de0) + at gmain.c:2799 + self = 0x7f90a8210440 + __PRETTY_FUNCTION__ = "IA__g_main_loop_run" +#37 0x0000003138ac06d4 in IA__gtk_dialog_run (dialog=0x7f90823486c0) + at gtkdialog.c:1089 + ri = {dialog = 0x0, response_id = -1, loop = 0x7f907d921de0, + destroyed = 0} + was_modal = <value optimized out> + response_handler = 1453 + unmap_handler = 1454 + destroy_handler = 1456 + delete_handler = 1455 + __PRETTY_FUNCTION__ = "IA__gtk_dialog_run" +#38 0x00007f909d1799c7 in nsFilePicker::Show (this=0x7f907d95c900, + aReturn=0x7fff32defb20) + at /usr/src/debug/thunderbird-3.1.1/comm-1.9.2/mozilla/widget/src/gtk2/nsFilePicker.cpp:541 + count = 1 + response = <value optimized out> + parent_widget = 0x7f907dab9ee0 + action = <value optimized out> + accept_button = <value optimized out> + file_chooser = 0x7f90823486c0 + title = {<nsCString> = {<nsACString_internal> = { + mData = 0x7f907d951a30 "Za\305\202\304\205cz plik do tej wiadomo\305\233ci", mLength = 32, mFlags = 9}, <No data fields>}, <No data fields>} + defaultName = {<nsCAutoString> = {<nsFixedCString> = {<nsCString> = {<nsACString_internal> = {mData = 0x7fff32def8a0 "", mLength = 0, + mFlags = 65553}, <No data fields>}, mFixedCapacity = 63, + mFixedBuf = 0x7fff32def8a0 ""}, + mStorage = "\000\016\032\235\220\177\000\000\b\000\000\000\001\000\000\000\240\241\313\177\220\177\000\000\001\000\000\000\t\000\000\000\300\267\224}\220\177\000\000\017\000\000\000\t\000\000\000\330\246\031\235\220\177\000\000\374\370\336\062\377\177\000"}, <No data fields>} + defaultPath = {<nsCOMPtr_base> = { + mRawPtr = 0x7f908c7f6780}, <No data fields>} +#39 0x0000003139a78001 in NS_InvokeByIndex_P (that=0x7f907d95c900, + methodIndex=17, paramCount=1, params=<value optimized out>) + at /usr/src/debug/thunderbird-3.1.1/comm-1.9.2/mozilla/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_x86_64_unix.cpp:208 + nr_stack = <value optimized out> + gpregs = {140734046863264, 140734046862112, 0, 0, 140258884963168, + 140259009756772} + d0 = <value optimized out> + d5 = <value optimized out> + result = <value optimized out> + nr_gpr = 2 + d1 = <value optimized out> + d6 = <value optimized out> + nr_fpr = 0 + d2 = <value optimized out> + d7 = <value optimized out> + methodAddress = <value optimized out> + stack = 0x3139a77fdf + fpregs = {6.9296957829877067e-310, 6.9297208369785449e-310, + -nan(0xfffffffffffff), 1.4821969375237396e-323, + 6.9296935571784944e-310, 1.3137800876962641e-314, + 6.9531857754670951e-310, -1.983372149135684e-91} + d3 = <value optimized out> + d4 = <value optimized out> +#40 0x00007f909e801e8f in XPCWrappedNative::CallMethod (ccx=..., + mode=<value optimized out>) + at /usr/src/debug/thunderbird-3.1.1/comm-1.9.2/mozilla/js/src/xpconnect/src/xpcwrappednative.cpp:2722 + req = warning: bits 96-128 in computed object were optimized out; replacing with zeroes +{mCX = 0x0, mDepth = -1745217232} + rv = <value optimized out> + retval = 0 + paramCount = 1 '\001' + err = <value optimized out> + tls = <value optimized out> + secAction = <value optimized out> + methodInfo = 0x7f909bdd8b08 + src = 0 + foundDependentParam = 0 + argc = 0 + i = 1 '\001' + xpcc = 0x7f90823f0700 + argv = 0x7f908097a2d0 + secFlag = <value optimized out> + autoStringUsed = 0 + invokeResult = <value optimized out> + param_iid = {m0 = 0, m1 = 0, m2 = 0, m3 = "\323\345\341\212;\000\000"} + ifaceInfo = 0x7f909103cb60 + paramBuffer = {{<nsXPTCMiniVariant> = {val = {i8 = 0 '\000', i16 = 0, + i32 = 0, i64 = 0, u8 = 0 '\000', u16 = 0, u32 = 0, u64 = 0, + f = 0, d = 0, b = 0, c = 0 '\000', wc = 0, p = 0x0}}, + ptr = 0x7fff32defb20, type = {<XPTTypeDescriptorPrefix> = { + flags = 1 '\001'}, <No data fields>}, flags = 1 '\001'}, + {<nsXPTCMiniVariant> = {val = {i8 = 33 '!', i16 = -14047, + i32 = -1964652255, i64 = 255733385505, u8 = 33 '!', + u16 = 51489, u32 = 2330315041, u64 = 255733385505, + f = -2.21275541e-32, d = 1.263490802726963e-312, + b = -1964652255, c = 33 '!', wc = 51489, p = 0x3b8ae5c921}}, + ptr = 0x7f90a0ee0470, type = {<XPTTypeDescriptorPrefix> = { + flags = 0 '\000'}, <No data fields>}, flags = 196 '\304'}, + {<nsXPTCMiniVariant> = {val = {i8 = -120 '\210', i16 = -1144, + i32 = 853474184, i64 = 140734046862216, u8 = 136 '\210', + u16 = 64392, u32 = 853474184, u64 = 140734046862216, + f = 2.59585846e-08, d = 6.9531857754833005e-310, + b = 853474184, c = -120 '\210', wc = 64392, + p = 0x7fff32defb88}}, ptr = 0x7fff32defbb8, + type = {<XPTTypeDescriptorPrefix> = { + flags = 184 '\270'}, <No data fields>}, flags = 251 '\373'}, + {<nsXPTCMiniVariant> = {val = {i8 = 0 '\000', i16 = 0, i32 = 0, + i64 = 0, u8 = 0 '\000', u16 = 0, u32 = 0, u64 = 0, f = 0, + d = 0, b = 0, c = 0 '\000', wc = 0, p = 0x0}}, + ptr = 0x7f9096d1c400, type = {<XPTTypeDescriptorPrefix> = { + flags = 0 '\000'}, <No data fields>}, flags = 196 '\304'}, + {<nsXPTCMiniVariant> = {val = {i8 = 0 '\000', i16 = 0, i32 = 0, + i64 = 0, u8 = 0 '\000', u16 = 0, u32 = 0, u64 = 0, f = 0, + d = 0, b = 0, c = 0 '\000', wc = 0, p = 0x0}}, + ptr = 0x3b8b0ca6b0, type = {<XPTTypeDescriptorPrefix> = { + flags = 184 '\270'}, <No data fields>}, flags = 251 '\373'}, + {<nsXPTCMiniVariant> = {val = {i8 = 62 '>', i16 = 15166, + i32 = 1489124158, i64 = 242007292734, u8 = 62 '>', + u16 = 15166, u32 = 1489124158, u64 = 242007292734, + f = 1.70847759e+15, d = 1.1956748938291532e-312, + b = 1489124158, c = 62 '>', wc = 15166, p = 0x3858c23b3e}}, + ptr = 0x1, type = {<XPTTypeDescriptorPrefix> = { + flags = 192 '\300'}, <No data fields>}, flags = 88 'X'}, + {<nsXPTCMiniVariant> = {val = {i8 = -1 '\377', i16 = -1, i32 = -1, + i64 = 4294967295, u8 = 255 '\377', u16 = 65535, + u32 = 4294967295, u64 = 4294967295, f = -nan(0x7fffff), + d = 2.1219957904712067e-314, b = -1, c = -1 '\377', + wc = 65535, p = 0xffffffff}}, ptr = 0x0, + type = {<XPTTypeDescriptorPrefix> = { + flags = 0 '\000'}, <No data fields>}, flags = 0 '\000'}, + {<nsXPTCMiniVariant> = {val = {i8 = -16 '\360', i16 = -784, + i32 = 853474544, i64 = 140734046862576, u8 = 240 '\360', + u16 = 64752, u32 = 853474544, u64 = 140734046862576, + f = 2.59592241e-08, d = 6.9531857755010868e-310, + b = 853474544, c = -16 '\360', wc = 64752, + p = 0x7fff32defcf0}}, ptr = 0x7f909873fe64, + type = {<XPTTypeDescriptorPrefix> = { + flags = 251 '\373'}, <No data fields>}, flags = 77 'M'}} + autoString = "\000+v\214\220\177", '\000' <repeats 27 times>, "yv\214\220\177\000\000\204Q~\236\220\177\000\000\a\000\000\000\000\000\000\000\360\271#\250\220\177\000\000\000+v\214\220\177\000\000\000\000\000\000\001\000\000\000@\354}\214\220\177\000\000\000|F\200\220\177\000\000@\354}\214\220\177\000\000\000|F\200\220\177\000\000\000|F\200\220\177\000\000@\000\337\062\377\177\000\000\000yv\214\220\177\000\000@\000\337\062\377\177\000\000\060\000\337\062\377\177\000\000\070\000\337\062\377\177\000" + dispatchParams = 0x7fff32defb20 + requiredArgs = <value optimized out> + sm = <value optimized out> + rt = 0x7f90a0a2ac00 + callee = 0x7f907d95c900 + vtblIndex = 17 + name = <value optimized out> +#41 0x00007f909e80b09d in XPC_WN_CallMethod (cx=0x7f9080467c00, + obj=0x7f908c762b00, argc=0, argv=0x7f908097a2d0, vp=<value optimized out>) + at /usr/src/debug/thunderbird-3.1.1/comm-1.9.2/mozilla/js/src/xpconnect/src/xpcwrappednativejsops.cpp:1740 + funobj = <value optimized out> + wrapper = <value optimized out> + member = 0x7f907d971120 + ccx = {<nsAXPCNativeCallContext> = { + _vptr.nsAXPCNativeCallContext = 0x7f909ea74c50}, + mState = XPCCallContext::READY_TO_CALL, mXPC = 0x7f90a0a16c10, + mThreadData = 0x7f90a0aa1a60, mXPCContext = 0x7f90823f0700, + mJSContext = 0x7f9080467c00, mContextPopRequired = 0, + mDestroyJSContextInDestructor = 0, + mCallerLanguage = XPCContext::LANG_JS, + mPrevCallerLanguage = XPCContext::LANG_NATIVE, + mPrevCallContext = 0x7fff32df0940, + mOperandJSObject = 0x7f908c762b00, + mCurrentJSObject = 0x7f908c762b00, + mFlattenedJSObject = 0x7f908c762b00, mWrapper = 0x7f907dab9d00, + mTearOff = 0x7f907dab9d38, mScriptableInfo = 0x0, + mSet = 0x7f907d94b660, mInterface = 0x7f907d971000, + mMember = 0x7f907d971120, mName = 140259009756772, + mStaticMemberIsLocal = 0, mArgc = 0, mArgv = 0x7f908097a2d0, + mRetVal = 0x7fff32df0228, mReturnValueWasSet = 0, + mMethodIndex = 17, mCallee = 0x0, + mStringWrapperData = "d\376s\230\220\177\000\000\000|F\200\220\177\000\000\000\000\000\000\220\177\000\000\330\241\227\200\220\177\000\000\000\000\000\000\021\000\000\000\000\000\000\000\220\177\000"} + iface = 0x7f907d971000 +#42 0x0000003b8ae55084 in js_Invoke (cx=0x7f9080467c00, argc=0, + vp=0x7f908097a2c0, flags=2) + at /usr/src/debug/thunderbird-3.1.1/comm-1.9.2/mozilla/js/src/jsinterp.cpp:1360 + frame = {regs = 0x0, imacpc = 0x0, slots = 0x0, callobj = 0x0, + argsobj = 0, varobj = 0x0, script = 0x0, fun = 0x7f90885e9af0, + thisp = 0x7f908c762b00, argc = 0, argv = 0x7f908097a2d0, rval = 22, + down = 0x7f908097a1d8, annotation = 0x0, + scopeChain = 0x7f90910dcb40, blockChain = 0x0, sharpDepth = 0, + sharpArray = 0x0, flags = 34, dormantNext = 0x0, displaySave = 0x0} + argv = 0x7f908097a2d0 + funobj = <value optimized out> + ok = 59 + clasp = <value optimized out> + i = <value optimized out> + mark = 0x7f908097a2f0 + sp = <value optimized out> + newvp = <value optimized out> + v = 140258808592640 + ops = <value optimized out> + hookData = 0x0 + parent = 0x7f908c762b00 + fun = <value optimized out> + rootedArgsFlag = 32 + native = 0x7f909e80afb5 <XPC_WN_CallMethod(JSContext*, JSObject*, uintN, jsval*, jsval*)> + script = 0x0 + nslots = <value optimized out> + hook = 0 +#43 0x0000003b8ae4e5d1 in js_Interpret (cx=0x7f9080467c00) + at /usr/src/debug/thunderbird-3.1.1/comm-1.9.2/mozilla/js/src/jsops.cpp:2240 + getter = 0x7f90885e9af0 + op = JSOP_CALL + prop = 0x7f90885d2720 + npairs = -2137546048 + currentVersion = 12468 + obj = 0x7f908c767900 + d = 6.9296960457484177e-310 + off = 48 + fp = 0x7f908097a1d8 + inlineCallCount = 1 + regs = {pc = 0x7f907fd611b6 ":", sp = 0x7f908097a2d0} + pc2 = 0x7f9000000000 <Address 0x7f9000000000 out of bounds> + clasp = 0x0 + low = 0 + rt = 0x7f90a0ee0000 + op2 = JSOP_PROPINC + vp = 0x3a + script = 0x7f907fd61000 + originalVersion = 12468 + obj2 = 0x7f90910dcb40 + cond = 1 + lval = 58 + id = 140259009756772 + d2 = 0 + fun = 0x7f90885e9af0 + normalJumpTable = {0x3b8ae47d6e, 0x3b8ae47e55, 0x3b8ae47ef7, + 0x3b8ae47f34, 0x3b8ae47f78, 0x3b8ae47faa, 0x3b8ae48265, + 0x3b8ae482e8, 0x3b8ae483e1, 0x3b8ae4f5c6, 0x3b8ae48e31, + 0x3b8ae48e84, 0x3b8ae49091, 0x3b8ae490d5, 0x3b8ae491e3, + 0x3b8ae49532, 0x3b8ae49602, 0x3b8ae496d2, 0x3b8ae497a2, + 0x3b8ae49bf2, 0x3b8ae4a381, 0x3b8ae4a603, 0x3b8ae4a887, + 0x3b8ae4ab0f, 0x3b8ae4ad97, 0x3b8ae4ae6e, 0x3b8ae4af43, + 0x3b8ae4b019, 0x3b8ae4b3d5, 0x3b8ae4b505, 0x3b8ae4b635, + 0x3b8ae4b7ea, 0x3b8ae4b983, 0x3b8ae4ba19, 0x3b8ae4baa7, + 0x3b8ae4bb61, 0x3b8ae4bbc2, 0x3b8ae4bc96, 0x3b8ae4bd57, + 0x3b8ae4be50, 0x3b8ae4beab, 0x3b8ae4bfd4, 0x3b8ae4bef3, + 0x3b8ae4bedc, 0x3b8ae4bfd6, 0x3b8ae4bef5, 0x3b8ae4bede, + 0x3b8ae4bfd8, 0x3b8ae4bef7, 0x3b8ae4bee0, 0x3b8ae4bfd8, + 0x3b8ae4bef7, 0x3b8ae4bee0, 0x3b8ae4c984, 0x3b8ae4d1be, + 0x3b8ae4d92e, 0x3b8ae4dcc3, 0x3b8ae4e839, 0x3b8ae4e0f0, + 0x3b8ae4e839, 0x3b8ae4edd9, 0x3b8ae4edd9, 0x3b8ae4f059, + 0x3b8ae4f095, 0x3b8ae4f0d1, 0x3b8ae4c82b, 0x3b8ae4f10d, + 0x3b8ae4f149, 0x3b8ae484da, 0x3b8ae485a8, 0x3b8ae4f185, + 0x3b8ae4f35b, 0x3b8ae4a042, 0x3b8ae4a0b4, 0x3b8ae4e723, + 0x3b8ae48ce5, 0x3b8ae48d5f, 0x3b8ae48deb, 0x3b8ae4e0f2, + 0x3b8ae49129, 0x3b8ae4ee2c, 0x3b8ae47e91, 0x3b8ae4df8a, + 0x3b8ae4f552, 0x3b8ae4f70c, 0x3b8ae4f786, 0x3b8ae4f801, + 0x3b8ae4f8c5, 0x3b8ae4ebc9, 0x3b8ae50d1b, 0x3b8ae50db5, + 0x3b8ae50e0c, 0x3b8ae511c7, 0x3b8ae51306, 0x3b8ae513ec, + 0x3b8ae4c49f, 0x3b8ae4c488, 0x3b8ae4c4a6, 0x3b8ae4c494, + 0x3b8ae4c4ec, 0x3b8ae4c4d5, 0x3b8ae4c4f3, 0x3b8ae4c4e1, + 0x3b8ae49522, 0x3b8ae48ed7, 0x3b8ae48f90, 0x3b8ae4904d, + 0x3b8ae47ebb, 0x3b8ae4938e, 0x3b8ae4d1be, 0x3b8ae516df, + 0x3b8ae48ae5, 0x3b8ae518e1, 0x3b8ae51980, 0x3b8ae514d4, + 0x3b8ae515cb, 0x3b8ae51633, 0x3b8ae47e34, 0x3b8ae47d8f, + 0x3b8ae4a126, 0x3b8ae4825c, 0x3b8ae4e0f2, 0x3b8ae4de9c, + 0x3b8ae50881, 0x3b8ae50881, 0x3b8ae50068, 0x3b8ae4fe79, + 0x3b8ae4fe79, 0x3b8ae50675, 0x3b8ae50841, 0x3b8ae516ff, + 0x3b8ae4917a, 0x3b8ae47db0, 0x3b8ae51678, 0x3b8ae4fb6d, + 0x3b8ae4fb6d, 0x3b8ae4f61e, 0x3b8ae4f69d, 0x3b8ae50467, + 0x3b8ae4867f, 0x3b8ae48711, 0x3b8ae4881f, 0x3b8ae4892d, + 0x3b8ae48a09, 0x3b8ae5154a, 0x3b8ae4a24c, 0x3b8ae48676, + 0x3b8ae4f25c, 0x3b8ae4f354, 0x3b8ae527ba, 0x3b8ae527bc, + 0x3b8ae51698, 0x3b8ae47ef7, 0x3b8ae47fc8, 0x3b8ae4fbf4, + 0x3b8ae4fcd9, 0x3b8ae4c615, 0x3b8ae4c5e2, 0x3b8ae4c62e, + 0x3b8ae4c5fc, 0x3b8ae4ee9f, 0x3b8ae51a13, 0x3b8ae51a64, + 0x3b8ae51ab9, 0x3b8ae51b0c, 0x3b8ae51b81, 0x3b8ae51beb, + 0x3b8ae51c49, 0x3b8ae51ca5, 0x3b8ae51ca5, 0x3b8ae51d1f, + 0x3b8ae51d9f, 0x3b8ae51e70, 0x3b8ae51f21, 0x3b8ae52017, + 0x3b8ae52064, 0x3b8ae52182, 0x3b8ae521dc, 0x3b8ae52236, + 0x3b8ae5228c, 0x3b8ae52307, 0x3b8ae52393, 0x3b8ae5240a, + 0x3b8ae52481, 0x3b8ae4cd7d, 0x3b8ae4f940, 0x3b8ae4f940, + 0x3b8ae51f21, 0x3b8ae4ec27, 0x3b8ae4ed53, 0x3b8ae4edb4, + 0x3b8ae4edb4, 0x3b8ae47df2, 0x3b8ae47e13, 0x3b8ae4db85, + 0x3b8ae47fc8, 0x3b8ae4c984, 0x3b8ae51e70, 0x3b8ae4be50, + 0x3b8ae52558...} + len = 0 + str = 0x3a + ok = 58 + atom = 0x0 + rval = 140258808592640 + i = 58 + setter = 0x3a + index = 2157421248 + attrs = 2279691360 + flags = 0 + ltmp = 140258609439424 + j = 0 + atoms = 0x7f907fd61060 + parent = 0x7f908097a2c0 + argc = 0 + slot = 0 + str2 = 0x7f908097a2c0 + type = JSTYPE_VOID + interruptJumpTable = {0x3b8ae47cf9 <repeats 235 times>} + rtmp = 2 + sprop = 0x7f908097a2c0 +#44 0x0000003b8ae5508e in js_Invoke (cx=0x7f9080467c00, argc=1, + vp=0x7f908097a1a0, flags=0) + at /usr/src/debug/thunderbird-3.1.1/comm-1.9.2/mozilla/js/src/jsinterp.cpp:1368 + frame = {regs = 0x7f908097a280, imacpc = 0x0, slots = 0x7f908097a1b8, + callobj = 0x0, argsobj = 0, varobj = 0x0, script = 0x7f9088581000, + fun = 0x7f90969d30e0, thisp = 0x7f9096ef1040, argc = 1, + argv = 0x7f908097a1b0, rval = 22, down = 0x7fff32df14c0, + annotation = 0x0, scopeChain = 0x7f90910dcb40, blockChain = 0x0, + sharpDepth = 0, sharpArray = 0x0, flags = 32, dormantNext = 0x0, + displaySave = 0x7f908097a070} + argv = 0x7f908097a1b0 + funobj = <value optimized out> + ok = 32656 + clasp = <value optimized out> + i = <value optimized out> + mark = 0x7f908097a1b8 + sp = <value optimized out> + newvp = <value optimized out> + v = 140258984268032 + ops = <value optimized out> + hookData = 0x0 + parent = 0x7f90910dcb40 + fun = <value optimized out> + rootedArgsFlag = 32 + native = 0 + script = 0x7f9088581000 + nslots = <value optimized out> + hook = 0 +#45 0x00007f909e7feddd in nsXPCWrappedJSClass::CallMethod ( + this=0x7f908c311500, wrapper=<value optimized out>, methodIndex=5, + info=0x7f909bddbee8, nativeParams=0x7fff32df0aa0) + at /usr/src/debug/thunderbird-3.1.1/comm-1.9.2/mozilla/js/src/xpconnect/src/xpcwrappedjsclass.cpp:1696 + _val_1654 = {mVal = 0, mValPtr = 0x7fff32df07e8} + _automarker_1654 = {<AutoMarkingPtr> = { + _vptr.AutoMarkingPtr = 0x7f909ea74790, mNext = 0x0, + mTLS = 0x7f90a0aa1a60}, mPtr = 0x7fff32df0740} + stackbase = 0x7f908097a1a0 + paramCount = 1 '\001' + retval = 2147500037 + ssm = 0x7f90a8245740 + sp = 0x7f908097a1b8 + argc = 1 '\001' + fval = 140258984268032 + foundDependentParam = <value optimized out> + ccx = {<nsAXPCNativeCallContext> = { + _vptr.nsAXPCNativeCallContext = 0x7f909ea74c50}, + mState = XPCCallContext::HAVE_CONTEXT, mXPC = 0x7f90a0a16c10, + mThreadData = 0x7f90a0aa1a60, mXPCContext = 0x7f90823f0700, + mJSContext = 0x7f9080467c00, mContextPopRequired = 0, + mDestroyJSContextInDestructor = 0, + mCallerLanguage = XPCContext::LANG_NATIVE, + mPrevCallerLanguage = XPCContext::LANG_JS, + mPrevCallContext = 0x7fff32df1330, mOperandJSObject = 0x3858c23e28, + mCurrentJSObject = 0x7fff32df1330, + mFlattenedJSObject = 0x7f909e7e4781, mWrapper = 0x0, + mTearOff = 0x7f909e8067ba, mScriptableInfo = 0x2, + mSet = 0x7f907e685428, mInterface = 0x7f909ea74760, + mMember = 0x7fff32df0a80, mName = 140259147520608, + mStaticMemberIsLocal = 2106745680, mArgc = 32656, + mArgv = 0x7f907fb15720, mRetVal = 0xe11236a8, + mReturnValueWasSet = 655456, mMethodIndex = 0, + mCallee = 0x7f9096ef1100, + mStringWrapperData = "\000|F\200\220\177\000\000\021\n\200\236\220\177\000\000\000\000\000\000\220\177\000\000\060\023\337\062\377\177\000\000\060\023\337\062\377\177\000\000\000\000\000\000\220\177\000"} + scriptEval = {mJSContext = 0x7f9080467c00, mState = 0x0, + mErrorReporterSet = 0, mEvaluated = 1, + mContextHasThread = 140259272757312} + i = <value optimized out> + stack_size = <value optimized out> + success = <value optimized out> + readyToDoTheCall = -1474013376 + xpcc = 0x7f90823f0700 + context = <value optimized out> + param_iid = {m0 = 853478080, m1 = 32767, m2 = 0, + m3 = "\340n\316\177\220\177\000"} + mark = <value optimized out> + cx = 0x7f9080467c00 + popPrincipal = 1 + obj = 0x7f9096ef1040 + thisObj = 0x7f9096ef1040 + result = 0 + name = 0x7f909bddbf80 "doCommand" + kungFuDeathGrip = {<nsCOMPtr_base> = { + mRawPtr = 0x7f908c311500}, <No data fields>} +#46 0x0000003139a78be1 in PrepareAndDispatch (self=0x7f907fb15720, + methodIndex=<value optimized out>, args=<value optimized out>, + gpregs=0x7fff32df0ba0, fpregs=0x7fff32df0bd0) + at /usr/src/debug/thunderbird-3.1.1/comm-1.9.2/mozilla/xpcom/reflect/xptcall/src/md/unix/xptcstubs_x86_64_linux.cpp:153 + paramCount = <value optimized out> + nr_fpr = <value optimized out> + value = <value optimized out> + paramBuffer = {{val = {i8 = 112 'p', i16 = -31376, i32 = 2106688880, + i64 = 140258558707056, u8 = 112 'p', u16 = 34160, + u32 = 2106688880, u64 = 140258558707056, f = 2.41788633e+37, + d = 6.9296935392364016e-310, b = 2106688880, c = 112 'p', + wc = 34160, p = 0x7f907d918570}}, {val = {i8 = 40 '(', + i16 = 3624, i32 = 853478952, i64 = 140734046866984, + u8 = 40 '(', u16 = 3624, u32 = 853478952, + u64 = 140734046866984, f = 2.59670543e-08, + d = 6.953185775718871e-310, b = 853478952, c = 40 '(', + wc = 3624, p = 0x7fff32df0e28}}, {val = {i8 = 104 'h', + i16 = 19048, i32 = 969689704, i64 = 211423087208, u8 = 104 'h', + u16 = 19048, u32 = 969689704, u64 = 211423087208, + f = 0.000389653491, d = 1.0445688412717071e-312, b = 969689704, + c = 104 'h', wc = 19048, p = 0x3139cc4a68}}, {val = { + i8 = 0 '\000', i16 = 16128, i32 = -1681244416, + i64 = 140259065741056, u8 = 0 '\000', u16 = 16128, + u32 = 2613722880, u64 = 140259065741056, f = -3.34588095e-22, + d = 6.929718590044469e-310, b = -1681244416, c = 0 '\000', + wc = 16128, p = 0x7f909bca3f00}}, {val = {i8 = -32 '\340', + i16 = -11552, i32 = 2106774240, i64 = 140258558792416, + u8 = 224 '\340', u16 = 53984, u32 = 2106774240, + u64 = 140258558792416, f = 2.43952766e+37, + d = 6.929693543453746e-310, b = 2106774240, c = -32 '\340', + wc = 53984, p = 0x7f907d92d2e0}}, {val = {i8 = -112 '\220', + i16 = 2960, i32 = 853478288, i64 = 140734046866320, + u8 = 144 '\220', u16 = 2960, u32 = 853478288, + u64 = 140734046866320, f = 2.59658748e-08, + d = 6.953185775686065e-310, b = 853478288, c = -112 '\220', + wc = 2960, p = 0x7fff32df0b90}}, {val = {i8 = 1 '\001', + i16 = 1, i32 = 1, i64 = 140733193388033, u8 = 1 '\001', + u16 = 1, u32 = 1, u64 = 140733193388033, f = 1.40129846e-45, + d = 6.9531436082559572e-310, b = 1, c = 1 '\001', wc = 1, + p = 0x7fff00000001}}, {val = {i8 = 14 '\016', i16 = -19698, + i32 = -1792036082, i64 = 2502931214, u8 = 14 '\016', + u16 = 45838, u32 = 2502931214, u64 = 2502931214, + f = -3.54822178e-26, d = 1.2366123267411253e-314, + b = -1792036082, c = 14 '\016', wc = 45838, p = 0x952fb30e}}, { + val = {i8 = 77 'M', i16 = 5197, i32 = 1208030285, + i64 = 241726198861, u8 = 77 'M', u16 = 5197, u32 = 1208030285, + u64 = 241726198861, f = 132177.203, + d = 1.1942861055700956e-312, b = 1208030285, c = 77 'M', + wc = 5197, p = 0x384801144d}}, {val = {i8 = 56 '8', i16 = 4152, + i32 = 853479480, i64 = 140734046867512, u8 = 56 '8', + u16 = 4152, u32 = 853479480, u64 = 140734046867512, + f = 2.59679922e-08, d = 6.9531857757449576e-310, b = 853479480, + c = 56 '8', wc = 4152, p = 0x7fff32df1038}}, {val = { + i8 = -48 '\320', i16 = 3024, i32 = 853478352, + i64 = 140734046866384, u8 = 208 '\320', u16 = 3024, + u32 = 853478352, u64 = 140734046866384, f = 2.59659885e-08, + d = 6.953185775689227e-310, b = 853478352, c = -48 '\320', + wc = 3024, p = 0x7fff32df0bd0}}, {val = {i8 = 40 '(', + i16 = 3624, i32 = 853478952, i64 = 140734046866984, + u8 = 40 '(', u16 = 3624, u32 = 853478952, + u64 = 140734046866984, f = 2.59670543e-08, + d = 6.953185775718871e-310, b = 853478952, c = 40 '(', + wc = 3624, p = 0x7fff32df0e28}}, {val = {i8 = -88 '\250', + i16 = 4264, i32 = 853479592, i64 = 140734046867624, + u8 = 168 '\250', u16 = 4264, u32 = 853479592, + u64 = 140734046867624, f = 2.59681912e-08, + d = 6.9531857757504912e-310, b = 853479592, c = -88 '\250', + wc = 4264, p = 0x7fff32df10a8}}, {val = {i8 = 0 '\000', + i16 = 31744, i32 = -2142864384, i64 = 140258604121088, + u8 = 0 '\000', u16 = 31744, u32 = 2152102912, + u64 = 140258604121088, f = -6.47296755e-39, + d = 6.9296957829877067e-310, b = -2142864384, c = 0 '\000', + wc = 31744, p = 0x7f9080467c00}}, {val = {i8 = -128 '\200', + i16 = -896, i32 = -1676280704, i64 = 140259070704768, + u8 = 128 '\200', u16 = 64640, u32 = 2618686592, + u64 = 140259070704768, f = -4.96263131e-22, + d = 6.9297188352844265e-310, b = -1676280704, c = -128 '\200', + wc = 64640, p = 0x7f909c15fc80}}, {val = {i8 = 26 '\032', + i16 = 3610, i32 = -1635840486, i64 = 2659126810, + u8 = 26 '\032', u16 = 3610, u32 = 2659126810, u64 = 2659126810, + f = -1.35025037e-20, d = 1.3137832047564237e-314, + b = -1635840486, c = 26 '\032', wc = 3610, p = 0x9e7f0e1a}}} + dispatchParams = <value optimized out> + info = 0x7f909bddbee8 + nr_gpr = <value optimized out> + i = <value optimized out> + result = 2147500037 + ap = 0x7fff32df0c20 +#47 0x0000003139a780a3 in SharedStub () + from /usr/lib64/thunderbird-3.1/libxpcom_core.so +No symbol table info available. +#48 0x0000003139a78001 in NS_InvokeByIndex_P (that=0x7f907fb15720, + methodIndex=5, paramCount=1, params=<value optimized out>) + at /usr/src/debug/thunderbird-3.1.1/comm-1.9.2/mozilla/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_x86_64_unix.cpp:208 + nr_stack = <value optimized out> + gpregs = {140259272788352, 140258558707056, 0, 0, 140258804115488, + 140259010974516} + d0 = <value optimized out> + d5 = <value optimized out> + result = <value optimized out> + nr_gpr = 2 + d1 = <value optimized out> + d6 = <value optimized out> + nr_fpr = 0 + d2 = <value optimized out> + d7 = <value optimized out> + methodAddress = <value optimized out> + stack = 0x3139a77fdf + fpregs = {6.9297056640239467e-310, 6.9297158842153043e-310, + 6.9531857757825066e-310, 1.263489511150433e-312, + 6.9297154859551136e-310, 6.9297208330274031e-310, + 9.5023411082278302e-315, 1.8656250996705733e-314} + d3 = <value optimized out> + d4 = <value optimized out> +#49 0x00007f909e801e8f in XPCWrappedNative::CallMethod (ccx=..., + mode=<value optimized out>) + at /usr/src/debug/thunderbird-3.1.1/comm-1.9.2/mozilla/js/src/xpconnect/src/xpcwrappednative.cpp:2722 + req = warning: bits 96-128 in computed object were optimized out; replacing with zeroes +{mCX = 0x0, mDepth = -1745217232} + rv = <value optimized out> + retval = 0 + paramCount = 1 '\001' + err = <value optimized out> + tls = <value optimized out> + secAction = <value optimized out> + methodInfo = 0x7f909bddbee8 + src = 140259002913588 + foundDependentParam = 0 + argc = 1 + i = 1 '\001' + xpcc = 0x7f90823f0700 + argv = 0x7f908097a158 + secFlag = <value optimized out> + autoStringUsed = 0 + invokeResult = <value optimized out> + param_iid = {m0 = 1, m1 = 0, m2 = 0, m3 = "\323\345\341\212;\000\000"} + ifaceInfo = 0x7f908c322820 + paramBuffer = {{<nsXPTCMiniVariant> = {val = {i8 = 112 'p', + i16 = -31376, i32 = 2106688880, i64 = 140258558707056, + u8 = 112 'p', u16 = 34160, u32 = 2106688880, + u64 = 140258558707056, f = 2.41788633e+37, + d = 6.9296935392364016e-310, b = 2106688880, c = 112 'p', + wc = 34160, p = 0x7f907d918570}}, ptr = 0x7f9097fa18c0, + type = {<XPTTypeDescriptorPrefix> = { + flags = 144 '\220'}, <No data fields>}, flags = 0 '\000'}, + {<nsXPTCMiniVariant> = {val = {i8 = 33 '!', i16 = -14047, + i32 = -1964652255, i64 = 255733385505, u8 = 33 '!', + u16 = 51489, u32 = 2330315041, u64 = 255733385505, + f = -2.21275541e-32, d = 1.263490802726963e-312, + b = -1964652255, c = 33 '!', wc = 51489, p = 0x3b8ae5c921}}, + ptr = 0x7f90a0ee0470, type = {<XPTTypeDescriptorPrefix> = { + flags = 0 '\000'}, <No data fields>}, flags = 196 '\304'}, + {<nsXPTCMiniVariant> = {val = {i8 = 120 'x', i16 = 3704, + i32 = 853479032, i64 = 140734046867064, u8 = 120 'x', + u16 = 3704, u32 = 853479032, u64 = 140734046867064, + f = 2.59671964e-08, d = 6.9531857757228235e-310, + b = 853479032, c = 120 'x', wc = 3704, p = 0x7fff32df0e78}}, + ptr = 0x7fff32df0ea8, type = {<XPTTypeDescriptorPrefix> = { + flags = 168 '\250'}, <No data fields>}, flags = 14 '\016'}, + {<nsXPTCMiniVariant> = {val = {i8 = 0 '\000', i16 = 0, i32 = 0, + i64 = 0, u8 = 0 '\000', u16 = 0, u32 = 0, u64 = 0, f = 0, + d = 0, b = 0, c = 0 '\000', wc = 0, p = 0x0}}, + ptr = 0x7f9096d1c400, type = {<XPTTypeDescriptorPrefix> = { + flags = 0 '\000'}, <No data fields>}, flags = 196 '\304'}, + {<nsXPTCMiniVariant> = {val = {i8 = 0 '\000', i16 = 0, i32 = 0, + i64 = 0, u8 = 0 '\000', u16 = 0, u32 = 0, u64 = 0, f = 0, + d = 0, b = 0, c = 0 '\000', wc = 0, p = 0x0}}, + ptr = 0x3b8b0ca6b0, type = {<XPTTypeDescriptorPrefix> = { + flags = 168 '\250'}, <No data fields>}, flags = 14 '\016'}, + {<nsXPTCMiniVariant> = {val = {i8 = 62 '>', i16 = 15166, + i32 = 1489124158, i64 = 242007292734, u8 = 62 '>', + u16 = 15166, u32 = 1489124158, u64 = 242007292734, + f = 1.70847759e+15, d = 1.1956748938291532e-312, + b = 1489124158, c = 62 '>', wc = 15166, p = 0x3858c23b3e}}, + ptr = 0x1, type = {<XPTTypeDescriptorPrefix> = { + flags = 192 '\300'}, <No data fields>}, flags = 88 'X'}, + {<nsXPTCMiniVariant> = {val = {i8 = -1 '\377', i16 = -1, i32 = -1, + i64 = 4294967295, u8 = 255 '\377', u16 = 65535, + u32 = 4294967295, u64 = 4294967295, f = -nan(0x7fffff), + d = 2.1219957904712067e-314, b = -1, c = -1 '\377', + wc = 65535, p = 0xffffffff}}, ptr = 0x0, + type = {<XPTTypeDescriptorPrefix> = { + flags = 0 '\000'}, <No data fields>}, flags = 0 '\000'}, + {<nsXPTCMiniVariant> = {val = {i8 = -32 '\340', i16 = 4064, + i32 = 853479392, i64 = 140734046867424, u8 = 224 '\340', + u16 = 4064, u32 = 853479392, u64 = 140734046867424, + f = 2.59678359e-08, d = 6.9531857757406099e-310, + b = 853479392, c = -32 '\340', wc = 4064, + p = 0x7fff32df0fe0}}, ptr = 0x7f9098869334, + type = {<XPTTypeDescriptorPrefix> = { + flags = 251 '\373'}, <No data fields>}, flags = 77 'M'}} + autoString = "\000?\312\233\220\177\000\000\000\000\000\000\000\000\000\000\001", '\000' <repeats 15 times>"\200, *v\214\220\177\000\000\204Q~\236\220\177\000\000\a\000\000\000\000\000\000\000\360\271#\250\220\177\000\000\000?\312\233\220\177\000\000\000\000\000\000\001\000\000\000\004\222\206\230\220\177\000\000\000|F\200\220\177", '\000' <repeats 11 times>, "|F\200\220\177\000\000\000|F\200\220\177\000\000\060\023\337\062\377\177\000\000\200*v\214\220\177\000\000\060\023\337\062\377\177\000\000 \023\337\062\377\177\000\000(\023\337\062\377\177\000" + dispatchParams = 0x7fff32df0e10 + requiredArgs = <value optimized out> + sm = <value optimized out> + rt = 0x7f90a0a2ac00 + callee = 0x7f907fb15720 + vtblIndex = 5 + name = <value optimized out> +#50 0x00007f909e80b09d in XPC_WN_CallMethod (cx=0x7f9080467c00, + obj=0x7f909bca3f00, argc=1, argv=0x7f908097a158, vp=<value optimized out>) + at /usr/src/debug/thunderbird-3.1.1/comm-1.9.2/mozilla/js/src/xpconnect/src/xpcwrappednativejsops.cpp:1740 + funobj = <value optimized out> + wrapper = <value optimized out> + member = 0x7f907d9263b0 + ccx = {<nsAXPCNativeCallContext> = { + _vptr.nsAXPCNativeCallContext = 0x7f909ea74c50}, + mState = XPCCallContext::READY_TO_CALL, mXPC = 0x7f90a0a16c10, + mThreadData = 0x7f90a0aa1a60, mXPCContext = 0x7f90823f0700, + mJSContext = 0x7f9080467c00, mContextPopRequired = 0, + mDestroyJSContextInDestructor = 0, + mCallerLanguage = XPCContext::LANG_JS, + mPrevCallerLanguage = XPCContext::LANG_UNKNOWN, + mPrevCallContext = 0x0, mOperandJSObject = 0x7f909bca3f00, + mCurrentJSObject = 0x7f909bca3f00, + mFlattenedJSObject = 0x7f909bca3f00, mWrapper = 0x7f907d92d2e0, + mTearOff = 0x7f907d92d318, mScriptableInfo = 0x0, + mSet = 0x7f907d9144a0, mInterface = 0x7f907d926350, + mMember = 0x7f907d9263b0, mName = 140259010974516, + mStaticMemberIsLocal = 0, mArgc = 1, mArgv = 0x7f908097a158, + mRetVal = 0x7fff32df1518, mReturnValueWasSet = 0, mMethodIndex = 5, + mCallee = 0x0, + mStringWrapperData = "4\223\206\230\220\177\000\000\000|F\200\220\177\000\000\000\000\000\000\220\177\000\000p\240\227\200\220\177\000\000\000\000\000\000\005\000\000\000\000\000\000\000\220\177\000"} + iface = 0x7f907d926350 +#51 0x0000003b8ae55084 in js_Invoke (cx=0x7f9080467c00, argc=1, + vp=0x7f908097a148, flags=2) + at /usr/src/debug/thunderbird-3.1.1/comm-1.9.2/mozilla/js/src/jsinterp.cpp:1360 + frame = {regs = 0x0, imacpc = 0x0, slots = 0x0, callobj = 0x0, + argsobj = 0, varobj = 0x0, script = 0x0, fun = 0x7f9088563150, + thisp = 0x7f909bca3f00, argc = 1, argv = 0x7f908097a158, rval = 22, + down = 0x7f908097a070, annotation = 0x0, + scopeChain = 0x7f90910dcb40, blockChain = 0x0, sharpDepth = 0, + sharpArray = 0x0, flags = 34, dormantNext = 0x0, displaySave = 0x0} + argv = 0x7f908097a158 + funobj = <value optimized out> + ok = 59 + clasp = <value optimized out> + i = <value optimized out> + mark = 0x7f908097a190 + sp = <value optimized out> + newvp = <value optimized out> + v = 140258808572544 + ops = <value optimized out> + hookData = 0x0 + parent = 0x7f909bca3f00 + fun = <value optimized out> + rootedArgsFlag = 32 + native = 0x7f909e80afb5 <XPC_WN_CallMethod(JSContext*, JSObject*, uintN, jsval*, jsval*)> + script = 0x0 + nslots = <value optimized out> + hook = 0 +#52 0x0000003b8ae4e5d1 in js_Interpret (cx=0x7f9080467c00) + at /usr/src/debug/thunderbird-3.1.1/comm-1.9.2/mozilla/js/src/jsops.cpp:2240 + getter = 0x7f9088563150 + op = JSOP_CALL + prop = 0x7f90974243d8 + npairs = -2137546424 + currentVersion = 12468 + obj = 0x7f908c762a80 + d = 6.9296960457298409e-310 + off = 48 + fp = 0x7f908097a070 + inlineCallCount = 1 + regs = {pc = 0x7f9097606612 ":", sp = 0x7f908097a160} + pc2 = 0x7f9000000001 <Address 0x7f9000000001 out of bounds> + clasp = 0x0 + low = 0 + rt = 0x7f90a0ee0000 + op2 = JSOP_PROPINC + vp = 0x3a + script = 0x7f9097606500 + originalVersion = 8192 + obj2 = 0x7f908cc7c980 + cond = 1 + lval = 58 + id = 140259010974516 + d2 = 0 + fun = 0x7f9088563150 + normalJumpTable = {0x3b8ae47d6e, 0x3b8ae47e55, 0x3b8ae47ef7, + 0x3b8ae47f34, 0x3b8ae47f78, 0x3b8ae47faa, 0x3b8ae48265, + 0x3b8ae482e8, 0x3b8ae483e1, 0x3b8ae4f5c6, 0x3b8ae48e31, + 0x3b8ae48e84, 0x3b8ae49091, 0x3b8ae490d5, 0x3b8ae491e3, + 0x3b8ae49532, 0x3b8ae49602, 0x3b8ae496d2, 0x3b8ae497a2, + 0x3b8ae49bf2, 0x3b8ae4a381, 0x3b8ae4a603, 0x3b8ae4a887, + 0x3b8ae4ab0f, 0x3b8ae4ad97, 0x3b8ae4ae6e, 0x3b8ae4af43, + 0x3b8ae4b019, 0x3b8ae4b3d5, 0x3b8ae4b505, 0x3b8ae4b635, + 0x3b8ae4b7ea, 0x3b8ae4b983, 0x3b8ae4ba19, 0x3b8ae4baa7, + 0x3b8ae4bb61, 0x3b8ae4bbc2, 0x3b8ae4bc96, 0x3b8ae4bd57, + 0x3b8ae4be50, 0x3b8ae4beab, 0x3b8ae4bfd4, 0x3b8ae4bef3, + 0x3b8ae4bedc, 0x3b8ae4bfd6, 0x3b8ae4bef5, 0x3b8ae4bede, + 0x3b8ae4bfd8, 0x3b8ae4bef7, 0x3b8ae4bee0, 0x3b8ae4bfd8, + 0x3b8ae4bef7, 0x3b8ae4bee0, 0x3b8ae4c984, 0x3b8ae4d1be, + 0x3b8ae4d92e, 0x3b8ae4dcc3, 0x3b8ae4e839, 0x3b8ae4e0f0, + 0x3b8ae4e839, 0x3b8ae4edd9, 0x3b8ae4edd9, 0x3b8ae4f059, + 0x3b8ae4f095, 0x3b8ae4f0d1, 0x3b8ae4c82b, 0x3b8ae4f10d, + 0x3b8ae4f149, 0x3b8ae484da, 0x3b8ae485a8, 0x3b8ae4f185, + 0x3b8ae4f35b, 0x3b8ae4a042, 0x3b8ae4a0b4, 0x3b8ae4e723, + 0x3b8ae48ce5, 0x3b8ae48d5f, 0x3b8ae48deb, 0x3b8ae4e0f2, + 0x3b8ae49129, 0x3b8ae4ee2c, 0x3b8ae47e91, 0x3b8ae4df8a, + 0x3b8ae4f552, 0x3b8ae4f70c, 0x3b8ae4f786, 0x3b8ae4f801, + 0x3b8ae4f8c5, 0x3b8ae4ebc9, 0x3b8ae50d1b, 0x3b8ae50db5, + 0x3b8ae50e0c, 0x3b8ae511c7, 0x3b8ae51306, 0x3b8ae513ec, + 0x3b8ae4c49f, 0x3b8ae4c488, 0x3b8ae4c4a6, 0x3b8ae4c494, + 0x3b8ae4c4ec, 0x3b8ae4c4d5, 0x3b8ae4c4f3, 0x3b8ae4c4e1, + 0x3b8ae49522, 0x3b8ae48ed7, 0x3b8ae48f90, 0x3b8ae4904d, + 0x3b8ae47ebb, 0x3b8ae4938e, 0x3b8ae4d1be, 0x3b8ae516df, + 0x3b8ae48ae5, 0x3b8ae518e1, 0x3b8ae51980, 0x3b8ae514d4, + 0x3b8ae515cb, 0x3b8ae51633, 0x3b8ae47e34, 0x3b8ae47d8f, + 0x3b8ae4a126, 0x3b8ae4825c, 0x3b8ae4e0f2, 0x3b8ae4de9c, + 0x3b8ae50881, 0x3b8ae50881, 0x3b8ae50068, 0x3b8ae4fe79, + 0x3b8ae4fe79, 0x3b8ae50675, 0x3b8ae50841, 0x3b8ae516ff, + 0x3b8ae4917a, 0x3b8ae47db0, 0x3b8ae51678, 0x3b8ae4fb6d, + 0x3b8ae4fb6d, 0x3b8ae4f61e, 0x3b8ae4f69d, 0x3b8ae50467, + 0x3b8ae4867f, 0x3b8ae48711, 0x3b8ae4881f, 0x3b8ae4892d, + 0x3b8ae48a09, 0x3b8ae5154a, 0x3b8ae4a24c, 0x3b8ae48676, + 0x3b8ae4f25c, 0x3b8ae4f354, 0x3b8ae527ba, 0x3b8ae527bc, + 0x3b8ae51698, 0x3b8ae47ef7, 0x3b8ae47fc8, 0x3b8ae4fbf4, + 0x3b8ae4fcd9, 0x3b8ae4c615, 0x3b8ae4c5e2, 0x3b8ae4c62e, + 0x3b8ae4c5fc, 0x3b8ae4ee9f, 0x3b8ae51a13, 0x3b8ae51a64, + 0x3b8ae51ab9, 0x3b8ae51b0c, 0x3b8ae51b81, 0x3b8ae51beb, + 0x3b8ae51c49, 0x3b8ae51ca5, 0x3b8ae51ca5, 0x3b8ae51d1f, + 0x3b8ae51d9f, 0x3b8ae51e70, 0x3b8ae51f21, 0x3b8ae52017, + 0x3b8ae52064, 0x3b8ae52182, 0x3b8ae521dc, 0x3b8ae52236, + 0x3b8ae5228c, 0x3b8ae52307, 0x3b8ae52393, 0x3b8ae5240a, + 0x3b8ae52481, 0x3b8ae4cd7d, 0x3b8ae4f940, 0x3b8ae4f940, + 0x3b8ae51f21, 0x3b8ae4ec27, 0x3b8ae4ed53, 0x3b8ae4edb4, + 0x3b8ae4edb4, 0x3b8ae47df2, 0x3b8ae47e13, 0x3b8ae4db85, + 0x3b8ae47fc8, 0x3b8ae4c984, 0x3b8ae51e70, 0x3b8ae4be50, + 0x3b8ae52558...} + len = 0 + str = 0x3a + ok = 58 + atom = 0x0 + rval = 140258808572544 + i = 58 + setter = 0x3a + index = 2157420872 + attrs = 2823501960 + flags = 0 + ltmp = 140258609439048 + j = 0 + atoms = 0x7f9097606570 + parent = 0x7f908097a148 + argc = 1 + slot = 0 + str2 = 0x7f908097a148 + type = JSTYPE_VOID + interruptJumpTable = {0x3b8ae47cf9 <repeats 235 times>} + rtmp = 0 + sprop = 0x7f908097a148 +#53 0x0000003b8ae5508e in js_Invoke (cx=0x7f9080467c00, argc=1, + vp=0x7f908097a040, flags=0) + at /usr/src/debug/thunderbird-3.1.1/comm-1.9.2/mozilla/js/src/jsinterp.cpp:1368 + frame = {regs = 0x7f908097a118, imacpc = 0x0, slots = 0x7f908097a058, + callobj = 0x0, argsobj = 0, varobj = 0x0, script = 0x7f9088605160, + fun = 0x7f90885469a0, thisp = 0x7f908c762700, argc = 1, + argv = 0x7f908097a050, rval = 22, down = 0x0, annotation = 0x0, + scopeChain = 0x7f908c762700, blockChain = 0x0, sharpDepth = 0, + sharpArray = 0x0, flags = 32, dormantNext = 0x0, displaySave = 0x0} + argv = 0x7f908097a050 + funobj = <value optimized out> + ok = 32656 + clasp = <value optimized out> + i = <value optimized out> + mark = 0x7f908097a058 + sp = <value optimized out> + newvp = <value optimized out> + v = 140258808571776 + ops = <value optimized out> + hookData = 0x0 + parent = 0x7f908c762700 + fun = <value optimized out> + rootedArgsFlag = 32 + native = 0 + script = 0x7f9088605160 + nslots = <value optimized out> + hook = 0 +#54 0x0000003b8ae553fe in js_InternalInvoke (cx=0x7f9080467c00, + obj=0x7f908c762700, fval=140258808571776, flags=0, + argc=<value optimized out>, argv=<value optimized out>, + rval=0x7fff32df1a20) + at /usr/src/debug/thunderbird-3.1.1/comm-1.9.2/mozilla/js/src/jsinterp.cpp:1423 + invokevp = 0x7f908097a040 + mark = 0x7f908097a040 + ok = <value optimized out> +#55 0x0000003b8ae1d3d7 in JS_CallFunctionValue (cx=0x7f9080467c00, + obj=<value optimized out>, fval=<value optimized out>, + argc=<value optimized out>, argv=<value optimized out>, + rval=<value optimized out>) + at /usr/src/debug/thunderbird-3.1.1/comm-1.9.2/mozilla/js/src/jsapi.cpp:5112 + ok = <value optimized out> +#56 0x00007f909531b526 in nsJSContext::CallEventHandler (this=0x7f9087e15460, + aTarget=<value optimized out>, aScope=<value optimized out>, + aHandler=0x7f908c762780, aargv=0x7f907d94b300, arv=0x7fff32df1cb0) + at /usr/src/debug/thunderbird-3.1.1/comm-1.9.2/mozilla/dom/base/nsJSEnvironment.cpp:2177 + argv = 0x7f908097a038 + funval = 140258808571776 + ok = <value optimized out> + mark = 0x7f908097a028 + argc = 1 + stackGuard = {mContext = 0x7f9080467c00, mStack = 0x7f908097a028} + ar = {mContext = 0x7f9080467c00, mSaveDepth = 0} + rv = 0 + holder = {mContext = 0x7f9087e15460, mTerminations = 0x0} + targetVal = 140258808571648 + tvr = {mContext = 0x7f9080467c00, mTvr = {down = 0x0, count = 1, u = { + value = 140734046870064, object = 0x7fff32df1a30, + xml = 0x7fff32df1a30, trace = 0x7fff32df1a30, + sprop = 0x7fff32df1a30, weakRoots = 0x7fff32df1a30, + compiler = 0x7fff32df1a30, script = 0x7fff32df1a30, + array = 0x7fff32df1a30}}} + target = 0x7f908c762700 + rval = 22 + stack = {<nsCOMPtr_base> = { + mRawPtr = 0x7f90a0a16c48}, <No data fields>} + ar = {mContext = 0x7f908234b420, mSaveDepth = -1471465336} +#57 0x00007f909535925f in nsJSEventListener::HandleEvent ( + this=0x7f9082311680, aEvent=0x7f907ffe8f38) + at /usr/src/debug/thunderbird-3.1.1/comm-1.9.2/mozilla/dom/src/events/nsJSEventListener.cpp:266 + rv = 0 + iargv = {<nsCOMPtr_base> = { + mRawPtr = 0x7f907d94b300}, <No data fields>} + eventString = {<nsFixedString> = {<nsString> = {<nsAString_internal> = {mData = 0x7f907d94b2e8, mLength = 9, mFlags = 65541}, <No data fields>}, + mFixedCapacity = 63, mFixedBuf = 0x7fff32df1b40}, mStorage = {99, + 111, 109, 109, 97, 110, 100, 0, 31744, 32838, 32656, 0, 7488, + 13023, 32767, 0, 7, 0, 0, 0, 46112, 33332, 32656, 0, 53832, + 34808, 32656, 0, 29, 0, 5, 1, 63, 0, 32767, 0, 7056, 13023, + 32767, 0, 0, 0, 0, 0, 16384, 0, 0, 0, 61252, 61793, 0, 0, 14097, + 14756, 49, 0, 45800, 32148, 32656, 0, 9, 0, 0, 0}} + atomName = {<nsCOMPtr_base> = { + mRawPtr = 0x7f909768f4a0}, <No data fields>} + funcval = {mObject = 0x7f908c762780, mContext = {<nsCOMPtr_base> = { + mRawPtr = 0x7f9087e15460}, <No data fields>}} + handledScriptError = <value optimized out> + vrv = {<nsCOMPtr_base> = {mRawPtr = 0x0}, <No data fields>} +#58 0x00007f90952308e4 in nsEventListenerManager::HandleEventSubType ( + this=0x7f908ba7a700, aListenerStruct=0x7f908ba7a740, + aListener=0x7f9082311680, aDOMEvent=0x7f907ffe8f38, + aCurrentTarget=0x7f908234b420, aPhaseFlags=<value optimized out>) + at /usr/src/debug/thunderbird-3.1.1/comm-1.9.2/mozilla/content/events/src/nsEventListenerManager.cpp:1041 + result = <value optimized out> +#59 0x00007f9095230cce in nsEventListenerManager::HandleEvent ( + this=0x7f908ba7a700, aPresContext=0x7f9080228c00, aEvent=0x7f907dab9940, + aDOMEvent=0x7fff32df20a0, aCurrentTarget=0x7f908234b420, aFlags=6, + aEventStatus=0x7fff32df20a8) + at /usr/src/debug/thunderbird-3.1.1/comm-1.9.2/mozilla/content/events/src/nsEventListenerManager.cpp:1147 + kungFuDeathGrip = {mRawPtr = 0x7f9082311680} + ls = 0x7f908ba7a740 + useTypeInterface = 0 + useGenericInterface = 1 + popupStatePusher = {mOldState = openAllowed} + hasListener = 1 + pusher = {mScx = {<nsCOMPtr_base> = { + mRawPtr = 0x7f9087e15460}, <No data fields>}, + mScriptIsRunning = 0, mPushedSomething = 1} + currentGroup = 0 + typeData = 0x0 + dispData = 0x0 + iter = {<nsAutoTObserverArray<nsListenerStruct, 2u>::ForwardIterator> = {<nsAutoTObserverArray<nsListenerStruct, 2u>::Iterator> = {<nsTObserverArray_base::Iterator_base> = {mPosition = 1, mNext = 0x0}, + mArray = @0x7f908ba7a728}, <No data fields>}, + mEnd = {<nsAutoTObserverArray<nsListenerStruct, 2u>::Iterator> = {<nsTObserverArray_base::Iterator_base> = {mPosition = 1, + mNext = 0x7fff32df1ee0}, + mArray = @0x7f908ba7a728}, <No data fields>}} +#60 0x00007f90952447a6 in nsEventTargetChainItem::HandleEvent ( + this=0x7f9097d17d20, aVisitor=..., aFlags=6, + aMayHaveNewListenerManagers=1) + at /usr/src/debug/thunderbird-3.1.1/comm-1.9.2/mozilla/content/events/src/nsEventDispatcher.cpp:246 +No locals. +#61 0x00007f90952448ca in nsEventTargetChainItem::HandleEventTargetChain ( + this=0x7f9097d17690, aVisitor=..., aFlags=6, aCallback=0x0, + aMayHaveNewListenerManagers=1) + at /usr/src/debug/thunderbird-3.1.1/comm-1.9.2/mozilla/content/events/src/nsEventDispatcher.cpp:310 + createdELMs = 2410 + firstTarget = {<nsCOMPtr_base> = { + mRawPtr = 0x7f908234b420}, <No data fields>} + item = 0x7f9097d17d20 +#62 0x00007f9095244f69 in nsEventDispatcher::Dispatch ( + aTarget=<value optimized out>, aPresContext=<value optimized out>, + aEvent=0x7f907dab9940, aDOMEvent=0x7f907ffe8f38, + aEventStatus=0x7fff32df21ec, aCallback=0x0, aTargets=0x0) + at /usr/src/debug/thunderbird-3.1.1/comm-1.9.2/mozilla/content/events/src/nsEventDispatcher.cpp:573 + postVisitor = {<nsEventChainVisitor> = { + mPresContext = 0x7f9080228c00, mEvent = 0x7f907dab9940, + mDOMEvent = 0x7f907ffe8f38, mEventStatus = nsEventStatus_eIgnore, + mItemFlags = 0, mItemData = {<nsCOMPtr_base> = { + mRawPtr = 0x0}, <No data fields>}}, <No data fields>} + t = {<nsCOMPtr_base> = {mRawPtr = 0x7f908234b420}, <No data fields>} + topEtci = 0x7f9097d17690 + rv = 0 + pool = {static sEtciPool = 0x7f909782f600, static sEtciPoolUsers = 3} + targetEtci = 0x7f9097d17d20 + preVisitor = {<nsEventChainVisitor> = {mPresContext = 0x7f9080228c00, + mEvent = 0x7f907dab9940, mDOMEvent = 0x7f907ffe8f38, + mEventStatus = nsEventStatus_eIgnore, mItemFlags = 0, + mItemData = {<nsCOMPtr_base> = { + mRawPtr = 0x7f9080467400}, <No data fields>}}, + mCanHandle = 1 '\001', mForceContentDispatch = 1 '\001', + mRelatedTargetIsInAnon = 0 '\000', + mOriginalTargetIsInAnon = 0 '\000', + mWantsWillHandleEvent = 0 '\000', mParentTarget = 0x0, + mEventTargetAtParent = 0x0} + content = {<nsCOMPtr_base> = { + mRawPtr = 0x7f908234b420}, <No data fields>} + isInAnon = <value optimized out> + status = <value optimized out> + target = {<nsCOMPtr_base> = { + mRawPtr = 0x7f908234b420}, <No data fields>} + externalDOMEvent = 1 + kungFuDeathGrip = {<nsCOMPtr_base> = { + mRawPtr = 0x7f9080228c00}, <No data fields>} +#63 0x00007f9095245244 in nsEventDispatcher::DispatchDOMEvent ( + aTarget=0x7f908234b420, aEvent=<value optimized out>, + aDOMEvent=0x7f907ffe8f38, aPresContext=0x7f9080228c00, + aEventStatus=0x7fff32df21ec) + at /usr/src/debug/thunderbird-3.1.1/comm-1.9.2/mozilla/content/events/src/nsEventDispatcher.cpp:636 + innerEvent = 0x7f907dab9940 + dontResetTrusted = 0 + privEvt = {<nsCOMPtr_base> = { + mRawPtr = 0x7f907ffe8f48}, <No data fields>} +#64 0x00007f909522e773 in nsEventListenerManager::DispatchEvent ( + this=<value optimized out>, aEvent=0x7f907ffe8f38, _retval=0x7fff32df2318) + at /usr/src/debug/thunderbird-3.1.1/comm-1.9.2/mozilla/content/events/src/nsEventListenerManager.cpp:1274 + context = {<nsCOMPtr_base> = { + mRawPtr = 0x7f9080228c00}, <No data fields>} + status = nsEventStatus_eIgnore + rv = <value optimized out> + targetNode = {<nsCOMPtr_base> = { + mRawPtr = 0x7f908234b420}, <No data fields>} + document = {<nsCOMPtr_base> = { + mRawPtr = 0x7f907fff1000}, <No data fields>} + shell = <value optimized out> +#65 0x00007f90951f06db in nsDOMEventRTTearoff::DispatchEvent ( + this=<value optimized out>, aEvt=0x7f907ffe8f38, + _retval=<value optimized out>) + at /usr/src/debug/thunderbird-3.1.1/comm-1.9.2/mozilla/content/base/src/nsGenericElement.cpp:1672 + target = {<nsCOMPtr_base> = { + mRawPtr = 0x7f908ba7a710}, <No data fields>} +#66 0x00007f90951bdeda in nsContentUtils::DispatchXULCommand ( + aTarget=0x7f908234b420, aTrusted=<value optimized out>, + aSourceEvent=0x7f907fd57ed8, aShell=0x0, aCtrl=0, aAlt=0, aShift=0, + aMeta=0) + at /usr/src/debug/thunderbird-3.1.1/comm-1.9.2/mozilla/content/base/src/nsContentUtils.cpp:5140 + docEvent = {<nsCOMPtr_base> = { + mRawPtr = 0x7f907fff1118}, <No data fields>} + xulCommand = {<nsCOMPtr_base> = { + mRawPtr = 0x7f907ffe8fa8}, <No data fields>} + pEvent = {<nsCOMPtr_base> = { + mRawPtr = 0x7f907ffe8f48}, <No data fields>} + rv = 0 + doc = <value optimized out> + event = {<nsCOMPtr_base> = { + mRawPtr = 0x7f907ffe8f38}, <No data fields>} + view = {<nsCOMPtr_base> = { + mRawPtr = 0x7f9080467490}, <No data fields>} + target = {<nsCOMPtr_base> = { + mRawPtr = 0x7f907d9518b0}, <No data fields>} + dummy = -1793133634 +#67 0x00007f9095465398 in nsXULElement::PreHandleEvent ( + this=<value optimized out>, aVisitor=...) + at /usr/src/debug/thunderbird-3.1.1/comm-1.9.2/mozilla/content/xul/content/src/nsXULElement.cpp:1672 + nsevent = {<nsCOMPtr_base> = {mRawPtr = 0x0}, <No data fields>} + orig = <value optimized out> + domDoc = {<nsCOMPtr_base> = { + mRawPtr = 0x7f907fff1108}, <No data fields>} + commandElt = {<nsCOMPtr_base> = { + mRawPtr = 0x7f908234b458}, <No data fields>} + commandContent = {<nsCOMPtr_base> = { + mRawPtr = 0x7f908234b420}, <No data fields>} + xulEvent = {<nsCOMPtr_base> = { + mRawPtr = 0x7f907fd57f48}, <No data fields>} + command = {<nsFixedString> = {<nsString> = {<nsAString_internal> = { + mData = 0x7f908ba762b8, mLength = 14, + mFlags = 65541}, <No data fields>}, mFixedCapacity = 63, + mFixedBuf = 0x7fff32df23b0}, mStorage = {0, 0, 0, 0, 14472, + 43083, 32656, 0, 2, 0, 0, 0, 30128, 34956, 32656, 0, 0, 0, 0, 0, + 16463, 14756, 49, 0, 19048, 14796, 49, 0, 50024, 32677, 32656, 0, + 53, 0, 0, 0, 39920, 36000, 32656, 0, 10220, 13023, 32767, 0, 0, + 0, 0, 0, 5197, 18433, 56, 0, 8192, 41190, 32656, 0, 56103, 14755, + 49, 0, 25137, 14759, 49, 0}} + tag = <value optimized out> +#68 0x00007f909524462e in nsEventTargetChainItem::PreHandleEvent ( + this=0x7f9097d172d8, aVisitor=...) + at /usr/src/debug/thunderbird-3.1.1/comm-1.9.2/mozilla/content/events/src/nsEventDispatcher.cpp:215 + rv = <value optimized out> +#69 0x00007f9095244dfe in nsEventDispatcher::Dispatch ( + aTarget=<value optimized out>, aPresContext=0x7f9080228c00, + aEvent=0x7f907dab98e0, aDOMEvent=0x7f907fd57ed8, + aEventStatus=0x7fff32df27ec, aCallback=0x0, aTargets=0x0) + at /usr/src/debug/thunderbird-3.1.1/comm-1.9.2/mozilla/content/events/src/nsEventDispatcher.cpp:520 + rv = 0 + pool = {static sEtciPool = 0x7f909782f600, static sEtciPoolUsers = 3} + targetEtci = 0x7f9097d172d8 + preVisitor = {<nsEventChainVisitor> = {mPresContext = 0x7f9080228c00, + mEvent = 0x7f907dab98e0, mDOMEvent = 0x7f907fd57ed8, + mEventStatus = nsEventStatus_eIgnore, mItemFlags = 0, + mItemData = {<nsCOMPtr_base> = { + mRawPtr = 0x0}, <No data fields>}}, mCanHandle = 0 '\000', + mForceContentDispatch = 1 '\001', + mRelatedTargetIsInAnon = 0 '\000', + mOriginalTargetIsInAnon = 1 '\001', + mWantsWillHandleEvent = 0 '\000', mParentTarget = 0x0, + mEventTargetAtParent = 0x0} + content = {<nsCOMPtr_base> = { + mRawPtr = 0x7f908ca09bf0}, <No data fields>} + isInAnon = <value optimized out> + status = <value optimized out> + target = {<nsCOMPtr_base> = { + mRawPtr = 0x7f908ca09bf0}, <No data fields>} + externalDOMEvent = 1 + kungFuDeathGrip = {<nsCOMPtr_base> = { + mRawPtr = 0x7f9080228c00}, <No data fields>} +#70 0x00007f9095245244 in nsEventDispatcher::DispatchDOMEvent ( + aTarget=0x7f908ca09bf0, aEvent=<value optimized out>, + aDOMEvent=0x7f907fd57ed8, aPresContext=0x7f9080228c00, + aEventStatus=0x7fff32df27ec) + at /usr/src/debug/thunderbird-3.1.1/comm-1.9.2/mozilla/content/events/src/nsEventDispatcher.cpp:636 + innerEvent = 0x7f907dab98e0 + dontResetTrusted = 0 + privEvt = {<nsCOMPtr_base> = { + mRawPtr = 0x7f907fd57ee8}, <No data fields>} +#71 0x00007f909509ee49 in PresShell::HandleDOMEventWithTarget ( + this=0x7f9080229000, aTargetContent=0x7f908ca09bf0, + aEvent=0x7f907fd57ed8, aStatus=<value optimized out>) + at /usr/src/debug/thunderbird-3.1.1/comm-1.9.2/mozilla/layout/base/nsPresShell.cpp:6590 + container = {<nsCOMPtr_base> = { + mRawPtr = 0x7f9080466c08}, <No data fields>} +#72 0x00007f90951bde99 in nsContentUtils::DispatchXULCommand ( + aTarget=0x7f908ca09bf0, aTrusted=<value optimized out>, aSourceEvent=0x0, + aShell=0x7f9080229000, aCtrl=0, aAlt=0, aShift=0, aMeta=0) + at /usr/src/debug/thunderbird-3.1.1/comm-1.9.2/mozilla/content/base/src/nsContentUtils.cpp:5134 + status = nsEventStatus_eIgnore + kungFuDeathGrip = {<nsCOMPtr_base> = { + mRawPtr = 0x7f9080229000}, <No data fields>} + docEvent = {<nsCOMPtr_base> = { + mRawPtr = 0x7f907fff1118}, <No data fields>} + xulCommand = {<nsCOMPtr_base> = { + mRawPtr = 0x7f907fd57f48}, <No data fields>} + pEvent = {<nsCOMPtr_base> = { + mRawPtr = 0x7f907fd57ee8}, <No data fields>} + rv = 0 + doc = <value optimized out> + event = {<nsCOMPtr_base> = { + mRawPtr = 0x7f907fd57ed8}, <No data fields>} + view = {<nsCOMPtr_base> = { + mRawPtr = 0x7f9080467490}, <No data fields>} + target = {<nsCOMPtr_base> = {mRawPtr = 0x0}, <No data fields>} + dummy = 0 +#73 0x00007f909518d001 in nsButtonBoxFrame::DoMouseClick ( + this=0x7f907fa84768, aEvent=0x7fff32df2bb0, + aTrustEvent=<value optimized out>) + at /usr/src/debug/thunderbird-3.1.1/comm-1.9.2/mozilla/layout/xul/base/src/nsButtonBoxFrame.cpp:173 + isControl = 0 + isAlt = 0 + isShift = 0 + isMeta = 0 + shell = {<nsCOMPtr_base> = { + mRawPtr = 0x7f9080229000}, <No data fields>} +#74 0x00007f909518d1a8 in nsButtonBoxFrame::HandleEvent (this=0x7f907fa84768, + aPresContext=0x7f9080228c00, aEvent=0x7fff32df2bb0, + aEventStatus=0x7fff32df29c8) + at /usr/src/debug/thunderbird-3.1.1/comm-1.9.2/mozilla/layout/xul/base/src/nsButtonBoxFrame.cpp:138 +No locals. +#75 0x00007f90952449a4 in nsEventTargetChainItem::HandleEventTargetChain ( + this=0x7f9097d170a8, aVisitor=..., aFlags=6, aCallback=0x7fff32df2a80, + aMayHaveNewListenerManagers=<value optimized out>) + at /usr/src/debug/thunderbird-3.1.1/comm-1.9.2/mozilla/content/events/src/nsEventDispatcher.cpp:354 + createdELMs = 2410 + firstTarget = {<nsCOMPtr_base> = { + mRawPtr = 0x7f90888c75b0}, <No data fields>} + item = 0x0 +#76 0x00007f9095244f69 in nsEventDispatcher::Dispatch ( + aTarget=<value optimized out>, aPresContext=<value optimized out>, + aEvent=0x7fff32df2bb0, aDOMEvent=0x0, aEventStatus=0x7fff32df30bc, + aCallback=0x7fff32df2a80, aTargets=0x0) + at /usr/src/debug/thunderbird-3.1.1/comm-1.9.2/mozilla/content/events/src/nsEventDispatcher.cpp:573 + postVisitor = {<nsEventChainVisitor> = { + mPresContext = 0x7f9080228c00, mEvent = 0x7fff32df2bb0, + mDOMEvent = 0x7f907da565f8, mEventStatus = nsEventStatus_eIgnore, + mItemFlags = 0, mItemData = {<nsCOMPtr_base> = { + mRawPtr = 0x0}, <No data fields>}}, <No data fields>} + t = {<nsCOMPtr_base> = {mRawPtr = 0x7f908ca09bf0}, <No data fields>} + topEtci = 0x7f9097d170a8 + rv = 0 + pool = {static sEtciPool = 0x7f909782f600, static sEtciPoolUsers = 3} + targetEtci = 0x7f9097d17118 + preVisitor = {<nsEventChainVisitor> = {mPresContext = 0x7f9080228c00, + mEvent = 0x7fff32df2bb0, mDOMEvent = 0x0, + mEventStatus = nsEventStatus_eIgnore, mItemFlags = 0, + mItemData = {<nsCOMPtr_base> = { + mRawPtr = 0x7f9080467400}, <No data fields>}}, + mCanHandle = 1 '\001', mForceContentDispatch = 1 '\001', + mRelatedTargetIsInAnon = 0 '\000', + mOriginalTargetIsInAnon = 1 '\001', + mWantsWillHandleEvent = 0 '\000', mParentTarget = 0x0, + mEventTargetAtParent = 0x0} + content = {<nsCOMPtr_base> = { + mRawPtr = 0x7f908ca09bf0}, <No data fields>} + isInAnon = <value optimized out> + status = <value optimized out> + target = {<nsCOMPtr_base> = { + mRawPtr = 0x7f908ca09bf0}, <No data fields>} + externalDOMEvent = 0 + kungFuDeathGrip = {<nsCOMPtr_base> = { + mRawPtr = 0x7f9080228c00}, <No data fields>} +#77 0x00007f909509eadb in PresShell::HandleEventInternal ( + this=0x7f9080229000, aEvent=0x7fff32df2bb0, aView=<value optimized out>, + aStatus=0x7fff32df30bc) + at /usr/src/debug/thunderbird-3.1.1/comm-1.9.2/mozilla/layout/base/nsPresShell.cpp:6525 + eventCB = {<nsDispatchingCallback> = { + _vptr.nsDispatchingCallback = 0x7f9095a029b0}, mPresShell = { + mRawPtr = 0x7f9080229000}} + wasHandlingKeyBoardEvent = 0 + popupStatePusher = {mOldState = openControlled} + weakView = {mPrev = 0x0, mView = 0x0} + isHandlingUserInput = 0 + userInpStatePusher = {mIsHandlingUserInput = 0} + manager = {<nsCOMPtr_base> = { + mRawPtr = 0x7f9081cd2d00}, <No data fields>} + rv = 0 +#78 0x00007f909509ef33 in PresShell::HandleEventWithTarget ( + this=0x7f9080229000, aEvent=0x7fff32df2bb0, aFrame=<value optimized out>, + aContent=<value optimized out>, aStatus=<value optimized out>) + at /usr/src/debug/thunderbird-3.1.1/comm-1.9.2/mozilla/layout/base/nsPresShell.cpp:6381 +No locals. +#79 0x00007f9095237ff0 in nsEventStateManager::CheckForAndDispatchClick ( + this=0x7f9081cd2cf0, aPresContext=<value optimized out>, + aEvent=0x7fff32df3220, aStatus=0x7fff32df30bc) + at /usr/src/debug/thunderbird-3.1.1/comm-1.9.2/mozilla/content/events/src/nsEventStateManager.cpp:3994 + mouseContent = {<nsCOMPtr_base> = { + mRawPtr = 0x7f908ca09bf0}, <No data fields>} + event = {<nsMouseEvent_base> = {<nsInputEvent> = {<nsGUIEvent> = {<nsEvent> = {eventStructType = 10 '\n', message = 327, refPoint = {x = 268, + y = 55}, time = 12433188, flags = 2049, + userType = {<nsCOMPtr_base> = { + mRawPtr = 0x0}, <No data fields>}, + target = {<nsCOMPtr_base> = { + mRawPtr = 0x7f908ca09bf0}, <No data fields>}, + currentTarget = {<nsCOMPtr_base> = { + mRawPtr = 0x0}, <No data fields>}, + originalTarget = {<nsCOMPtr_base> = { + mRawPtr = 0x7f908ca09bf0}, <No data fields>}}, + widget = {<nsCOMPtr_base> = { + mRawPtr = 0x7f9089f4fc70}, <No data fields>}, + nativeMsg = 0x0}, isShift = 0, isControl = 0, isAlt = 0, + isMeta = 0}, relatedTarget = {<nsCOMPtr_base> = { + mRawPtr = 0x0}, <No data fields>}, button = 0, pressure = 0}, + acceptActivation = 0 '\000', ignoreRootScrollFrame = 0 '\000', + reason = nsMouseEvent::eReal, context = nsMouseEvent::eNormal, + exit = nsMouseEvent::eChild, clickCount = 1} + presShell = {<nsCOMPtr_base> = { + mRawPtr = 0x7f9080229000}, <No data fields>} + ret = 0 + flags = 0 +#80 0x00007f90952384c4 in nsEventStateManager::PostHandleEvent ( + this=0x7f9081cd2cf0, aPresContext=0x7f9080228c00, aEvent=0x7fff32df3220, + aTargetFrame=0x7f907fa84768, aStatus=0x7fff32df30bc, aView=0x7f908a064c00) + at /usr/src/debug/thunderbird-3.1.1/comm-1.9.2/mozilla/content/events/src/nsEventStateManager.cpp:2947 + shell = <value optimized out> + presContext = {mRawPtr = 0x7f9080228c00} + ret = 0 +#81 0x00007f909509ebf9 in PresShell::HandleEventInternal ( + this=0x7f9080229000, aEvent=0x7fff32df3220, aView=<value optimized out>, + aStatus=0x7fff32df30bc) + at /usr/src/debug/thunderbird-3.1.1/comm-1.9.2/mozilla/layout/base/nsPresShell.cpp:6548 + wasHandlingKeyBoardEvent = <value optimized out> + popupStatePusher = {mOldState = openAbused} + weakView = {mPrev = 0x0, mView = 0x7f908a064c00} + isHandlingUserInput = 1 + userInpStatePusher = {mIsHandlingUserInput = 1} + manager = {<nsCOMPtr_base> = { + mRawPtr = 0x7f9081cd2d00}, <No data fields>} + rv = <value optimized out> +#82 0x00007f909509f074 in PresShell::HandlePositionedEvent ( + this=0x7f9080229000, aView=0x7f908a064c00, + aTargetFrame=<value optimized out>, aEvent=0x7fff32df3220, + aEventStatus=0x7fff32df30bc) + at /usr/src/debug/thunderbird-3.1.1/comm-1.9.2/mozilla/layout/base/nsPresShell.cpp:6364 + rv = 0 +#83 0x00007f90950a7aad in PresShell::HandleEvent (this=0x7f9080229000, + aView=0x7f908a064c00, aEvent=0x7fff32df3220, aEventStatus=0x7fff32df30bc) + at /usr/src/debug/thunderbird-3.1.1/comm-1.9.2/mozilla/layout/base/nsPresShell.cpp:6228 + framePresContext = <value optimized out> + rootPresContext = <value optimized out> + eventPoint = {x = 16080, y = 3300} + targetFrame = 0x7f907fa84768 + frame = <value optimized out> + dispatchUsingCoordinates = <value optimized out> + rv = <value optimized out> +#84 0x00007f9095310bf2 in nsViewManager::HandleEvent ( + this=<value optimized out>, aView=<value optimized out>, + aPoint=<value optimized out>, aEvent=0x7fff32df3220, + aCaptured=<value optimized out>) + at /usr/src/debug/thunderbird-3.1.1/comm-1.9.2/mozilla/view/src/nsViewManager.cpp:1224 + obs = {<nsCOMPtr_base> = {mRawPtr = 0x7f90802290e0}, <No data fields>} + status = nsEventStatus_eIgnore +#85 0x00007f9095313621 in nsViewManager::DispatchEvent (this=0x7f908a064b80, + aEvent=0x7fff32df3220, aView=<value optimized out>, + aStatus=0x7fff32df31cc) + at /usr/src/debug/thunderbird-3.1.1/comm-1.9.2/mozilla/view/src/nsViewManager.cpp:1203 + p2a = 60 + offset = <value optimized out> + baseViewDimensions = <value optimized out> + pt = warning: bits 32-64 in computed object were optimized out; replacing with zeroes +{x = 16110, y = 0} + baseView = <value optimized out> + view = <value optimized out> + capturedEvent = 0 +#86 0x00007f909530deaa in HandleEvent (aEvent=0x7fff32df3220) + at /usr/src/debug/thunderbird-3.1.1/comm-1.9.2/mozilla/view/src/nsView.cpp:167 + vm = {<nsCOMPtr_base> = {mRawPtr = 0x7f908a064b80}, <No data fields>} + result = nsEventStatus_eIgnore + view = 0x7f908a064c00 +#87 0x00007f909d169999 in nsWindow::DispatchEvent (this=0x7f9089f4fc70, + aEvent=<value optimized out>, aStatus=@0x7fff32df32ac) + at /usr/src/debug/thunderbird-3.1.1/comm-1.9.2/mozilla/widget/src/gtk2/nsWindow.cpp:626 +No locals. +#88 0x00007f909d171b96 in nsWindow::OnButtonReleaseEvent ( + this=0x7f9089f4fc70, aWidget=<value optimized out>, aEvent=0x7f90886050f0) + at /usr/src/debug/thunderbird-3.1.1/comm-1.9.2/mozilla/widget/src/gtk2/nsWindow.cpp:3227 + pressure = 0 + status = nsEventStatus_eIgnore + domButton = 0 + event = {<nsMouseEvent_base> = {<nsInputEvent> = {<nsGUIEvent> = {<nsEvent> = {eventStructType = 10 '\n', message = 301, refPoint = {x = 268, + y = 55}, time = 12433188, flags = 1025, + userType = {<nsCOMPtr_base> = { + mRawPtr = 0x0}, <No data fields>}, + target = {<nsCOMPtr_base> = { + mRawPtr = 0x7f90888c75b0}, <No data fields>}, + currentTarget = {<nsCOMPtr_base> = { + mRawPtr = 0x0}, <No data fields>}, + originalTarget = {<nsCOMPtr_base> = { + mRawPtr = 0x7f908ca09bf0}, <No data fields>}}, + widget = {<nsCOMPtr_base> = { + mRawPtr = 0x7f9089f4fc70}, <No data fields>}, + nativeMsg = 0x0}, isShift = 0, isControl = 0, isAlt = 0, + isMeta = 0}, relatedTarget = {<nsCOMPtr_base> = { + mRawPtr = 0x0}, <No data fields>}, button = 0, pressure = 0}, + acceptActivation = 0 '\000', ignoreRootScrollFrame = 0 '\000', + reason = nsMouseEvent::eReal, context = nsMouseEvent::eNormal, + exit = nsMouseEvent::eChild, clickCount = 1} +#89 0x00007f909d171c01 in button_release_event_cb (widget=0x7f9088083380, + event=0x7f90886050f0) + at /usr/src/debug/thunderbird-3.1.1/comm-1.9.2/mozilla/widget/src/gtk2/nsWindow.cpp:5981 + window = <value optimized out> +#90 0x0000003138b51003 in _gtk_marshal_BOOLEAN__BOXED ( + closure=0x7f90885b6970, return_value=0x7fff32df34b0, + n_param_values=<value optimized out>, param_values=0x7f907d92fa90, + invocation_hint=<value optimized out>, marshal_data=<value optimized out>) + at gtkmarshalers.c:84 + callback = 0x7f909d171bd2 <button_release_event_cb(GtkWidget*, GdkEventButton*)> + cc = 0x7f90885b6970 + data1 = 0x7f9088083380 + data2 = 0x0 + v_return = <value optimized out> + __PRETTY_FUNCTION__ = "_gtk_marshal_BOOLEAN__BOXED" +#91 0x000000384b00b98e in IA__g_closure_invoke (closure=0x7f90885b6970, + return_value=0x7fff32df34b0, n_param_values=2, + param_values=0x7f907d92fa90, invocation_hint=0x7fff32df3470) + at gclosure.c:767 + marshal = <value optimized out> + marshal_data = <value optimized out> + in_marshal = <value optimized out> + __PRETTY_FUNCTION__ = "IA__g_closure_invoke" +#92 0x000000384b01f947 in signal_emit_unlocked_R (node=<value optimized out>, + detail=0, instance=0x7f9088083380, emission_return=0x7fff32df3600, + instance_and_params=0x7f907d92fa90) at gsignal.c:3248 + tmp = <value optimized out> + handler = 0x7f90885b6940 + accumulator = 0x7f90a82a0cd0 + emission = {next = 0x0, instance = 0x7f9088083380, ihint = { + signal_id = 34, detail = 0, run_type = G_SIGNAL_RUN_FIRST}, + state = EMISSION_RUN, chain_type = 4} + class_closure = 0x7f90a829fe80 + handler_list = 0x7f90885b6940 + return_accu = 0x7fff32df34b0 + accu = {g_type = 20, data = {{v_int = 0, v_uint = 0, v_long = 0, + v_ulong = 0, v_int64 = 0, v_uint64 = 0, v_float = 0, + v_double = 0, v_pointer = 0x0}, {v_int = 0, v_uint = 0, + v_long = 0, v_ulong = 0, v_int64 = 0, v_uint64 = 0, + v_float = 0, v_double = 0, v_pointer = 0x0}}} + signal_id = 34 + max_sequential_handler_number = 1235 + return_value_altered = 0 +#93 0x000000384b020c29 in IA__g_signal_emit_valist ( + instance=<value optimized out>, signal_id=<value optimized out>, + detail=<value optimized out>, var_args=0x7fff32df3660) at gsignal.c:2991 + return_value = {g_type = 20, data = {{v_int = 0, v_uint = 0, + v_long = 0, v_ulong = 0, v_int64 = 0, v_uint64 = 0, + v_float = 0, v_double = 0, v_pointer = 0x0}, {v_int = 0, + v_uint = 0, v_long = 0, v_ulong = 0, v_int64 = 0, v_uint64 = 0, + v_float = 0, v_double = 0, v_pointer = 0x0}}} + error = 0x0 + rtype = 20 + static_scope = 0 + instance_and_params = 0x7f907d92fa90 + signal_return_type = 20 + param_values = 0x7f907d92faa8 + node = 0x7f90a82880b0 + i = <value optimized out> + n_params = 1 + __PRETTY_FUNCTION__ = "IA__g_signal_emit_valist" +#94 0x000000384b0213a3 in IA__g_signal_emit (instance=<value optimized out>, + signal_id=<value optimized out>, detail=<value optimized out>) + at gsignal.c:3038 + var_args = {{gp_offset = 32, fp_offset = 48, + overflow_arg_area = 0x7fff32df3740, + reg_save_area = 0x7fff32df3680}} +#95 0x0000003138c8190f in gtk_widget_event_internal (widget=0x7f9088083380, + event=0x7f90886050f0) at gtkwidget.c:4958 + signal_num = <value optimized out> + return_val = 0 +#96 0x0000003138b47d63 in IA__gtk_propagate_event (widget=0x7f9088083380, + event=0x7f90886050f0) at gtkmain.c:2442 + tmp = <value optimized out> + handled_event = <value optimized out> + __PRETTY_FUNCTION__ = "IA__gtk_propagate_event" +#97 0x0000003138b48f2b in IA__gtk_main_do_event (event=0x7f90886050f0) + at gtkmain.c:1647 + event_widget = <value optimized out> + grab_widget = 0x7f9088083380 + window_group = <value optimized out> + rewritten_event = <value optimized out> + tmp_list = <value optimized out> + __PRETTY_FUNCTION__ = "IA__gtk_main_do_event" +#98 0x000000313926039c in gdk_event_dispatch (source=<value optimized out>, + callback=<value optimized out>, user_data=<value optimized out>) + at gdkevents-x11.c:2372 + display = <value optimized out> + event = 0x7f90886050f0 +#99 0x0000003849c3bd02 in g_main_dispatch (context=0x7f90a82177a0) + at gmain.c:1960 + dispatch = 0x3139260350 <gdk_event_dispatch> + was_in_call = 0 + user_data = 0x0 + callback = 0 + cb_funcs = 0x0 + cb_data = 0x0 + current_source_link = {data = 0x7f90a821d6a0, next = 0x0} + need_destroy = <value optimized out> + source = 0x7f90a821d6a0 + current = 0x7f9099d609d0 + i = <value optimized out> +#100 IA__g_main_context_dispatch (context=0x7f90a82177a0) at gmain.c:2513 +No locals. +#101 0x0000003849c3fae8 in g_main_context_iterate (context=0x7f90a82177a0, + block=1, dispatch=1, self=<value optimized out>) at gmain.c:2591 + max_priority = 2147483647 + timeout = -1 + some_ready = 1 + nfds = 13 + allocated_nfds = <value optimized out> + fds = <value optimized out> + __PRETTY_FUNCTION__ = "g_main_context_iterate" +#102 0x0000003849c3fc9c in IA__g_main_context_iteration ( + context=0x7f90a82177a0, may_block=1) at gmain.c:2654 + retval = <value optimized out> +#103 0x00007f909d189b13 in nsBaseAppShell::DoProcessNextNativeEvent ( + this=0x7f90a0a7e700, mayWait=<value optimized out>) + at /usr/src/debug/thunderbird-3.1.1/comm-1.9.2/mozilla/widget/src/xpwidgets/nsBaseAppShell.cpp:155 + prevVal = nsBaseAppShell::eEventloopNone + result = 0 +#104 0x00007f909d189c79 in nsBaseAppShell::OnProcessNextEvent ( + this=0x7f90a0a7e700, thr=0x7f90a82438b0, mayWait=0, + recursionDepth=<value optimized out>) + at /usr/src/debug/thunderbird-3.1.1/comm-1.9.2/mozilla/widget/src/xpwidgets/nsBaseAppShell.cpp:311 + start = 1099877142 + limit = 20 + oldBlockedWait = 0x0 + needEvent = 1 +#105 0x0000003139a6c712 in nsThread::ProcessNextEvent (this=0x7f90a82438b0, + mayWait=1, result=0x7fff32df3a3c) + at /usr/src/debug/thunderbird-3.1.1/comm-1.9.2/mozilla/xpcom/threads/nsThread.cpp:508 + notifyGlobalObserver = 1 + obs = {<nsCOMPtr_base> = {mRawPtr = 0x7f90a0a7e708}, <No data fields>} + rv = <value optimized out> +#106 0x0000003139a3db88 in NS_ProcessNextEvent_P ( + thread=<value optimized out>, mayWait=<value optimized out>) + at nsThreadUtils.cpp:250 + val = 1 +#107 0x00007f909d189d69 in nsBaseAppShell::Run (this=0x7f90a0a7e700) + at /usr/src/debug/thunderbird-3.1.1/comm-1.9.2/mozilla/widget/src/xpwidgets/nsBaseAppShell.cpp:177 + thread = 0x7f90a82438b0 +#108 0x00007f909c4b589c in nsAppStartup::Run (this=0x7f90a0ad9d80) + at /usr/src/debug/thunderbird-3.1.1/comm-1.9.2/mozilla/toolkit/components/startup/src/nsAppStartup.cpp:183 + rv = <value optimized out> +#109 0x0000003139e1934d in XRE_main (argc=<value optimized out>, + argv=<value optimized out>, aAppData=<value optimized out>) + at /usr/src/debug/thunderbird-3.1.1/comm-1.9.2/mozilla/toolkit/xre/nsAppRunner.cpp:3483 + remoteService = {<nsCOMPtr_base> = { + mRawPtr = 0x7f9099ebc9b0}, <No data fields>} + appStartup = {<nsCOMPtr_base> = { + mRawPtr = 0x7f90a0ad9d80}, <No data fields>} + shuttingDown = 0 + cmdLine = {<nsCOMPtr_base> = { + mRawPtr = 0x7f9097395cc0}, <No data fields>} + workingDir = {<nsCOMPtr_base> = { + mRawPtr = 0x7f909753ce00}, <No data fields>} + xpcom = {mServiceManager = 0x7f90a829a148} + desktopStartupIDEnv = <value optimized out> + updRoot = {<nsCOMPtr_base> = { + mRawPtr = 0x7f90a821a180}, <No data fields>} + persistent = 1 + profLD = {<nsCOMPtr_base> = { + mRawPtr = 0x7f90a0e02fc0}, <No data fields>} + dirProvider = + {<nsIDirectoryServiceProvider2> = {<nsIDirectoryServiceProvider> = {<nsISupports> = { + _vptr.nsISupports = 0x313a02f4c0}, <No data fields>}, <No data fields>}, <nsIProfileStartup> = {<nsISupports> = { + _vptr.nsISupports = 0x313a02f508}, <No data fields>}, + mAppProvider = {<nsCOMPtr_base> = { + mRawPtr = 0x0}, <No data fields>}, + mGREDir = {<nsCOMPtr_base> = { + mRawPtr = 0x7f90a821a300}, <No data fields>}, + mXULAppDir = {<nsCOMPtr_base> = { + mRawPtr = 0x7f90a821a180}, <No data fields>}, + mProfileDir = {<nsCOMPtr_base> = { + mRawPtr = 0x7f90a0e02f00}, <No data fields>}, + mProfileLocalDir = {<nsCOMPtr_base> = { + mRawPtr = 0x7f90a0e02fc0}, <No data fields>}, + mProfileNotified = 1 '\001', mExtensionsLoaded = 1 '\001', + mAppBundleDirectories = {<nsCOMArray_base> = {mArray = { + mImpl = 0x0}}, <No data fields>}, + mExtensionDirectories = {<nsCOMArray_base> = {mArray = { + mImpl = 0x7f90a0e11600}}, <No data fields>}, + mThemeDirectories = {<nsCOMArray_base> = {mArray = { + mImpl = 0x7f90a0e11650}}, <No data fields>}} + desktopStartupIDPtr = <value optimized out> + nativeApp = {<nsCOMPtr_base> = { + mRawPtr = 0x7f90a82d4250}, <No data fields>} + startOffline = 0 + profileName = {<nsFixedCString> = {<nsCString> = {<nsACString_internal> = {mData = 0x7f90a0e10218 "default", mLength = 7, + mFlags = 65541}, <No data fields>}, mFixedCapacity = 63, + mFixedBuf = 0x7fff32df4040 ""}, + mStorage = "\000\000\000\000\000\000\000\000\200\241!\250\220\177\000\000\240@\337\062\377\177\000\000\260@\337\062\377\177\000\000\016\000\a\200\000\000\000\000T\r\246\071\061", '\000' <repeats 11 times>"\371, \062\246\071\061\000\000"} + upgraded = <value optimized out> + versionOK = -1712600656 + appInitiatedRestart = 0 + desktopStartupID = {<nsFixedCString> = {<nsCString> = {<nsACString_internal> = {mData = 0x7fff32df40a0 "", mLength = 0, + mFlags = 65553}, <No data fields>}, mFixedCapacity = 63, + mFixedBuf = 0x7fff32df40a0 ""}, + mStorage = "\000\003!\250\220\177\000\000\032\000\000\000\001\000\000\000\200\241!\250\220\177\000\000\000\000\000\000\000\000\000\000\"\030\246\071\061\000\000\000\371\062\246\071\061\000\000\000HA\337\062\377\177\000\000\000\000\000\000\000\000\000"} + display_name = <value optimized out> + xremotearg = <value optimized out> + _g_set_application_name = <value optimized out> + canRun = 1 + profileLock = {<nsCOMPtr_base> = { + mRawPtr = 0x7f90a0e11560}, <No data fields>} + profD = {<nsCOMPtr_base> = { + mRawPtr = 0x7f90a0e02f00}, <No data fields>} + version = {<nsFixedCString> = {<nsCString> = {<nsACString_internal> = {mData = 0x7fff32df3fe0 "3.1.1_20100720161535/20100720161535", mLength = 35, + mFlags = 65553}, <No data fields>}, mFixedCapacity = 63, + mFixedBuf = 0x7fff32df3fe0 "3.1.1_20100720161535/20100720161535"}, mStorage = "3.1.1_20100720161535/20100720161535\000\377\177\000\000\270\000\000\000\000\000\000\000\260@\337\062\377\177\000\000\360@\337\062\377\177\000"} + needsRestart = 0 + display = 0x7f90a8264190 + _gtk_window_set_auto_startup_notification = <value optimized out> + osABI = {<nsCString> = {<nsACString_internal> = { + mData = 0x3139e24927 "Linux_x86_64-gcc3", mLength = 17, + mFlags = 1}, <No data fields>}, <No data fields>} + rv = 0 + gtkModules = <value optimized out> + appData = {<nsXREAppData> = {size = 112, directory = 0x7f90a821a180, + vendor = 0x0, name = 0x7f90a8202070 "Thunderbird", + version = 0x7f90a82040b0 "3.1.1", + buildID = 0x7f90a8202080 "20100720161535", + ID = 0x7f90a8219220 "{3550f703-e582-4d05-9a08-453d09bdfdc6}", + copyright = 0x0, flags = 14, xreDirectory = 0x7f90a821a300, + minVersion = 0x7f90a82040b8 "1.9.2.7", + maxVersion = 0x7f90a82040c0 "1.9.2.7", + crashReporterURL = 0x7f90a8219250 "https://crash-reports.mozilla.com/submit", profile = 0x0}, <No data fields>} + localIniFile = {<nsCOMPtr_base> = { + mRawPtr = 0x7f90a821a240}, <No data fields>} + parser = { + mSections = {<nsBaseHashtable<nsDepCharHashKey, nsAutoPtr<nsINIParser_internal::INIValue>, nsINIParser_internal::INIValue*>> = {<nsTHashtable<nsBaseHashtableET<nsDepCharHashKey, nsAutoPtr<nsINIParser_internal::INIValue> > >> = {mTable = {ops = 0x3139cc6110, data = 0x0, hashShift = 28, + maxAlphaFrac = 192 '\300', minAlphaFrac = 64 '@', + entrySize = 24, entryCount = 1, removedCount = 0, + generation = 0, + entryStore = 0x7f90a8226180 ""}}, <No data fields>}, <No data fields>}, mFileContents = {mRawPtr = 0x7f90a8210400 "[Build"}} + ar = <value optimized out> + override = 0x0 + iniFile = {<nsCOMPtr_base> = { + mRawPtr = 0x7f90a821a240}, <No data fields>} + i = <value optimized out> +#110 0x0000000000401a94 in main (argc=1, argv=0x7fff32df4268) + at /usr/src/debug/thunderbird-3.1.1/comm-1.9.2/mail/app/nsMailApp.cpp:101 + rv = <value optimized out> + appData = 0x7f90a821d080 + appini = {<nsCOMPtr_base> = { + mRawPtr = 0x7f90a821a0c0}, <No data fields>} + result = <value optimized out> +From To Syms Read Shared Object Library +0x0000003848c05640 0x0000003848c10e48 Yes /lib64/libpthread.so.0 +0x0000003b8ae1bcb0 0x0000003b8aea19c8 Yes /usr/lib64/thunderbird-3.1/libmozjs.so +0x0000003139e0af70 0x0000003139e22878 Yes /usr/lib64/thunderbird-3.1/libxul.so +0x0000003139602890 0x0000003139602ae8 Yes /usr/lib64/thunderbird-3.1/libxpcom.so +0x0000003139a37eb0 0x0000003139a87f98 Yes /usr/lib64/thunderbird-3.1/libxpcom_core.so +0x0000003859400e70 0x0000003859401ce8 Yes /lib64/libplds4.so +0x00000038598013d0 0x0000003859802b18 Yes /lib64/libplc4.so +0x0000003858c0cfc0 0x0000003858c2c968 Yes /lib64/libnspr4.so +0x0000003849000de0 0x0000003849001998 Yes /lib64/libdl.so.2 +0x0000003138a681c0 0x0000003138d0d268 Yes /usr/lib64/libgtk-x11-2.0.so.0 +0x00000038544096b0 0x00000038544150f8 Yes /usr/lib64/libatk-1.0.so.0 +0x000000384c819b60 0x000000384c8812c8 Yes /lib64/libgio-2.0.so.0 +0x0000003851407650 0x0000003851421348 Yes /usr/lib64/libpangoft2-1.0.so.0 +0x000000384d40c850 0x000000384d4745a8 Yes /usr/lib64/libfreetype.so.6 +0x000000384dc05c80 0x000000384dc1ff28 Yes /usr/lib64/libfontconfig.so.1 +0x000000313921d260 0x000000313927f2a8 Yes /usr/lib64/libgdk-x11-2.0.so.0 +0x0000003854005940 0x0000003854017ba8 Yes /usr/lib64/libgdk_pixbuf-2.0.so.0 +0x0000003853404630 0x0000003853408eb8 Yes /usr/lib64/libpangocairo-1.0.so.0 +0x000000385200ede0 0x000000385202d768 Yes /usr/lib64/libpango-1.0.so.0 +0x0000003853809c50 0x000000385385b058 Yes /usr/lib64/libcairo.so.2 +0x000000384b008d20 0x000000384b032a78 Yes /lib64/libgobject-2.0.so.0 +0x000000384b401080 0x000000384b401fc8 Yes /lib64/libgmodule-2.0.so.0 +0x000000384a801590 0x000000384a8029f8 Yes /lib64/libgthread-2.0.so.0 +0x0000003849802140 0x00000038498055a8 Yes /lib64/librt.so.1 +0x0000003849c155c0 0x0000003849c99d58 Yes /lib64/libglib-2.0.so.0 +0x000000384b81dd80 0x000000384b8ab938 Yes /usr/lib64/libX11.so.6 +0x0000003137e09060 0x0000003137e19878 Yes /usr/lib64/libdbus-glib-1.so.2 +0x000000384ac07090 0x000000384ac2e4c8 Yes /lib64/libdbus-1.so.3 +0x0000003850009230 0x000000385002abd8 Yes /usr/lib64/libhunspell-1.2.so.0 +0x00000038508563f0 0x00000038508c33f6 Yes /usr/lib64/libstdc++.so.6 +0x0000003848803ea0 0x0000003848843fa8 Yes /lib64/libm.so.6 +0x000000384d802910 0x000000384d812f48 Yes /lib64/libgcc_s.so.1 +0x000000384841e9a0 0x000000384852b820 Yes /lib64/libc.so.6 +0x0000003848000af0 0x0000003848018904 Yes /lib64/ld-linux-x86-64.so.2 +0x0000003136a03530 0x0000003136a0e638 Yes /usr/lib64/libXext.so.6 +0x000000313ae130d0 0x000000313ae4f938 Yes /usr/lib64/libXt.so.6 +0x000000384fc2d6c0 0x000000384fcadb98 Yes /lib64/libasound.so.2 +0x000000384f001370 0x000000384f004178 Yes /usr/lib64/libXfixes.so.3 +0x000000384a4038c0 0x000000384a412528 Yes /lib64/libresolv.so.2 +0x0000003849401ef0 0x000000384940d228 Yes /lib64/libz.so.1 +0x000000384a005550 0x000000384a015038 Yes /lib64/libselinux.so.1 +0x000000384c403b70 0x000000384c41ca08 Yes /lib64/libexpat.so.1 +0x000000384ec018c0 0x000000384ec07f58 Yes /usr/lib64/libXrender.so.1 +0x0000003137600a20 0x0000003137601508 Yes /usr/lib64/libXinerama.so.1 +0x0000003136e01eb0 0x0000003136e0c608 Yes /usr/lib64/libXi.so.6 +0x0000003137201720 0x0000003137206828 Yes /usr/lib64/libXrandr.so.2 +0x000000384f402880 0x000000384f407678 Yes /usr/lib64/libXcursor.so.1 +0x0000003138600b40 0x0000003138601908 Yes /usr/lib64/libXcomposite.so.1 +0x0000003853c00a90 0x0000003853c01638 Yes /usr/lib64/libXdamage.so.1 +0x000000384d004830 0x000000384d01e7a8 Yes /usr/lib64/libpng12.so.0 +0x0000003851807230 0x0000003851851e78 Yes /usr/lib64/libpixman-1.so.0 +0x000000384c008650 0x000000384c013898 Yes /usr/lib64/libxcb.so.1 +0x00000031382019f0 0x00000031382062a8 Yes /usr/lib64/libSM.so.6 +0x0000003855804d70 0x0000003855813778 Yes /usr/lib64/libICE.so.6 +0x000000384bc00dd0 0x000000384bc01b68 Yes /usr/lib64/libXau.so.6 +0x0000003137a014b0 0x0000003137a02be8 Yes /lib64/libuuid.so.1 +0x00007f90a2164110 0x00007f90a216c258 Yes /lib64/libnss_files.so.2 +0x00007f90a1f3abc0 0x00007f90a1f5c818 Yes /usr/lib64/gtk-2.0/2.10.0/engines/libclearlooks.so +0x00007f90a1d35620 0x00007f90a1d35e08 Yes /usr/lib64/gtk-2.0/modules/libpk-gtk-module.so +0x00007f90a1b2ffb0 0x00007f90a1b321e8 Yes /usr/lib64/gtk-2.0/modules/libcanberra-gtk-module.so +0x00007f90a192bc60 0x00007f90a192d0a8 Yes /usr/lib64/libcanberra-gtk.so.0 +0x0000003860c03280 0x0000003860c0c318 Yes /usr/lib64/libcanberra.so.0 +0x000000385ec01fa0 0x000000385ec05fd8 Yes /usr/lib64/libvorbisfile.so.3 +0x000000385c003700 0x000000385c01a718 Yes /usr/lib64/libvorbis.so.0 +0x000000385bc018a0 0x000000385bc03bb8 Yes /usr/lib64/libogg.so.0 +0x000000385c801e30 0x000000385c809ca8 Yes /usr/lib64/libtdb.so.1 +0x000000385b402370 0x000000385b406758 Yes /usr/lib64/libltdl.so.7 +0x000000313c222430 0x000000313c268f08 Yes /usr/lib64/libgnomeui-2.so.0 +0x00007f90a16d6d70 0x00007f90a170d068 Yes /usr/lib64/libbonoboui-2.so.0 +0x000000313b20bcf0 0x000000313b228cd8 Yes /usr/lib64/libgnomecanvas-2.so.0 +0x000000313b606ee0 0x000000313b610e28 Yes /usr/lib64/libgnome-2.so.0 +0x0000003861402ef0 0x00000038614155e8 Yes /usr/lib64/libart_lgpl_2.so.2 +0x000000313a617900 0x000000313a64f618 Yes /usr/lib64/libgnomevfs-2.so.0 +0x0000003856411b30 0x000000385642da28 Yes /usr/lib64/libgconf-2.so.4 +0x000000399ea06d70 0x000000399ea15bd8 Yes /usr/lib64/libgnome-keyring.so.0 +0x0000003859027fa0 0x0000003859052ee8 Yes /usr/lib64/libbonobo-2.so.0 +0x000000385f80adf0 0x000000385f812f58 Yes /usr/lib64/libbonobo-activation.so.4 +0x0000003855427990 0x000000385544b6a8 Yes /usr/lib64/libORBit-2.so.0 +0x00007f90a1393950 0x00007f90a1470048 Yes /usr/lib64/libxml2.so.2 +0x0000003858401b10 0x0000003858406ee8 Yes /lib64/libpopt.so.0 +0x00007f90a11629a0 0x00007f90a1166178 Yes /usr/lib64/libgailutil.so.18 +0x0000003856014500 0x0000003856046708 Yes /usr/lib64/libssl.so.10 +0x000000385105c900 0x0000003851121288 Yes /lib64/libcrypto.so.10 +0x000000399ee00ca0 0x000000399ee01aa8 Yes /usr/lib64/libavahi-glib.so.1 +0x00000039a2803390 0x00000039a2808698 Yes /usr/lib64/libavahi-common.so.3 +0x00000039a24038b0 0x00000039a240bf68 Yes /usr/lib64/libavahi-client.so.3 +0x0000003857c00e10 0x0000003857c01688 Yes /lib64/libutil.so.1 +0x00000039a1406d00 0x00000039a1450078 Yes /lib64/libgcrypt.so.11 +0x000000385f003110 0x000000385f003ad8 Yes /usr/lib64/libORBitCosNaming-2.so.0 +0x0000003851c06c00 0x0000003851c27268 Yes /lib64/libgssapi_krb5.so.2 +0x0000003852c18540 0x0000003852c73f08 Yes /lib64/libkrb5.so.3 +0x00007f90a0f5e220 0x00007f90a0f5ed08 Yes /lib64/libcom_err.so.2 +0x00000038528055c0 0x000000385281e6b8 Yes /lib64/libk5crypto.so.3 +0x00000038570007f0 0x0000003857000d58 Yes /lib64/libgpg-error.so.0 +0x00000038524026c0 0x00000038524067b8 Yes /lib64/libkrb5support.so.0 +0x0000003850c00aa0 0x0000003850c00fa8 Yes /lib64/libkeyutils.so.1 +0x00007f90a0bfc580 0x00007f90a0bfdce8 Yes /usr/lib64/gconv/UTF-16.so +0x00007f90a04c9c30 0x00007f90a06ec5a8 Yes /usr/lib64/thunderbird-3.1/components/libmail.so +0x00007f90a0230990 0x00007f90a023ca88 Yes /usr/lib64/thunderbird-3.1/components/libspellchecker.so +0x00007f90a001ecf0 0x00007f90a0026708 Yes /usr/lib64/thunderbird-3.1/components/libchrome.so +0x00007f909fd280b0 0x00007f909fda86f8 Yes /usr/lib64/thunderbird-3.1/components/libnecko.so +0x00007f909f0d6890 0x00007f909f0de728 Yes /usr/lib64/thunderbird-3.1/components/libpref.so +0x00007f909eea9370 0x00007f909eeb4cf8 Yes /usr/lib64/thunderbird-3.1/components/libi18n.so +0x00007f909ec9a2b0 0x00007f909ec9de38 Yes /usr/lib64/thunderbird-3.1/components/libdbusservice.so +0x00007f909ea86e60 0x00007f909ea8ffe8 Yes /usr/lib64/thunderbird-3.1/components/libjar50.so +0x00007f909e7dfa20 0x00007f909e8425f8 Yes /usr/lib64/thunderbird-3.1/components/libxpconnect.so +0x00007f909d163930 0x00007f909d199b68 Yes /usr/lib64/thunderbird-3.1/components/libwidget_gtk2.so +0x00007f909cf3eeb0 0x00007f909cf42bc8 Yes /usr/lib64/thunderbird-3.1/libgkgfx.so +0x00007f909cd047b0 0x00007f909cd26068 Yes /usr/lib64/thunderbird-3.1/libthebes.so +0x00007f909cae9ee0 0x00007f909caeb0c8 Yes /usr/lib64/thunderbird-3.1/libgtkxtbin.so +0x00007f909c8e6300 0x00007f909c8e6b98 Yes /usr/lib64/thunderbird-3.1/libgfxpsshar.so +0x00007f909c6e2480 0x00007f909c6e2f28 Yes /usr/lib64/gconv/ISO8859-2.so +0x00007f909c4b4ca0 0x00007f909c4d1af8 Yes /usr/lib64/thunderbird-3.1/components/libtoolkitcomps.so +0x00007f909c27cc80 0x00007f909c29c008 Yes /usr/lib64/thunderbird-3.1/components/libembedcomponents.so +0x00007f909bee98f0 0x00007f909bef7b38 Yes /usr/lib64/thunderbird-3.1/components/libcaps.so +0x00007f909aeba890 0x00007f909aebc898 Yes /usr/lib64/thunderbird-3.1/components/libsystem-pref.so +0x00007f909acb4ea0 0x00007f909acb6738 Yes /usr/lib64/thunderbird-3.1/components/libwindowds.so +0x00007f909aa8d010 0x00007f909aaa3608 Yes /usr/lib64/thunderbird-3.1/components/librdf.so +0x00007f909a86a600 0x00007f909a878df8 Yes /usr/lib64/thunderbird-3.1/components/libnsappshell.so +0x00007f909a600930 0x00007f909a63e748 Yes /usr/lib64/thunderbird-3.1/components/libdocshell.so +0x00007f909a3e1970 0x00007f909a3e6f38 Yes /usr/lib64/thunderbird-3.1/components/libmozgnome.so +0x000000313aa033f0 0x000000313aa06538 Yes /usr/lib64/libnotify.so.1 +0x00007f909a1d3de0 0x00007f909a1daab8 Yes /usr/lib64/gnome-vfs-2.0/modules/libfile.so +0x0000003858801350 0x0000003858803448 Yes /lib64/libattr.so.1 +0x000000385a801d30 0x000000385a805c08 Yes /lib64/libacl.so.1 +0x00007f9099fc9770 0x00007f9099fcd038 Yes /usr/lib64/libfam.so.0 +0x00007f9099aaf560 0x00007f9099ae0c88 Yes /usr/lib64/thunderbird-3.1/components/libhtmlpars.so +0x00007f90997d5130 0x00007f90997e6588 Yes /usr/lib64/thunderbird-3.1/components/libuconv.so +0x00007f90995abe20 0x00007f90995b8d88 Yes /usr/lib64/thunderbird-3.1/components/libstoragecomps.so +0x00007f9099333780 0x00007f90993860f8 Yes /usr/lib64/thunderbird-3.1/libsqlite3.so +0x00007f9095061630 0x00007f90955612c8 Yes /usr/lib64/thunderbird-3.1/components/libgklayout.so +0x00007f9094b821e0 0x00007f9094ba2da8 Yes /usr/lib64/thunderbird-3.1/components/libimglib2.so +0x00007f90949584a0 0x00007f9094972008 Yes /usr/lib64/libjpeg.so.62 +0x00007f9094748910 0x00007f909474f0f8 Yes /usr/lib64/thunderbird-3.1/components/libgkgfxthebes.so +0x00007f909453ef30 0x00007f90945407e8 Yes /usr/lib64/thunderbird-3.1/components/libcommandlines.so +0x00007f90940ece30 0x00007f90940f7838 Yes /usr/lib64/thunderbird-3.1/components/libwebbrwsr.so +0x00007f9093ee45c0 0x00007f9093ee5558 Yes /usr/lib64/thunderbird-3.1/components/libpermissions.so +0x00007f9093cdbbc0 0x00007f9093cdf968 Yes /usr/lib64/thunderbird-3.1/components/libcookie.so +0x00007f9093ad0ae0 0x00007f9093ad5598 Yes /usr/lib64/thunderbird-3.1/components/libpipboot.so +0x00007f90964fcfb0 0x00007f90964fe438 Yes /usr/lib64/thunderbird-3.1/components/libremoteservice.so +0x00007f90962f2ca0 0x00007f90962f6258 Yes /usr/lib64/thunderbird-3.1/components/libchardet.so +0x000000313be00be0 0x000000313be01c08 Yes /usr/lib64/libXss.so.1 +0x00007f9095df7730 0x00007f9095dfc2d8 Yes /usr/lib64/thunderbird-3.1/components/libintlapp.so +0x00007f9095be9290 0x00007f9095bef168 Yes /usr/lib64/thunderbird-3.1/components/libimgicon.so +0x00007f908d204aa0 0x00007f908d21dbb8 Yes /usr/lib64/gio/modules/libgvfsdbus.so +0x00007f908cfed190 0x00007f908cff7418 Yes /usr/lib64/libgvfscommon.so.0 +0x00007f908cdd8770 0x00007f908cde02b8 Yes /lib64/libudev.so.0 +0x00007f908c4fa070 0x00007f908c4fd1a8 Yes /usr/lib64/thunderbird-3.1/components/libtxmgr.so +0x00007f908bfe57f0 0x00007f908bff3978 Yes (*) /usr/lib64/mozilla/extensions/{3550f703-e582-4d05-9a08-453d09bdfdc6}/{e2fda1a4-762b-4020-b5ad-a41df1933103}/components/libcalbasecomps.so +0x00000038662194f0 0x0000003866242668 Yes /usr/lib64/libical.so.0 +0x00007f908bbf7340 0x00007f908bbfbc58 Yes /usr/lib64/thunderbird-3.1/components/libtkautocomplete.so +0x00007f908b7fd0f0 0x00007f908b7fea98 Yes /usr/lib64/gtk-2.0/2.10.0/immodules/im-ibus.so +0x000000384f80f2e0 0x000000384f82b6f8 Yes /usr/lib64/libibus.so.2 +0x00007f908b2f52a0 0x00007f908b2fa618 Yes /usr/lib64/thunderbird-3.1/components/libsatchel.so +0x00007f908b0bf7d0 0x00007f908b0da458 Yes /usr/lib64/thunderbird-3.1/components/libmork.so +0x00007f908aa8f9d0 0x00007f908aad2ac8 Yes /usr/lib64/thunderbird-3.1/components/libpipnss.so +0x000000385ac07c40 0x000000385ac29948 Yes /usr/lib64/libssl3.so +0x0000003859c09880 0x0000003859c216a8 Yes /usr/lib64/libsmime3.so +0x000000385a0184d0 0x000000385a0fc6b8 Yes /usr/lib64/libnss3.so +0x000000385a4083a0 0x000000385a4135c8 Yes /usr/lib64/libnssutil3.so +0x00007f908a83aa10 0x00007f908a863c68 Yes /usr/lib64/libsoftokn3.so +0x000000385cc08b20 0x000000385cc758c8 Yes /usr/lib64/libsqlite3.so.0 +0x00007f908a612180 0x00007f908a62e858 Yes /usr/lib64/libnssdbm3.so +0x00000038568030c0 0x000000385683d848 Yes /usr/lib64/libfreebl3.so +0x00007f908a3a4d70 0x00007f908a3b3f48 Yes /usr/lib64/libnssckbi.so +0x00007f908a1830b0 0x00007f908a186438 Yes /usr/lib64/thunderbird-3.1/components/libmsgsmime.so +0x00007f9089cdd0c0 0x00007f9089cf42c8 Yes /usr/lib64/thunderbird-3.1/components/libmailcomps.so +0x00007f9089ad6920 0x00007f9089ad8008 Yes /usr/lib64/thunderbird-3.1/components/libunixproxy.so +0x00007f9088ed2af0 0x00007f9088ed3768 Yes /lib64/libnss_mdns4_minimal.so.2 +0x00007f9088ccd000 0x00007f9088cd0348 Yes /lib64/libnss_dns.so.2 +0x00007f90882f86b0 0x00007f90882fd318 Yes /usr/lib64/libesd.so.0 +0x000000399e2062f0 0x000000399e21ceb8 Yes /usr/lib64/libaudiofile.so.0 +0x00007f9087bfc050 0x00007f9087bfef88 Yes /usr/lib64/libcanberra-0.24/libcanberra-pulse.so +0x00007f90879c2e50 0x00007f90879ea398 Yes /usr/lib64/libpulse.so.0 +0x00007f9087778460 0x00007f90877a3758 Yes /usr/lib64/libpulsecommon-0.9.21.so +0x00007f90875643b0 0x00007f90875673b8 Yes /usr/lib64/libXtst.so.6 +0x000000385c402ee0 0x000000385c406a88 Yes /lib64/libwrap.so.0 +0x00007f9087304540 0x00007f9087345ec8 Yes /usr/lib64/libsndfile.so.1 +0x00007f90870fb1c0 0x00007f90870fd7e8 Yes /usr/lib64/libasyncns.so.0 +0x00007f9086ee5070 0x00007f9086ef2a08 Yes /lib64/libnsl.so.1 +0x000000385d00be70 0x000000385d030e08 Yes /usr/lib64/libFLAC.so.8 +0x000000385d4139c0 0x000000385d415eb8 Yes /usr/lib64/libvorbisenc.so.2 +0x00007f9081fd7960 0x00007f9081ff0fd8 Yes /usr/lib64/thunderbird-3.1/components/libgkplugin.so +0x00007f907f7ec480 0x00007f907f7f7758 Yes /usr/lib64/thunderbird-3.1/components/libcomposer.so +0x00007f907d3efc00 0x00007f907d3fc128 Yes /usr/lib64/gio/modules/libgioremote-volume-monitor.so +(*): Shared library is missing debugging information. +$1 = 0x0 +$2 = 0x0 +rax 0x0 0 +rbx 0xb 11 +rcx 0xffffffffffffffff -1 +rdx 0xb 11 +rsi 0x4deb 19947 +rdi 0x4deb 19947 +rbp 0x7fff32dedc20 0x7fff32dedc20 +rsp 0x7fff32dedc08 0x7fff32dedc08 +r8 0x0 0 +r9 0x1 1 +r10 0x8 8 +r11 0x206 518 +r12 0xffffffff 4294967295 +r13 0x7f907d912a60 140258558683744 +r14 0x7f9097882000 140258994298880 +r15 0x7fff32dee2f0 140734046855920 +rip 0x3848c0f30b 0x3848c0f30b <raise+43> +eflags 0x206 [ PF IF ] +cs 0x33 51 +ss 0x2b 43 +ds 0x0 0 +es 0x0 0 +fs 0x0 0 +gs 0x0 0 +Dump of assembler code for function raise: + 0x0000003848c0f2e0 <+0>: mov %fs:0x2d4,%ecx + 0x0000003848c0f2e8 <+8>: mov %fs:0x2d0,%esi + 0x0000003848c0f2f0 <+16>: mov %ecx,%eax + 0x0000003848c0f2f2 <+18>: movslq %edi,%rdx + 0x0000003848c0f2f5 <+21>: movslq %esi,%rsi + 0x0000003848c0f2f8 <+24>: sar $0x1f,%eax + 0x0000003848c0f2fb <+27>: mov %eax,%edi + 0x0000003848c0f2fd <+29>: xor %ecx,%edi + 0x0000003848c0f2ff <+31>: sub %eax,%edi + 0x0000003848c0f301 <+33>: mov $0xea,%eax + 0x0000003848c0f306 <+38>: movslq %edi,%rdi + 0x0000003848c0f309 <+41>: syscall +=> 0x0000003848c0f30b <+43>: cmp $0xfffffffffffff000,%rax + 0x0000003848c0f311 <+49>: ja 0x3848c0f315 <raise+53> + 0x0000003848c0f313 <+51>: repz retq + 0x0000003848c0f315 <+53>: mov 0x207c64(%rip),%rdx # 0x3848e16f80 + 0x0000003848c0f31c <+60>: neg %eax + 0x0000003848c0f31e <+62>: mov %eax,%fs:(%rdx) + 0x0000003848c0f321 <+65>: or $0xffffffffffffffff,%eax + 0x0000003848c0f324 <+68>: retq +End of assembler dump. +Debuginfo absent: 412783fb5e761fdab4f06a8d0a5381e173c4db31 diff --git a/btparser/tests/frame.at b/btparser/tests/frame.at new file mode 100644 index 00000000..28c34ac5 --- /dev/null +++ b/btparser/tests/frame.at @@ -0,0 +1,615 @@ +# Checking the btparser. -*- Autotest -*- + +AT_BANNER([Frames]) + +## ------------- ## +## btp_frame_dup ## +## ------------- ## + +AT_TESTFUN([btp_frame_dup], +[[ +#include <lib/frame.h> +#include <lib/utils.h> +#include <assert.h> + +int main(void) +{ + struct btp_frame *frame1 = btp_frame_new();; + frame1->function_name = btp_strdup("test1"); + frame1->function_type = btp_strdup("type1"); + frame1->number = 10; + frame1->source_file = btp_strdup("file1"); + frame1->source_line = 11; + frame1->address = 12; + + struct btp_frame *frame0 = btp_frame_new();; + frame0->function_name = btp_strdup("test0"); + frame0->function_type = btp_strdup("type0"); + frame0->number = 13; + frame0->source_file = btp_strdup("file0"); + frame0->source_line = 14; + frame0->address = 15; + frame0->next = frame1; + + /* Test the duplication without siblings. */ + struct btp_frame *frame = btp_frame_dup(frame0, false); + assert(NULL == frame->next); + assert(frame->function_name != frame0->function_name); + assert(frame->function_type != frame0->function_type); + assert(frame->source_file != frame0->source_file); + assert(0 == btp_frame_cmp(frame, frame0, true)); + btp_frame_free(frame); + + /* Test the duplication with the siblings. */ + frame = btp_frame_dup(frame0, true); + assert(frame->function_name != frame0->function_name); + assert(frame->function_type != frame0->function_type); + assert(frame->source_file != frame0->source_file); + assert(0 == btp_frame_cmp(frame, frame0, true)); + assert(frame->next != frame1); + assert(0 == btp_frame_cmp(frame->next, frame1, true)); + btp_frame_free(frame->next); + btp_frame_free(frame); + + btp_frame_free(frame1); + btp_frame_free(frame0); + return 0; +} +]]) + +## --------------------------- ## +## btp_frame_parse_frame_start ## +## --------------------------- ## + +AT_TESTFUN([btp_frame_parse_frame_start], +[[ +#include <lib/frame.h> +#include <assert.h> + +/** + * @param input + * The input text stream. + * @param parsed_char_count + * The expected number of characters parsed (taken) from input. + * @param expected_frame_number + * The expected parsed frame number. + */ +void check(char *input, + int parsed_char_count, + unsigned expected_frame_number) +{ + int number; + char *old_input = input; + assert(parsed_char_count == btp_frame_parse_frame_start(&input, &number)); + if (0 < parsed_char_count) + { + assert(number == expected_frame_number); + assert(*input == '\0'); + } + else + { + /* Check that the pointer is not moved. */ + assert(old_input == input); + } +} + +int main(void) +{ + check("#10 " , 4, 10); + check("#0 " , 4, 0); + check("#99999 ", 8, 99999); + check("ab " , 0, 0); + check("#ab " , 0, 0); + check("#-9999 " , 0, 9999); + return 0; +} +]]) + +## --------------------------- ## +## btp_frame_parseadd_operator ## +## --------------------------- ## + +AT_TESTFUN([btp_frame_parseadd_operator], +[[ +#include <lib/frame.h> +#include <lib/strbuf.h> +#include <assert.h> +#include <string.h> + +void check(char *input, int parsed_length) +{ + printf("Testing '%s' -> %d\n", input, parsed_length); + char *old_input = input; + struct btp_strbuf *strbuf = btp_strbuf_new(); + assert(parsed_length == btp_frame_parseadd_operator(&input, strbuf)); + printf(" input = '%s', old_input = '%s'\n", input, old_input); + + /* Check that the input pointer was updated properly. */ + assert(*input == old_input[parsed_length]); + + /* Check that the strbuf has been modified accordingly to what was parsed. */ + assert(0 == strncmp(strbuf->buf, old_input, parsed_length)); + assert(strbuf->len == parsed_length); + + btp_strbuf_free(strbuf); +} + +int main(void) +{ + check("operator>", strlen("operator>")); + check("operator->", strlen("operator->")); + check("operator new", strlen("operator new")); + check("operator new[]", strlen("operator new[]")); + check("operator delete", strlen("operator delete")); + check("operator del", 0); + check("operator delete[] (test)", strlen("operator delete[]")); + /* Red Hat Bugzilla bug #542445 */ + check("cairo_add_operator (test)", 0); + return 0; +} +]]) + +## ----------------------------- ## +## btp_frame_parse_function_name ## +## ----------------------------- ## + +AT_TESTFUN([btp_frame_parse_function_name], +[[ +#include <lib/frame.h> +#include <lib/utils.h> +#include <lib/location.h> +#include <assert.h> +#include <stdlib.h> +#include <string.h> + +void check(bool success, char *input) +{ + /* Function name must be ended with a space. */ + char *input_with_space = btp_malloc(strlen(input) + 2); + strcpy(input_with_space, input); + input_with_space[strlen(input)] = ' '; + input_with_space[strlen(input) + 1] = '\0'; + + char *function_name = NULL, *function_type = NULL; + char *old_input_with_space = input_with_space; + printf("Parsing '%s'\n", input); + struct btp_location location; + btp_location_init(&location); + assert(success == btp_frame_parse_function_name(&input_with_space, + &function_name, + &function_type, + &location)); + + if (success) + { + assert(function_name); + printf("Function name '%s'\n", function_name); + assert(strcmp(function_name, input) == 0); + assert(function_type == NULL); + free(function_name); + assert(*input_with_space == ' '); + } + else + { + /* Check that the pointer is not moved. */ + assert(old_input_with_space == input_with_space); + } + + free(old_input_with_space); +} + +int main(void) +{ + check(true, "??"); + check(true, "IA__g_bookmark_file_to_file"); + check(true, "pthread_cond_timedwait@@GLIBC_2.3.2"); + check(true, "_pixman_walk_composite_region"); + check(true, "CairoOutputDev::tilingPatternFill"); + check(true, "sdr::(anonymous namespace)::ViewContact::~ViewContact"); + check(true, "operator==<nsIAtom, nsICSSPseudoClass>"); + return 0; +} +]]) + +## ---------------------------- ## +## btp_frame_skip_function_args ## +## ---------------------------- ## + +AT_TESTFUN([btp_frame_skip_function_args], +[[ +#include <lib/frame.h> +#include <lib/location.h> +#include <assert.h> + +void check(bool success, char *input) +{ + char *old_input = input; + struct btp_location location; + btp_location_init(&location); + assert(success == btp_frame_skip_function_args(&input, &location)); + if (success) + { + assert(*input == '\0'); + } + else + { + /* Check that the pointer is not moved. */ + assert(old_input == input); + } +} + +int main(void) +{ + /* minimal */ + check(true, "()"); + /* newline */ + check(true, "(\n" + "page=0x7f186003e280, \n" + "cairo=0x7f18600efd10, printing=0)"); + /* value optimized out */ + check(true, "(this=0x7f1860023400, DPI=<value optimized out>)"); + /* string */ + check(true, "(filename=0x18971b0 \"/home/jfclere/.recently-used.xbel\")"); + /* TODO: parentesis balance */ + return 0; +} +]]) + +## ----------------------------- ## +## btp_frame_parse_function_call ## +## ----------------------------- ## + +AT_TESTFUN([btp_frame_parse_function_call], +[[ +#include <lib/frame.h> +#include <lib/location.h> +#include <assert.h> +#include <stdlib.h> +void check(bool success, + char *input, + char *expected_function_name, + char *expected_function_type) +{ + char *old_input = input; + char *function_name, *function_type; + struct btp_location location; + btp_location_init(&location); + assert(success == btp_frame_parse_function_call(&input, + &function_name, + &function_type, + &location)); + if (success) + { + printf("Expected: '%s', got '%s'\n", expected_function_name, function_name); + assert(0 == strcmp(expected_function_name, function_name)); + assert((!expected_function_type && !function_type) || + 0 == strcmp(expected_function_type, function_type)); + assert(*input == '\0'); + free(function_name); + } + else + { + /* Check that the pointer is not moved. */ + assert(old_input == input); + } +} + +int main(void) +{ + /* minimal */ + check(true, "?? ()", "??", NULL); + check(true, "fsync ()", "fsync", NULL); + /* newlines */ + check(true, + "write_to_temp_file (\n" + "filename=0x18971b0 \"/home/jfclere/.recently-used.xbel\", \n" + "contents=<value optimized out>, length=29917, error=0x7fff3cbe4110)", + "write_to_temp_file", + NULL); + /* C++ */ + check(true, + "osgText::Font::GlyphTexture::apply(osg::State&) const ()", + "osgText::Font::GlyphTexture::apply(osg::State&) const", + NULL); + check(true, + "osgUtil::RenderStage::drawInner(osg::RenderInfo&, osgUtil::RenderLeaf*&, bool&) ()", + "osgUtil::RenderStage::drawInner(osg::RenderInfo&, osgUtil::RenderLeaf*&, bool&)", + NULL); + check(true, + "nsRegion::RgnRect::operator new ()", + "nsRegion::RgnRect::operator new", + NULL); + check(true, + "sigc::internal::slot_call0<sigc::bound_mem_functor0<void, Driver>, void>::call_it (this=0x6c)", + "sigc::internal::slot_call0<sigc::bound_mem_functor0<void, Driver>, void>::call_it", + NULL); + check(true, + "sigc::internal::slot_call0<sigc::bound_mem_functor0<void, GameWindow>, void>::call_it(sigc::internal::slot_rep*) ()", + "sigc::internal::slot_call0<sigc::bound_mem_functor0<void, GameWindow>, void>::call_it(sigc::internal::slot_rep*)", + NULL); + /* C++ operator< and templates */ + check(true, + "operator< <char, std::char_traits<char>, std::allocator<char> > (__s1=<value optimized out>)", + "operator< <char, std::char_traits<char>, std::allocator<char> >", + NULL); + /* C++ plain operator-> */ + check(true, "operator-> ()", "operator->", NULL); + /* Not an operator, but includes the keyword 'operator' (Red Hat Bugzilla bug #542445) */ + check(true, + "cairo_set_operator (cr=0x0, op=CAIRO_OPERATOR_OVER)", + "cairo_set_operator", + NULL); + /* type included */ + #define TYPE "void" + #define FUNCTION "boost::throw_exception<" \ + "boost::filesystem::basic_filesystem_error<" \ + "boost::filesystem::basic_path<" \ + "std::basic_string<" \ + "char, std::char_traits<char>, " \ + "std::allocator<char> >, " \ + "boost::filesystem::path_traits> > >" \ + "(boost::filesystem::basic_filesystem_error<" \ + "boost::filesystem::basic_path<" \ + "std::basic_string<char, std::char_traits<char>, " \ + "std::allocator<char> >, " \ + "boost::filesystem::path_traits> > const&)" + #define ARGS "()" + #define FUNCALL TYPE " " FUNCTION " " ARGS + check(true, FUNCALL, FUNCTION, TYPE); + return 0; +} +]]) + +## ----------------------------------- ## +## btp_frame_parse_address_in_function ## +## ----------------------------------- ## + +AT_TESTFUN([btp_frame_parse_address_in_function], +[[ +#include <lib/frame.h> +#include <lib/location.h> +#include <assert.h> +#include <stdlib.h> +void check(bool success, + char *input, + uint64_t expected_address, + char *expected_function) +{ + char *old_input = input; + char *function; + char *type; + uint64_t address; + struct btp_location location; + btp_location_init(&location); + assert(success == btp_frame_parse_address_in_function(&input, + &address, + &function, + &type, + &location)); + if (success) + { + assert(strcmp(function, expected_function) == 0); + assert(address == expected_address); + assert(*input == '\0'); + free(function); + free(type); + } + else + { + /* Check that the pointer is not moved. */ + assert(old_input == input); + } +} + +int main(void) +{ + /* minimal */ + check(true, "0x00ad0a91 in raise (sig=6)", 0xad0a91, "raise"); + /* longnum */ + check(true, "0xf00000322221730e in IA__g_bookmark_file_to_file (\n" + "filename=0x18971b0 \"/home/jfclere/.recently-used.xbel\", \n" + "error=0x7fff3cbe4160)", 0xf00000322221730eULL, + "IA__g_bookmark_file_to_file"); + return 0; +} +]]) + +## ----------------------------- ## +## btp_frame_parse_file_location ## +## ----------------------------- ## + +AT_TESTFUN([btp_frame_parse_file_location], +[[ +#include <lib/frame.h> +#include <lib/location.h> +#include <assert.h> +#include <stdlib.h> +void check(bool success, + char *input, + char *expected_file, + unsigned expected_line) +{ + char *old_input = input; + char *file; + unsigned line; + struct btp_location location; + btp_location_init(&location); + assert(success == btp_frame_parse_file_location(&input, + &file, + &line, + &location)); + if (success) + { + assert(strcmp(file, expected_file) == 0); + assert(line == expected_line); + assert(*input == '\0'); + free(file); + } + else + { + /* Check that the pointer is not moved. */ + assert(old_input == input); + } +} + +int main(void) +{ + /* Test with a newline and without a line number. */ + check(true, "\n at gtkrecentmanager.c", "gtkrecentmanager.c", -1); + + /* Test with a newline and with a line number. */ + check(true, "\n at gtkrecentmanager.c:1377", "gtkrecentmanager.c", 1377); + + /* Test without a newline and a file name with a dash and an upper letter. */ + check(true, + " at ../sysdeps/unix/syscall-template.S:82", + "../sysdeps/unix/syscall-template.S", + 82); + + /* A file name starting with an underscore: Red Hat Bugzilla bug #530678. */ + check(true, + " at _polkitauthenticationagent.c:885", + "_polkitauthenticationagent.c", + 885); + + return 0; +} +]]) + +## ---------------------- ## +## btp_frame_parse_header ## +## ---------------------- ## + +AT_TESTFUN([btp_frame_parse_header], +[[ +#include <lib/frame.h> +#include <lib/location.h> +#include <assert.h> +#include <stdlib.h> +#include <stdio.h> + +void check(char *input, + struct btp_frame *expected_frame) +{ + printf("=================================================\n" + "Testing %s\n", + input); + + char *old_input = input; + struct btp_location location; + btp_location_init(&location); + struct btp_frame *frame = btp_frame_parse_header(&input, &location); + if (frame) + { + assert(*input == '\0'); + assert(btp_frame_cmp(frame, expected_frame, true) == 0); + btp_frame_free(frame); + } + else + { + printf(" - parsing failed: %d:%d %s\n", location.line, location.column, location.message); + + /* Check that the pointer is not moved. */ + assert(old_input == input); + assert(!expected_frame); + } +} + +int main(void) +{ + /* basic */ + struct btp_frame frame; + btp_frame_init(&frame); + frame.function_name = "fsync"; + frame.number = 1; + frame.source_file = "../sysdeps/unix/syscall-template.S"; + frame.source_line = 82; + frame.address = 0x322160e7fdULL; + check("#1 0x000000322160e7fd in fsync () at ../sysdeps/unix/syscall-template.S:82", &frame); + + /* C++ */ + btp_frame_init(&frame); + frame.function_name = "nsRegion::RgnRect::operator new"; + frame.number = 4; + frame.source_file = "nsRegion.cpp"; + frame.source_line = 214; + frame.address = 0x3f96d71056ULL; + check("#4 0x0000003f96d71056 in nsRegion::RgnRect::operator new ()\n" + " at nsRegion.cpp:214", &frame); + + /* Templates and no filename. */ + btp_frame_init(&frame); + frame.function_name = "sigc::internal::slot_call0<sigc::bound_mem_functor0<void, GameWindow>, void>::call_it(sigc::internal::slot_rep*)"; + frame.number = 15; + frame.address = 0x08201bdfULL; + check("#15 0x08201bdf in sigc::internal::slot_call0<sigc::bound_mem_functor0<void, GameWindow>," + " void>::call_it(sigc::internal::slot_rep*) ()", &frame); + + /* No address, just the function call. Red Hat Bugzilla bug #530678 */ + btp_frame_init(&frame); + frame.function_name = "handle_message"; + frame.number = 30; + frame.source_file = "_polkitauthenticationagent.c"; + frame.source_line = 885; + check("#30 handle_message (message=<value optimized out>,\n" + "interface=<value optimized out>) at _polkitauthenticationagent.c:885", &frame); + + return 0; +} +]]) + +## --------------- ## +## btp_frame_parse ## +## --------------- ## + +AT_TESTFUN([btp_frame_parse], +[[ +#include <lib/frame.h> +#include <lib/location.h> +#include <assert.h> +#include <stdlib.h> +#include <string.h> +void check(char *input, + struct btp_frame *expected_frame, + char *expected_input) +{ + char *old_input = input; + struct btp_location location; + btp_location_init(&location); + struct btp_frame *frame = btp_frame_parse(&input, &location); + assert(input == expected_input); + if (frame) + { + assert(btp_frame_cmp(frame, expected_frame, true) == 0); + btp_frame_free(frame); + } + else + { + /* Check that the pointer is not moved. */ + assert(old_input == input); + assert(!expected_frame); + } +} + +int main(void) +{ + /* basic */ + struct btp_frame frame; + btp_frame_init(&frame); + frame.function_name = "fsync"; + frame.number = 1; + frame.source_file = "../sysdeps/unix/syscall-template.S"; + frame.source_line = 82; + frame.address = 0x322160e7fdULL; + char *c = "#1 0x000000322160e7fd in fsync () at ../sysdeps/unix/syscall-template.S:82\n" + "No locals."; + check(c, &frame, c + strlen(c)); + c = "#1 0x000000322160e7fd in fsync () at ../sysdeps/unix/syscall-template.S:82\n" + "No locals.\n" + "#2 0x003f4f3f in IA__g_main_loop_run (loop=0x90e2c50) at gmain.c:2799\n" + " self = 0x8b80038\n" + " __PRETTY_FUNCTION__ = \"IA__g_main_loop_run\"\n"; + check(c, &frame, strstr(c, "#2")); + return 0; +} +]]) diff --git a/btparser/tests/local.at b/btparser/tests/local.at new file mode 100644 index 00000000..758906d4 --- /dev/null +++ b/btparser/tests/local.at @@ -0,0 +1,27 @@ +# Source: bison local.at + +# ---------------------------------------- +# AT_COMPILE(OUTPUT, [SOURCES = OUTPUT.c]) +# ---------------------------------------- +# Compile SOURCES into OUTPUT. If OUTPUT does not contain '.', +# assume that we are linking too; this is a hack. +m4_define([AT_COMPILE], +[AT_CHECK([$LIBTOOL --mode=link $CC $CFLAGS m4_bmatch([$1], [[.]], [], [$LDFLAGS ])-o $1 m4_default([$2], [$1.c])[]m4_bmatch([$1], [[.]], [], [ $LIBS])], + 0, [ignore], [ignore])]) + +# ------------------------ +# AT_TESTFUN(NAME, SOURCE) +# ------------------------ + +# Create a test named NAME by compiling and running C file with +# contents SOURCE. The stdout and stderr output of the C program is +# ignored by Autotest. + +m4_define([AT_TESTFUN], +[AT_SETUP([$1]) +AT_DATA([$1.c], [$2]) +AT_COMPILE([$1]) +AT_CHECK([./$1], 0, [ignore], [ignore]) +AT_CLEANUP]) + +AT_INIT diff --git a/btparser/tests/package.m4 b/btparser/tests/package.m4 new file mode 100644 index 00000000..9f6a83d8 --- /dev/null +++ b/btparser/tests/package.m4 @@ -0,0 +1,13 @@ +# Signature of the current package. +m4_define([AT_PACKAGE_NAME], + [btparser]) +m4_define([AT_PACKAGE_TARNAME], + [btparser]) +m4_define([AT_PACKAGE_VERSION], + [0.7]) +m4_define([AT_PACKAGE_STRING], + [btparser 0.7]) +m4_define([AT_PACKAGE_BUGREPORT], + [kklic@redhat.com]) +m4_define([AT_PACKAGE_URL], + [@PACKAGE_URL@]) diff --git a/btparser/tests/strbuf.at b/btparser/tests/strbuf.at new file mode 100644 index 00000000..18535c15 --- /dev/null +++ b/btparser/tests/strbuf.at @@ -0,0 +1,73 @@ +# Checking the btparser. -*- Autotest -*- + +AT_BANNER([strbuf]) + +## ---------------------- ## +## btp_strbuf_append_char ## +## ---------------------- ## + +AT_TESTFUN([btp_strbuf_append_char], +[[ +#include <lib/strbuf.h> +#include <assert.h> +int main(void) +{ + int i; + struct btp_strbuf *strbuf = btp_strbuf_new(); + for (i = 0; i < 100; ++i) + { + assert(strbuf->len == i); + assert(strbuf->alloc > strbuf->len); + assert(strbuf->buf[i] == '\0'); + btp_strbuf_append_char(strbuf, 'a'); + assert(strbuf->buf[i] == 'a'); + assert(strbuf->buf[i+1] == '\0'); + assert(strbuf->len == i + 1); + assert(strbuf->alloc > strbuf->len); + } + btp_strbuf_free(strbuf); + return 0; +} +]]) + +## --------------------- ## +## btp_strbuf_append_str ## +## --------------------- ## + +AT_TESTFUN([btp_strbuf_append_str], +[[ +#include <lib/strbuf.h> +#include <assert.h> + +/* Test appending strings of certain length. 'len' must be < 50. */ +void test(int len) +{ + int i; + char str[50]; + for (i = 0; i < len; ++i) + str[i] = 'a'; + str[i] = '\0'; + + struct btp_strbuf *strbuf = btp_strbuf_new(); + for (i = 0; i < 100; ++i) + { + assert(strbuf->len == i*len); + assert(strbuf->alloc > strbuf->len); + assert(strbuf->buf[i*len] == '\0'); + btp_strbuf_append_str(strbuf, str); + assert(strbuf->buf[i*len] == str[0]); + assert(strbuf->buf[i*len+len] == '\0'); + assert(strbuf->len == i*len + len); + assert(strbuf->alloc > strbuf->len); + } + btp_strbuf_free(strbuf); +} + +int main(void) +{ + int i; + for (i = 0; i < 50; ++i) + test(i); + return 0; +} +]]) diff --git a/btparser/tests/testsuite.at b/btparser/tests/testsuite.at new file mode 100644 index 00000000..96fbe9da --- /dev/null +++ b/btparser/tests/testsuite.at @@ -0,0 +1,8 @@ +# Test suite for btparser. +# See http://www.gnu.org/software/hello/manual/autoconf/Writing-Testsuites.html + +m4_include([utils.at]) +m4_include([strbuf.at]) +m4_include([frame.at]) +m4_include([thread.at]) +m4_include([backtrace.at]) diff --git a/btparser/tests/thread.at b/btparser/tests/thread.at new file mode 100644 index 00000000..143a8e1f --- /dev/null +++ b/btparser/tests/thread.at @@ -0,0 +1,349 @@ +# Checking the btparser. -*- Autotest -*- + +AT_BANNER([Threads]) + +## ----------------------- ## +## btp_thread_remove_frame ## +## ----------------------- ## +AT_TESTFUN([btp_thread_remove_frame], +[[ +#include <lib/thread.h> +#include <lib/frame.h> +#include <lib/location.h> +#include <lib/utils.h> +#include <assert.h> +#include <stdlib.h> + +int main(void) +{ + struct btp_frame *frame2 = btp_frame_new(); + frame2->function_name = btp_strdup("write"); + frame2->number = 2; + frame2->source_file = btp_strdup("gfileutils.c"); + frame2->source_line = 120; + frame2->address = 0x322160e7fdULL; + + struct btp_frame *frame1 = btp_frame_new(); + frame1->function_name = btp_strdup("write_to_temp_file"); + frame1->number = 1; + frame1->source_file = btp_strdup("gfileutils.c"); + frame1->source_line = 980; + frame1->address = 0x322160e7fdULL; + frame1->next = frame2; + + struct btp_frame *frame0 = btp_frame_new(); + frame0->function_name = btp_strdup("fsync"); + frame0->number = 0; + frame0->source_file = btp_strdup("../sysdeps/unix/syscall-template.S"); + frame0->source_line = 82; + frame0->address = 0x322160e7fdULL; + frame0->next = frame1; + + struct btp_thread thread; + btp_thread_init(&thread); + thread.number = 3; + thread.frames = frame0; + + /* Remove the frame from the top of the stack. */ + assert(btp_thread_remove_frame(&thread, frame0)); + assert(frame1 == thread.frames); + assert(frame2 == thread.frames->next); + + /* Remove the frame from the bottom of the stack. */ + assert(btp_thread_remove_frame(&thread, frame2)); + assert(frame1 == thread.frames); + assert(NULL == thread.frames->next); + + /* Remove the last remaining frame. */ + assert(btp_thread_remove_frame(&thread, frame1)); + assert(NULL == thread.frames); + + /* Remove nonexistant frame -> should return false. */ + assert(!btp_thread_remove_frame(&thread, frame0)); + assert(NULL == thread.frames); + + return 0; +} +]]) + +## ------------------------------ ## +## btp_thread_remove_frames_above ## +## ------------------------------ ## +AT_TESTFUN([btp_thread_remove_frames_above], +[[ +#include <lib/thread.h> +#include <lib/frame.h> +#include <lib/location.h> +#include <lib/utils.h> +#include <assert.h> +#include <stdlib.h> + +int main(void) +{ + struct btp_frame *frame2 = btp_frame_new(); + frame2->function_name = btp_strdup("write"); + frame2->number = 2; + frame2->source_file = btp_strdup("gfileutils.c"); + frame2->source_line = 120; + frame2->address = 0x322160e7fdULL; + + struct btp_frame *frame1 = btp_frame_new(); + frame1->function_name = btp_strdup("write_to_temp_file"); + frame1->number = 1; + frame1->source_file = btp_strdup("gfileutils.c"); + frame1->source_line = 980; + frame1->address = 0x322160e7fdULL; + frame1->next = frame2; + + struct btp_frame *frame0 = btp_frame_new(); + frame0->function_name = btp_strdup("fsync"); + frame0->number = 0; + frame0->source_file = btp_strdup("../sysdeps/unix/syscall-template.S"); + frame0->source_line = 82; + frame0->address = 0x322160e7fdULL; + frame0->next = frame1; + + struct btp_thread thread; + btp_thread_init(&thread); + thread.number = 3; + thread.frames = frame0; + + /* Remove the frames above the top of the stack. */ + assert(btp_thread_remove_frames_above(&thread, frame0)); + assert(frame0 == thread.frames); + assert(frame1 == thread.frames->next); + + /* Remove the frames above the second frame from the top of the stack. */ + assert(btp_thread_remove_frames_above(&thread, frame1)); + assert(frame1 == thread.frames); + assert(frame2 == thread.frames->next); + + /* Remove the frames above the bottom of the stack. */ + assert(btp_thread_remove_frames_above(&thread, frame2)); + assert(frame2 == thread.frames); + assert(NULL == thread.frames->next); + + /* Remove frames above a nonexistant frame -> should return false. */ + assert(!btp_thread_remove_frames_above(&thread, frame0)); + assert(frame2 == thread.frames); + + return 0; +} +]]) + +## -------------------------------- ## +## btp_thread_remove_frames_below_n ## +## -------------------------------- ## +AT_TESTFUN([btp_thread_remove_frames_below_n], +[[ +#include <lib/thread.h> +#include <lib/frame.h> +#include <lib/location.h> +#include <lib/utils.h> +#include <assert.h> +#include <stdlib.h> + +int main(void) +{ + struct btp_frame *frame2 = btp_frame_new(); + frame2->function_name = btp_strdup("write"); + frame2->number = 2; + frame2->source_file = btp_strdup("gfileutils.c"); + frame2->source_line = 120; + frame2->address = 0x322160e7fdULL; + + struct btp_frame *frame1 = btp_frame_new(); + frame1->function_name = btp_strdup("write_to_temp_file"); + frame1->number = 1; + frame1->source_file = btp_strdup("gfileutils.c"); + frame1->source_line = 980; + frame1->address = 0x322160e7fdULL; + frame1->next = frame2; + + struct btp_frame *frame0 = btp_frame_new(); + frame0->function_name = btp_strdup("fsync"); + frame0->number = 0; + frame0->source_file = btp_strdup("../sysdeps/unix/syscall-template.S"); + frame0->source_line = 82; + frame0->address = 0x322160e7fdULL; + frame0->next = frame1; + + struct btp_thread thread; + btp_thread_init(&thread); + thread.number = 3; + thread.frames = frame0; + + /* Remove no frame as n is too large. */ + btp_thread_remove_frames_below_n(&thread, 5); + assert(frame0 == thread.frames); + assert(frame1 == thread.frames->next); + assert(frame2 == thread.frames->next->next); + assert(NULL == thread.frames->next->next->next); + + /* Remove the frames below 1. */ + btp_thread_remove_frames_below_n(&thread, 1); + assert(frame0 == thread.frames); + assert(NULL == thread.frames->next); + + /* Remove the frames below 0. */ + btp_thread_remove_frames_below_n(&thread, 0); + assert(NULL == thread.frames); + + /* Try to remove frames when no frame is present. */ + btp_thread_remove_frames_below_n(&thread, 4); + assert(NULL == thread.frames); + + return 0; +} +]]) + +## ---------------- ## +## btp_thread_parse ## +## ---------------- ## + +AT_TESTFUN([btp_thread_parse], +[[ +#include <lib/thread.h> +#include <lib/frame.h> +#include <lib/location.h> +#include <assert.h> +#include <stdlib.h> +#include <stdio.h> + +void check(char *input, + struct btp_thread *expected_thread) +{ + printf("===============================================\n" + "Testing input: %s", + input); + + char *old_input = input; + struct btp_location location; + btp_location_init(&location); + struct btp_thread *thread = btp_thread_parse(&input, &location); + assert(!expected_thread || thread); + if (thread) + { + assert(*input == '\0'); + assert(btp_thread_cmp(thread, expected_thread) == 0); + btp_thread_free(thread); + } + else + { + /* Check that the pointer is not moved. */ + assert(old_input == input); + assert(!expected_thread); + } +} + +int main(void) +{ + /* Basic test. */ + struct btp_frame frame0, frame1; + btp_frame_init(&frame0); + frame0.function_name = "fsync"; + frame0.number = 0; + frame0.source_file = "../sysdeps/unix/syscall-template.S"; + frame0.source_line = 82; + frame0.address = 0x322160e7fdULL; + frame0.next = &frame1; + + btp_frame_init(&frame1); + frame1.function_name = "write_to_temp_file"; + frame1.number = 1; + frame1.source_file = "gfileutils.c"; + frame1.source_line = 980; + frame1.address = 0x322160e7fdULL; + + struct btp_thread thread; + btp_thread_init(&thread); + thread.number = 3; + thread.frames = &frame0; + + check("Thread 3 (Thread 11917):\n" + "#0 0x000000322160e7fd in fsync () at ../sysdeps/unix/syscall-template.S:82\n" + "No locals.\n" + "#1 0x000000322222987a in write_to_temp_file (\n" + " filename=0x18971b0 \"/home/jfclere/.recently-used.xbel\", \n" + " contents=<value optimized out>, length=29917, error=0x7fff3cbe4110)\n" + " at gfileutils.c:980\n" + " statbuf = {st_dev = 64768, st_ino = 13709, st_nlink = 1, \n" + " st_mode = 33152, st_uid = 500, st_gid = 500, __pad0 = 0, \n" + " st_rdev = 0, st_size = 29917, st_blksize = 4096, st_blocks = 64, \n" + " st_atim = {tv_sec = 1273231242, tv_nsec = 73521863}, st_mtim = {\n" + " tv_sec = 1273231242, tv_nsec = 82521015}, st_ctim = {\n" + " tv_sec = 1273231242, tv_nsec = 190522021}, __unused = {0, 0, 0}}\n", + &thread); + + return 0; +} +]]) + +## -------------------------- ## +## btp_thread_parse-locations ## +## -------------------------- ## + +AT_TESTFUN([btp_thread_parse-locations], +[[ +#include <lib/thread.h> +#include <lib/frame.h> +#include <lib/location.h> +#include <assert.h> +#include <stdlib.h> + +/** + * Checks that the thread parser fails on ceratin location + * (line and column), with an error message. + */ +void check(char *input, + int expected_line, + int expected_column) +{ + char *old_input = input; + struct btp_location location; + btp_location_init(&location); + assert(NULL == btp_thread_parse(&input, &location)); + + /* Check that the pointer is not moved. */ + assert(old_input == input); + + /* Check the location. */ + printf("location %d:%d '%s', expected %d:%d\n", + location.line, location.column, location.message, + expected_line, expected_column); + + assert(location.line == expected_line); + assert(location.column == expected_column); + assert(location.message); + assert(location.message[0] != '\0'); +} + +int main(void) +{ + /* Thread keyword */ + check("Thraed 3 (Thread 11917):\n", 1, 0); + + /* Spaces after the thread keyword. */ + check("Thread3 (Thread 11917):\n", 1, 6); + + /* Thread number. */ + check("Thread a (Thread 11917):\n", 1, 8); + + /* Spaces after the thread number. */ + check("Thread 8(Thread 11917):\n", 1, 8); + + /* A parenthesis. */ + check("Thread 8 (11917):\n", 1, 9); + + /* Second number. */ + check("Thread 8 (Thread ffff):\n", 1, 17); + + /* Semicolon missing. */ + check("Thread 8 (Thread 1)\n", 1, 18); + + /* Not a single frame. */ + check("Thread 3 (Thread 11917):\n\n", 2, 0); + + return 0; +} +]]) diff --git a/btparser/tests/utils.at b/btparser/tests/utils.at new file mode 100644 index 00000000..c12d05fa --- /dev/null +++ b/btparser/tests/utils.at @@ -0,0 +1,442 @@ +# Checking the btparser. -*- Autotest -*- + +AT_BANNER([Utils]) + +## ------------ ## +## btp_strcmp0 ## +## ------------ ## + +AT_TESTFUN([btp_strcmp0], +[[ +#include <lib/utils.h> +#include <assert.h> +int main(void) +{ + assert(0 == btp_strcmp0(NULL, NULL)); + assert(0 == btp_strcmp0("abab", "abab")); + assert(0 > btp_strcmp0("aba", "abab")); + assert(0 > btp_strcmp0(NULL, "abab")); + assert(0 < btp_strcmp0("abab", NULL)); + assert(0 < btp_strcmp0("abab", "aba")); + return 0; +} +]]) + +## ------------------- ## +## btp_strchr_location ## +## ------------------- ## + +AT_TESTFUN([btp_strchr_location], +[[ +#include <lib/utils.h> +#include <assert.h> +int main(void) +{ + /* The character is on the first line.*/ + int line, column; + char *result = btp_strchr_location("test string", 'r', &line, &column); + assert(0 == strcmp(result, "ring")); + assert(1 == line); + assert(7 == column); + + /* The character is on the third line. */ + result = btp_strchr_location("\ntest\n string", 'r', &line, &column); + assert(0 == strcmp(result, "ring")); + assert(3 == line); + assert(3 == column); + + /* The character is not found. */ + result = btp_strchr_location("\ntest\n string", 'z', &line, &column); + assert(!result); + + /* The character _is_ a newline. */ + result = btp_strchr_location("abcd\nefgh", '\n', &line, &column); + assert(0 == strcmp(result, "\nefgh")); + assert(1 == line); + assert(4 == column); + return 0; +} +]]) + +## ------------------- ## +## btp_strstr_location ## +## ------------------- ## + +AT_TESTFUN([btp_strstr_location], +[[ +#include <lib/utils.h> +#include <assert.h> +int main(void) +{ + /* The substring is on the first line.*/ + int line, column; + char *result = btp_strstr_location("test string", "ri", &line, &column); + assert(0 == strcmp(result, "ring")); + assert(1 == line); + assert(7 == column); + + /* The substring is on the third line. */ + result = btp_strstr_location("\ntest\n string", "ri", &line, &column); + assert(0 == strcmp(result, "ring")); + assert(3 == line); + assert(3 == column); + + /* The substring is not found, but the first char is. */ + result = btp_strstr_location("\ntest\n string", "rz", &line, &column); + assert(!result); + + /* The substring is not found. */ + result = btp_strstr_location("\ntest\n string", "zr", &line, &column); + assert(!result); + + /* The substring _is_ a newline. */ + result = btp_strstr_location("abcd\nefgh", "\n", &line, &column); + assert(0 == strcmp(result, "\nefgh")); + assert(1 == line); + assert(4 == column); + return 0; +} +]]) + +## ------------------- ## +## btp_strspn_location ## +## ------------------- ## + +AT_TESTFUN([btp_strspn_location], +[[ +#include <lib/utils.h> +#include <assert.h> +int main(void) +{ + /* No newline in the input.*/ + int line, column; + size_t count = btp_strspn_location("test string", + "tes ", + &line, + &column); + assert(7 == count); + assert(1 == line); + assert(7 == column); + + /* With some newlines. */ + count = btp_strspn_location("te\nst \nstring", + "tes \n", + &line, + &column); + assert(9 == count); + assert(3 == line); + assert(2 == column); + + return 0; +} +]]) + +## ------------- ## +## btp_skip_char ## +## ------------- ## + +AT_TESTFUN([btp_skip_char], +[[ +#include <lib/utils.h> +#include <assert.h> +int main(void) +{ + char *input = "abc"; + assert(btp_skip_char(&input, 'a')); + assert(!btp_skip_char(&input, 'c')); + return 0; +} +]]) + +## --------------------- ## +## btp_skip_char_limited ## +## --------------------- ## + +AT_TESTFUN([btp_skip_char_limited], +[[ +#include <lib/utils.h> +#include <assert.h> +int main(void) +{ + char *input = "abc"; + assert(btp_skip_char_limited(&input, "ab")); + assert(btp_skip_char_limited(&input, "ab")); + assert(!btp_skip_char_limited(&input, "ab")); + return 0; +} +]]) + +## ---------------------- ## +## btp_parse_char_limited ## +## ---------------------- ## + +AT_TESTFUN([btp_parse_char_limited], +[[ +#include <lib/utils.h> +#include <assert.h> +int main(void) +{ + char *input = "abc"; + char result; + + /* First char in allowed is used. */ + assert(btp_parse_char_limited(&input, "ab", &result)); + assert(*input == 'b' && result == 'a'); + + /* No char in allowed is used. */ + assert(!btp_parse_char_limited(&input, "cd", &result)); + assert(*input == 'b' && result == 'a'); + + /* Second char in allowed is used. */ + assert(btp_parse_char_limited(&input, "ab", &result)); + assert(*input == 'c' && result == 'b'); + + /* Empty set of allowed chars. */ + assert(!btp_parse_char_limited(&input, "", &result)); + assert(*input == 'c' && result == 'b'); + + /* Char is multiple times in allowed. */ + assert(btp_parse_char_limited(&input, "cdc", &result)); + assert(*input == '\0' && result == 'c'); + + return 0; +} +]]) + +## ---------------------- ## +## btp_skip_char_sequence ## +## ---------------------- ## + +AT_TESTFUN([btp_skip_char_sequence], +[[ +#include <lib/utils.h> +#include <assert.h> +int main(void) +{ + char *input = "aaaaabc"; + assert(5 == btp_skip_char_sequence(&input, 'a')); + assert(1 == btp_skip_char_sequence(&input, 'b')); + assert(0 == btp_skip_char_sequence(&input, 'b')); + return 0; +} +]]) + +## ------------------ ## +## btp_skip_char_span ## +## ------------------ ## + +AT_TESTFUN([btp_skip_char_span], +[[ +#include <lib/utils.h> +#include <assert.h> +int main(void) +{ + char *input = "aabaabc"; + assert(6 == btp_skip_char_span(&input, "ba")); + assert(0 == btp_skip_char_span(&input, "b")); + assert(1 == btp_skip_char_span(&input, "bc")); + + /* Test that it can parse empty string. */ + assert(0 == btp_skip_char_span(&input, "abc")); + + return 0; +} +]]) + +## --------------------------- ## +## btp_skip_char_span_location ## +## --------------------------- ## + +AT_TESTFUN([btp_skip_char_span_location], +[[ +#include <lib/utils.h> +#include <assert.h> +int main(void) +{ + char *input = "aab\naabc"; + int line, column; + + assert(7 == btp_skip_char_span_location(&input, "ba\n", &line, &column)); + assert(2 == line); + assert(3 == column); + + assert(0 == btp_skip_char_span_location(&input, "b", &line, &column)); + assert(1 == line); + assert(0 == column); + + assert(1 == btp_skip_char_span_location(&input, "bc", &line, &column)); + assert(1 == line); + assert(1 == column); + + /* Test that it can parse empty string. */ + assert(0 == btp_skip_char_span_location(&input, "abc", &line, &column)); + assert(1 == line); + assert(0 == column); + + return 0; +} +]]) + +## ------------------- ## +## btp_parse_char_span ## +## ------------------- ## + +AT_TESTFUN([btp_parse_char_span], +[[ +#include <lib/utils.h> +#include <assert.h> +int main(void) +{ + char *input = "abcd"; + char *result; + assert(2 == btp_parse_char_span(&input, "ba", &result)); + assert(*input == 'c' && strcmp(result, "ab") == 0); + assert(0 == btp_parse_char_span(&input, "ba", &result)); + assert(*input == 'c' && strcmp(result, "ab") == 0); + free(result); + assert(2 == btp_parse_char_span(&input, "ecfd", &result)); + assert(*input == '\0' && strcmp(result, "cd") == 0); + free(result); + return 0; +} +]]) + +## -------------------- ## +## btp_parse_char_cspan ## +## -------------------- ## + +AT_TESTFUN([btp_parse_char_cspan], +[[ +#include <lib/utils.h> +#include <assert.h> +int main(void) +{ + char *input = "abcd"; + char *result; + assert(btp_parse_char_cspan(&input, "c", &result)); + assert(*input == 'c' && strcmp(result, "ab") == 0); + assert(!btp_parse_char_cspan(&input, "c", &result)); + assert(*input == 'c' && strcmp(result, "ab") == 0); + free(result); + assert(btp_parse_char_cspan(&input, "e", &result)); + assert(*input == '\0' && strcmp(result, "cd") == 0); + free(result); + return 0; +} +]]) + +## --------------- ## +## btp_skip_string ## +## --------------- ## + +AT_TESTFUN([btp_skip_string], +[[ +#include <lib/utils.h> +#include <assert.h> +int main(void) +{ + char *input = "abcd"; + assert(2 == btp_skip_string(&input, "ab")); + assert(*input == 'c'); + assert(0 == btp_skip_string(&input, "cde")); + assert(2 == btp_skip_string(&input, "cd")); + assert(0 == btp_skip_string(&input, "cd")); + return 0; +} +]]) + +## ---------------- ## +## btp_parse_string ## +## ---------------- ## + +AT_TESTFUN([btp_parse_string], +[[ +#include <lib/utils.h> +#include <assert.h> +int main(void) +{ + char *input = "abcd"; + char *result; + assert(btp_parse_string(&input, "ab", &result)); + assert(0 == strcmp(result, "ab")); + assert(*input == 'c'); + free(result); + return 0; +} +]]) + +## ------------------------- ## +## btp_skip_unsigned_integer ## +## ------------------------- ## + +AT_TESTFUN([btp_skip_unsigned_integer], +[[ +#include <lib/utils.h> +#include <assert.h> +int main(void) +{ + char *input = "10"; + assert(2 == btp_skip_unsigned_integer(&input)); + assert(*input == '\0'); + return 0; +} +]]) + +## ------------------------- ## +## btp_parse_unsigned_integer ## +## ------------------------- ## + +AT_TESTFUN([btp_parse_unsigned_integer], +[[ +#include <lib/utils.h> +#include <assert.h> +int main(void) +{ + char *input = "10"; + unsigned result; + assert(2 == btp_parse_unsigned_integer(&input, &result)); + assert('\0' == *input); + assert(10 == result); + return 0; +} +]]) + +## --------------------------- ## +## btp_skip_hexadecimal_number ## +## --------------------------- ## + +AT_TESTFUN([btp_skip_hexadecimal_number], +[[ +#include <lib/utils.h> +#include <assert.h> +int main(void) +{ + char *input = "0xffddffddff"; + assert(12 == btp_skip_hexadecimal_number(&input)); + assert(*input == '\0'); + return 0; +} +]]) + +## ---------------------------- ## +## btp_parse_hexadecimal_number ## +## ---------------------------- ## + +AT_TESTFUN([btp_parse_hexadecimal_number], +[[ +#include <lib/utils.h> +#include <assert.h> +int main(void) +{ + char *input = "0x0fafaffff 0x2badf00dbaadf00d"; + uint64_t num; + assert(11 == btp_parse_hexadecimal_number(&input, &num)); + assert(*input == ' '); + assert(num == 0xfafaffff); + *input++; + assert(18 == btp_parse_hexadecimal_number(&input, &num)); + assert(*input == '\0'); + assert(num == 0x2badf00dbaadf00d); + return 0; +} +]]) diff --git a/configure.ac b/configure.ac index 37363999..64995df1 100644 --- a/configure.ac +++ b/configure.ac @@ -18,15 +18,6 @@ CXXFLAGS="$CXXFLAGS -D_LARGEFILE_SOURCE -D_LARGEFILE64_SOURCE \ CFLAGS="$CFLAGS -D_LARGEFILE_SOURCE -D_LARGEFILE64_SOURCE \ -D_FILE_OFFSET_BITS=64 -fno-strict-aliasing -std=gnu99 -Wall" -AC_CHECK_PROGS(YACC, 'bison -y', [no]) -[if test "$YACC" = "no"] -[then] - [echo "bison not found in the search path. Please ensure that it is"] - [echo "installed and its directory is included in the search path."] - [echo "Then run configure again before attempting to build ABRT."] - [exit 1] -[fi] - dnl ****** INTERNATIONALIZATION ********************** GETTEXT_PACKAGE=abrt AC_SUBST(GETTEXT_PACKAGE) @@ -56,7 +47,7 @@ PKG_CHECK_MODULES([LIBNOTIFY], [libnotify]) #PKG_CHECK_MODULES([NSS], [nss]) PKG_CHECK_MODULES([XMLRPC], [xmlrpc]) PKG_CHECK_MODULES([XMLRPC_CLIENT], [xmlrpc_client]) -PKG_CHECK_MODULES([POLKIT],[polkit-gobject-1]) +PKG_CHECK_MODULES([POLKIT], [polkit-gobject-1]) PKG_PROG_PKG_CONFIG AC_ARG_WITH([systemdsystemunitdir], @@ -127,10 +118,10 @@ AC_CONFIG_FILES([ src/applet/Makefile src/gui/Makefile src/cli/Makefile - src/utils/Makefile inc/Makefile po/Makefile.in icons/Makefile ]) +AC_CONFIG_SUBDIRS([btparser]) AC_OUTPUT diff --git a/lib/plugins/CCpp.cpp b/lib/plugins/CCpp.cpp index 2bae89d6..e5b50c34 100644 --- a/lib/plugins/CCpp.cpp +++ b/lib/plugins/CCpp.cpp @@ -24,7 +24,6 @@ #include "abrt_exception.h" #include "comm_layer_inner.h" #include "Polkit.h" -#include "backtrace.h" using namespace std; diff --git a/lib/plugins/Makefile.am b/lib/plugins/Makefile.am index 2e50cc2d..f07b376d 100644 --- a/lib/plugins/Makefile.am +++ b/lib/plugins/Makefile.am @@ -66,7 +66,6 @@ UTILS_PATH=$(srcdir)/../utils # CCpp libCCpp_la_SOURCES = CCpp.cpp CCpp.h libCCpp_la_LDFLAGS = -avoid-version -#libCCpp_la_LIBADD = libCCpp_la_CPPFLAGS = -Wall -Werror \ -I$(INC_PATH) -I$(UTILS_PATH) \ -DCCPP_HOOK_PATH=\"${libexecdir}/abrt-hook-ccpp\" \ diff --git a/lib/utils/Makefile.am b/lib/utils/Makefile.am index ac5f4837..79df31e5 100644 --- a/lib/utils/Makefile.am +++ b/lib/utils/Makefile.am @@ -3,7 +3,6 @@ lib_LTLIBRARIES = libABRTUtils.la libABRTdUtils.la HEADER_DIR = $(srcdir)/../../inc AM_CPPFLAGS = -I$(HEADER_DIR) -AM_YFLAGS = --verbose # Not used just yet: # time.cpp @@ -27,8 +26,6 @@ libABRTUtils_la_SOURCES = \ abrt_dbus.c abrt_dbus.h \ CrashTypes.cpp \ ABRTException.cpp \ - backtrace.c backtrace.h \ - backtrace_parser.y \ strbuf.c strbuf.h \ abrt_packages.c abrt_packages.h \ hooklib.c hooklib.h \ @@ -53,7 +50,6 @@ libABRTUtils_la_LIBADD = \ $(DBUS_LIBS) \ -ldl - libABRTdUtils_la_SOURCES = \ parse_release.cpp \ make_descr.cpp \ diff --git a/lib/utils/backtrace.c b/lib/utils/backtrace.c deleted file mode 100644 index f507cba3..00000000 --- a/lib/utils/backtrace.c +++ /dev/null @@ -1,846 +0,0 @@ -/* - Copyright (C) 2009 RedHat inc. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License along - with this program; if not, write to the Free Software Foundation, Inc., - 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. -*/ -#include <stdlib.h> -#include <string.h> -#include <ctype.h> -#include "backtrace.h" -#include "strbuf.h" -#include "xfuncs.h" - -struct frame *frame_new() -{ - struct frame *f = malloc(sizeof(struct frame)); - if (!f) - { - puts("Error while allocating memory for backtrace frame."); - exit(5); - } - - f->function = NULL; - f->number = 0; - f->sourcefile = NULL; - f->signal_handler_called = false; - f->next = NULL; - return f; -} - -void frame_free(struct frame *f) -{ - if (f->function) - free(f->function); - if (f->sourcefile) - free(f->sourcefile); - free(f); -} - -struct frame *frame_add_sibling(struct frame *a, struct frame *b) -{ - struct frame *aa = a; - while (aa->next) - aa = aa->next; - - aa->next = b; - return a; -} - -/* Appends a string representation of 'frame' to the 'str'. */ -static void frame_append_str(struct frame *frame, struct strbuf *str, bool verbose) -{ - if (verbose) - strbuf_append_strf(str, " #%d", frame->number); - else - strbuf_append_str(str, " "); - - if (frame->function) - strbuf_append_strf(str, " %s", frame->function); - if (verbose && frame->sourcefile) - { - if (frame->function) - strbuf_append_str(str, " at"); - strbuf_append_strf(str, " %s", frame->sourcefile); - } - - if (frame->signal_handler_called) - strbuf_append_str(str, " <signal handler called>"); - - strbuf_append_str(str, "\n"); -} - -static bool frame_is_exit_handler(struct frame *frame) -{ - return (frame->function - && frame->sourcefile - && 0 == strcmp(frame->function, "__run_exit_handlers") - && NULL != strstr(frame->sourcefile, "exit.c")); -} - -/* Checks if a frame contains abort function used - * by operating system to exit application. - * E.g. in C it's called "abort" or "raise". - */ -static bool frame_is_abort_frame(struct frame *frame) -{ - if (!frame->function || !frame->sourcefile) - return false; - - if (0 == strcmp(frame->function, "raise") - && (NULL != strstr(frame->sourcefile, "pt-raise.c") - || NULL != strstr(frame->sourcefile, "/libc.so.6"))) - return true; - else if (0 == strcmp(frame->function, "exit") - && NULL != strstr(frame->sourcefile, "exit.c")) - return true; - else if (0 == strcmp(frame->function, "abort") - && (NULL != strstr(frame->sourcefile, "abort.c") - || NULL != strstr(frame->sourcefile, "/libc.so.6"))) - return true; - else if (frame_is_exit_handler(frame)) - return true; - - return false; -} - -static bool frame_is_noncrash_frame(struct frame *frame) -{ - /* Abort frames. */ - if (frame_is_abort_frame(frame)) - return true; - - if (!frame->function) - return false; - - if (0 == strcmp(frame->function, "__kernel_vsyscall")) - return true; - - if (0 == strcmp(frame->function, "__assert_fail")) - return true; - - if (!frame->sourcefile) - return false; - - /* GDK */ - if (0 == strcmp(frame->function, "gdk_x_error") - && 0 == strcmp(frame->sourcefile, "gdkmain-x11.c")) - return true; - - /* X.org */ - if (0 == strcmp(frame->function, "_XReply") - && 0 == strcmp(frame->sourcefile, "xcb_io.c")) - return true; - if (0 == strcmp(frame->function, "_XError") - && 0 == strcmp(frame->sourcefile, "XlibInt.c")) - return true; - if (0 == strcmp(frame->function, "XSync") - && 0 == strcmp(frame->sourcefile, "Sync.c")) - return true; - if (0 == strcmp(frame->function, "process_responses") - && 0 == strcmp(frame->sourcefile, "xcb_io.c")) - return true; - - /* glib */ - if (0 == strcmp(frame->function, "IA__g_log") - && 0 == strcmp(frame->sourcefile, "gmessages.c")) - return true; - if (0 == strcmp(frame->function, "IA__g_logv") - && 0 == strcmp(frame->sourcefile, "gmessages.c")) - return true; - if (0 == strcmp(frame->function, "IA__g_assertion_message") - && 0 == strcmp(frame->sourcefile, "gtestutils.c")) - return true; - if (0 == strcmp(frame->function, "IA__g_assertion_message_expr") - && 0 == strcmp(frame->sourcefile, "gtestutils.c")) - return true; - - /* DBus */ - if (0 == strcmp(frame->function, "gerror_to_dbus_error_message") - && 0 == strcmp(frame->sourcefile, "dbus-gobject.c")) - return true; - if (0 == strcmp(frame->function, "dbus_g_method_return_error") - && 0 == strcmp(frame->sourcefile, "dbus-gobject.c")) - return true; - - /* libstdc++ */ - if (0 == strcmp(frame->function, "__gnu_cxx::__verbose_terminate_handler") - && NULL != strstr(frame->sourcefile, "/vterminate.cc")) - return true; - if (0 == strcmp(frame->function, "__cxxabiv1::__terminate") - && NULL != strstr(frame->sourcefile, "/eh_terminate.cc")) - return true; - if (0 == strcmp(frame->function, "std::terminate") - && NULL != strstr(frame->sourcefile, "/eh_terminate.cc")) - return true; - if (0 == strcmp(frame->function, "__cxxabiv1::__cxa_throw") - && NULL != strstr(frame->sourcefile, "/eh_throw.cc")) - return true; - - return false; -} - -struct thread *thread_new() -{ - struct thread *t = malloc(sizeof(struct thread)); - if (!t) - { - puts("Error while allocating memory for backtrace thread."); - exit(5); - } - - t->number = 0; - t->frames = NULL; - t->next = NULL; - return t; -} - -void thread_free(struct thread *t) -{ - while (t->frames) - { - struct frame *rm = t->frames; - t->frames = rm->next; - frame_free(rm); - } - - free(t); -} - -struct thread *thread_add_sibling(struct thread *a, struct thread *b) -{ - struct thread *aa = a; - while (aa->next) - aa = aa->next; - - aa->next = b; - return a; -} - -static int thread_get_frame_count(struct thread *thread) -{ - struct frame *f = thread->frames; - int count = 0; - while (f) - { - f = f->next; - ++count; - } - return count; -} - -/* Appends string representation of 'thread' to the 'str'. */ -static void thread_append_str(struct thread *thread, struct strbuf *str, bool verbose) -{ - int framecount = thread_get_frame_count(thread); - if (verbose) - strbuf_append_strf(str, "Thread no. %d (%d frames)\n", thread->number, framecount); - else - strbuf_append_str(str, "Thread\n"); - struct frame *frame = thread->frames; - while (frame) - { - frame_append_str(frame, str, verbose); - frame = frame->next; - } -} - -/* - * Checks whether the thread it contains some known "abort" function. - * If a frame with the function is found, it is returned. - * If there are multiple frames with abort function, the lowest - * one is returned. - * Nonrecursive. - */ -struct frame *thread_find_abort_frame(struct thread *thread) -{ - struct frame *frame = thread->frames; - struct frame *result = NULL; - while (frame) - { - if (frame_is_abort_frame(frame)) - result = frame; - - frame = frame->next; - } - - return result; -} - -static void thread_remove_exit_handlers(struct thread *thread) -{ - struct frame *frame = thread->frames; - while (frame) - { - if (frame_is_exit_handler(frame)) - { - /* Delete all frames from the beginning to this frame. */ - while (thread->frames != frame) - { - struct frame *rm = thread->frames; - thread->frames = thread->frames->next; - frame_free(rm); - } - return; - } - - frame = frame->next; - } -} - -static void thread_remove_noncrash_frames(struct thread *thread) -{ - struct frame *prev = NULL; - struct frame *cur = thread->frames; - while (cur) - { - if (frame_is_noncrash_frame(cur)) - { - /* This frame must be skipped, because it will - be deleted. */ - if (prev) - prev->next = cur->next; - else - thread->frames = cur->next; - - frame_free(cur); - - /* Set cur to be valid, as it will be used to - advance to next item. */ - if (prev) - cur = prev; - else - { - cur = thread->frames; - continue; - } - } - - prev = cur; - cur = cur->next; - } -} - -/* Counts the number of quality frames and the number of all frames - * in a thread. - * @param ok_count - * @param all_count - * Not zeroed. This function just adds the numbers to - * ok_count and all_count. - */ -static void thread_rating(struct thread *thread, int *ok_count, int *all_count) -{ - struct frame *frame = thread->frames; - while (frame) - { - *all_count += 1; - if (frame->signal_handler_called || - (frame->function && 0 != strcmp(frame->function, "??"))) - { - *ok_count += 1; - } - frame = frame->next; - } -} - -struct backtrace *backtrace_new() -{ - struct backtrace *bt = malloc(sizeof(struct backtrace)); - if (!bt) - { - puts("Error while allocating memory for backtrace."); - exit(5); - } - - bt->threads = NULL; - bt->crash = NULL; - return bt; -} - -void backtrace_free(struct backtrace *bt) -{ - while (bt->threads) - { - struct thread *rm = bt->threads; - bt->threads = rm->next; - thread_free(rm); - } - - if (bt->crash) - frame_free(bt->crash); - - free(bt); -} - -static int backtrace_get_thread_count(struct backtrace *bt) -{ - struct thread *t = bt->threads; - int count = 0; - while (t) - { - t = t->next; - ++count; - } - return count; -} - -void backtrace_print_tree(struct backtrace *backtrace, bool verbose) -{ - struct strbuf *strbuf = backtrace_tree_as_str(backtrace, verbose); - puts(strbuf->buf); - strbuf_free(strbuf); -} - -struct strbuf *backtrace_tree_as_str(struct backtrace *backtrace, bool verbose) -{ - struct strbuf *str = strbuf_new(); - if (verbose) - strbuf_append_strf(str, "Thread count: %d\n", backtrace_get_thread_count(backtrace)); - - if (backtrace->crash && verbose) - { - strbuf_append_str(str, "Crash frame: "); - frame_append_str(backtrace->crash, str, verbose); - } - - struct thread *thread = backtrace->threads; - while (thread) - { - thread_append_str(thread, str, verbose); - thread = thread->next; - } - - return str; -} - -void backtrace_remove_threads_except_one(struct backtrace *backtrace, - struct thread *one) -{ - while (backtrace->threads) - { - struct thread *rm = backtrace->threads; - backtrace->threads = rm->next; - if (rm != one) - thread_free(rm); - } - - one->next = NULL; - backtrace->threads = one; -} - -/* - * Loop through all threads and if a single one contains the crash frame on the top, - * return it. Otherwise, return NULL. - * - * If require_abort is true, it is also required that the thread containing - * the crash frame contains some known "abort" function. In this case there can be - * multiple threads with the crash frame on the top, but only one of them might - * contain the abort function to succeed. - */ -static struct thread *backtrace_find_crash_thread_from_crash_frame(struct backtrace *backtrace, - bool require_abort) -{ - /* - * This code can be extended to compare something else when the function - * name is not available. - */ - if (!backtrace->threads || !backtrace->crash || !backtrace->crash->function) - return NULL; - - struct thread *result = NULL; - struct thread *thread = backtrace->threads; - while (thread) - { - if (thread->frames - && thread->frames->function - && 0 == strcmp(thread->frames->function, backtrace->crash->function) - && (!require_abort || thread_find_abort_frame(thread))) - { - if (result == NULL) - result = thread; - else - { - /* Second frame with the same function. Failure. */ - return NULL; - } - } - - thread = thread->next; - } - - return result; -} - -struct thread *backtrace_find_crash_thread(struct backtrace *backtrace) -{ - /* If there is no thread, be silent and report NULL. */ - if (!backtrace->threads) - return NULL; - - /* If there is just one thread, it is simple. */ - if (!backtrace->threads->next) - return backtrace->threads; - - /* If we have a crash frame *and* there is just one thread which has - * this frame on the top, it is also simple. - */ - struct thread *thread; - thread = backtrace_find_crash_thread_from_crash_frame(backtrace, false); - if (thread) - return thread; - - /* There are multiple threads with a frame indistinguishable from - * the crash frame on the top of stack. - * Try to search for known abort functions. - */ - thread = backtrace_find_crash_thread_from_crash_frame(backtrace, true); - - return thread; /* result or null */ -} - -void backtrace_limit_frame_depth(struct backtrace *backtrace, int depth) -{ - if (depth <= 0) - return; - - struct thread *thread = backtrace->threads; - while (thread) - { - struct frame *frame = thread_find_abort_frame(thread); - if (frame) - frame = frame->next; /* Start counting from the frame following the abort fr. */ - else - frame = thread->frames; /* Start counting from the first frame. */ - - /* Skip some frames to get the required stack depth. */ - int i = depth; - struct frame *last_frame = NULL; - while (frame && i) - { - last_frame = frame; - frame = frame->next; - --i; - } - - /* Delete the remaining frames. */ - if (last_frame) - last_frame->next = NULL; - - while (frame) - { - struct frame *rm = frame; - frame = frame->next; - frame_free(rm); - } - - thread = thread->next; - } -} - -void backtrace_remove_exit_handlers(struct backtrace *backtrace) -{ - struct thread *thread = backtrace->threads; - while (thread) - { - thread_remove_exit_handlers(thread); - thread = thread->next; - } -} - -void backtrace_remove_noncrash_frames(struct backtrace *backtrace) -{ - struct thread *thread = backtrace->threads; - while (thread) - { - thread_remove_noncrash_frames(thread); - thread = thread->next; - } -} - -/* Belongs to independent_backtrace(). */ -struct header -{ - struct strbuf *text; - struct header *next; -}; - -/* Belongs to independent_backtrace(). */ -static struct header *header_new() -{ - struct header *head = malloc(sizeof(struct header)); - if (!head) - { - puts("Error while allocating memory for backtrace header."); - exit(5); - } - head->text = NULL; - head->next = NULL; - return head; -} - -/* Recursively frees siblings. */ -/* Belongs to independent_backtrace(). */ -static void header_free(struct header *head) -{ - if (head->text) - strbuf_free(head->text); - if (head->next) - header_free(head->next); - free(head); -} - -/* Inserts new header to array if it is not already there. */ -/* Belongs to independent_backtrace(). */ -static void header_set_insert(struct header *cur, struct strbuf *new) -{ - /* Duplicate found case. */ - if (strcmp(cur->text->buf, new->buf) == 0) - return; - - /* Last item case, insert new header here. */ - if (cur->next == NULL) - { - cur->next = header_new(); - cur->next->text = new; - return; - } - - /* Move to next item in array case. */ - header_set_insert(cur->next, new); -} - -struct strbuf *independent_backtrace(const char *input) -{ - struct strbuf *header = strbuf_new(); - bool in_bracket = false; - bool in_quote = false; - bool in_header = false; - bool in_digit = false; - bool has_at = false; - bool has_filename = false; - bool has_bracket = false; - struct header *headers = NULL; - - const char *bk = input; - while (*bk) - { - if (bk[0] == '#' - && bk[1] >= '0' && bk[1] <= '7' - && bk[2] == ' ' /* take only #0...#7 (8 last stack frames) */ - && !in_quote) - { - if (in_header && !has_filename) - strbuf_clear(header); - in_header = true; - } - - if (!in_header) - { - ++bk; - continue; - } - - if (isdigit(*bk) && !in_quote && !has_at) - in_digit = true; - else if (bk[0] == '\\' && bk[1] == '\"') - bk++; - else if (*bk == '\"') - in_quote = in_quote == true ? false : true; - else if (*bk == '(' && !in_quote) - { - in_bracket = true; - in_digit = false; - strbuf_append_char(header, '('); - } - else if (*bk == ')' && !in_quote) - { - in_bracket = false; - has_bracket = true; - in_digit = false; - strbuf_append_char(header, '('); - } - else if (*bk == '\n' && has_filename) - { - if (headers == NULL) - { - headers = header_new(); - headers->text = header; - } - else - header_set_insert(headers, header); - - header = strbuf_new(); - in_bracket = false; - in_quote = false; - in_header = false; - in_digit = false; - has_at = false; - has_filename = false; - has_bracket = false; - } - else if (*bk == ',' && !in_quote) - in_digit = false; - else if (isspace(*bk) && !in_quote) - in_digit = false; - else if (bk[0] == 'a' && bk[1] == 't' && has_bracket && !in_quote) - { - has_at = true; - strbuf_append_char(header, 'a'); - } - else if (bk[0] == ':' && has_at && isdigit(bk[1]) && !in_quote) - has_filename = true; - else if (in_header && !in_digit && !in_quote && !in_bracket) - strbuf_append_char(header, *bk); - - bk++; - } - - strbuf_free(header); - - struct strbuf *result = strbuf_new(); - struct header *loop = headers; - while (loop) - { - strbuf_append_str(result, loop->text->buf); - strbuf_append_char(result, '\n'); - loop = loop->next; - } - - if (headers) - header_free(headers); /* recursive */ - - return result; -} - -/* Belongs to backtrace_rate_old(). */ -enum line_rating -{ - // RATING EXAMPLE - MissingEverything = 0, // #0 0x0000dead in ?? () - MissingFunction = 1, // #0 0x0000dead in ?? () from /usr/lib/libfoobar.so.4 - MissingLibrary = 2, // #0 0x0000dead in foobar() - MissingSourceFile = 3, // #0 0x0000dead in FooBar::FooBar () from /usr/lib/libfoobar.so.4 - Good = 4, // #0 0x0000dead in FooBar::crash (this=0x0) at /home/user/foobar.cpp:204 - BestRating = Good, -}; - -/* Belongs to backtrace_rate_old(). */ -static enum line_rating rate_line(const char *line) -{ -#define FOUND(x) (strstr(line, x) != NULL) - /* see the comments at enum line_rating for possible combinations */ - if (FOUND(" at ")) - return Good; - const char *function = strstr(line, " in "); - if (function && function[4] == '?') /* " in ??" does not count */ - function = NULL; - bool library = FOUND(" from "); - if (function && library) - return MissingSourceFile; - if (function) - return MissingLibrary; - if (library) - return MissingFunction; - - return MissingEverything; -#undef FOUND -} - -/* just a fallback function, to be removed one day */ -int backtrace_rate_old(const char *backtrace) -{ - int i, len; - int multiplier = 0; - int rating = 0; - int best_possible_rating = 0; - char last_lvl = 0; - - /* We look at the frames in reversed order, since: - * - rate_line() checks starting from the first line of the frame - * (note: it may need to look at more than one line!) - * - we increase weight (multiplier) for every frame, - * so that topmost frames end up most important - */ - len = 0; - for (i = strlen(backtrace) - 1; i >= 0; i--) - { - if (backtrace[i] == '#' - && (backtrace[i+1] >= '0' && backtrace[i+1] <= '9') /* #N */ - && (i == 0 || backtrace[i-1] == '\n')) /* it's at line start */ - { - /* For one, "#0 xxx" always repeats, skip repeats */ - if (backtrace[i+1] == last_lvl) - continue; - last_lvl = backtrace[i+1]; - - char *s = xstrndup(backtrace + i + 1, len); - /* Replace tabs with spaces, rate_line() does not expect tabs. - * Actually, even newlines may be there. Example of multiline frame - * where " at SRCFILE" is on 2nd line: - * #3 0x0040b35d in __libc_message (do_abort=<value optimized out>, - * fmt=<value optimized out>) at ../sysdeps/unix/sysv/linux/libc_fatal.c:186 - */ - char *p; - for (p = s; *p; p++) - { - if (*p == '\t' || *p == '\n') - *p = ' '; - } - int lrate = rate_line(s); - multiplier++; - rating += lrate * multiplier; - best_possible_rating += BestRating * multiplier; - //log("lrate:%d rating:%d best_possible_rating:%d s:'%-.40s'", - // lrate, rating, best_possible_rating, s); - free(s); - len = 0; /* starting new line */ - } - else - { - len++; - } - } - - /* Bogus 'backtrace' with zero frames? */ - if (best_possible_rating == 0) - return 0; - - /* Returning number of "stars" to show */ - if (rating*10 >= best_possible_rating*8) /* >= 0.8 */ - return 4; - if (rating*10 >= best_possible_rating*6) - return 3; - if (rating*10 >= best_possible_rating*4) - return 2; - if (rating*10 >= best_possible_rating*2) - return 1; - - return 0; -} - -float backtrace_quality(struct backtrace *backtrace) -{ - int ok_count = 0; - int all_count = 0; - struct thread *thread = backtrace->threads; - while (thread) - { - thread_rating(thread, &ok_count, &all_count); - thread = thread->next; - } - - if (all_count == 0) - return 0; - return ok_count / (float)all_count; -} diff --git a/lib/utils/backtrace.h b/lib/utils/backtrace.h deleted file mode 100644 index df5def56..00000000 --- a/lib/utils/backtrace.h +++ /dev/null @@ -1,152 +0,0 @@ -/* - Backtrace parsing and processing. - - If we transform analyzer plugins to separate applications one day, - this functionality should be moved to CCpp analyzer, which will - then easily provide what abrt-backtrace utility provides now. Currently - the code is used by abrt-backtrace, so it is shared in the utils - library. - - Copyright (C) 2009, 2010 RedHat inc. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License along - with this program; if not, write to the Free Software Foundation, Inc., - 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. -*/ -#ifndef BACKTRACE_H -#define BACKTRACE_H - -#ifdef __cplusplus -extern "C" { -#endif - -#include <stdio.h> -#include <stdbool.h> - -struct frame -{ - /* Function name, or NULL. */ - char *function; - /* Frame number. */ - int number; - /* Name of the source file, or binary file, or NULL. */ - char *sourcefile; - bool signal_handler_called; - /* Sibling frame, or NULL if this is the last frame in a thread. */ - struct frame *next; -}; - -struct thread -{ - int number; - struct frame *frames; - /* Sibling thread, or NULL if this is the last thread in a backtrace. */ - struct thread *next; -}; - -struct backtrace -{ - struct thread *threads; - /* - * The frame where the crash happened according to GDB. - * It might be that we can not tell to which thread this frame belongs, - * because all threads end with mutually indistinguishable frames. - */ - struct frame *crash; -}; - -extern struct frame *frame_new(); -extern void frame_free(struct frame *f); -extern struct frame *frame_add_sibling(struct frame *a, struct frame *b); - -extern struct thread *thread_new(); -extern void thread_free(struct thread *t); -extern struct thread *thread_add_sibling(struct thread *a, struct thread *b); -extern struct frame *thread_find_abort_frame(struct thread *thread); - -extern struct backtrace *backtrace_new(); -extern void backtrace_free(struct backtrace *bt); - -/* Prints how internal backtrace representation looks to stdout. */ -extern void backtrace_print_tree(struct backtrace *backtrace, bool verbose); - -/* Returns the backtrace tree string representation. */ -extern struct strbuf *backtrace_tree_as_str(struct backtrace *backtrace, bool verbose); - -/* - * Frees all threads except the one provided as parameters. - * It does not check whether one is a member of backtrace. - * Caller must know that. - */ -extern void backtrace_remove_threads_except_one(struct backtrace *backtrace, - struct thread *one); - -/* - * Search all threads and tries to find the one that caused the crash. - * It might return NULL if the thread cannot be determined. - */ -extern struct thread *backtrace_find_crash_thread(struct backtrace *backtrace); - -extern void backtrace_limit_frame_depth(struct backtrace *backtrace, int depth); - -/* - * Exit handlers are all stack frames above __run_exit_handlers() - */ -extern void backtrace_remove_exit_handlers(struct backtrace *backtrace); - -/* - * Removes frames known as not causing crash, but that are often - * a part of a backtrace. - */ -extern void backtrace_remove_noncrash_frames(struct backtrace *backtrace); - -/* Parses the backtrace and stores it to a structure. - * @returns - * Returns the backtrace struct representation, or NULL if the parser failed. - * Caller of this function is responsible for backtrace_free()ing the returned value. - * Defined in backtrace_parser.y. - */ -extern struct backtrace *backtrace_parse(char *input, bool debug_parser, bool debug_scanner); - -/* Reads the input file and calculates "independent" backtrace from it. "Independent" means - * that the memory addresses that differ from run to run are removed from the backtrace, and - * also variable names and values are removed. - * - * This function can be called when backtrace_parse() call fails. It provides a shorter - * version of backtrace, with a chance that hash calculated from the returned value can be used - * to detect duplicates. However, this kind of duplicate detection is very low-quality. - * @returns - * The independent backtrace. Caller is responsible for calling - * strbuf_free() on it. - */ -extern struct strbuf *independent_backtrace(const char *input); - -/* Get the quality of backtrace, as a number of "stars". - * @returns - * Value 0 to 4. - */ -extern int backtrace_rate_old(const char *backtrace); - -/* Evaluates the quality of the backtrace, meaning the ratio of frames - * with function name fully known to all frames. - * @returns - * A number between 0 and 1. 0 means the lowest quality, - * 1 means full backtrace is known. - */ -extern float backtrace_quality(struct backtrace *backtrace); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/lib/utils/backtrace_parser.y b/lib/utils/backtrace_parser.y deleted file mode 100644 index 8e2fc2b1..00000000 --- a/lib/utils/backtrace_parser.y +++ /dev/null @@ -1,684 +0,0 @@ -%{ /* -*- mode: yacc -*- - Copyright (C) 2009 RedHat inc. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License along - with this program; if not, write to the Free Software Foundation, Inc., - 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. -*/ -#include <math.h> -#include <stdio.h> -#include <stdlib.h> -#include "backtrace.h" -#include "strbuf.h" - -struct backtrace *g_backtrace; - -#define YYDEBUG 1 -#define YYMAXDEPTH 10000000 -void yyerror(char const *s) -{ - fprintf (stderr, "\nParser error: %s\n", s); -} - -int yylex(); - -%} - -/* This defines the type of yylval */ -%union { - struct backtrace *backtrace; - struct thread *thread; - struct frame *frame; - char *str; - int num; - char c; - - struct strbuf *strbuf; -} - -/* Bison declarations. */ -%token END 0 "end of file" - -%type <backtrace> backtrace -%type <thread> threads - thread -%type <frame> frames - frame - frame_head - frame_head_1 - frame_head_2 - frame_head_3 - frame_head_4 - frame_head_5 -%type <strbuf> identifier - hexadecimal_digit_sequence - hexadecimal_number - file_name - file_location - function_call - function_name - digit_sequence - frame_address_in_function - identifier_braces - identifier_braces_inside - identifier_template - identifier_template_inside -%type <c> nondigit - digit - hexadecimal_digit - file_name_char - identifier_char - identifier_char_no_templates - identifier_first_char - identifier_braces_inside_char - identifier_template_inside_char - variables_char - variables_char_no_framestart - ws - ws_nonl - '(' ')' '+' '-' '/' '.' '_' '~' '[' ']' '\r' '?' '{' '}' - 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' - 'm' 'n' 'o' 'p' 'q' 'r' 's' 't' 'u' 'v' 'w' 'x' 'y' 'z' - 'A' 'B' 'C' 'D' 'E' 'F' 'G' 'H' 'I' 'J' 'K' 'L' 'M' 'N' - 'O' 'P' 'Q' 'R' 'S' 'T' 'U' 'V' 'W' 'X' 'Y' 'Z' - '0' '1' '2' '3' '4' '5' '6' '7' '8' '9' - '\'' '`' ',' '#' '@' '<' '>' '=' ':' '"' ';' ' ' - '\n' '\t' '\\' '!' '*' '%' '|' '^' '&' '$' -%type <num> frame_start - -%destructor { thread_free($$); } <thread> -%destructor { frame_free($$); } <frame> -%destructor { strbuf_free($$); } <strbuf> - -%start backtrace -%glr-parser -%error-verbose -%locations - -%% /* The grammar follows. */ - -backtrace : /* empty */ %dprec 1 - { $$ = g_backtrace = backtrace_new(); } - | threads wsa %dprec 2 - { - $$ = g_backtrace = backtrace_new(); - $$->threads = $1; - } - | frame_head wss threads wsa %dprec 4 - { - $$ = g_backtrace = backtrace_new(); - $$->threads = $3; - $$->crash = $1; - } - | frame wss threads wsa %dprec 3 - { - $$ = g_backtrace = backtrace_new(); - $$->threads = $3; - $$->crash = $1; - } -; - -threads : thread - | threads '\n' thread { $$ = thread_add_sibling($1, $3); } -; - -thread : keyword_thread wss digit_sequence wsa '(' keyword_thread wss digit_sequence wsa ')' ':' wsa frames - { - $$ = thread_new(); - $$->frames = $13; - - if (sscanf($3->buf, "%d", &$$->number) != 1) - { - printf("Error while parsing thread number '%s'", $3->buf); - exit(5); - } - strbuf_free($3); - strbuf_free($8); - } -; - -frames : frame { $$ = $1; } - | frames frame { $$ = frame_add_sibling($1, $2); } -; - -frame : frame_head_1 wss variables %dprec 3 - | frame_head_2 wss variables %dprec 4 - | frame_head_3 wss variables %dprec 5 - | frame_head_4 wss variables %dprec 2 - | frame_head_5 wss variables %dprec 1 -; - -frame_head : frame_head_1 %dprec 3 - | frame_head_2 %dprec 4 - | frame_head_3 %dprec 5 - | frame_head_4 %dprec 2 - | frame_head_5 %dprec 1 -; - -frame_head_1 : frame_start wss function_call wsa keyword_at wss file_location - { - $$ = frame_new(); - $$->number = $1; - $$->function = $3->buf; - strbuf_free_nobuf($3); - $$->sourcefile = $7->buf; - strbuf_free_nobuf($7); - } -; - -frame_head_2 : frame_start wss frame_address_in_function wss keyword_at wss file_location - { - $$ = frame_new(); - $$->number = $1; - $$->function = $3->buf; - strbuf_free_nobuf($3); - $$->sourcefile = $7->buf; - strbuf_free_nobuf($7); - } -; - -frame_head_3 : frame_start wss frame_address_in_function wss keyword_from wss file_location - { - $$ = frame_new(); - $$->number = $1; - $$->function = $3->buf; - strbuf_free_nobuf($3); - $$->sourcefile = $7->buf; - strbuf_free_nobuf($7); - } -; - -frame_head_4 : frame_start wss frame_address_in_function - { - $$ = frame_new(); - $$->number = $1; - $$->function = $3->buf; - strbuf_free_nobuf($3); - } -; - -frame_head_5 : frame_start wss keyword_sighandler - { - $$ = frame_new(); - $$->number = $1; - $$->signal_handler_called = true; - } - -frame_start: '#' digit_sequence - { - if (sscanf($2->buf, "%d", &$$) != 1) - { - printf("Error while parsing frame number '%s'.\n", $2->buf); - exit(5); - } - strbuf_free($2); - } -; - -frame_address_in_function : hexadecimal_number wss keyword_in wss function_call - { - strbuf_free($1); - $$ = $5; - } - | hexadecimal_number wss keyword_in wss keyword_vtable wss keyword_for wss function_call - { - strbuf_free($1); - $$ = $9; - } -; - -file_location : file_name ':' digit_sequence - { - $$ = $1; - strbuf_free($3); /* line number not needed for now */ - } - | file_name -; - -variables : variables_line '\n' - | variables_line END - | variables_line wss_nonl '\n' - | variables_line wss_nonl END - | variables variables_line '\n' - | variables variables_line END - | variables variables_line wss_nonl '\n' - | variables variables_line wss_nonl END - | variables wss_nonl variables_line '\n' - | variables wss_nonl variables_line END - | variables wss_nonl variables_line wss_nonl '\n' - | variables wss_nonl variables_line wss_nonl END -; - -variables_line : variables_char_no_framestart - | variables_line variables_char - | variables_line wss_nonl variables_char -; - -variables_char : '#' | variables_char_no_framestart -; - -/* Manually synchronized with function_args_char_base, except the first line. */ -variables_char_no_framestart : digit | nondigit | '"' | '(' | ')' | '\\' - | '+' | '-' | '<' | '>' | '/' | '.' - | '[' | ']' | '?' | '\'' | '`' | ',' - | '=' | '{' | '}' | '^' | '&' | '$' - | ':' | ';' | '!' | '@' | '*' - | '%' | '|' | '~' -; - -function_call : function_name wss function_args %dprec 3 - | return_type wss_nonl function_name wss function_args %dprec 2 - { $$ = $3; } - | function_name wss_nonl identifier_template wss function_args %dprec 1 - { $$ = $1; strbuf_free($3); } -; - -return_type : identifier { strbuf_free($1); } -; - -function_name : identifier - | '?' '?' - { - $$ = strbuf_new(); - strbuf_append_str($$, "??"); - } -; - -function_args : '(' wsa ')' - | '(' wsa function_args_sequence wsa ')' -; - -function_args_sequence : function_args_char - | function_args_sequence wsa '(' wsa ')' - | function_args_sequence wsa '(' wsa function_args_string wsa ')' - | function_args_sequence wsa '(' wsa function_args_sequence wsa ')' - | function_args_sequence wsa function_args_char - | function_args_sequence wsa function_args_string -; - -function_args_string : '"' wsa function_args_string_sequence wsa '"' - | '"' wsa '"' -; - -/* Manually synchronized with variables_char_no_framestart, - * except the first line. - */ -function_args_char_base : digit | nondigit | '#' - | '+' | '-' | '<' | '>' | '/' | '.' - | '[' | ']' | '?' | '\'' | '`' | ',' - | '=' | '{' | '}' | '^' | '&' | '$' - | ':' | ';' | '!' | '@' | '*' - | '%' | '|' | '~' -; -function_args_escaped_char : '\\' function_args_char_base - | '\\' '\\' - | '\\' '"' -; -function_args_char : function_args_char_base - | function_args_escaped_char -; - - -function_args_string_sequence : function_args_string_char - | function_args_string_sequence function_args_string_char - | function_args_string_sequence wss_nonl function_args_string_char -; - -function_args_string_char : function_args_char | '(' | ')' -; - -file_name : file_name_char { $$ = strbuf_new(); strbuf_append_char($$, $1); } - | file_name file_name_char { $$ = strbuf_append_char($1, $2); } -; - -file_name_char : digit | nondigit | '-' | '+' | '/' | '.' -; - - /* Function name, sometimes mangled. - * Example: something@GLIB_2_2 - * CClass::operator= - */ -identifier : identifier_first_char %dprec 1 - { - $$ = strbuf_new(); - strbuf_append_char($$, $1); - } - | identifier_braces %dprec 1 /* e.g. (anonymous namespace)::WorkerThread */ - | identifier identifier_char %dprec 1 - { $$ = strbuf_append_char($1, $2); } - | identifier identifier_braces %dprec 1 - { - $$ = strbuf_append_str($1, $2->buf); - strbuf_free($2); - } - | identifier identifier_template %dprec 2 - { - $$ = strbuf_append_str($1, $2->buf); - strbuf_free($2); - } -; - -identifier_first_char: nondigit - | '~' /* destructor */ - | '*' -; - -identifier_char_no_templates : digit | nondigit | '@' | '.' | ':' | '=' - | '!' | '*' | '+' | '-' | '[' | ']' - | '~' | '&' | '/' | '%' | '^' - | '|' | ',' -; - -/* Most of the special characters are required to support C++ - * operator overloading. - */ -identifier_char : identifier_char_no_templates | '<'| '>' -; - -identifier_braces : '(' ')' - { - $$ = strbuf_new(); - strbuf_append_char($$, $1); - strbuf_append_char($$, $2); - } - | '(' identifier_braces_inside ')' - { - $$ = strbuf_new(); - strbuf_append_char($$, $1); - strbuf_append_str($$, $2->buf); - strbuf_free($2); - strbuf_append_char($$, $3); - } -; - -identifier_braces_inside : identifier_braces_inside_char %dprec 1 - { - $$ = strbuf_new(); - strbuf_append_char($$, $1); - } - | identifier_braces_inside identifier_braces_inside_char %dprec 1 - { $$ = strbuf_append_char($1, $2); } - | identifier_braces_inside '(' identifier_braces_inside ')' %dprec 1 - { - $$ = strbuf_append_char($1, $2); - $$ = strbuf_append_str($1, $3->buf); - strbuf_free($3); - $$ = strbuf_append_char($1, $4); - } - | identifier_braces_inside '(' ')' %dprec 1 - { - $$ = strbuf_append_char($1, $2); - $$ = strbuf_append_char($1, $3); - } - | identifier_braces_inside identifier_template %dprec 2 - { - $$ = strbuf_append_str($1, $2->buf); - strbuf_free($2); - } -; - -identifier_braces_inside_char : identifier_char | ws_nonl -; - -identifier_template : '<' identifier_template_inside '>' - { - $$ = strbuf_new(); - strbuf_append_char($$, $1); - strbuf_append_str($$, $2->buf); - strbuf_free($2); - strbuf_append_char($$, $3); - } -; - -identifier_template_inside : identifier_template_inside_char - { - $$ = strbuf_new(); - strbuf_append_char($$, $1); - } - | identifier_template_inside identifier_template_inside_char - { $$ = strbuf_append_char($1, $2); } - | identifier_template_inside '<' identifier_template_inside '>' - { - $$ = strbuf_append_char($1, $2); - $$ = strbuf_append_str($1, $3->buf); - strbuf_free($3); - $$ = strbuf_append_char($1, $4); - } - | identifier_template_inside identifier_braces - { - $$ = strbuf_append_str($1, $2->buf); - strbuf_free($2); - } -; - -identifier_template_inside_char : identifier_char_no_templates | ws_nonl -; - -digit_sequence : digit { $$ = strbuf_new(); strbuf_append_char($$, $1); } - | digit_sequence digit { $$ = strbuf_append_char($1, $2); } -; - -hexadecimal_number : '0' 'x' hexadecimal_digit_sequence - { - $$ = $3; - strbuf_prepend_str($$, "0x"); - } - | '0' 'X' hexadecimal_digit_sequence - { - $$ = $3; - strbuf_prepend_str($$, "0X"); - } -; - -hexadecimal_digit_sequence : hexadecimal_digit - { - $$ = strbuf_new(); - strbuf_append_char($$, $1); - } - | hexadecimal_digit_sequence hexadecimal_digit - { $$ = strbuf_append_char($1, $2); } -; - -hexadecimal_digit : digit - | 'a' | 'b' | 'c' | 'd' | 'e' | 'f' - | 'A' | 'B' | 'C' | 'D' | 'E' | 'F' -; - -digit : '0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9' -; - -nondigit : 'a' | 'b' | 'c' | 'd' | 'e' | 'f' | 'g' | 'h' | 'i' | 'j' | 'k' - | 'l' | 'm' | 'n' | 'o' | 'p' | 'q' | 'r' | 's' | 't' | 'u' | 'v' | 'w' - | 'x' | 'y' | 'z' - | 'A' | 'B' | 'C' | 'D' | 'E' | 'F' | 'G' | 'H' | 'I' | 'J' | 'K' - | 'L' | 'M' | 'N' | 'O' | 'P' | 'Q' | 'R' | 'S' | 'T' | 'U' | 'V' | 'W' - | 'X' | 'Y' | 'Z' - | '_' -; - - /* whitespace */ -ws : ws_nonl | '\n' | '\r' -; - - /* No newline.*/ -ws_nonl : '\t' | ' ' -; - - /* whitespace sequence without a newline */ -wss_nonl : ws_nonl - | wss_nonl ws_nonl -; - - /* whitespace sequence */ -wss : ws - | wss ws -; - - /* whitespace sequence allowed */ -wsa : - | wss -; - -keyword_in : 'i' 'n' -; - -keyword_at : 'a' 't' -; - -keyword_for : 'f' 'o' 'r' -; - -keyword_vtable : 'v' 't' 'a' 'b' 'l' 'e' -; - -keyword_from : 'f' 'r' 'o' 'm' -; - -keyword_thread: 'T' 'h' 'r' 'e' 'a' 'd' -; - -keyword_sighandler: '<' 's' 'i' 'g' 'n' 'a' 'l' ' ' 'h' 'a' 'n' 'd' 'l' 'e' 'r' ' ' 'c' 'a' 'l' 'l' 'e' 'd' '>' -; - -%% - -static bool scanner_echo = false; -static char *yyin; - -int yylex() -{ - char c = *yyin; - if (c == '\0') - return END; - ++yyin; - - /* Debug output. */ - if (scanner_echo) - putchar(c); - - yylval.c = c; - - /* Return a single char. */ - return c; -} - -/* This is the function that is actually called from outside. - * @returns - * Backtrace structure. Caller is responsible for calling - * backtrace_free() on this. - * Returns NULL when parsing failed. - */ -struct backtrace *backtrace_parse(char *input, bool debug_parser, bool debug_scanner) -{ - /* Skip the backtrace header information. */ - char *btnoheader_a = strstr(input, "\nThread "); - char *btnoheader_b = strstr(input, "\n#"); - char *btnoheader = input; - if (btnoheader_a) - { - if (btnoheader_b && btnoheader_b < btnoheader_a) - btnoheader = btnoheader_b + 1; - else - btnoheader = btnoheader_a + 1; - } - else if (btnoheader_b) - btnoheader = btnoheader_b + 1; - - /* Bug fixing hack for broken backtraces. - * Sometimes the empty line is missing before new Thread section. - * This is against rules, but a bug (now fixed) in Linux kernel caused - * this. - */ - char *thread_fixer = btnoheader + 1; - while ((thread_fixer = strstr(thread_fixer, "\nThread")) != NULL) - { - if (thread_fixer[-1] != '\n') - thread_fixer[-1] = '\n'; - - ++thread_fixer; - } - - /* Bug fixing hack for GDB - remove wrongly placed newlines from the backtrace. - * Sometimes there is a newline in the local variable section. - * This is caused by some GDB hooks. - * Example: rhbz#538440 - * #1 0x0000000000420939 in sync_deletions (mse=0x0, mfld=0x1b85020) - * at mail-stub-exchange.c:1119 - * status = <value optimized out> - * iter = 0x1af38d0 - * known_messages = 0x1b5c460Traceback (most recent call last): - * File "/usr/share/glib-2.0/gdb/glib.py", line 98, in next - * if long (node["key_hash"]) >= 2: - * RuntimeError: Cannot access memory at address 0x11 - * - * __PRETTY_FUNCTION__ = "sync_deletions" - * #2 0x0000000000423e6b in refresh_folder (stub=0x1b77f10 [MailStubExchange], - * ... - * - * The code removes every empty line (also those containing only spaces), - * which is not followed by a new Thread section. - * - * rhbz#555251 contains empty lines with spaces - */ - char *empty_line = btnoheader; - char *c = btnoheader; - while (*c) - { - if (*c == '\n') - { - char *cend = c + 1; - while (*cend == ' ' || *cend == '\t') - ++cend; - if (*cend == '\n' && 0 != strncmp(cend, "\nThread", strlen("\nThread"))) - memmove(c, cend, strlen(cend) + 1); - } - ++c; - } - while ((empty_line = strstr(empty_line, "\n\n")) != NULL) - { - if (0 != strncmp(empty_line, "\n\nThread", strlen("\n\nThread"))) - { - /* Remove the empty line by converting the first newline to char. */ - empty_line[0] = 'X'; - } - ++empty_line; - } - - /* Prepare for running parser. */ - g_backtrace = 0; - yyin = btnoheader; -#if YYDEBUG == 1 - if (debug_parser) - yydebug = 1; -#endif - scanner_echo = debug_scanner; - - /* Parse. */ - int failure = yyparse(); - - /* Separate debugging output. */ - if (scanner_echo) - putchar('\n'); - - if (failure) - { - if (g_backtrace) - { - backtrace_free(g_backtrace); - g_backtrace = NULL; - } - fprintf(stderr, "Error while parsing backtrace.\n"); - } - - return g_backtrace; -} diff --git a/scripts/abrt-bz-downloader b/scripts/abrt-bz-downloader deleted file mode 100755 index d7f5a719..00000000 --- a/scripts/abrt-bz-downloader +++ /dev/null @@ -1,82 +0,0 @@ -#!/usr/bin/python -# -*- mode:python -*- -# ABRT Bugzilla Backtrace Downloader -# Downloads all backtraces reported by ABRT from Bugzilla. -# -# Please do not run this script unless it's neccessary to do so. -# It forces Bugzilla to send data related to thousands of bug reports. - -from bugzilla import RHBugzilla -from optparse import OptionParser -import sys -import os.path - -parser = OptionParser(version="%prog 1.0") -parser.add_option("-u", "--user", dest="user", - help="Bugzilla user name (REQUIRED)", metavar="USERNAME") -parser.add_option("-p", "--password", dest="password", - help="Bugzilla password (REQUIRED)", metavar="PASSWORD") -parser.add_option("-b", "--bugzilla", dest="bugzilla", - help="Bugzilla URL (defaults to Red Hat Bugzilla)", metavar="URL") -parser.add_option("-f", "--fields", - action="store_true", dest="fields", default=False, - help="Print possible bug fields and exit.") - -(options, args) = parser.parse_args() - -if not options.user or len(options.user) == 0: - parser.error("User name is required.\nTry {0} --help".format(sys.argv[0])) - -if not options.password or len(options.password) == 0: - parser.error("Password is required.\nTry {0} --help".format(sys.argv[0])) - -if not options.bugzilla or len(options.bugzilla) == 0: - options.bugzilla = "https://bugzilla.redhat.com/xmlrpc.cgi" - -bz = RHBugzilla() -bz.connect(options.bugzilla) -bz.login(options.user, options.password) - -if options.fields: - print bz.bugfields - exit(0) - -buginfos = bz.query({'status_whiteboard_type':'allwordssubstr','status_whiteboard':'abrt_hash'}) - -print "{0} bugs found.".format(len(buginfos)) - -for buginfo in buginfos: - # Skip bugs with already downloaded backtraces. - filename = "{0}.bt".format(buginfo.bug_id) - if os.path.isfile(filename): - print "Skipping {0} (already exists).".format(filename) - continue - - # Skip bugs with broken or Python backtraces - broken_backtrace_bugs = [ 517116, # binary file :) - 518516, # not a backtrace, GDB fail - 524259, # multiple backtraces in single file - 524427, # multiple backtraces in single file - 528529, # just [New Thread xx] lines - #528915, 10000 frames, out of memory, to be fixed - #529422, 10000 frames, out of memory, to be fixed - #530239, 10000 frames, out of memory, to be fixed - 532264, # no header - 533475, # no backtrace - #537819, 50000 frames, out of memory, to be fixed - #539699, to be fixed, parser bug - 539992] # completely broken backtrace - if buginfo.bug_id in broken_backtrace_bugs: - continue - - # Get backtrace from bug and store it as a file. - bug = bz.getbug(buginfo.bug_id) - for attachment in bug.attachments: - if attachment['filename'] == 'backtrace': - data = bz.openattachment(attachment['id']) - f = open(filename, 'w') - f.write(data.read()) - f.close() - print "Attachment {0} downloaded.".format(filename) - -bz.logout() diff --git a/scripts/abrt-bz-dupchecker b/scripts/abrt-bz-dupchecker deleted file mode 100755 index 65e11531..00000000 --- a/scripts/abrt-bz-dupchecker +++ /dev/null @@ -1,281 +0,0 @@ -#!/usr/bin/python -# -*- mode:python -*- -# ABRT Bugzilla Duplication Checker -# Downloads all backtraces reported by ABRT from Bugzilla, -# and search for duplicates using the newest ABRT duplication -# checker. -# -# Some bugs in Bugzilla were reported by older ABRT -# versions, which had poor duplication detection. -# -# Please do not run this script unless it's neccessary to do so. -# It forces Bugzilla to send data related to thousands of bug reports. -# -# -# Useful text to be pasted to Bugzilla: -""" -This bug appears to have been filled using a buggy version of ABRT, because -it contains unusable backtrace. Sorry for the inconvenience. -Closing as INSUFFICIENT_DATA. -""" - -from bugzilla import RHBugzilla -from optparse import OptionParser -import sys -import os.path -import subprocess -import cPickle -import urllib -import json - -parser = OptionParser(version="%prog 1.0") -parser.add_option("-u", "--user", dest="user", - help="Bugzilla user name (REQUIRED)", metavar="USERNAME") -parser.add_option("-p", "--password", dest="password", - help="Bugzilla password (REQUIRED)", metavar="PASSWORD") -parser.add_option("-b", "--bugzilla", dest="bugzilla", default="https://bugzilla.redhat.com/xmlrpc.cgi", - help="Bugzilla URL (defaults to Red Hat Bugzilla)", metavar="URL") -parser.add_option("-v", "--verbose", dest="verbose", - help="Detailed output") -parser.add_option("-c", "--close", help="Close some of the bugs in Bugzilla (DANGEROUS)", - action="store_true", default=False, dest="close") -parser.add_option("-i", "--wiki", help="Generate output in wiki syntax", - action="store_true", default=False, dest="wiki") - -(options, args) = parser.parse_args() - -if not options.user or len(options.user) == 0: - parser.error("User name is required.\nTry {0} --help".format(sys.argv[0])) - -if not options.password or len(options.password) == 0: - parser.error("Password is required.\nTry {0} --help".format(sys.argv[0])) - -bz = RHBugzilla() -bz.connect(options.bugzilla) -bz.login(options.user, options.password) - -buginfos = bz.query({'status_whiteboard_type':'allwordssubstr','status_whiteboard':'abrt_hash', 'product':'Fedora'}) - -print "{0} bugs found.".format(len(buginfos)) - -# -# Load cache from previous run. Speeds up the case Bugzilla closes connection. -# The cache should be manually removed after a day or so, because the data in it -# are no longer valid. -# -database = {} -ids = {} -CACHE_FILE = "abrt-bz-dupchecker-cache.tmp" -if os.path.isfile(CACHE_FILE): - f = open(CACHE_FILE, 'r') - database = cPickle.load(f) - ids = cPickle.load(f) - f.close() - -def save_to_cache(): - global database - f = open(CACHE_FILE, 'w') - cPickle.dump(database, f, 2) - cPickle.dump(ids, f, 2) - f.close() - -count = 0 -for buginfo in buginfos: - count += 1 - print "{0}/{1}".format(count, len(buginfos)) - if count % 100 == 0: - save_to_cache() - - if ids.has_key(buginfo.bug_id): - continue - - ids[buginfo.bug_id] = True - - if not buginfo.bug_status in ["NEW", "ASSIGNED", "MODIFIED", "VERIFIED"]: - if options.verbose: - print "Bug {0} has status {1}, skipping.".format(buginfo.bug_id, buginfo.bug_status) - continue - - bug = bz.getbug(buginfo.bug_id) - - # Skip bugs with already downloaded backtraces. - filename = "{0}.bt".format(buginfo.bug_id) - if os.path.isfile(filename): - if options.verbose: - print "Skipping {0} (already exists).".format(filename) - else: - # Get backtrace from bug and store it as a file. - downloaded = False - for attachment in bug.attachments: - if attachment['filename'] == 'backtrace': - data = bz.openattachment(attachment['id']) - f = open(filename, 'w') - f.write(data.read()) - f.close() - downloaded = True - if options.verbose: - print "Attachment {0} downloaded.".format(filename) - - # Silently skip bugs without backtrace. - # Those are usually duplicates of bugs; the duplication copies - # abrt_hash, but it does not copy the attachment. - if not downloaded: - continue - - command = ["abrt-backtrace"] - command.append(filename) - command.append("--single-thread") - command.append("--frame-depth=5") - command.append("--remove-exit-handlers") - command.append("--remove-noncrash-frames") - - helper = subprocess.Popen(command, stdout=subprocess.PIPE) - backtrace, err = helper.communicate() - helper.wait() - - if helper.returncode != 0: - print "Problems parsing {0}".format(filename) - continue - - # Empty backtrace is provided by Python apps. - if len(backtrace) == 0: - continue - - bugitem = {'id':buginfo.bug_id, 'comments':len(bug.longdescs)} - if backtrace in database: - components = database[backtrace] - if buginfo.component in components: - components[buginfo.component].append(bugitem) - if options.verbose: - print "Duplicate found: {0}".format(database[out]['id']) - print "Backtrace: {0}".format(out) - else: - components[buginfo.component] = [ bugitem ] - else: - database[backtrace] = { buginfo.component: [ bugitem ] } - -# The number of duplicates. -dupcount = 0 -# The number of duplicates that can be closed. -dupclosecount = 0 -for backtrace, components in database.items(): - for component, bugitems in components.items(): - dupcount += len(bugitems) - 1 - dupclosecount += min(len(filter(lambda x: x <= 2, - map(lambda x: x["comments"], - bugitems))), - len(bugitems) - 1) - -# Get the component owner. -# Sort the duplicates by the component owner, and -# filter out those which should not be printed. -dups = [] -for backtrace, components in database.items(): - for component, bugitems in components.items(): - if len(bugitems) <= 1: - continue - - # Get the component owner - owner = "Failed to get component owner" - try: - component_info = json.load(urllib.urlopen("https://admin.fedoraproject.org/pkgdb/acls/name/{0}?tg_format=json".format(component))) - component_packages = component_info['packageListings'] - component_f12 = filter(lambda x:x["collection"]["version"]=="12", component_packages) - if len(component_f12) == 1: - owner = component_f12[0]["owner"] - except KeyError: - pass - - dups.append((component, owner, bugitems, backtrace)) - print "." - -# Close all bugs where it is appropriate. -if options.close: - LIMIT = 10000 # infinite - counter = 0 - for (component, owner, bugitems, backtrace) in dups: - # Find the master bug item - # Its the one with the most comments. - - # Sort function sorting by comment count. - def commentCmp(x, y): - if x['comments'] < y['comments']: - return 1 - elif x['comments'] == y['comments']: - # Sort by bug id, older bugs should became the master bug - if x['id'] > y['id']: - return 1 - elif x['id'] == y['id']: - return 0 - else: - return -1 - else: - return -1 - - # Sort the duplicates by the number of comments. - # Select the bug with the highest number of comments as the master bug. - # All other bugs without user comments will be closed as a duplicate of - # the master bug. - sorteditems = sorted(bugitems, commentCmp) - master = sorteditems[0] - - # Check the master bug status AGAIN to make sure the bug is still opened. - bug = bz.getbug(int(master['id'])) - if not bug.bug_status in ["NEW", "ASSIGNED"]: - continue - - for item in sorteditems[1:]: - if item['comments'] > 2: - continue - - # Check the bug status AGAIN to make sure the bug is still opened. - bug = bz.getbug(int(item['id'])) - if not bug.bug_status in ["NEW", "ASSIGNED"]: - continue - - print "Closing bug #{0} with {1} comments as a duplicate of #{2}.".format(item['id'], item['comments'], master['id']) - bug.close("DUPLICATE", int(master['id']), "", - ("This bug appears to have been filled using a buggy version of ABRT, because\n" + - "it contains a backtrace which is a duplicate of backtrace from bug #{0}.\n\n" + - "Sorry for the inconvenience.").format(master['id'])) - - counter += 1 - if counter > LIMIT: - sys.exit(0) - -bz.logout() - -print -print "SUMMARY" -print "==========================================================================" -print "Total number of duplicate bugs detected: {0}".format(dupcount) -print "Number of duplicate bugs that will be closed : {0}".format(dupclosecount) -print "------------------------------" - -# Print the duplicates sorted by package owner. -def cmp(x, y): - if x[1] < y[1]: - return -1 - elif x[1] == y[1]: - return 0 - else: - return 1 - -for (component, owner, bugitems, backtrace) in sorted(dups, cmp): - if options.wiki: - print "----" - print "* component: '''{0}''' ({1})".format(component, owner) - print "* duplicates: {0}".format( - reduce(lambda x,y: x+", "+y, - map(lambda x: "#[https://bugzilla.redhat.com/show_bug.cgi?id={0} {0}] ({1} comments)".format(x['id'],x['comments']), - bugitems))) - print "* backtrace:" - for line in backtrace.replace("Thread\n", "").splitlines(): - print "*# {0}".format(line) - else: - print "Component: {0} ({1})".format(component, owner) - print "Duplicates: {0}".format( - reduce(lambda x,y: x+", "+y, - map(lambda x: "{0} ({1})".format(x['id'],x['comments']), - bugitems))) - print "Backtrace: {0}".format(backtrace) diff --git a/scripts/abrt-bz-hashchecker b/scripts/abrt-bz-hashchecker deleted file mode 100755 index bb66c7d4..00000000 --- a/scripts/abrt-bz-hashchecker +++ /dev/null @@ -1,59 +0,0 @@ -#!/usr/bin/python -# -*- mode:python -*- -# Checks how many bugs in Bugzilla have the same hash. -# -# Please do not run this script unless it's neccessary to do so. -# It forces Bugzilla to send data related to thousands of bug reports. - -from bugzilla import RHBugzilla -from optparse import OptionParser -import sys -import os.path -import subprocess -import re - -parser = OptionParser(version="%prog 1.0") -parser.add_option("-u", "--user", dest="user", - help="Bugzilla user name (REQUIRED)", metavar="USERNAME") -parser.add_option("-p", "--password", dest="password", - help="Bugzilla password (REQUIRED)", metavar="PASSWORD") -parser.add_option("-b", "--bugzilla", dest="bugzilla", - help="Bugzilla URL (defaults to Red Hat Bugzilla)", metavar="URL") - -(options, args) = parser.parse_args() - -if not options.user or len(options.user) == 0: - parser.error("User name is required.\nTry {0} --help".format(sys.argv[0])) - -if not options.password or len(options.password) == 0: - parser.error("Password is required.\nTry {0} --help".format(sys.argv[0])) - -if not options.bugzilla or len(options.bugzilla) == 0: - options.bugzilla = "https://bugzilla.redhat.com/xmlrpc.cgi" - -bz = RHBugzilla() -bz.connect(options.bugzilla) -bz.login(options.user, options.password) - -buginfos = bz.query({'status_whiteboard_type':'allwordssubstr','status_whiteboard':'abrt_hash'}) - -print "{0} bugs found.".format(len(buginfos)) - -hashes = {} -for buginfo in buginfos: - match = re.search("abrt_hash:([^ ]+)", buginfo.status_whiteboard) - if not match: - continue - hash = match.group(1) - if not hash: - continue - if hash in hashes: - hashes[hash].append(buginfo.bug_id) - else: - hashes[hash] = [ buginfo.bug_id ] - print hash -bz.logout() - -for hash, ids in hashes.items(): - if len(ids) > 1: - print "Duplicates found: ", reduce(lambda x,y: str(x)+", "+str(y), ids) diff --git a/scripts/abrt-bz-ratingfixer b/scripts/abrt-bz-ratingfixer deleted file mode 100755 index d7881978..00000000 --- a/scripts/abrt-bz-ratingfixer +++ /dev/null @@ -1,210 +0,0 @@ -#!/usr/bin/python -# -*- mode:python -*- -# -# Finds bugs with incomplete backtraces in Buzilla. -# Incomplete backtraces are caused by missing debuginfo. -# -# Please do not run this script unless it's neccessary to do so. -# It forces Bugzilla to send data related to thousands of bug reports. - -from bugzilla import RHBugzilla -from optparse import OptionParser -import sys -import os.path -import subprocess -import cPickle -import urllib -import json - -# -# Parse command line options. -# Exit if mandatory options are missing. -# -parser = OptionParser(version="%prog 1.0") -parser.add_option("-u", "--user", dest="user", - help="Bugzilla user name (REQUIRED)", metavar="USERNAME") -parser.add_option("-p", "--password", dest="password", - help="Bugzilla password (REQUIRED)", metavar="PASSWORD") -parser.add_option("-b", "--bugzilla", dest="bugzilla", default="https://bugzilla.redhat.com/xmlrpc.cgi", - help="Bugzilla URL (defaults to Red Hat Bugzilla)", metavar="URL") -parser.add_option("-i", "--wiki", help="Generate output in wiki syntax", - action="store_true", default=False, dest="wiki") -parser.add_option("-c", "--close", help="Close some of the bugs in Bugzilla (DANGEROUS)", - action="store_true", default=False, dest="close") -(options, args) = parser.parse_args() - -if not options.user or len(options.user) == 0: - parser.error("User name is required.\nTry {0} --help".format(sys.argv[0])) - -if not options.password or len(options.password) == 0: - parser.error("Password is required.\nTry {0} --help".format(sys.argv[0])) - -# -# Connect to the Bugzilla and get all bugs reported by ABRT -# -bz = RHBugzilla() -bz.connect(options.bugzilla) -bz.login(options.user, options.password) - -buginfos = bz.query({'status_whiteboard_type':'allwordssubstr','status_whiteboard':'abrt_hash'}) -print "{0} bugs found.".format(len(buginfos)) - -# -# Load cache from previous run. It speeds up the case Bugzilla closes connection. -# The cache should be manually removed after a day or so, because the data in it -# are no longer valid. -# -ids = {} -CACHE_FILE = "abrt-bz-ratingfixer-cache.tmp" -if os.path.isfile(CACHE_FILE): - f = open(CACHE_FILE, 'r') - ids = cPickle.load(f) - f.close() - -def save_to_cache(): - global database - f = open(CACHE_FILE, 'w') - cPickle.dump(ids, f, 2) - f.close() - -# -# Go through all bugs, and get the rating for their backtraces. -# The result is stored into ids map. -# -count = 0 -for buginfo in buginfos: - # The progress indicator. - count += 1 - print "{0}/{1}".format(count, len(buginfos)) - - # Save to cache for the case the connection will be closed by the Bugzilla. - # This happens pretty often. - if count % 100 == 0: - save_to_cache() - - # Skip the bugs already loaded from cache. - if ids.has_key(buginfo.bug_id): - continue - - # We handle only unprocessed bugs. - if not buginfo.bug_status in ["NEW", "ASSIGNED"]: - continue - - # By default: rating 4, no comments. Do not touch strange bugs. - ids[buginfo.bug_id] = { - 'rating': 4, - 'comment_count': 0, - 'component': buginfo.component - } - - # Skip bugs with already downloaded backtraces. - filename = "{0}.bt".format(buginfo.bug_id) - if not os.path.isfile(filename): - # Get backtrace from bug and store it as a file. - downloaded = False - bug = bz.getbug(buginfo.bug_id) - for attachment in bug.attachments: - if attachment['filename'] == 'backtrace': - data = bz.openattachment(attachment['id']) - f = open(filename, 'w') - f.write(data.read()) - f.close() - downloaded = True - - # Silently skip bugs without backtrace. - # Those are usually duplicates of bugs; the duplication copies - # abrt_hash, but it does not copy the attachment. - if not downloaded: - continue - - # Rate the backtrace using external program. - command = ["abrt-backtrace", "--rate"] - command.append(filename) - helper = subprocess.Popen(command, stdout=subprocess.PIPE) - rating, err = helper.communicate() - helper.wait() - if helper.returncode != 0: - print "Problems with rating {0}".format(filename) - continue - - # Get the comment count. We do not want to close bugs which - # are in the middle of a discussion. - bug = bz.getbug(buginfo.bug_id) - comment_count = 0 - for comment in bug.longdescs: - # Do not count "rawhide" comments from Bug Zappers - if comment["body"].find("against 'rawhide' during") > 0: - continue - comment_count += 1 - - # Put the result to the database. - ids[buginfo.bug_id] = { - 'rating': int(rating), - 'comment_count': comment_count, - 'component': buginfo.component - } - - # Close the bug if it's appropriate. - if options.close and comment_count <= 2 and int(rating) < 3: - print "Closing bug #{0} with {1} comments and rating {2}/4.".format(buginfo.bug_id, comment_count, int(rating)) - bug.close("INSUFFICIENT_DATA", 0, "", - "This bug appears to have been filled using a buggy version of ABRT, because\n" + - "it contains unusable backtrace. Sorry for the inconvenience.\n\n" + - "Closing as INSUFFICIENT_DATA.") - -bz.logout() - -# -# Get the component owners -# -bugids = [] -for id, bug in ids.items(): - # Skip bugs with good rating. - if bug['rating'] >= 3: - continue - - # Get the component owner - owner = "Failed to get component owner" - try: - component_info = json.load(urllib.urlopen("https://admin.fedoraproject.org/pkgdb/acls/name/{0}?tg_format=json".format(bug['component']))) - component_packages = component_info['packageListings'] - component_f12 = filter(lambda x:x["collection"]["version"]=="12", component_packages) - if len(component_f12) == 1: - owner = component_f12[0]["owner"] - except KeyError: - pass - - bug['id'] = id - bug['owner'] = owner - bugids.append(bug) - -def ownerCmp(a, b): - if a['owner'] < b['owner']: - return -1 - elif a['owner'] == b['owner']: - return 0 - else: - return 1 - -print "============= SUMMARY" -closedcount = 0 -if options.wiki: - print "{|" - print " ! Bug !! Backtrace rating !! Comment count !! Component !! Owner" - print " |-" -for bug in sorted(bugids, ownerCmp): - count += 1 - if bug['comment_count'] <= 2: - closedcount += 1 - - if options.wiki: - print " | #[https://bugzilla.redhat.com/show_bug.cgi?id={0} {0}] || {1}/4 || {2} || {3} || {4}".format(bug['id'], bug['rating'], bug['comment_count'], bug['component'], bug['owner']) - print " |-" - else: - print "#{0} has a backtrace with rating {1}/4 and {2} comments, component {3}, owner {4}".format(bug['id'], bug['rating'], bug['comment_count'], bug['component'], bug['owner']) - -if options.wiki: - print " |}" - -print "{0} bugs are included.".format(len(bugids)) -print "{0} bugs should be closed.".format(closedcount) diff --git a/scripts/abrt-bz-stats b/scripts/abrt-bz-stats deleted file mode 100755 index ea44f5bd..00000000 --- a/scripts/abrt-bz-stats +++ /dev/null @@ -1,313 +0,0 @@ -#!/usr/bin/python -# -*- mode:python -*- -# ABRT Bugzilla Statistics script -# -# Please do not run this script unless it's neccessary to do so. -# It forces Bugzilla to send info about thousands of bug reports. - -from bugzilla import RHBugzilla -from optparse import OptionParser -import sys -import os.path -import subprocess -from datetime import datetime -import pickle - -# -# Parse the command line input -# -parser = OptionParser(version="%prog 1.0") -parser.add_option("-u", "--user", dest="user", - help="Bugzilla user name (REQUIRED)", metavar="USERNAME") -parser.add_option("-p", "--password", dest="password", - help="Bugzilla password (REQUIRED)", metavar="PASSWORD") -parser.add_option("-b", "--bugzilla", dest="bugzilla", - help="Bugzilla URL (defaults to Red Hat Bugzilla)", metavar="URL") -# Weekly stats shows the impact of changes in ABRT early. -parser.add_option("-w", "--weekly", help="Generate weekly report instead of monthly", - action="store_true", default=False, dest="weekly") -# HTML output for blogs etc. -parser.add_option("-t", "--html", help="Generate HTML output", - action="store_true", default=False, dest="html") -parser.add_option("-i", "--wiki", help="Generate output in wiki syntax", - action="store_true", default=False, dest="wiki") -# Newest stats first -parser.add_option("-r", "--reversed", help="Display the newest stats first", - action="store_true", default=False, dest="reversed") -(options, args) = parser.parse_args() -if not options.user or len(options.user) == 0: - parser.error("User name is required.\nTry {0} --help".format(sys.argv[0])) -if not options.password or len(options.password) == 0: - parser.error("Password is required.\nTry {0} --help".format(sys.argv[0])) -if not options.bugzilla or len(options.bugzilla) == 0: - options.bugzilla = "https://bugzilla.redhat.com/xmlrpc.cgi" - -# -# Connect to Bugzilla and get the list of all bugs reported by ABRT -# -bz = RHBugzilla() -bz.connect(options.bugzilla) -bz.login(options.user, options.password) - -buginfos = bz.query({'status_whiteboard_type':'allwordssubstr','status_whiteboard':'abrt_hash'}) -total = len(buginfos) -print "{0} bugs found.".format(total) - -# -# Load cache from previous run. Speeds up the case Bugzilla closes connection. -# -buginfos_loaded = {} -CACHE_FILE = "abrt-bz-stats-cache.tmp" -if os.path.isfile(CACHE_FILE): - f = open(CACHE_FILE, 'r') - buginfos_loaded = pickle.load(f) - f.close() - -def save_to_cache(): - global buginfos_loaded - f = open(CACHE_FILE, 'w') - pickle.dump(buginfos_loaded, f, 2) - f.close() - -# -# Load data from Bugzilla -# -count = 0 -for buginfo in buginfos: - count += 1 - print "{0}/{1}".format(count, total) - - if count % 100 == 0: - save_to_cache() - - if buginfos_loaded.has_key(buginfo.bug_id): - continue - - # creation date, format YEAR-MONTH-DAY - created = buginfo.creation_ts[0:10].replace(".", "-") - # last change to bug, format YEAR-MONTH-DAY - lastchange = buginfo.delta_ts[0:10].replace(".", "-") - status = buginfo.bug_status # status during the last change - if buginfo.resolution != "": - status += "_" + buginfo.resolution - buginfos_loaded[buginfo.bug_id] = { - 'created':created, - 'lastchange':lastchange, - 'status':status, - 'component':buginfo.component} - -bz.logout() -save_to_cache() - -# -# Interpret data from Bugzilla -# -# Bugs reported this month/week by ABRT -# Bugs closed as useful this month/week by ABRT -# Bugs closed as waste this month/week by ABRT -# Top crashers this month/week. -# -class TimeSpan: - """ - It's either a week or month. - """ - def __init__(self): - # Number of bugs reported to certain component this month. - self.components = {} - - self.closed_as_useful = 0 - self.closed_as_waste = 0 - self.closed_as_other = 0 - - def bugs_reported(self): - result = 0 - for component in self.components.values(): - result += component - return result - - def top_crashers(self, n = 10): - """ - Top n components causing crash this month. - Returns list of tuples (component, number of crashes) - """ - result = sorted(self.components.items(), key=lambda x: x[1]) - result.reverse() - return result[0:n] - - def closed_as_useful_percentage(self): - return int(100 * self.closed_as_useful / self.closed()) - - def closed_as_waste_percentage(self): - return int(100 * self.closed_as_waste / self.closed()) - - def closed_as_other_percentage(self): - return 100 - self.closed_as_useful_percentage() \ - - self.closed_as_waste_percentage() - - def closed(self): - return self.closed_as_useful + self.closed_as_waste + self.closed_as_other - - def add_component_crash(self, component): - if component in self.components: - self.components[component] += 1 - else: - self.components[component] = 1 - - def add_resolution(self, resolution): - # Catches only resolutions starting with "CLOSED_" - if resolution in ["CLOSED_CURRENTRELEASE", "CLOSED_RAWHIDE", "CLOSED_ERRATA", - "CLOSED_UPSTREAM", "CLOSED_NEXTRELEASE"]: - self.closed_as_useful += 1 - elif resolution in ["CLOSED_DUPLICATE", "CLOSED_CANTFIX", - "CLOSED_INSUFFICIENT_DATA"]: - self.closed_as_waste += 1 - elif resolution in ["CLOSED_NOTABUG", "CLOSED_WONTFIX", - "CLOSED_DEFERRED", "CLOSED_WORKSFORME"]: - self.closed_as_other += 1 - - def __str__(self): - def bug(count): - if count == 1: - return "%d bug" % count - else: - return "%d bugs" % count - - def crash(count): - if count == 1: - return "%d crash" % count - else: - return "%d crashes" % count - - start = "" - bugs_reported = " - %s reported\n" - bugs_closed = " - %s closed\n" - bugs_cl_useful = " - %s (%d%%) as fixed, so ABRT was useful\n" - bugs_cl_notuseful = " - %s (%d%%) as duplicate, can't fix, insuf. data, so ABRT was not useful\n" - bugs_cl_other = " - %s (%d%%) as notabug, wontfix, worksforme\n" - bugs_closed_end = "" - top_crashers = " - top crashers:\n" - top_crasher_item = " # %s: %s\n" - top_crashers_end = "" - end = "" - if options.html: - start = "<ul>\n" - bugs_reported = "<li>%s reported</li>\n" - bugs_closed = "<li>%s closed\n<ul>\n" - bugs_cl_useful = " <li>%s (%d%%) as fixed, so ABRT was useful</li>\n" - bugs_cl_notuseful = " <li>%s (%d%%) as duplicate, can't fix, insuf. data, so ABRT was not useful</li>\n" - bugs_cl_other = " <li>%s (%d%%) as notabug, wontfix, worksforme</li>\n" - bugs_closed_end = "</ul></li>\n" - top_crashers = "<li>top crashers:\n<ol>\n" - top_crasher_item = " <li>%s: %s</li>\n" - top_crashers_end = "</ol></li>\n" - end = "</ul>\n" - elif options.wiki: - start = "" - bugs_reported = "* %s reported\n" - bugs_closed = "* %s closed\n" - bugs_cl_useful = "** %s (%d%%) as fixed, so ABRT was useful\n" - bugs_cl_notuseful = "** %s (%d%%) as duplicate, can't fix, insuf. data, so ABRT was not useful\n" - bugs_cl_other = "** %s (%d%%) as notabug, wontfix, worksforme\n" - bugs_closed_end = "" - top_crashers = "* top crashers:\n" - top_crasher_item = "*# %s: %s\n" - top_crashers_end = "" - end = "" - - - str = start - str += bugs_reported % bug(self.bugs_reported()) - if self.closed() > 0: - str += bugs_closed % bug(self.closed()) - if self.closed_as_useful > 0: - str += bugs_cl_useful % (bug(self.closed_as_useful), self.closed_as_useful_percentage()) - if self.closed_as_waste > 0: - str += bugs_cl_notuseful % (bug(self.closed_as_waste), self.closed_as_waste_percentage()) - if self.closed_as_other > 0: - str += bugs_cl_other % (bug(self.closed_as_other), self.closed_as_other_percentage()) - str += bugs_closed_end - if len(self.top_crashers()) > 0: - str += top_crashers - for (component, num_crashes) in self.top_crashers(): - str += top_crasher_item % (component, crash(num_crashes)) - str += top_crashers_end - str += end - return str - -monthly_stats = {} # key == YEAR-MONTH, value == Month() -weekly_stats = {} # key == YEAR-WEEK, value == Month() - -def get_month(month): - global monthly_stats - if month in monthly_stats: - return monthly_stats[month] - else: - monthly_stats[month] = TimeSpan() - return monthly_stats[month] - -def get_week(week): - global weekly_stats - if week in weekly_stats: - return weekly_stats[week] - else: - weekly_stats[week] = TimeSpan() - return weekly_stats[week] - -for buginfo in buginfos_loaded.values(): - # Bugs reported this month by ABRT - # Top crashers this month - month_key = buginfo['created'][0:7] - month = get_month(month_key) - month.add_component_crash(buginfo['component']) - - # Bugs reported this week by ABRT - # Top crashers this week - week_key = datetime.strptime(buginfo['created'], "%Y-%m-%d").strftime("%Y-%W") - week = get_week(week_key) - week.add_component_crash(buginfo['component']) - - # Bugs closed as useful this month by ABRT - # Bugs closed as waste this month by ABRT - month_key = buginfo['lastchange'][0:7] - month = get_month(month_key) - month.add_resolution(buginfo['status']) - - # Bugs closed as useful this week by ABRT - # Bugs closed as waste this week by ABRT - week_key = datetime.strptime(buginfo['lastchange'], "%Y-%m-%d").strftime("%Y-%W") - week = get_week(week_key) - week.add_resolution(buginfo['status']) - -# -# Print interpreted data -# -print "STATS" -print "==========================================================================" -if not options.weekly: - months = monthly_stats.keys() - months.sort() - if options.reversed: - months.reverse() - for month in months: - m = monthly_stats[month] - if options.html: - print "<h2>Month %s</h2>" % month - elif options.wiki: - print "==Month %s==" % month - else: - print "MONTH %s" % month - print m -else: - weeks = weekly_stats.keys() - weeks.sort() - if options.reversed: - weeks.reverse() - for week in weeks: - w = weekly_stats[week] - if options.html: - print "<h2>Week %s</h2>" % week - elif options.wiki: - print "==Week %s==" % week - else: - print "WEEK %s" % week - print w diff --git a/scripts/check-bt-parsability b/scripts/check-bt-parsability deleted file mode 100755 index b154ad88..00000000 --- a/scripts/check-bt-parsability +++ /dev/null @@ -1,20 +0,0 @@ -#!/bin/bash -# -*- mode: bash -*- - -PASS=0 -FAIL=0 -for file in *.bt -do - #echo "$file" - ./abrt-backtrace $file 1> /dev/null - if [ "$?" -eq "0" ] - then - echo -n "." - PASS=$(($PASS+1)) - else - echo "-$file" - FAIL=$(($FAIL+1)) - fi -done -echo "" -echo "Passed $PASS and failed $FAIL." diff --git a/src/Makefile.am b/src/Makefile.am index c2576c4e..f4f621ca 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -1 +1 @@ -SUBDIRS = hooks daemon applet gui cli utils +SUBDIRS = hooks daemon applet gui cli diff --git a/src/daemon/Makefile.am b/src/daemon/Makefile.am index 2aaf41d4..980268cb 100644 --- a/src/daemon/Makefile.am +++ b/src/daemon/Makefile.am @@ -93,7 +93,8 @@ abrt_action_generate_backtrace_CPPFLAGS = \ -D_GNU_SOURCE \ -Wall -Werror abrt_action_generate_backtrace_LDADD = \ - ../../lib/utils/libABRTUtils.la + ../../lib/utils/libABRTUtils.la \ + ../../btparser/lib/libbtparser.la abrt_action_save_package_data_SOURCES = \ rpm.h rpm.c \ diff --git a/src/daemon/abrt-action-generate-backtrace.c b/src/daemon/abrt-action-generate-backtrace.c index f46ef7d3..d13eccc1 100644 --- a/src/daemon/abrt-action-generate-backtrace.c +++ b/src/daemon/abrt-action-generate-backtrace.c @@ -17,7 +17,9 @@ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #include "abrtlib.h" -#include "backtrace.h" +#include "btparser/lib/backtrace.h" +#include "btparser/lib/frame.h" +#include "btparser/lib/location.h" #include "parse_options.h" @@ -306,97 +308,77 @@ int main(int argc, char **argv) dd_save_text(dd, FILENAME_BACKTRACE, backtrace_str); /* Compute and store backtrace hash. */ - char *backtrace_cpy = xstrdup(backtrace_str); - struct backtrace *backtrace = backtrace_parse(backtrace_cpy, false, false); - free(backtrace_cpy); - if (backtrace) + struct btp_location location; + btp_location_init(&location); + char *backtrace_str_ptr = backtrace_str; + struct btp_backtrace *backtrace = btp_backtrace_parse(&backtrace_str_ptr, &location); + if (!backtrace) { - /* Get the quality of the full backtrace. */ - float q1 = backtrace_quality(backtrace); - - /* Remove all the other threads except the crash thread. */ - struct thread *crash_thread = backtrace_find_crash_thread(backtrace); - if (crash_thread) - backtrace_remove_threads_except_one(backtrace, crash_thread); - else - log_msg("Detection of crash thread failed"); - - /* Get the quality of the crash thread. */ - float q2 = backtrace_quality(backtrace); - - backtrace_remove_noncrash_frames(backtrace); - - /* Do the frame removal now. */ - backtrace_limit_frame_depth(backtrace, 5); - /* Frame removal can be done before removing exit handlers. */ - backtrace_remove_exit_handlers(backtrace); - - /* Get the quality of frames around the crash. */ - float q3 = backtrace_quality(backtrace); - - /* Compute UUID. */ - struct strbuf *bt = backtrace_tree_as_str(backtrace, false); - strbuf_prepend_str(bt, executable); - strbuf_prepend_str(bt, package); + VERB1 log(_("Backtrace parsing failed for %s"), dump_dir_name); + VERB1 log("%d:%d: %s", location.line, location.column, location.message); + /* If the parser failed compute the UUID from the executable + and package only. This is not supposed to happen often. + Do not store the rating, as we do not know how good the + backtrace is. */ + struct strbuf *emptybt = strbuf_new(); + strbuf_prepend_str(emptybt, executable); + strbuf_prepend_str(emptybt, package); char hash_str[SHA1_RESULT_LEN*2 + 1]; - create_hash(hash_str, bt->buf); + create_hash(hash_str, emptybt->buf); dd_save_text(dd, FILENAME_DUPHASH, hash_str); - strbuf_free(bt); - - /* Compute and store backtrace rating. The crash frame - is more important that the others. The frames around - the crash are more important than the rest. */ - float qtot = 0.25f * q1 + 0.35f * q2 + 0.4f * q3; - - /* Turn the quality to rating. */ - const char *rating; - if (qtot < 0.6f) rating = "0"; - else if (qtot < 0.7f) rating = "1"; - else if (qtot < 0.8f) rating = "2"; - else if (qtot < 0.9f) rating = "3"; - else rating = "4"; - dd_save_text(dd, FILENAME_RATING, rating); - - /* Get the function name from the crash frame. */ - if (crash_thread) - { - struct frame *crash_frame = crash_thread->frames; - struct frame *abort_frame = thread_find_abort_frame(crash_thread); - if (abort_frame) - crash_frame = abort_frame->next; - if (crash_frame && crash_frame->function && 0 != strcmp(crash_frame->function, "??")) - dd_save_text(dd, FILENAME_CRASH_FUNCTION, crash_frame->function); - } - backtrace_free(backtrace); - } - else - { - /* If the parser failed fall back to the independent backtrace. */ - /* If we write and use a hand-written parser instead of the bison one, - the parser never fails, and it will be possible to get rid of - the independent_backtrace and backtrace_rate_old. */ - struct strbuf *ibt = independent_backtrace(backtrace_str); - strbuf_prepend_str(ibt, executable); - strbuf_prepend_str(ibt, package); - char hash_str[SHA1_RESULT_LEN*2 + 1]; - create_hash(hash_str, ibt->buf); - dd_save_text(dd, FILENAME_DUPHASH, hash_str); - strbuf_free(ibt); - - /* Compute and store backtrace rating. */ - /* Crash frame is not known so store nothing. */ - int rate = backtrace_rate_old(backtrace_str); - char rate_buf[sizeof(rate)*3 + 2]; - sprintf(rate_buf, "%d", rate); - dd_save_text(dd, FILENAME_RATING, rate_buf); + strbuf_free(emptybt); + free(backtrace_str); + free(package); + free(executable); + dd_close(dd); + return 2; } + free(backtrace_str); + /* Compute UUID. */ + char *str_hash_core = btp_backtrace_get_duplication_hash(backtrace); + struct strbuf *str_hash = strbuf_new(); + strbuf_append_str(str_hash, package); + strbuf_append_str(str_hash, executable); + strbuf_append_str(str_hash, str_hash_core); + char hash_str[SHA1_RESULT_LEN*2 + 1]; + create_hash(hash_str, str_hash->buf); + dd_save_text(dd, FILENAME_GLOBAL_UUID, hash_str); + strbuf_free(str_hash); + free(str_hash_core); + + /* Compute the backtrace rating. */ + float quality = btp_backtrace_quality_complex(backtrace); + const char *rating; + if (quality < 0.6f) + rating = "0"; + else if (quality < 0.7f) + rating = "1"; + else if (quality < 0.8f) + rating = "2"; + else if (quality < 0.9f) + rating = "3"; + else + rating = "4"; + dd_save_text(dd, FILENAME_RATING, rating); + + /* Get the function name from the crash frame. */ + struct btp_frame *crash_frame = btp_backtrace_get_crash_frame(backtrace); + if (crash_frame) + { + if (crash_frame->function_name && + 0 != strcmp(crash_frame->function_name, "??")) + { + dd_save_text(dd, FILENAME_CRASH_FUNCTION, crash_frame->function_name); + } + btp_frame_free(crash_frame); + } + btp_backtrace_free(backtrace); dd_close(dd); free(executable); free(package); - free(backtrace_str); return 0; } diff --git a/src/utils/Makefile.am b/src/utils/Makefile.am deleted file mode 100644 index 29e06645..00000000 --- a/src/utils/Makefile.am +++ /dev/null @@ -1,11 +0,0 @@ -bin_PROGRAMS = abrt-backtrace -abrt_backtrace_CFLAGS = -Wall -abrt_backtrace_SOURCES = abrt-backtrace.c -abrt_backtrace_CPPFLAGS = \ - -I$(srcdir)/../../inc \ - -I$(srcdir)/../../lib/utils -abrt_backtrace_LDADD = \ - ../../lib/utils/libABRTUtils.la - -man_MANS = abrt-backtrace.1 -EXTRA_DIST = $(man_MANS) diff --git a/src/utils/abrt-backtrace.1 b/src/utils/abrt-backtrace.1 deleted file mode 100644 index 4383f1d0..00000000 --- a/src/utils/abrt-backtrace.1 +++ /dev/null @@ -1,59 +0,0 @@ -.TH abrt\-backtrace "1" "23 Nov 2009" "" -.SH NAME -abrt\-backtrace \- a backtrace analyzer for abrt -.SH SYNOPSIS -.B abrt\-backtrace -[option]... [FILE] -.SH DESCRIPTION -.I abrt\-backtrace -is a command line tool that analyzes backtraces produced by -GDB and provides their textual representation useful for -crash duplication detection. - -By default, abrt\-backtrace prints the backtrace tree created by -parsing the input file. - -.SH OPTIONS -.B Basic startup options -.IP "\-V, \-\-version" -Displays version of abrt\-backtrace. -.IP "\-?, \-\-help" -Print a help message describing all of abrt-backtrace’s command-line options. - -.PP -.B Actions -.IP "\-i, \-\-independent" -Prints independent backtrace fallback. The "independent backtrace" -is used as a fallback internal representation of backtrace -when the internal parser fails to process the input due to -unsupported format. - -.PP -.B Various options -.IP "\-n, \-\-single\-thread" -Removes all threads except the one that caused the crash from -the internal representation of the backtrace. -.IP "\-d=N, \-\-frame\-depth=N" -Display only the top N frames in every thread. -Frames that are a part of system error handling do not count to the N. -So more than N frames can be displayed, but N of them are useful for examination. -N must be larger than 1. -.IP "\-r, \-\-remove\-exit\-handlers" -Do not display exit handlers and frames that comes after them in the backtrace. -.IP "\-m, \-\-remove\-noncrash\-frames" -Do not display frames known as not causing the crash, but which are a common -part of backtraces. -.IP "\-a, \-\-rate" -Print backtrace rating from 0 to 4. -.IP "\-c, \-\-crash\-function" -Print crash function if it's successfully detected. -.IP "\-p, \-\-debug\-parser" -Prints debug information when parsing the backtrace. -.IP "\-s, \-\-debug\-scanner" -Prints debug information when scanning the input file for the parser. - -.SH "SEE ALSO" -.IR abrtd (8), -.IR abrt.conf (5), -.IR abrt-cli (1), -.IR abrt-plugins (7) diff --git a/src/utils/abrt-backtrace.c b/src/utils/abrt-backtrace.c deleted file mode 100644 index d02c9633..00000000 --- a/src/utils/abrt-backtrace.c +++ /dev/null @@ -1,339 +0,0 @@ -/* - abrt-backtrace.c - parses command line arguments - - Copyright (C) 2009 RedHat inc. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License along - with this program; if not, write to the Free Software Foundation, Inc., - 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. -*/ -#include <argp.h> -#include <stdlib.h> -#include <sysexits.h> -#include <string.h> -#include "config.h" -#include "backtrace.h" -#include "strbuf.h" - -/* Too large files are trimmed. */ -#define FILE_SIZE_LIMIT 20000000 /* ~ 20 MB */ - -#define EX_PARSINGFAILED EX__MAX + 1 /* = 79 */ -#define EX_THREADDETECTIONFAILED EX__MAX + 2 /* = 80 */ - -const char *argp_program_version = "abrt-backtrace " VERSION; -const char *argp_program_bug_address = "<crash-catcher@lists.fedorahosted.org>"; - -static char doc[] = "abrt-backtrace -- backtrace analyzer"; - -/* A description of the arguments we accept. */ -static char args_doc[] = "FILE"; - -static struct argp_option options[] = { - {"independent" , 'i', 0 , 0, "Prints independent backtrace (fallback)"}, - {"single-thread" , 'n', 0 , 0, "Display the crash thread only in the backtrace"}, - {"frame-depth" , 'd', "N", 0, "Display only top N frames under the crash frame"}, - {"remove-exit-handlers" , 'r', 0 , 0, "Removes exit handler frames from the displayed backtrace"}, - {"remove-noncrash-frames", 'm', 0 , 0, "Removes common frames known as not causing crash"}, - {"rate" , 'a', 0 , 0, "Prints the backtrace rating from 0 to 4"}, - {"crash-function" , 'c', 0 , 0, "Prints crash function"}, - {"debug-parser" , 'p', 0 , 0, "Prints parser debug information"}, - {"debug-scanner" , 's', 0 , 0, "Prints scanner debug information"}, - {"verbose" , 'v', 0 , 0, "Prints human-friendly superfluous output."}, - { 0 } -}; - -struct arguments -{ - bool independent; - bool single_thread; - int frame_depth; /* negative == do not limit the depth */ - bool remove_exit_handlers; - bool remove_noncrash_frames; - bool debug_parser; - bool debug_scanner; - bool verbose; - bool rate; - bool crash_function; - char *filename; -}; - -static error_t -parse_opt (int key, char *arg, struct argp_state *state) -{ - /* Get the input argument from argp_parse, which we - know is a pointer to our arguments structure. */ - struct arguments *arguments = (struct arguments*)state->input; - - switch (key) - { - case 'i': arguments->independent = true; break; - case 'n': arguments->single_thread = true; break; - case 'd': - if (1 != sscanf(arg, "%d", &arguments->frame_depth)) - { - /* Must be a number. */ - argp_usage(state); - exit(EX_USAGE); /* Invalid argument */ - } - break; - case 'r': arguments->remove_exit_handlers = true; break; - case 'm': arguments->remove_noncrash_frames = true; break; - case 'p': arguments->debug_parser = true; break; - case 's': arguments->debug_scanner = true; break; - case 'v': arguments->verbose = true; break; - case 'a': arguments->rate = true; break; - case 'c': arguments->crash_function = true; break; - - case ARGP_KEY_ARG: - if (arguments->filename) - { - /* Too many arguments. */ - argp_usage(state); - exit(EX_USAGE); /* Invalid argument */ - } - arguments->filename = arg; - break; - - case ARGP_KEY_END: - break; - - default: - return ARGP_ERR_UNKNOWN; - } - return 0; -} - -/* Our argp parser. */ -static struct argp argp = { options, parse_opt, args_doc, doc }; - -#define PYTHON_BACKTRACE_ID1 "\n\nTraceback (most recent call last):\n" -#define PYTHON_BACKTRACE_ID2 "\n\nLocal variables in innermost frame:\n" - -int main(int argc, char **argv) -{ - /* Set options default values and parse program command line. */ - struct arguments arguments; - arguments.independent = false; - arguments.frame_depth = -1; - arguments.single_thread = false; - arguments.remove_exit_handlers = false; - arguments.remove_noncrash_frames = false; - arguments.debug_parser = false; - arguments.debug_scanner = false; - arguments.verbose = false; - arguments.filename = 0; - arguments.rate = false; - arguments.crash_function = false; - argp_parse(&argp, argc, argv, 0, 0, &arguments); - - /* If we are about to rate a backtrace, the other values must be set accordingly, - no matter what the user set on the command line. */ - if (arguments.rate) - { - arguments.independent = false; - arguments.frame_depth = 5; - arguments.single_thread = true; - arguments.remove_exit_handlers = true; - arguments.remove_noncrash_frames = true; - } - - /* If we are about to print the crash function, the other values must be set - accordingly. */ - if (arguments.crash_function) - { - arguments.independent = false; - arguments.single_thread = true; - } - - char *bttext = NULL; - - /* If a filename was provided, read input from file. - Otherwise read from stdin. */ - if (arguments.filename) - { - /* Open input file, and parse it. */ - FILE *fp = fopen(arguments.filename, "r"); - if (!fp) - { - fprintf(stderr, "Unable to open '%s'.\n", arguments.filename); - exit(EX_NOINPUT); /* No such file or directory */ - } - - /* Header and footer of the backtrace is stripped to simplify the parser. - * A drawback is that the backtrace must be loaded to memory. - */ - fseek(fp, 0, SEEK_END); - size_t size = ftell(fp); - fseek(fp, 0, SEEK_SET); - - if (size > FILE_SIZE_LIMIT) - { - fprintf(stderr, "Input file too big (%zd). Maximum size is %d.\n", - size, FILE_SIZE_LIMIT); - exit(EX_IOERR); - } - - /* Handle the case that the input file is empty. - * The code is not designed to support completely empty backtrace. - * Silently exit indicating success. - */ - if (size == 0) - { - fclose(fp); - exit(0); - } - - bttext = malloc(size + 1); - if (!bttext) - { - fclose(fp); - fputs("malloc failed", stderr); - exit(EX_OSERR); - } - - if (1 != fread(bttext, size, 1, fp)) - { - fclose(fp); - fprintf(stderr, "Unable to read from '%s'.\n", arguments.filename); - exit(EX_IOERR); /* IO Error */ - } - - bttext[size] = '\0'; - fclose(fp); - } - else - { - struct strbuf *btin = strbuf_new(); - int c; - while ((c = getchar()) != EOF && c != '\0') - strbuf_append_char(btin, (char)c); - - strbuf_append_char(btin, '\0'); - bttext = btin->buf; - strbuf_free_nobuf(btin); /* free btin, but not its internal buffer */ - } - - /* Detect Python backtraces. If it is a Python backtrace, - * silently exit for now. - */ - if (strstr(bttext, PYTHON_BACKTRACE_ID1) != NULL - && strstr(bttext, PYTHON_BACKTRACE_ID2) != NULL) - { - if (arguments.rate) - puts("4"); - exit(0); - } - - /* Print independent backtrace and exit. */ - if (arguments.independent) - { - struct strbuf *ibt = independent_backtrace(bttext); - puts(ibt->buf); - strbuf_free(ibt); - free(bttext); - return 0; /* OK */ - } - - /* Try to parse the backtrace. */ - struct backtrace *backtrace; - backtrace = backtrace_parse(bttext, arguments.debug_parser, arguments.debug_scanner); - - /* If the parser failed print independent backtrace. */ - if (!backtrace) - { - if (arguments.rate) - { - free(bttext); - puts("0"); - /* Parsing failed, but the output can be used. */ - return EX_PARSINGFAILED; - } - struct strbuf *ibt = independent_backtrace(bttext); - puts(ibt->buf); - strbuf_free(ibt); - free(bttext); - /* Parsing failed, but the output can be used. */ - return EX_PARSINGFAILED; - } - - free(bttext); - - /* [--rate] Get the quality of the full backtrace. */ - float q1 = backtrace_quality(backtrace); - - /* If a single thread is requested, remove all other threads. */ - int retval = 0; - struct thread *crash_thread = NULL; - if (arguments.single_thread) - { - crash_thread = backtrace_find_crash_thread(backtrace); - if (crash_thread) - backtrace_remove_threads_except_one(backtrace, crash_thread); - else - { - fprintf(stderr, "Detection of crash thread failed.\n"); - /* THREAD DETECTION FAILED, BUT THE OUTPUT CAN BE USED */ - retval = EX_THREADDETECTIONFAILED; - } - } - - /* [--rate] Get the quality of the crash thread. */ - float q2 = backtrace_quality(backtrace); - - if (arguments.remove_noncrash_frames) - backtrace_remove_noncrash_frames(backtrace); - - /* If a frame removal is requested, do it now. */ - if (arguments.frame_depth > 0) - backtrace_limit_frame_depth(backtrace, arguments.frame_depth); - - /* Frame removal can be done before removing exit handlers */ - if (arguments.remove_exit_handlers > 0) - backtrace_remove_exit_handlers(backtrace); - - /* [--rate] Get the quality of frames around the crash. */ - float q3 = backtrace_quality(backtrace); - - if (arguments.rate) - { - /* Compute and store backtrace rating. */ - /* Compute and store backtrace rating. The crash frame - is more important that the others. The frames around - the crash are more important than the rest. */ - float qtot = 0.25f * q1 + 0.35f * q2 + 0.4f * q3; - - /* Turn the quality to rating. */ - const char *rating; - if (qtot < 0.6f) rating = "0"; - else if (qtot < 0.7f) rating = "1"; - else if (qtot < 0.8f) rating = "2"; - else if (qtot < 0.9f) rating = "3"; - else rating = "4"; - puts(rating); - } - - if (arguments.crash_function && crash_thread) - { - struct frame *crash_frame = crash_thread->frames; - struct frame *abort_frame = thread_find_abort_frame(crash_thread); - if (abort_frame) - crash_frame = abort_frame->next; - if (crash_frame && crash_frame->function) - puts(crash_frame->function); - } - - backtrace_print_tree(backtrace, arguments.verbose); - backtrace_free(backtrace); - return retval; -} |