summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.gitignore5
-rw-r--r--Makefile.am2
-rw-r--r--abrt.spec2
-rw-r--r--btparser/COPYING339
-rw-r--r--btparser/ChangeLog544
-rw-r--r--btparser/Makefile.am38
-rw-r--r--btparser/NEWS120
-rw-r--r--btparser/README38
-rw-r--r--btparser/TODO19
-rwxr-xr-xbtparser/autogen.sh1
-rw-r--r--btparser/btparser.140
-rw-r--r--btparser/btparser.c189
-rw-r--r--btparser/btparser.pc.in10
-rw-r--r--btparser/btparser.spec.in68
-rw-r--r--btparser/configure.ac24
-rw-r--r--btparser/lib/Makefile.am53
-rw-r--r--btparser/lib/backtrace.c445
-rw-r--r--btparser/lib/backtrace.h269
-rw-r--r--btparser/lib/frame.c1027
-rw-r--r--btparser/lib/frame.h470
-rw-r--r--btparser/lib/location.c78
-rw-r--r--btparser/lib/location.h118
-rw-r--r--btparser/lib/normalize.c68
-rw-r--r--btparser/lib/normalize.h74
-rw-r--r--btparser/lib/normalize_dbus.c44
-rw-r--r--btparser/lib/normalize_gdk.c44
-rw-r--r--btparser/lib/normalize_glib.c60
-rw-r--r--btparser/lib/normalize_glibc.c120
-rw-r--r--btparser/lib/normalize_libstdcpp.c46
-rw-r--r--btparser/lib/normalize_linux.c41
-rw-r--r--btparser/lib/normalize_xorg.c46
-rw-r--r--btparser/lib/strbuf.c151
-rw-r--r--btparser/lib/strbuf.h124
-rw-r--r--btparser/lib/thread.c364
-rw-r--r--btparser/lib/thread.h204
-rw-r--r--btparser/lib/utils.c423
-rw-r--r--btparser/lib/utils.h284
-rw-r--r--btparser/tests/Makefile.am60
-rw-r--r--btparser/tests/atlocal.in15
-rw-r--r--btparser/tests/backtrace.at152
-rw-r--r--btparser/tests/backtraces/621492.bt2668
-rw-r--r--btparser/tests/frame.at615
-rw-r--r--btparser/tests/local.at27
-rw-r--r--btparser/tests/package.m413
-rw-r--r--btparser/tests/strbuf.at73
-rw-r--r--btparser/tests/testsuite.at8
-rw-r--r--btparser/tests/thread.at349
-rw-r--r--btparser/tests/utils.at442
-rw-r--r--configure.ac13
-rw-r--r--lib/plugins/CCpp.cpp1
-rw-r--r--lib/plugins/Makefile.am1
-rw-r--r--lib/utils/Makefile.am4
-rw-r--r--lib/utils/backtrace.c846
-rw-r--r--lib/utils/backtrace.h152
-rw-r--r--lib/utils/backtrace_parser.y684
-rwxr-xr-xscripts/abrt-bz-downloader82
-rwxr-xr-xscripts/abrt-bz-dupchecker281
-rwxr-xr-xscripts/abrt-bz-hashchecker59
-rwxr-xr-xscripts/abrt-bz-ratingfixer210
-rwxr-xr-xscripts/abrt-bz-stats313
-rwxr-xr-xscripts/check-bt-parsability20
-rw-r--r--src/Makefile.am2
-rw-r--r--src/daemon/Makefile.am3
-rw-r--r--src/daemon/abrt-action-generate-backtrace.c146
-rw-r--r--src/utils/Makefile.am11
-rw-r--r--src/utils/abrt-backtrace.159
-rw-r--r--src/utils/abrt-backtrace.c339
67 files changed, 10475 insertions, 3165 deletions
diff --git a/.gitignore b/.gitignore
index b621b336..51469091 100644
--- a/.gitignore
+++ b/.gitignore
@@ -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)
diff --git a/abrt.spec b/abrt.spec
index d3a6a42a..4367c233 100644
--- a/abrt.spec
+++ b/abrt.spec
@@ -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;
-}