Revision: 169 http://geany-plugins.svn.sourceforge.net/geany-plugins/?rev=169&view=rev Author: yurand Date: 2008-09-07 20:36:07 +0000 (Sun, 07 Sep 2008)
Log Message: ----------- Added geanydebug plugin
Added Paths: ----------- trunk/geanydebug/ trunk/geanydebug/.gitignore trunk/geanydebug/AUTHORS trunk/geanydebug/COPYING trunk/geanydebug/ChangeLog trunk/geanydebug/INSTALL trunk/geanydebug/Makefile.am trunk/geanydebug/NEWS trunk/geanydebug/README trunk/geanydebug/THANKS trunk/geanydebug/autogen.sh trunk/geanydebug/configure.in trunk/geanydebug/indent-all.sh trunk/geanydebug/makefile.win32 trunk/geanydebug/po/ trunk/geanydebug/po/.gitignore trunk/geanydebug/po/ChangeLog trunk/geanydebug/po/LINGUAS trunk/geanydebug/po/POTFILES.in trunk/geanydebug/po/POTFILES.skip trunk/geanydebug/src/ trunk/geanydebug/src/Makefile.am trunk/geanydebug/src/gdb-io-break.c trunk/geanydebug/src/gdb-io-envir.c trunk/geanydebug/src/gdb-io-frame.c trunk/geanydebug/src/gdb-io-priv.h trunk/geanydebug/src/gdb-io-read.c trunk/geanydebug/src/gdb-io-run.c trunk/geanydebug/src/gdb-io-stack.c trunk/geanydebug/src/gdb-io.h trunk/geanydebug/src/gdb-lex.c trunk/geanydebug/src/gdb-lex.h trunk/geanydebug/src/gdb-ui-break.c trunk/geanydebug/src/gdb-ui-envir.c trunk/geanydebug/src/gdb-ui-frame.c trunk/geanydebug/src/gdb-ui-locn.c trunk/geanydebug/src/gdb-ui-main.c trunk/geanydebug/src/gdb-ui.h trunk/geanydebug/src/geanydebug.c trunk/geanydebug/src/ttyhelper.c trunk/geanydebug/tests/ trunk/geanydebug/tests/Makefile.am trunk/geanydebug/tests/unittests.c
Added: trunk/geanydebug/.gitignore =================================================================== --- trunk/geanydebug/.gitignore (rev 0) +++ trunk/geanydebug/.gitignore 2008-09-07 20:36:07 UTC (rev 169) @@ -0,0 +1,26 @@ +autom4te.cache +Makefile +Makefile.in +aclocal.m4 +config.log +config.status +config.guess +config.sub +config.h +config.h.in +configure +.deps +.libs +*.o +*.la +*.lo +libtool +*.tar.gz +unittests +ltmain.sh +depcomp +install-sh +missing +intltool-* +mkinstalldirs +stamp-h1
Added: trunk/geanydebug/AUTHORS =================================================================== --- trunk/geanydebug/AUTHORS (rev 0) +++ trunk/geanydebug/AUTHORS 2008-09-07 20:36:07 UTC (rev 169) @@ -0,0 +1 @@ +Jeff Pohlmeyer yetanothergeek@gmail.com
Added: trunk/geanydebug/COPYING =================================================================== --- trunk/geanydebug/COPYING (rev 0) +++ trunk/geanydebug/COPYING 2008-09-07 20:36:07 UTC (rev 169) @@ -0,0 +1,340 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 51 Franklin St, 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 Library 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 St, 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 Library General +Public License instead of this License.
Added: trunk/geanydebug/Makefile.am =================================================================== --- trunk/geanydebug/Makefile.am (rev 0) +++ trunk/geanydebug/Makefile.am 2008-09-07 20:36:07 UTC (rev 169) @@ -0,0 +1,22 @@ +SUBDIRS = src po tests + +EXTRA_DIST = \ + autogen.sh \ + makefile.win32 \ + intltool-extract.in \ + intltool-merge.in \ + intltool-update.in \ + indent-all.sh + +DISTCLEANFILES = \ + intltool-extract \ + intltool-merge \ + intltool-update + +.PHONY: ChangeLog mrproper + +ChangeLog: + git log > ChangeLog + +mrproper: + git clean -d -x -f
Added: trunk/geanydebug/NEWS =================================================================== --- trunk/geanydebug/NEWS (rev 0) +++ trunk/geanydebug/NEWS 2008-09-07 20:36:07 UTC (rev 169) @@ -0,0 +1 @@ +See "ChangeLog"
Added: trunk/geanydebug/README =================================================================== --- trunk/geanydebug/README (rev 0) +++ trunk/geanydebug/README 2008-09-07 20:36:07 UTC (rev 169) @@ -0,0 +1,48 @@ + +This is a plugin to provide integrated debugging from Geany using the GNU +debugger (gdb). It was developed and tested on openSUSE-10.3 with GDB-6.7.50. +Other recent versions of GDB will probably work, but operating systems other +than Linux-PC will not work, at least not without some considerable hacking. + +There is no real documentation, but if you hover your mouse over the buttons +in the "Debug" sidebar panel in Geany the tooltips should give you some idea +of what to do next. There are also a few "rough draft" notes below: + +Most of the console output from GDB is sent to the "Compiler" message window +in Geany, and you can send standard commands to GDB using the "Console" entry +on the debug sidebar. This should be used with caution, since GDB's machine +interface and console interface don't always play well together. + +Also note that the plugin sets its own internal breakpoint #1 to grab the +program's PID on startup, so any user-specified breakpoint numbers begin +at #2, and if you manually delete the #1 breakpoint it will likely cause +you some problems. + +Whenever the target program hits a breakpoint or encounters a segfault etc. +it will try to open the appropriate source file and jump to the correct line. + +To examine the state of the program's variables, you can click on the "Stack" +button in the debug sidebar. Note that the interaction between the plugin and +the debugger can sometimes be quite slow, so please be patient when waiting +for the dialogs to open. + +The "Add breakpoint", "Add watchpoint", and "Run to" dialogs will try to +suggest some values based on your current position in whatever file you +have open in Geany, but if you don't like the choice, just click the "Clear" +button and type in whatever you please. + +The plugin tries to enable only the buttons that are relevant to the current +state, but ocassionally it might end up getting things wrong. If this happens, +you should be able to click the "Unload" button and everything will be reset. + +If you try to unload the plugin using the plugin manager while it has a +program loaded, the plugin manager might appear to hang for a few seconds, +while GDB tries to shut down. Again, just be patient, but note that it is +much better use the "Unload" button in the debug sidebar before trying to +disable the plugin. + +There also seems to be some conflict with the GeanyLua plugin, if you have +any ~/.geany/plugins/events/ scripts. ( The GeanyLua author tells me it is +a problem with that plugin, and it will be fixed in the 0.6.2 release. :-) + +
Added: trunk/geanydebug/THANKS =================================================================== --- trunk/geanydebug/THANKS (rev 0) +++ trunk/geanydebug/THANKS 2008-09-07 20:36:07 UTC (rev 169) @@ -0,0 +1,20 @@ +Thanks to: + +Salvador E. Tropea <set(at)users(dot)sf(dot)net> + Author of the libmigdb library. ( This project doesn't use any code from + libmigdb, but his project made me believe such a thing was even possible. ) + + +Enrico Troeger <enrico(dot)troeger(at)uvena(dot)de> + Geany IDE author. + + +Nick Treleaven <nick(dot)treleaven(at)btinternet(dot)com> + Chief architect of the Geany plugin API. + + +Yura Siamashka yurand2(at)gmail(dot)com + Initial autotools scripts ( adapted from the geanyvc plugin. ) + and improvements to INSTALL instructions. + +
Added: trunk/geanydebug/autogen.sh =================================================================== --- trunk/geanydebug/autogen.sh (rev 0) +++ trunk/geanydebug/autogen.sh 2008-09-07 20:36:07 UTC (rev 169) @@ -0,0 +1,165 @@ +#!/bin/sh +# Run this to generate all the initial makefiles, etc. + +srcdir=`dirname $0` +test -z "$srcdir" && srcdir=. + +DIE=0 + +if [ -n "$GNOME2_DIR" ]; then + ACLOCAL_FLAGS="-I $GNOME2_DIR/share/aclocal $ACLOCAL_FLAGS" + LD_LIBRARY_PATH="$GNOME2_DIR/lib:$LD_LIBRARY_PATH" + PATH="$GNOME2_DIR/bin:$PATH" + export PATH + export LD_LIBRARY_PATH +fi + +(test -f $srcdir/configure.in) || { + echo -n "**Error**: Directory "`$srcdir'" does not look like the" + echo " top-level package directory" + exit 1 +} + +(autoconf --version) < /dev/null > /dev/null 2>&1 || { + echo + echo "**Error**: You must have `autoconf' installed." + echo "Download the appropriate package for your distribution," + echo "or get the source tarball at ftp://ftp.gnu.org/pub/gnu/" + DIE=1 +} + +(grep "^AC_PROG_INTLTOOL" $srcdir/configure.in >/dev/null) && { + (intltoolize --version) < /dev/null > /dev/null 2>&1 || { + echo + echo "**Error**: You must have `intltool' installed." + echo "You can get it from:" + echo " ftp://ftp.gnome.org/pub/GNOME/" + DIE=1 + } +} + +(grep "^AM_PROG_XML_I18N_TOOLS" $srcdir/configure.in >/dev/null) && { + (xml-i18n-toolize --version) < /dev/null > /dev/null 2>&1 || { + echo + echo "**Error**: You must have `xml-i18n-toolize' installed." + echo "You can get it from:" + echo " ftp://ftp.gnome.org/pub/GNOME/" + DIE=1 + } +} + +(grep "^AM_PROG_LIBTOOL" $srcdir/configure.in >/dev/null) && { + (libtool --version) < /dev/null > /dev/null 2>&1 || { + echo + echo "**Error**: You must have `libtool' installed." + echo "You can get it from: ftp://ftp.gnu.org/pub/gnu/" + DIE=1 + } +} + +(grep "^AM_GLIB_GNU_GETTEXT" $srcdir/configure.in >/dev/null) && { + (grep "sed.*POTFILES" $srcdir/configure.in) > /dev/null || \ + (glib-gettextize --version) < /dev/null > /dev/null 2>&1 || { + echo + echo "**Error**: You must have `glib' installed." + echo "You can get it from: ftp://ftp.gtk.org/pub/gtk" + DIE=1 + } +} + +(automake --version) < /dev/null > /dev/null 2>&1 || { + echo + echo "**Error**: You must have `automake' installed." + echo "You can get it from: ftp://ftp.gnu.org/pub/gnu/" + DIE=1 + NO_AUTOMAKE=yes +} + + +# if no automake, don't bother testing for aclocal +test -n "$NO_AUTOMAKE" || (aclocal --version) < /dev/null > /dev/null 2>&1 || { + echo + echo "**Error**: Missing `aclocal'. The version of `automake'" + echo "installed doesn't appear recent enough." + echo "You can get automake from ftp://ftp.gnu.org/pub/gnu/" + DIE=1 +} + +if test "$DIE" -eq 1; then + exit 1 +fi + +if test -z "$*"; then + echo "**Warning**: I am going to run `configure' with no arguments." + echo "If you wish to pass any to it, please specify them on the" + echo `$0'" command line." + echo +fi + +case $CC in +xlc ) + am_opt=--include-deps;; +esac + +for coin in `find $srcdir -path $srcdir/CVS -prune -o -name configure.in -print` +do + dr=`dirname $coin` + if test -f $dr/NO-AUTO-GEN; then + echo skipping $dr -- flagged as no auto-gen + else + echo processing $dr + ( cd $dr + + aclocalinclude="$ACLOCAL_FLAGS" + + if grep "^AM_GLIB_GNU_GETTEXT" configure.in >/dev/null; then + echo "Creating $dr/aclocal.m4 ..." + test -r $dr/aclocal.m4 || touch $dr/aclocal.m4 + echo "Running glib-gettextize... Ignore non-fatal messages." + echo "no" | glib-gettextize --force --copy + echo "Making $dr/aclocal.m4 writable ..." + test -r $dr/aclocal.m4 && chmod u+w $dr/aclocal.m4 + fi + if grep "^AC_PROG_INTLTOOL" configure.in >/dev/null; then + echo "Running intltoolize..." + intltoolize --copy --force --automake + fi + if grep "^AM_PROG_XML_I18N_TOOLS" configure.in >/dev/null; then + echo "Running xml-i18n-toolize..." + xml-i18n-toolize --copy --force --automake + fi + if grep "^AM_PROG_LIBTOOL" configure.in >/dev/null; then + if test -z "$NO_LIBTOOLIZE" ; then + echo "Running libtoolize..." + libtoolize --force --copy + fi + fi + if grep "^AC_PROG_LIBTOOL" configure.in >/dev/null; then + if test -z "$NO_LIBTOOLIZE" ; then + echo "Running libtoolize..." + libtoolize --force --copy + fi + fi + echo "Running aclocal $aclocalinclude ..." + aclocal $aclocalinclude + if grep "^AM_CONFIG_HEADER" configure.in >/dev/null; then + echo "Running autoheader..." + autoheader + fi + echo "Running automake --gnu $am_opt ..." + automake --add-missing --gnu $am_opt + echo "Running autoconf ..." + autoconf + ) + fi +done + +conf_flags="--enable-maintainer-mode" + +if test x$NOCONFIGURE = x; then + echo Running $srcdir/configure $conf_flags "$@" ... + $srcdir/configure $conf_flags "$@" \ + && echo Now type `make' to compile. || exit 1 +else + echo Skipping configure process. +fi
Property changes on: trunk/geanydebug/autogen.sh ___________________________________________________________________ Added: svn:executable + *
Added: trunk/geanydebug/configure.in =================================================================== --- trunk/geanydebug/configure.in (rev 0) +++ trunk/geanydebug/configure.in 2008-09-07 20:36:07 UTC (rev 169) @@ -0,0 +1,73 @@ +dnl Process this file with autoconf to produce a configure script. + +AC_INIT([geanydebug], [0.1], [yurand2@gmail.com]) +AM_INIT_AUTOMAKE([1.9 foreign]) + +AM_CONFIG_HEADER(config.h) + +AC_PROG_CC + +AC_DISABLE_STATIC +AM_PROG_LIBTOOL +LIBTOOL="$LIBTOOL --silent" + +AC_PROG_INSTALL +AC_PROG_INTLTOOL + + +# checking for Geany +PKG_CHECK_MODULES(GEANY, [geany >= 0.15]) +AC_SUBST(GTK_CFLAGS) +AC_SUBST(GTK_LIBS) + +GEANY_VERSION=`$PKG_CONFIG --modversion geany` +GTK_VERSION=`$PKG_CONFIG --modversion gtk+-2.0` + + +# i18n +GETTEXT_PACKAGE=geanydebug +AC_SUBST(GETTEXT_PACKAGE) +AC_DEFINE_UNQUOTED(GETTEXT_PACKAGE,"$GETTEXT_PACKAGE", [Gettext package.]) + +ALL_LINGUAS="`sed -e '/^#/d' $srcdir/po/LINGUAS`" # take all languages found in file po/LINGUAS + +AM_GLIB_GNU_GETTEXT +# workaround for intltool bug (http://bugzilla.gnome.org/show_bug.cgi?id=490845) +if test "x$MSGFMT" = "xno"; then + AC_MSG_ERROR([msgfmt not found. Please install the gettext package.]) +fi + +# intltool hack to define install_sh on Debian/Ubuntu systems +if test "x$install_sh" = "x"; then + install_sh="`pwd`/install-sh" + AC_SUBST(install_sh) +fi + +# get the plugin installed at the correct location for Geany +# TODO find a way to NOT override --libdir command line option if given +libdir="`$PKG_CONFIG --variable=libdir geany`/geany" + +dnl unittests +PKG_CHECK_MODULES([CHECK], [check >= 0.9.4], [ +AC_SUBST(CHECK_CFLAGS) +AC_SUBST(CHECK_LIBS) +AM_CONDITIONAL(UNITTESTS, true) +], [ +AM_CONDITIONAL(UNITTESTS, false) +]) + + +AC_OUTPUT([ +Makefile +src/Makefile +tests/Makefile +po/Makefile.in +]) + +echo "----------------------------------------" +echo "Install geanydebug in : ${libdir}" +echo "Using Geany version : ${GEANY_VERSION}" +echo "Using GTK version : ${GTK_VERSION}" +echo "" +echo "Configuration is done OK." +echo ""
Added: trunk/geanydebug/indent-all.sh =================================================================== --- trunk/geanydebug/indent-all.sh (rev 0) +++ trunk/geanydebug/indent-all.sh 2008-09-07 20:36:07 UTC (rev 169) @@ -0,0 +1,4 @@ +#!/bin/sh +indent -bli0 -i8 -cli8 -npcs -l100 src/*.c src/*.h +rm src/*~ +
Property changes on: trunk/geanydebug/indent-all.sh ___________________________________________________________________ Added: svn:executable + *
Added: trunk/geanydebug/makefile.win32 =================================================================== --- trunk/geanydebug/makefile.win32 (rev 0) +++ trunk/geanydebug/makefile.win32 2008-09-07 20:36:07 UTC (rev 169) @@ -0,0 +1,63 @@ +# Running make creates config.h then calls the sub makefiles. +# +# Other targets are: +# deps: delete the dependencies so they are regenerated on next make +# clean: clean all generated files +# +# localwin32.mk is an optional file to override make variables. +# Use localwin32.mk instead of editing variables as it is included in sub +# makefiles. +# localwin32.mk to set PREFIX instead of the default C:\libs +# For MSYS use localwin32.mk to set CP and RM. +# By default this will work in a Windows command prompt. + +CC = gcc +CP = copy +RM = del +PREFIX = C:/libs +GEANY_SRC = ../geany +TARGET = geanydebug.dll +.SUFFIXES: .c .o +-include localwin32.mk + +VPATH = src + +OBJS = insert_object_here.o +INCLUDEDIRS= -I. -I.. \ + -I$(GEANY_SRC) \ + -I$(GEANY_SRC)/src \ + -I$(GEANY_SRC)/plugins \ + -I$(GEANY_SRC)/tagmanager/include \ + -I$(GEANY_SRC)/scintilla/include \ + -I$(PREFIX)/include/gtk-2.0 \ + -I$(PREFIX)/lib/gtk-2.0/include \ + -I$(PREFIX)/include/atk-1.0 \ + -I$(PREFIX)/include/pango-1.0 \ + -I$(PREFIX)/include/cairo \ + -I$(PREFIX)/include/glib-2.0 \ + -I$(PREFIX)/lib/glib-2.0/include \ + -I$(PREFIX)/include/gettext \ + -I$(PREFIX)/include +ALL_GTK_LIBS= \ + -L"$(PREFIX)/lib" \ + -lgtk-win32-2.0 -lgdk-win32-2.0 -latk-1.0 -lgdk_pixbuf-2.0 -lpangowin32-1.0 -lgdi32 \ + -lpango-1.0 -lgobject-2.0 -lgmodule-2.0 -lgthread-2.0 -lglib-2.0 -lintl -liconv +CCFLAGS=-Wall -O2 -mms-bitfields -DHAVE_CONFIG_H + + +all: $(TARGET) + +deps.mak: + $(CC) -MM $(CCFLAGS) $(INCLUDEDIRS) src/*.c >deps.mak + +.c.o: + $(CC) $(CCFLAGS) $(INCLUDEDIRS) -c $< + +$(TARGET): $(OBJS) deps.mak + $(CC) -shared $(OBJS) $(ALL_GTK_LIBS) -o $(TARGET) + +clean: + -$(RM) deps.mak *.o *.dll + +# Generate header dependencies with "make deps.mak" +include deps.mak
Added: trunk/geanydebug/po/.gitignore =================================================================== --- trunk/geanydebug/po/.gitignore (rev 0) +++ trunk/geanydebug/po/.gitignore 2008-09-07 20:36:07 UTC (rev 169) @@ -0,0 +1,7 @@ +Makefile +Makefile.in +Makefile.in.in +POTFILES +*.gmo +*.pot +stamp-it
Added: trunk/geanydebug/po/LINGUAS =================================================================== --- trunk/geanydebug/po/LINGUAS (rev 0) +++ trunk/geanydebug/po/LINGUAS 2008-09-07 20:36:07 UTC (rev 169) @@ -0,0 +1,2 @@ +# set of available languages (in alphabetic order) +
Added: trunk/geanydebug/po/POTFILES.in =================================================================== --- trunk/geanydebug/po/POTFILES.in (rev 0) +++ trunk/geanydebug/po/POTFILES.in 2008-09-07 20:36:07 UTC (rev 169) @@ -0,0 +1,19 @@ +# List of source files containing translatable strings. + +src/gdb-io-break.c +src/gdb-io-envir.c +src/gdb-io-frame.c +src/gdb-io-priv.h +src/gdb-io-read.c +src/gdb-io-run.c +src/gdb-io-stack.c +src/gdb-io.h +src/gdb-lex.c +src/gdb-lex.h +src/gdb-ui-break.c +src/gdb-ui-envir.c +src/gdb-ui-frame.c +src/gdb-ui-locn.c +src/gdb-ui-main.c +src/gdb-ui.h +src/geanydebug.c
Added: trunk/geanydebug/po/POTFILES.skip =================================================================== --- trunk/geanydebug/po/POTFILES.skip (rev 0) +++ trunk/geanydebug/po/POTFILES.skip 2008-09-07 20:36:07 UTC (rev 169) @@ -0,0 +1 @@ +# List of source files containing translatable strings but should be ignored.
Added: trunk/geanydebug/src/Makefile.am =================================================================== --- trunk/geanydebug/src/Makefile.am (rev 0) +++ trunk/geanydebug/src/Makefile.am 2008-09-07 20:36:07 UTC (rev 169) @@ -0,0 +1,28 @@ + +lib_LTLIBRARIES = geanydebug.la +geanydebug_la_SOURCES = gdb-io-break.c \ + gdb-io-envir.c \ + gdb-io-frame.c \ + gdb-io-priv.h \ + gdb-io-read.c \ + gdb-io-run.c \ + gdb-io-stack.c \ + gdb-io.h \ + gdb-lex.c \ + gdb-lex.h \ + gdb-ui-break.c \ + gdb-ui-envir.c \ + gdb-ui-frame.c \ + gdb-ui-locn.c \ + gdb-ui-main.c \ + gdb-ui.h \ + geanydebug.c + +geanydebug_la_LDFLAGS = -module -avoid-version +geanydebug_la_LIBADD = @GEANY_LIBS@ $(INTLLIBS) + +bin_PROGRAMS = ttyhelper +ttyhelper_SOURCES = ttyhelper.c + +AM_CFLAGS = @GEANY_CFLAGS@ -DLOCALEDIR=""$(localedir)"" +
Added: trunk/geanydebug/src/gdb-io-break.c =================================================================== --- trunk/geanydebug/src/gdb-io-break.c (rev 0) +++ trunk/geanydebug/src/gdb-io-break.c 2008-09-07 20:36:07 UTC (rev 169) @@ -0,0 +1,312 @@ + +/* + * gdb-io-break.c - Breakpoint management functions for GDB wrapper library. + * + * See the file "gdb-io.h" for license information. + * + */ + + +#include <string.h> +#include <glib.h> +#include "gdb-io-priv.h" + + +static GdbListFunc gdbio_break_list_func = NULL; + +static GSList *breakpoint_list = NULL; + + +static void +free_breakpoint_list() +{ + GSList *p; + for (p = breakpoint_list; p; p = p->next) + { + GdbBreakPointInfo *bpi = p->data; + if (bpi) + { + g_free(bpi->addr); + g_free(bpi->disp); + g_free(bpi->enabled); + g_free(bpi->file); + g_free(bpi->fullname); + g_free(bpi->func); + g_free(bpi->line); + g_free(bpi->number); + g_free(bpi->times); + g_free(bpi->type); + g_free(bpi->what); + g_free(bpi->cond); + g_free(bpi->ignore); + g_free(bpi); + } + } + g_slist_free(breakpoint_list); + breakpoint_list = NULL; +} + + + +#define populate(rec, hash, key) \ + rec->key=gdblx_lookup_string(hash, #key""); \ + if (rec->key) {rec->key=g_strdup(rec->key);} + + + +static void +breakpoint_cb(gpointer data, gpointer user_data) +{ + GdbLxValue *v = (GdbLxValue *) data; + if (v && (v->type == vt_HASH) && (v->hash)) + { + GHashTable *bkpt = v->hash; + if (bkpt) + { + GdbBreakPointInfo *bpi = g_new0(GdbBreakPointInfo, 1); + populate(bpi, bkpt, addr); + populate(bpi, bkpt, disp); + populate(bpi, bkpt, enabled); + populate(bpi, bkpt, file); + populate(bpi, bkpt, fullname); + populate(bpi, bkpt, func); + populate(bpi, bkpt, line); + populate(bpi, bkpt, number); + populate(bpi, bkpt, times); + populate(bpi, bkpt, type); + populate(bpi, bkpt, what); + populate(bpi, bkpt, cond); + populate(bpi, bkpt, ignore); + breakpoint_list = g_slist_append(breakpoint_list, bpi); + } + } +} + + +static void +parse_break_list(gint seq, gchar ** list, gchar * resp) +{ + GHashTable *h = gdbio_get_results(resp, list); + HTAB(h, BreakpointTable); + gdbio_pop_seq(seq); + if (BreakpointTable && gdbio_break_list_func) + { + HLST(BreakpointTable, body); + if (body) + { + free_breakpoint_list(); + g_slist_foreach(body, breakpoint_cb, NULL); + gdbio_break_list_func(breakpoint_list); + free_breakpoint_list(); + } + else + { + gdbio_break_list_func(NULL); + } + } + if (h) + g_hash_table_destroy(h); +} + + + +void +gdbio_show_breaks(GdbListFunc func) +{ + gdbio_break_list_func = func; + if (func) + { + gdbio_send_seq_cmd(parse_break_list, "-break-list\n"); + } +} + + + +static void +added_break(gint seq, gchar ** list, gchar * resp) +{ + GHashTable *h = gdbio_get_results(resp, list); + gdbio_pop_seq(seq); + if (h) + { + HTAB(h, bkpt); + if (bkpt) + { + HSTR(bkpt, file); + HSTR(bkpt, line); + HSTR(bkpt, func); + HSTR(bkpt, number); + if (func) + { + gdbio_info_func("Added breakpoint #%s in %s() at %s:%s\n", number, + func, file, line); + } + else + { + gdbio_info_func("Added breakpoint #%s at %s:%s\n", number, file, + line); + } + + } + else + { + HTAB(h, wpt); + if (wpt) + { + HSTR(wpt, exp); + HSTR(wpt, number); + gdbio_info_func("Added write watchpoint #%s for %s\n", number, exp); + } + else + { + HTAB(h, hw_awpt); + if (hw_awpt) + { + HSTR(hw_awpt, exp); + HSTR(hw_awpt, number); + gdbio_info_func("Added read/write watchpoint #%s for %s\n", + number, exp); + } + else + { + HTAB(h, hw_rwpt); + if (hw_rwpt) + { + HSTR(hw_rwpt, exp); + HSTR(hw_rwpt, number); + gdbio_info_func + ("Added read watchpoint #%s for %s\n", + number, exp); + } + } + } + } + g_hash_table_destroy(h); + } + if (gdbio_break_list_func) + { + gdbio_show_breaks(gdbio_break_list_func); + } +} + +/* opt is "-r" (read) or "-a" (r/w) or NULL or empty (write) */ +void +gdbio_add_watch(GdbListFunc func, const gchar * option, const gchar * varname) +{ + gdbio_break_list_func = func; + gdbio_send_seq_cmd(added_break, "-break-watch %s %s\n", option ? option : "", varname); +} + + + +void +gdbio_add_break(GdbListFunc func, const gchar * filename, const gchar * locn) +{ + gdbio_break_list_func = func; + if (filename && *filename) + { + gdbio_send_seq_cmd(added_break, "-break-insert %s:%s\n", filename, locn); + } + else + { + gdbio_send_seq_cmd(added_break, "-break-insert %s\n", locn); + } +} + + +static void +deleted_break(gint seq, gchar ** list, gchar * resp) +{ + GHashTable *h = gdbio_get_results(resp, list); + gdbio_pop_seq(seq); + if (h) + { + g_hash_table_destroy(h); + gdbio_info_func("Watch/breakpoint deleted.\n"); + } + if (gdbio_break_list_func) + { + gdbio_show_breaks(gdbio_break_list_func); + } +} + + + +static void +toggled_break(gint seq, gchar ** list, gchar * resp) +{ + gdbio_pop_seq(seq); + if (strncmp(resp, "^error", 6) == 0) + { + if (resp[6] == ',') + { + GHashTable *h = gdblx_parse_results(resp + 7); + HSTR(h, msg); + + if (msg) + { + gchar *tmp = + g_strconcat("Failed to toggle breakpoint -\n", msg, NULL); + gdbio_error_func(tmp); + if (tmp) + { + g_free(tmp); + } + } + else + { + } + if (h) + { + g_hash_table_destroy(h); + } + } + } + else + { + gdbio_info_func("Watch/breakpoint toggled.\n"); + } +} + + + +static void +edited_break(gint seq, gchar ** list, gchar * resp) +{ + GHashTable *h = gdbio_get_results(resp, list); + gdbio_pop_seq(seq); + if (h) + { + g_hash_table_destroy(h); + gdbio_info_func("Watch/breakpoint modified.\n"); + } +} + + +void +gdbio_delete_break(GdbListFunc func, const gchar * number) +{ + gdbio_break_list_func = func; + gdbio_send_seq_cmd(deleted_break, "-break-delete %s\n", number); +} + + +void +gdbio_enable_break(const gchar * number, gboolean enabled) +{ + gdbio_send_seq_cmd(toggled_break, "-break-%s %s\n", enabled ? "enable" : "disable", number); +} + + +void +gdbio_ignore_break(const gchar * number, const gchar * times) +{ + gdbio_send_seq_cmd(edited_break, "-break-after %s %s\n", number, times); +} + + +void +gdbio_break_cond(const gchar * number, const gchar * expr) +{ + gdbio_send_seq_cmd(edited_break, "-break-condition %s %s\n", number, expr); +}
Added: trunk/geanydebug/src/gdb-io-envir.c =================================================================== --- trunk/geanydebug/src/gdb-io-envir.c (rev 0) +++ trunk/geanydebug/src/gdb-io-envir.c 2008-09-07 20:36:07 UTC (rev 169) @@ -0,0 +1,182 @@ + +/* + * gdb-io-envir.c - Environment settings for GDB wrapper library. + * + * See the file "gdb-io.h" for license information. + * + */ + + +#include <string.h> +#include <glib.h> +#include "gdb-io-priv.h" + + +static GdbEnvironFunc gdbio_environ_func = NULL; + +static GdbEnvironInfo env_info = { NULL, NULL, NULL, NULL }; + + +static void +free_env_info() +{ + g_free(env_info.cwd); + g_free(env_info.path); + g_free(env_info.args); + g_free(env_info.dirs); + memset(&env_info, '\0', sizeof(env_info)); +} + + + +static gchar * +unquote(gchar * quoted) +{ + gint len = quoted ? strlen(quoted) : 0; + if (len && (quoted[0] == '"') && (quoted[len - 1] == '"')) + { + gchar *tmp = g_strndup(quoted + 1, len - 2); + gchar *rv = g_strcompress(tmp); + g_free(tmp); + return rv; + } + else + return NULL; +} + + + +static void +get_env_args(gint seq, gchar ** list, gchar * resp) +{ + gchar *args; + gint i; + gdbio_pop_seq(seq); + for (i = 0; list[i]; i++) + { + if (strncmp(list[i], "~"", 2) == 0) + { + args = unquote(list[i] + 1); + if (args && *args) + { + g_strstrip(args); + gchar *quote = strchr(args, '"'); + if (quote) + { + memmove(args, quote + 1, strlen(quote)); + quote = strrchr(args, '"'); + if (quote && g_str_equal(quote, "".")) + { + *quote = '\0'; + break; + } + } + } + g_free(args); + args = NULL; + } + } + env_info.args = args; + if (gdbio_environ_func) + { + gdbio_environ_func(&env_info); + } +} + + + +static void +get_env_dirs(gint seq, gchar ** list, gchar * resp) +{ + GHashTable *h = gdbio_get_results(resp, list); + HSTR(h, source_path); + gdbio_pop_seq(seq); + if (source_path) + { + gchar *p; + env_info.dirs = g_strdup(source_path); + p = strstr(env_info.dirs, "$cdir:$cwd"); + if (p) + { + memmove(p, p + 10, strlen(p + 10) + 1); + } + p = strchr(env_info.dirs, '\0'); + if (p) + { + while (p > env_info.dirs) + { + p--; + if (*p == ':') + { + *p = '\0'; + } + else + { + break; + } + } + } + } + else + { + gdbio_info_func("Failed to retrieve source search path setting from GDB."); +// gdblx_dump_table(h); + } + if (h) + g_hash_table_destroy(h); + gdbio_send_seq_cmd(get_env_args, "show args\n"); +} + + +static void +get_env_path(gint seq, gchar ** list, gchar * resp) +{ + GHashTable *h = gdbio_get_results(resp, list); + HSTR(h, path); + gdbio_pop_seq(seq); + if (path) + { + env_info.path = g_strdup(path); + } + else + { + gdbio_info_func("Failed to retrieve executable search path setting from GDB."); +// gdblx_dump_table(h); + } + if (h) + g_hash_table_destroy(h); + gdbio_send_seq_cmd(get_env_dirs, "-environment-directory\n"); +} + + +static void +get_env_cwd(gint seq, gchar ** list, gchar * resp) +{ + GHashTable *h = gdbio_get_results(resp, list); + HSTR(h, cwd); + gdbio_pop_seq(seq); + free_env_info(); + if (cwd) + { + env_info.cwd = g_strdup(cwd); + } + else + { + gdbio_info_func("Failed to retrieve working directory setting from GDB."); +// gdblx_dump_table(h); + } + if (h) + g_hash_table_destroy(h); + gdbio_send_seq_cmd(get_env_path, "-environment-path\n"); +} + + +void +gdbio_get_env(GdbEnvironFunc func) +{ + gdbio_environ_func = func; + if (func) + { + gdbio_send_seq_cmd(get_env_cwd, "-environment-pwd\n"); + } +}
Added: trunk/geanydebug/src/gdb-io-frame.c =================================================================== --- trunk/geanydebug/src/gdb-io-frame.c (rev 0) +++ trunk/geanydebug/src/gdb-io-frame.c 2008-09-07 20:36:07 UTC (rev 169) @@ -0,0 +1,542 @@ + +/* + * gdb-io-frame.c - Stack frame information functions for GDB wrapper library. + * + * See the file "gdb-io.h" for license information. + * + */ + + +#include <string.h> +#include <glib.h> + +#include "gdb-io-priv.h" + + +static GdbFrameFunc gdbio_locals_func = NULL; + +static GSList *locals_list = NULL; +static GSList **which_list = NULL; + +static gint locals_index = 0; +static gint args_index = 0; +static gint *which_index = NULL; + +static void var_created(gint seq, gchar ** list, gchar * resp); +static void got_varlist(gint seq, gchar ** list, gchar * resp); + +typedef enum _FrameProcState +{ + fpBegin, + fpGotLocals, + fpGotArgs +} FrameProcState; + + +static FrameProcState state = fpBegin; +static GdbFrameInfo current_frame; + + + +static void +gdbio_free_var(GdbVar * v) +{ + if (v) + { + g_free(v->type); + g_free(v->name); + g_free(v->value); + g_free(v->numchild); + g_free(v); + } +} + + +void +gdbio_free_var_list(GSList * args) +{ + GSList *p; + for (p = args; p; p = p->next) + { + gdbio_free_var((GdbVar *) p->data); + } + g_slist_free(args); +} + + + +static void +free_lists() +{ + gdbio_free_var_list(locals_list); + locals_list = NULL; + locals_index = 0; + args_index = 0; + which_list = &locals_list; + which_index = &locals_index; + state = fpBegin; + g_free(current_frame.func); + g_free(current_frame.filename); + gdbio_free_var_list(current_frame.args); + memset(¤t_frame, 0, sizeof(current_frame)); +} + +static void +get_arglist() +{ + which_list = ¤t_frame.args; + which_index = &args_index; + gdbio_send_seq_cmd(got_varlist, "-stack-list-arguments 1 %s %s\n", + current_frame.level, current_frame.level); +} + + +static void +create_var(gchar * varname) +{ + gdbio_send_seq_cmd(var_created, "-var-create x%s * %s\n", varname, varname); +} + + +static void +var_deleted(gint seq, gchar ** list, gchar * resp) +{ + gdbio_pop_seq(seq); + (*which_index)++; + GdbVar *lv = g_slist_nth_data(*which_list, *which_index); + if (lv) + { + create_var(lv->name); + } + else + { + if (state == fpBegin) + { + state = fpGotLocals; + get_arglist(); + } + else + { + if (gdbio_locals_func) + { + gdbio_locals_func(¤t_frame, locals_list); + } + free_lists(); + } + } +} + + + +static void +delete_var(gchar * varname) +{ + gdbio_send_seq_cmd(var_deleted, "-var-delete x%s\n", varname); +} + + + +static gchar * +fmt_val(gchar * value) +{ + gchar buf[256]; + if (!value) + return g_strdup("0"); + if (strlen(value) < sizeof(buf)) + { + return g_strdup(value); + } + strncpy(buf, value, sizeof(buf) - 1); + buf[sizeof(buf) - 1] = '\0'; + return g_strdup_printf("%s...%s", buf, strchr(buf, '"') ? """ : ""); +} + + + +static void +var_created(gint seq, gchar ** list, gchar * resp) +{ + GHashTable *h = gdbio_get_results(resp, list); + HSTR(h, type); + HSTR(h, value); + HSTR(h, numchild); + gdbio_pop_seq(seq); + if (type) + { + GdbVar *lv = g_slist_nth_data(*which_list, *which_index); + if (lv) + { + lv->type = g_strdup(type ? type : "int"); + lv->value = fmt_val(value); + lv->numchild = g_strdup(numchild ? numchild : "0"); + } + delete_var(lv->name); + } + if (h) + g_hash_table_destroy(h); +} + + + +void +got_varlist(gint seq, gchar ** list, gchar * resp) +{ + GHashTable *h = gdbio_get_results(resp, list); + GSList *hlist = NULL; + HLST(h, locals); + HLST(h, stack_args); + gdbio_pop_seq(seq); + if (state == fpBegin) + { + hlist = locals; + } + else + { + GdbLxValue *v = stack_args->data; + if (v && (v->type == vt_HASH)) + { + HLST(v->hash, args); + if (args) + { + hlist = args; + } + } + } + if (hlist) + { + GSList *p; + GdbVar *lv; + for (p = hlist; p; p = p->next) + { + GdbLxValue *v = p->data; + if (v && (v->type == vt_HASH) && v->hash) + { + HSTR(v->hash, name); + if (name) + { + GdbVar *lv = g_new0(GdbVar, 1); + lv->name = g_strdup(name); + *which_list = g_slist_append(*which_list, lv); + } + } + } + lv = g_slist_nth_data(*which_list, *which_index); + if (lv) + { + create_var(lv->name); + } + } + else + { + if (state == fpBegin) + { + state = fpGotLocals; + get_arglist(); + } + else + { + if (gdbio_locals_func) + { + gdbio_locals_func(¤t_frame, locals_list); + } + } + } + if (h) + g_hash_table_destroy(h); +} + + + + + +static void +got_current_level(gint seq, gchar ** list, gchar * resp) +{ + GHashTable *h = gdbio_get_results(resp, list); + HTAB(h, frame); + gdbio_pop_seq(seq); + if (frame) + { + HSTR(frame, level); + if (level) + { + HSTR(frame, addr); + HSTR(frame, func); + HSTR(frame, file); + HSTR(frame, fullname); + HSTR(frame, line); + strncpy(current_frame.level, level, sizeof(current_frame.level) - 1); + strncpy(current_frame.addr, addr ? addr : "", + sizeof(current_frame.addr) - 1); + strncpy(current_frame.line, line ? line : "", + sizeof(current_frame.line) - 1); + current_frame.filename = g_strdup(fullname ? fullname : file ? file : ""); + current_frame.func = g_strdup(func ? func : ""); + } + } + if (h) + g_hash_table_destroy(h); + gdbio_send_seq_cmd(got_varlist, "-stack-list-locals 1\n"); +} + + +static void +set_current_level(gint seq, gchar ** list, gchar * resp) +{ + gdbio_pop_seq(seq); + gdbio_send_seq_cmd(got_current_level, "-stack-info-frame\n"); +} + +void +gdbio_show_locals(GdbFrameFunc func, gchar * level) +{ + free_lists(); + gdbio_locals_func = func; + gdbio_send_seq_cmd(set_current_level, "-stack-select-frame %s\n", level); +} + + + + +static gpointer +qpop(GQueue ** q) +{ + gpointer p = NULL; + if (*q) + { + p = g_queue_pop_head(*q); + if (g_queue_get_length(*q) == 0) + { + g_queue_free(*q); + *q = NULL; + } + } + return p; +} + +static void +qpush(GQueue ** q, gpointer p) +{ + if (p) + { + if (!*q) + { + *q = g_queue_new(); + } + g_queue_push_head(*q, p); + } +} + +static gpointer +qtop(GQueue * q) +{ + return q ? g_queue_peek_head(q) : NULL; +} + + + +/* +static gpointer qnth(GQueue*q, gint n) +{ + return q?g_queue_peek_nth(q, n):NULL; +} + +static gint qlen(GQueue*q) +{ + return q?g_queue_get_length(q):0; +} +*/ + + +static GQueue *obj_list_queue = NULL; +static void +push_list(GSList * p) +{ + qpush(&obj_list_queue, p); +} +static void +pop_list() +{ + gdbio_free_var_list(qpop(&obj_list_queue)); +} +static GSList * +top_list() +{ + return qtop(obj_list_queue); +} + + +static GQueue *obj_var_queue = NULL; +static void +push_var(GdbVar * p) +{ + qpush(&obj_var_queue, p); +} +static void +pop_var() +{ + gdbio_free_var(qpop(&obj_var_queue)); +} +static GdbVar * +top_var() +{ + return qtop(obj_var_queue); +} + + + + +//static GdbObjectFunc gdbio_object_list_func=NULL; + +static GQueue *obj_func_queue = NULL; +static void +push_func(GdbObjectFunc p) +{ + qpush(&obj_func_queue, p); +} +static void +pop_func() +{ + qpop(&obj_func_queue); +} +static GdbObjectFunc +top_func() +{ + return qtop(obj_func_queue); +} + + + + +static void +done_top() +{ + pop_var(); + pop_list(); +// pop_name(); + pop_func(); +} + + + +static void +object_deleted(gint seq, gchar ** list, gchar * resp) +{ + GHashTable *h = gdbio_get_results(resp, list); + gdbio_pop_seq(seq); + if (h) + { + if (top_func() && top_var() && top_list()) + { + top_func()(top_var(), top_list()); + } + done_top(); + g_hash_table_destroy(h); + } +} + + + +static GdbVar * +hash_val_to_var(GHashTable * h) +{ + HSTR(h, name); + if (name) + { + GdbVar *var = g_new0(GdbVar, 1); + HSTR(h, type); + HSTR(h, value); + HSTR(h, numchild); + var->name = g_strdup(name + 1); + var->type = g_strdup(type ? type : "int"); + var->value = fmt_val(value); + var->numchild = g_strdup(numchild ? numchild : "0"); + return var; + } + return NULL; +} + + +#define MAX_ITEMS 1024 + +static GSList * +hash_list_to_var_list(GSList * hlist) +{ + GSList *vlist = NULL; + GSList *p; + gint i; + for (p = hlist, i = 0; p; p = p->next, i++) + { + GdbLxValue *hv = p->data; + if (hv && (hv->type == vt_HASH) && hv->hash) + { + GdbVar *var = hash_val_to_var(hv->hash); + if (var) + { + vlist = g_slist_append(vlist, var); + } + } + if (i >= MAX_ITEMS) + { + GdbVar *var = g_new0(GdbVar, 1); + var->type = g_strdup(" "); + var->name = g_strdup_printf("* LIST TRUNCATED AT ITEM #%d *", i + 1); + var->value = g_strdup(" "); + var->numchild = g_strdup("0"); + vlist = g_slist_append(vlist, var); + gdbio_error_func("Field list too long, not all items can be displayed.\n"); + break; + } + } + return vlist; +} + + + +static void +object_listed(gint seq, gchar ** list, gchar * resp) +{ + GHashTable *h = gdbio_get_results(resp, list); + gdbio_pop_seq(seq); + if (h) + { + HLST(h, children); + if (children) + { + push_list(hash_list_to_var_list(children)); + } + gdbio_send_seq_cmd(object_deleted, "-var-delete x%s\n", top_var()->name); + g_hash_table_destroy(h); + } +} + + + +static void +object_created(gint seq, gchar ** list, gchar * resp) +{ + GHashTable *h = gdbio_get_results(resp, list); + gdbio_pop_seq(seq); + if (h) + { + HSTR(h, name); + if (name) + { + push_var(hash_val_to_var(h)); + gdbio_send_seq_cmd(object_listed, "-var-list-children 1 %s\n", name); + } + g_hash_table_destroy(h); + } +} + + +void +gdbio_show_object(GdbObjectFunc func, const gchar * varname) +{ + + if (func) + { + push_func(func); + gdbio_send_seq_cmd(object_created, "-var-create x%s * %s\n", varname, varname); + } +}
Added: trunk/geanydebug/src/gdb-io-priv.h =================================================================== --- trunk/geanydebug/src/gdb-io-priv.h (rev 0) +++ trunk/geanydebug/src/gdb-io-priv.h 2008-09-07 20:36:07 UTC (rev 169) @@ -0,0 +1,95 @@ + +/* + * gdb-io-priv.h - private header for GDB wrapper library. + * + * See the file "gdb-io.h" for license information. + * + */ + + +#include "gdb-lex.h" +#include "gdb-io.h" + + +void gdbio_free_var_list(GSList * args); + + +typedef void (*ResponseHandler) (gint seq, gchar ** lines, gchar * resp); + + +/* + Sends a command to GDB, and returns the results to the specified + ResponseHandler function. +*/ +gint gdbio_send_seq_cmd(ResponseHandler func, const gchar * fmt, ...); + + +/* Look up a handler function */ +ResponseHandler gdbio_seq_lookup(gint seq); + + +/* + gdbio_pop_seq() removes a handler function from the sequencer. + This should (almost) always be called from the associated + ResponseHandler function, to avoid filling up the sequencer + with stale commands. +*/ +void gdbio_pop_seq(gint seq); + + +/* + Parses the output of GDB and returns it as a hash table, + unless the response is an error message, it calls the + error handler function and then returns NULL. +*/ +GHashTable *gdbio_get_results(gchar * resp, gchar ** list); + +/* +Preprocessor sugar for declaring C variables from hash key names, e.g. + HSTR(myhash,somevar) +expands to: + gchar *somevar = gdblx_lookup_string ( myhash, "somevar" ); +*/ +#define HSTR(hash,token) gchar* token = gdblx_lookup_string(hash, #token""); +#define HTAB(hash,token) GHashTable* token = gdblx_lookup_hash(hash, #token""); +#define HLST(hash,token) GSList* token = gdblx_lookup_list(hash, #token""); + + +#if 0 +#define do_loop() \ + while (g_main_context_pending(NULL)) \ + g_main_context_iteration(NULL,FALSE); +#else +#define do_loop() g_main_context_iteration(NULL,FALSE); +#endif + + + + +void gdbio_info_func(gchar * fmt, ...); +void gdbio_error_func(gchar * fmt, ...); +void gdbio_do_status(GdbStatus s); + + +void gdbio_target_exited(gchar * reason); +void gdbio_set_target_pid(GPid pid); +GPid gdbio_get_target_pid(); +void gdbio_set_running(gboolean running); + +/* + Max/Min values for sequencer tokens. +The current values of 100000-999999 allow for 899999 pending commands. +I can't imagine why you would need more, but if you change this,keep in mind +that the number of digits for any possible value *must* be exactly SEQ_LEN. +*/ + +#define SEQ_MIN 100000 +#define SEQ_MAX 999999 +#define SEQ_LEN 6 + + + +void gdbio_consume_response(GString * recv_buf); + +void gdbio_set_starting(gboolean s); +void gdbio_target_started(gint seq, gchar ** list, gchar * resp);
Added: trunk/geanydebug/src/gdb-io-read.c =================================================================== --- trunk/geanydebug/src/gdb-io-read.c (rev 0) +++ trunk/geanydebug/src/gdb-io-read.c 2008-09-07 20:36:07 UTC (rev 169) @@ -0,0 +1,810 @@ +/* + * + * gdb-io-read.c - Output reading functions for GDB wrapper library. + * + * See the file "gdb-io.h" for license information. + */ + + +#include <stdlib.h> +#include <sys/time.h> + +#include <string.h> +#include <unistd.h> +#include <stdarg.h> +#include <glib.h> + +#include "gdb-io-priv.h" + + + +static GSList *source_files = NULL; + +static gboolean starting = FALSE; + + + +static void +free_string_list(GSList ** list) +{ + GSList *p; + for (p = *list; p; p = p->next) + { + if (p->data) + { + g_free(p->data); + } + } + *list = NULL; +} + + +static void +free_source_list() +{ + free_string_list(&source_files); +} + + + +static gint +find_file_and_fullname(gconstpointer data, gconstpointer user_data) +{ + GdbLxValue *v = (GdbLxValue *) data; + gchar *ref = (gchar *) user_data; + HSTR(v->hash, fullname); + HSTR(v->hash, file); + return (fullname && file + && (g_str_equal(ref, file) || g_str_equal(ref, fullname))) ? 0 : -1; +} + + + +static void +parse_file_list_cb(gpointer data, gpointer user_data) +{ + GdbLxValue *v = (GdbLxValue *) data; + if (v && (v->type == vt_HASH)) + { + HSTR(v->hash, fullname); + HSTR(v->hash, file); + if (file && !fullname) + { + if (g_slist_find_custom((GSList *) user_data, file, find_file_and_fullname)) + { + return; + } + } + if (fullname) + { + file = fullname; + } + if (file) + { + if (!g_slist_find_custom(source_files, file, (GCompareFunc) strcmp)) + { + source_files = g_slist_append(source_files, g_strdup(file)); + } + } + } +} + + + +static void handle_response_line(gchar * str, gchar ** list); + + +static void +handle_response_lines(gchar ** list) +{ + if (list) + { + gint i; + for (i = 0; list[i]; i++) + { + handle_response_line(list[i], list); + } + } +} + + + +static gboolean +response_is_error(gchar * resp, gchar ** list) +{ + if (strncmp(resp, "^error", 6) == 0) + { + handle_response_line(resp, list); + return TRUE; + } + else + { + return FALSE; + } +} + +#define CHK_RESP_ERR(resp, list) if (response_is_error(resp,list)) { return; } + +#define IsDigit g_ascii_isdigit + +static void +parse_process_info(gint seq, gchar ** list, gchar * resp) +{ + CHK_RESP_ERR(resp, list); + gdbio_pop_seq(seq); + if (g_str_equal(resp, "^done")) + { + gchar *pidstr = strchr(list[0], ' '); + if (pidstr) + { + GPid pid = -1; + while (g_ascii_isspace(*pidstr)) + { + pidstr++; + } + if (IsDigit(*pidstr)) + { + gchar *end = pidstr; + while (IsDigit(*end)) + { + end++; + } + *end = '\0'; + pid = gdbio_atoi(pidstr); + if ((pid > 0) && (!gdbio_get_target_pid())) + { + gdbio_set_target_pid(pid); + gdbio_send_cmd("-exec-continue\n"); + } + } + } + } +} + + +GHashTable * +gdbio_get_results(gchar * resp, gchar ** list) +{ + if (strncmp(resp, "^error", 6) == 0) + { + if (resp[6] == ',') + { + GHashTable *h = gdblx_parse_results(resp + 7); + HSTR(h, msg); + gchar *tmp = NULL; + if (msg) + { + if (g_str_equal(msg, "unknown error")) + { + gint len = g_strv_length(list); + if ((len > 1) && list[len - 2] && *list[len - 2]) + { + tmp = list[len - 2]; + if (tmp[0] == '&') + { + tmp++; + } + tmp = g_strcompress(tmp); + g_strstrip(tmp); + msg = tmp; + } + } + gdbio_error_func(msg); + if (tmp) + { + g_free(tmp); + } + } + if (h) + { + g_hash_table_destroy(h); + } + } + return NULL; + } + if (strncmp(resp, "^done,", 6) == 0) + return gdblx_parse_results(resp + 6); + if (strncmp(resp, "*stopped,", 9) == 0) + { + gdbio_do_status(GdbStopped); + return gdblx_parse_results(resp + 9); + } + return NULL; +} + + + +static void handle_response_line(gchar * str, gchar ** list); + + +void +gdbio_set_starting(gboolean s) +{ + starting = s; +} + +void +gdbio_target_started(gint seq, gchar ** list, gchar * resp) +{ + if ((strncmp(resp, "^error", 6) == 0) && (!gdbio_get_target_pid())) + { + gdbio_error_func("Error starting target process!\n"); + gdbio_do_status(GdbFinished); + } + else + { + handle_response_lines(list); + } +} + + + +static void +set_main_break(gint seq, gchar ** list, gchar * resp) +{ + GHashTable *h = gdbio_get_results(resp, list); + HTAB(h, bkpt); + gdbio_pop_seq(seq); + if (bkpt) + { + if (gdblx_check_keyval(bkpt, "number", "1")) + { + gdbio_do_status(GdbLoaded); + } + } + if (h) + g_hash_table_destroy(h); +} + + +void +gdbio_parse_file_list(gint seq, gchar ** list, gchar * resp) +{ + GHashTable *h = gdbio_get_results(resp, list); + HLST(h, files); + gdbio_pop_seq(seq); + if (files) + { + free_source_list(); + g_slist_foreach(files, parse_file_list_cb, files); + free_source_list(); + gdbio_send_seq_cmd(set_main_break, "-break-insert _start\n"); + } + else + { + gdbio_error_func + ("This executable does not appear to contain the required debugging information."); + } + if (h) + g_hash_table_destroy(h); +} + + + + + +static gboolean +do_step_func(GHashTable * h, gchar * reason) +{ + HTAB(h, frame); + HSTR(frame, fullname); + HSTR(frame, line); + if (fullname && line) + { + if (gdbio_setup.step_func) + { + gchar *p; + for (p = reason; *p; p++) + { + if (*p == '-') + { + *p = ' '; + } + } + gdbio_setup.step_func(fullname, line, reason); + } + else + { + gdbio_info_func("%s:%s", fullname, line); + } + return TRUE; + } + else + { + HSTR(frame, func); + if (func) + { + return TRUE; + } + } + return FALSE; +} + + + +#define reason_is(r) (r && reason && g_str_equal(reason, r)) + +static void +finish_function(gint seq, gchar ** list, gchar * resp) +{ + if (strncmp(resp, "^running", 8) == 0) + { + gdbio_set_running(TRUE); + gdbio_do_status(GdbRunning); + } + else + { + GHashTable *h = gdbio_get_results(resp, list); + HSTR(h, reason); + gdbio_pop_seq(seq); + if (reason_is("function-finished")) + { + gdbio_do_status(GdbStopped); + do_step_func(h, reason); + } + else + { + handle_response_lines(list); + } + if (h) + g_hash_table_destroy(h); + } +} + + +static void +return_function(gint seq, gchar ** list, gchar * resp) +{ + GHashTable *h = gdbio_get_results(resp, list); + gdbio_pop_seq(seq); + if (h) + { + do_step_func(h, "returned"); + } + else + { + handle_response_lines(list); + } +} + + + + +static void +watchpoint_trigger(GHashTable * h, GHashTable * wp, gchar * reason) +{ + HTAB(h, value); + HSTR(wp, exp); + HSTR(wp, number); + HSTR(value, new); + HSTR(value, old); + gchar *readval = gdblx_lookup_string(value, "value"); + if (new && old) + { + gdbio_info_func("%s #%s expression:%s old-value:%s new-value:%s\n", + reason, number ? number : "?", exp ? exp : "?", old, new); + } + else + { + if (old) + { + gdbio_info_func("%s #%s expression:%s value:%s", reason, + number ? number : "?", exp ? exp : "?", old); + } + else + { + if (new) + { + gdbio_info_func("%s #%s expression:%s value:%s", reason, + number ? number : "?", exp ? exp : "?", new); + } + else + { + if (readval) + { + gdbio_info_func("%s #%s expression:%s value:%s", reason, + number ? number : "?", exp ? exp : "?", + readval); + } + else + { + gdbio_info_func("%s #%s expression:%s", reason, + number ? number : "?", exp ? exp : "?"); + } + } + } + } +} + +static gboolean +handle_results_hash(GHashTable * h, gchar * rectype, gchar ** list) +{ + if (g_str_equal(rectype, "^error")) + { + HSTR(h, msg); + gchar *tmp = NULL; + if (msg) + { + if (g_str_equal(msg, "unknown error")) + { + gint len = g_strv_length(list); + if ((len > 1) && list[len - 2] && *list[len - 2]) + { + tmp = list[len - 2]; + if (tmp[0] == '&') + { + tmp++; + } + tmp = g_strcompress(tmp); + g_strstrip(tmp); + msg = tmp; + } + } + gdbio_error_func(msg); + if (tmp) + { + g_free(tmp); + } + return TRUE; + } + else + return FALSE; + } + if (g_str_equal(rectype, "^done")) + { + + HTAB(h, frame); + if (frame) + { + HSTR(frame, fullname); + HSTR(frame, line); + if (fullname && line) + { + return do_step_func(h, "done"); + } + } + return FALSE; + } + if (g_str_equal(rectype, "*stopped")) + { + HSTR(h, reason); + if (!reason) + { + return FALSE; + } + if (reason_is("breakpoint-hit")) + { + if (gdblx_check_keyval(h, "bkptno", "1")) + { + gdbio_send_seq_cmd(parse_process_info, + "-interpreter-exec console "info proc"\n"); + return TRUE; + } + else + { + return (do_step_func(h, reason)); + } + return FALSE; + } + gdbio_set_running(FALSE); + if (reason_is("signal-received")) + { + HSTR(h, signal_name); + HSTR(h, signal_meaning); + HSTR(h, thread_id); + HTAB(h, frame); + HSTR(frame, func); + HSTR(frame, file); + HSTR(frame, fullname); + HSTR(frame, line); + HSTR(frame, addr); + HSTR(frame, from); + HLST(frame, args); + if (!fullname) + { + fullname = "??"; + } + if (!file) + { + file = "??"; + } + if (!line) + { + line = "??"; + } + if (!args) + { + args = NULL; + } + if (signal_name && signal_meaning && thread_id && frame && + addr && func && file && fullname) + { + if (gdbio_setup.signal_func) + { + GdbSignalInfo si; + si.signal_name = signal_name; + si.signal_meaning = signal_meaning; + si.addr = addr; + si.func = func; + si.file = file; + si.fullname = fullname; + si.line = line; + si.from = from; + gdbio_setup.signal_func(&si); + } + else + { + gdbio_info_func + ("Program received signal %s (%s) at %s in function %s() at %s:%s", + signal_name, signal_meaning, addr, func, file, + line); + } + return TRUE; + } + } + + + if (reason_is("end-stepping-range")) + { + return do_step_func(h, reason); + } + if (reason_is("function-finished")) + { + return do_step_func(h, reason); + } + if (reason_is("location-reached")) + { + return do_step_func(h, reason); + } + if (reason_is("watchpoint-trigger")) + { + HTAB(h, wpt); + if (wpt) + { + watchpoint_trigger(h, wpt, reason); + } + return do_step_func(h, reason); + } + if (reason_is("access-watchpoint-trigger")) + { + HTAB(h, hw_awpt); + if (hw_awpt) + { + watchpoint_trigger(h, hw_awpt, reason); + } + return do_step_func(h, reason); + } + if (reason_is("read-watchpoint-trigger")) + { + HTAB(h, hw_rwpt); + if (hw_rwpt) + { + watchpoint_trigger(h, hw_rwpt, reason); + } + return do_step_func(h, reason); + } + if (reason_is("watchpoint-scope")) + { + HSTR(h, wpnum); + gdbio_info_func("Watchpoint #%s out of scope", wpnum ? wpnum : "?"); + gdbio_send_cmd("-exec-continue\n"); + return do_step_func(h, reason); + } + + if (reason_is("exited-signalled")) + { + HSTR(h, signal_name); + HSTR(h, signal_meaning); + gdbio_info_func("Program exited on signal %s (%s).\n", + signal_name ? signal_name : "UNKNOWN", + signal_meaning ? signal_meaning : "Unknown signal"); + gdbio_target_exited(signal_name); + return TRUE; + } + if (reason_is("exited")) + { + HSTR(h, exit_code); + gchar *tail = NULL; + gint ec = -1; + if (exit_code) + { + ec = strtoull(exit_code, &tail, 8); + if ((!tail) || (*tail)) + { + ec = -1; + } + } + gdbio_info_func("Program exited with code %d [%s]\n", ec, + exit_code ? exit_code : "(unknown)"); + gdbio_target_exited(exit_code); + return TRUE; + } + if (g_str_equal(reason, "exited-normally")) + { + gdbio_info_func("Program exited normally.\n"); + gdbio_target_exited("0"); + return TRUE; + } + } + return FALSE; +} + + + +static void +handle_response_line(gchar * str, gchar ** list) +{ + gchar *rv = str; + if (!rv) + { + return; + } + switch (rv[0]) + { + case '~': + case '@': + case '&': + { + rv++; + if (rv[0] == '"') + { + gint len = strlen(rv); + memmove(rv, rv + 1, len); + if (rv[len - 2] == '"') + { + rv[len - 2] = '\0'; + } + } + rv = g_strcompress(rv); + gdbio_info_func(rv); + g_free(rv); + break; + } + case '^': + case '*': + { + gchar *comma = strchr(rv, ','); + if (comma) + { + GHashTable *h = gdblx_parse_results(comma + 1); + *comma = '\0'; + if (g_str_equal(rv, "*stopped")) + { + gdbio_do_status(GdbStopped); + } + if (!handle_results_hash(h, rv, list)) + { + gdblx_dump_table(h); + } + g_hash_table_destroy(h); + } + else + { + if (g_str_equal(rv, "^running")) + { + if (starting) + { + starting = FALSE; + } + else + { + gdbio_do_status(GdbRunning); + } + gdbio_set_running(TRUE); + } + } + break; + } + default: + { + break; + } + } +} + + + + +#define prompt "\n(gdb) \n" +#define prlen 8 + + +#define starts_with_token(resp) \ + ( IsDigit(resp[0]) && IsDigit(resp[1]) && \ + IsDigit(resp[2]) && IsDigit(resp[3]) && \ + IsDigit(resp[4]) && IsDigit(resp[5]) && \ + strchr("^*=+", resp[6]) ) + + +void +gdbio_consume_response(GString * recv_buf) +{ + gchar *eos = NULL; + do + { + if (recv_buf->len) + { + eos = strstr(recv_buf->str, prompt); + } + else + { + eos = NULL; + } + if (eos) + { + gint seq = -1; + gchar seqbuf[SEQ_LEN + 2]; + ResponseHandler handler = NULL; + gchar **lines; + gint len; + *eos = '\0'; + lines = g_strsplit(recv_buf->str, "\n", 0); + *eos = '\n'; + len = g_strv_length(lines); + g_string_erase(recv_buf, 0, (eos - recv_buf->str) + 8); + if (len) + { + gchar *resp = lines[len - 1]; + if (starts_with_token(resp)) + { + strncpy(seqbuf, resp, SEQ_LEN); + seqbuf[SEQ_LEN] = '\0'; + seq = gdbio_atoi(seqbuf); + if (seq >= 0) + { + handler = gdbio_seq_lookup(seq); + if (handler) + { + memmove(resp, resp + SEQ_LEN, + strlen(resp + SEQ_LEN) + 1); + g_strstrip(resp); + handler(seq, lines, resp); + g_strfreev(lines); + do_loop(); + continue; + } + else + { + g_printerr + ("***Error: Could not find handler for token #%s\n", + seqbuf); + } + } + } + } + if (lines) + { + handle_response_lines(lines); + g_strfreev(lines); + } + } + do_loop(); + } + while (eos); +} + + + + + +void +gdbio_continue() +{ + gdbio_send_cmd("-exec-continue\n"); +} + + + + +void +gdbio_return() +{ + gdbio_send_seq_cmd(return_function, "-exec-return\n"); +} + + +void +gdbio_finish() +{ + gdbio_send_seq_cmd(finish_function, "-exec-finish\n"); +}
Added: trunk/geanydebug/src/gdb-io-run.c =================================================================== --- trunk/geanydebug/src/gdb-io-run.c (rev 0) +++ trunk/geanydebug/src/gdb-io-run.c 2008-09-07 20:36:07 UTC (rev 169) @@ -0,0 +1,778 @@ + +/* + * gdb-io-run.c - Process execution and input functions for GDB wrapper library. + * + * See the file "gdb-io.h" for license information. + * + */ + + +#include <unistd.h> +#include <signal.h> +#include <string.h> +#include <glib.h> +#include "gdb-io-priv.h" + + +extern gint g_unlink(const gchar * filename); + + +GdbIoSetup gdbio_setup; + + +static gchar *gdbio_args[] = { "gdb", "--interpreter=mi", "-nx", NULL }; + +static GPid gdbio_pid = 0; +static GPid target_pid = 0; +static GPid xterm_pid = 0; + +static GSource *gdbio_src; +static gint gdbio_in; +static gint gdbio_out; +static GIOChannel *gdbio_ch_in; +static GIOChannel *gdbio_ch_out; +static guint gdbio_id_in; +static guint gdbio_id_out; + +static GString send_buf = { NULL, 0, 0 }; +static GString recv_buf = { NULL, 0, 0 }; + +static gchar *xterm_tty_file = NULL; + + +static gint sequence = SEQ_MIN; +static gboolean is_running = FALSE; +static gint process_token = 0; + + +/* + Hash table to associate a "tokenized" GDB command with a function call. + This stores a list of key-value pairs where the unique sequence-number + (GDB token) is the key, and a ResponseHandler function pointer is the value. +*/ +static GHashTable *sequencer; + + + +/* Add a handler function to the sequencer */ +gint +gdbio_send_seq_cmd(ResponseHandler func, const gchar * fmt, ...) +{ + va_list args; + if (!gdbio_pid) + { + return 0; + } + if (sequence >= SEQ_MAX) + { + sequence = SEQ_MIN; + } + else + { + sequence++; + } + if (!sequencer) + { + sequencer = g_hash_table_new(g_direct_hash, g_direct_equal); + } + g_hash_table_insert(sequencer, GINT_TO_POINTER(sequence), func); + g_string_append_printf(&send_buf, "%d", sequence); + va_start(args, fmt); + g_string_append_vprintf(&send_buf, fmt, args); + va_end(args); + return sequence; +} + + +ResponseHandler +gdbio_seq_lookup(gint seq) +{ + return g_hash_table_lookup(sequencer, GINT_TO_POINTER(seq)); +} + + +void +gdbio_pop_seq(gint seq) +{ + g_hash_table_remove(sequencer, GINT_TO_POINTER(seq)); +} + +static gboolean +gerror(gchar * msg, GError ** err) +{ + if (*err) + { + if (msg) + { + gdbio_error_func("%s\n%s\n", msg, (*err)->message); + } + else + { + gdbio_error_func("%s\n", (*err)->message); + } + g_error_free(*err); + *err = NULL; + return TRUE; + } + else + { + return FALSE; + } +} + + +gint +gdbio_atoi(gchar * str) +{ + gchar *tail = NULL; + gint rv = strtol(str, &tail, 10); + return (tail && !*tail) ? rv : -1; +} + + +void +gdbio_error_func(gchar * fmt, ...) +{ + va_list args; + va_start(args, fmt); + gchar *msg = g_strdup_vprintf(fmt, args); + if (gdbio_setup.error_func) + { + gdbio_setup.error_func(g_strstrip(msg)); + } + else + { + g_printerr(msg); + } + g_free(msg); + va_end(args); +} + + +void +gdbio_info_func(gchar * fmt, ...) +{ + va_list args; + va_start(args, fmt); + gchar *msg = g_strdup_vprintf(fmt, args); + if (gdbio_setup.info_func) + { + gdbio_setup.info_func(g_strstrip(msg)); + } + else + { + g_printerr(msg); + } + g_free(msg); + va_end(args); +} + + +gint +gdbio_wait(gint ms) +{ + struct timespec req = { 0, 0 }, rem = + { + 0, 0}; + gint rms = ms; + if (ms >= 1000) + { + req.tv_sec = ms / 1000; + rms = ms % 1000; + } + req.tv_nsec = rms * 1000000; /* 1 millisecond = 1,000,000 nanoseconds */ + do + { + nanosleep(&req, &rem); + if ((rem.tv_sec || rem.tv_nsec)) + { + memcpy(&req, &rem, sizeof(req)); + memset(&rem, 0, sizeof(rem)); + } + else + { + break; + } + + } + while (1); + return ms; +} + + + +void +gdbio_send_cmd(const gchar * fmt, ...) +{ + va_list args; + if (!gdbio_pid) + { + return; + } + va_start(args, fmt); + g_string_append_vprintf(&send_buf, fmt, args); + va_end(args); +} + + + +void +gdbio_set_running(gboolean running) +{ + is_running = running; +} + + + +static void +kill_xterm() +{ + if (xterm_pid) + { + kill(xterm_pid, SIGKILL); + xterm_pid = 0; + } +} + + + +static gchar * +start_xterm(gchar * term_cmd) +{ + gchar *term_args[] = { "xterm", "-title", "Debug terminal", "-e", NULL, NULL, NULL }; + GError *err = NULL; + gint i = 0; + gchar *tty_name = NULL; + const gchar *exe_name = basename(term_cmd); + gchar *all; + if (!gdbio_setup.temp_dir) + { + gdbio_error_func("tty temporary directory not specified!\n"); + return NULL; + } + if (!g_file_test(gdbio_setup.temp_dir, G_FILE_TEST_IS_DIR)) + { + gdbio_error_func("tty temporary directory not found!\n"); + return NULL; + } + if (!xterm_tty_file) + { + xterm_tty_file = g_strdup_printf("%s/%d.tty", gdbio_setup.temp_dir, getpid()); + } + if (g_file_set_contents(xterm_tty_file, "", -1, &err)) + { + g_unlink(xterm_tty_file); + } + else + { + gerror("writing ttyname logfile", &err); + g_unlink(xterm_tty_file); + return FALSE; + } + if (!gdbio_setup.tty_helper) + { + gdbio_error_func("tty helper program not specified!\n"); + return NULL; + } + if (! + (g_file_test(gdbio_setup.tty_helper, G_FILE_TEST_IS_EXECUTABLE) && + g_file_test(gdbio_setup.tty_helper, G_FILE_TEST_IS_REGULAR))) + { + gdbio_error_func("tty helper program not found!\n"); + return NULL; + } + term_args[0] = term_cmd; + if (g_str_equal(exe_name, "xterm") || g_str_equal(exe_name, "konsole")) + { + term_args[1] = "-T"; + } + else + { + if (g_str_equal(exe_name, "gnome-terminal")) + { + term_args[1] = "--title"; + term_args[3] = "-x"; + } + else + { + if (g_str_equal(exe_name, "rxvt") || g_str_equal(exe_name, "urxvt")) + { + term_args[1] = "-title"; + } + else + { + term_args[1] = "-e"; + term_args[2] = NULL; + } + } + } + i = 0; + while (term_args[i]) + { + i++; + } + term_args[i] = gdbio_setup.tty_helper; + term_args[i + 1] = xterm_tty_file; + all = g_strjoinv("" "", term_args); + gdbio_info_func(""%s"\n", all); + g_free(all); + if (g_spawn_async(NULL, term_args, NULL, G_SPAWN_SEARCH_PATH, NULL, NULL, &xterm_pid, &err)) + { + gchar *contents = NULL; + gsize len; + gint ms = 0; + do + { + if (g_file_test(xterm_tty_file, G_FILE_TEST_EXISTS)) + { + if (g_file_get_contents(xterm_tty_file, &contents, &len, &err)) + { + g_strstrip(contents); + if (strlen(contents)) + { + tty_name = g_strdup(contents); + gdbio_info_func("Attaching to terminal %s\n", + tty_name); + } + break; + } + else + { + gerror("Error getting tty name:", &err); + } + } + ms += gdbio_wait(250); + } + while (ms <= 10000); + if (ms > 10000) + { + gdbio_error_func("Timeout waitng for TTY name.\n"); + kill_xterm(); + } + } + else + { + gerror("Error starting terminal: ", &err); + } + g_unlink(xterm_tty_file); + return tty_name; +} + + + +static void +free_buf(GString * buf) +{ + if (buf->str) + { + g_free(buf->str); + buf->str = NULL; + buf->len = 0; + buf->allocated_len = 0; + } +} + +static void +shutdown_channel(GIOChannel ** ch) +{ + if (*ch) + { + GError *err = NULL; + gint fd = g_io_channel_unix_get_fd(*ch); + g_io_channel_shutdown(*ch, TRUE, &err); + gerror("Shutting down channel", &err); + g_io_channel_unref(*ch); + *ch = NULL; + if (fd >= 0) + { + close(fd); + } + } +} + + +static void +on_gdb_exit(GPid pid, gint status, gpointer data) +{ + gdbio_pid = 0; + gdbio_info_func("GDB exited (pid=%d)\n", pid); + g_spawn_close_pid(pid); + + + g_source_remove(gdbio_id_in); + shutdown_channel(&gdbio_ch_in); + + g_source_remove(gdbio_id_out); + shutdown_channel(&gdbio_ch_out); + + free_buf(&send_buf); + if (recv_buf.len) + { + gdbio_info_func("%s\n", recv_buf.str); + } + free_buf(&recv_buf); + + if (target_pid) + { + kill(target_pid, SIGKILL); + target_pid = 0; + } + gdbio_set_running(FALSE); + gdblx_scanner_done(); + gdbio_do_status(GdbDead); +} + + + +static gboolean +on_send_to_gdb(GIOChannel * src, GIOCondition cond, gpointer data) +{ + GIOStatus st; + GError *err = NULL; + gsize count; + if (send_buf.len) + { + while (send_buf.len) + { + st = g_io_channel_write_chars(src, send_buf.str, send_buf.len, &count, + &err); + g_string_erase(&send_buf, 0, count); + if (err || (st == G_IO_STATUS_ERROR) || (st == G_IO_STATUS_EOF)) + { + gerror("Error sending command", &err); + break; + } + } + st = g_io_channel_flush(src, &err); + gerror("Error pushing command", &err); + } + do_loop(); + gdbio_wait(10); + return TRUE; +} + + + +void +gdbio_target_exited(gchar * reason) +{ + gdbio_info_func("Target process exited. (pid=%d; %s%s)\n", target_pid, + reason + && g_ascii_isdigit(reason[0]) ? "code=" : "reason:", + reason ? reason : "unknown"); + target_pid = 0; + kill_xterm(); + gdbio_set_running(FALSE); + gdbio_do_status(GdbFinished); + if (process_token) + { + gdbio_pop_seq(process_token); + process_token = 0; + } +} + +static GdbStatus gdbio_status = GdbDead; + +void +gdbio_do_status(GdbStatus s) +{ + gdbio_status = s; + if (gdbio_setup.status_func) + { + gdbio_setup.status_func(s); + } +} + + + +void +gdbio_pause_target() +{ + if (target_pid) + { + kill(target_pid, SIGINT); + } +} + + + +static void +target_killed(gint seq, gchar ** list, gchar * resp) +{ + GHashTable *h = gdbio_get_results(resp, list); + gdbio_pop_seq(seq); + if (h) + { + g_hash_table_destroy(h); + } + if (strncmp(resp, "^done", 5) == 0) + { + gdbio_target_exited("killed by GDB"); + } +} + + + +void +gdbio_kill_target(gboolean force) +{ + if (target_pid) + { + gchar pidstr[64]; + GPid this_pid = target_pid; + gint ms = 0; + snprintf(pidstr, sizeof(pidstr) - 1, "/proc/%d", target_pid); + if (!g_file_test(pidstr, G_FILE_TEST_IS_DIR)) + { + gdbio_info_func("Directory %s not found!\n", pidstr); + pidstr[0] = '\0'; + } + if (!force) + { + gdbio_info_func("Shutting down target program.\n"); + gdbio_send_seq_cmd(target_killed, "kill SIGKILL\n"); + gdbio_wait(250); + do_loop(); + } + else + { + gdbio_info_func("Killing target program.\n"); + kill(this_pid, SIGKILL); + } + while (1) + { + do_loop(); + if (ms >= 2000) + { + gdbio_info_func("Timeout waiting for target process.\n"); + if (!force) + { + gdbio_info_func("Using a bigger hammer!\n"); + gdbio_kill_target(TRUE); + } + break; + } + if (target_pid != this_pid) + { + break; + } + if ((pidstr[0]) && !g_file_test(pidstr, G_FILE_TEST_EXISTS)) + { + break; + } + if (!(ms % 1000)) + gdbio_info_func("Waiting for target process to exit.\n"); + ms += gdbio_wait(250); + } + } + kill_xterm(); +} + +static gboolean +have_console() +{ + return (gdbio_status == GdbLoaded) || (gdbio_status == GdbStopped) + || (gdbio_status == GdbFinished); +} + +void +gdbio_exit() +{ + gdbio_kill_target(!have_console()); + if (gdbio_pid) + { + GPid this_gdb = gdbio_pid; + gint ms = 0; + gchar pidstr[64]; + snprintf(pidstr, sizeof(pidstr) - 1, "/proc/%d", this_gdb); + if (is_running) + { + if (!g_file_test(pidstr, G_FILE_TEST_IS_DIR)) + { + gdbio_info_func("Directory %s not found!\n", pidstr); + pidstr[0] = '\0'; + } + do + { + do_loop(); + if (gdbio_pid == this_gdb) + { + gdbio_info_func("Killing GDB (pid=%d)\n", this_gdb); + } + else + { + break; + } + kill(this_gdb, SIGKILL); + ms += gdbio_wait(500); + if (pidstr[0] && !g_file_test(pidstr, G_FILE_TEST_EXISTS)) + { + break; + } + if (ms > 2000) + { + gdbio_error_func("Timeout trying to kill GDB.\n"); + break; + } + } + while (1); + free_buf(&send_buf); + gdbio_wait(500); + } + else + { + gdbio_info_func("Shutting down GDB\n"); + gdbio_send_cmd("-gdb-exit\n"); + while (1) + { + do_loop(); + ms += gdbio_wait(250); + if (pidstr[0] && !g_file_test(pidstr, G_FILE_TEST_EXISTS)) + { + break; + } + if (gdbio_pid == this_gdb) + { + if (!(ms % 1000)) + gdbio_info_func("Waiting for GDB to exit.\n"); + } + else + { + break; + } + if (ms > 2000) + { + gdbio_info_func("Timeout waiting for GDB to exit.\n"); + gdbio_set_running(TRUE); + gdbio_exit(); + break; + } + } + } + } + if (sequencer) + { + g_hash_table_destroy(sequencer); + sequencer = NULL; + } + g_free(xterm_tty_file); + xterm_tty_file = NULL; +} + + + +void gdbio_parse_file_list(gint seq, gchar ** list, gchar * resp); + +static void +load_target(const gchar * exe_name) +{ + gdbio_set_running(FALSE); + gdbio_send_cmd("-file-exec-and-symbols %s\n", exe_name); + gdbio_send_seq_cmd(gdbio_parse_file_list, "-file-list-exec-source-files\n"); + +} + + + +static gboolean +on_read_from_gdb(GIOChannel * src, GIOCondition cond, gpointer data) +{ + gchar buf[1024]; + GIOStatus st; + GError *err = NULL; + gsize count; + st = g_io_channel_read_chars(src, buf, sizeof(buf) - 1, &count, &err); + buf[count] = '\0'; + g_string_append_len(&recv_buf, buf, count); + gerror("Error reading response", &err); + gdbio_consume_response(&recv_buf); + gdbio_wait(10); + return TRUE; +} + + +#define GDB_SPAWN_FLAGS \ +G_SPAWN_SEARCH_PATH | \ +G_SPAWN_DO_NOT_REAP_CHILD + + +void +gdbio_load(const gchar * exe_name) +{ + GError *err = NULL; + gdbio_exit(); + if (g_spawn_async_with_pipes(NULL, gdbio_args, NULL, + GDB_SPAWN_FLAGS, NULL, + NULL, &gdbio_pid, &gdbio_in, &gdbio_out, NULL, &err)) + { + gdbio_info_func("Starting gdb (pid=%d)\n", gdbio_pid); + + g_child_watch_add(gdbio_pid, on_gdb_exit, NULL); + gdbio_src = g_child_watch_source_new(gdbio_pid); + + gdbio_ch_in = g_io_channel_unix_new(gdbio_in); + g_io_channel_set_encoding(gdbio_ch_in, NULL, &err); + gerror("Error setting encoding", &err); + g_io_channel_set_buffered(gdbio_ch_in, FALSE); + + gdbio_ch_out = g_io_channel_unix_new(gdbio_out); + g_io_channel_set_encoding(gdbio_ch_out, NULL, &err); + gerror("Error setting encoding", &err); + g_io_channel_set_buffered(gdbio_ch_out, FALSE); + + gdbio_id_in = g_io_add_watch(gdbio_ch_in, G_IO_OUT, on_send_to_gdb, NULL); + gdbio_id_out = g_io_add_watch(gdbio_ch_out, G_IO_IN, on_read_from_gdb, NULL); + + gdbio_send_cmd("-gdb-set width 0\n-gdb-set height 0\n"); + if (exe_name) + { + load_target(exe_name); + } + } + else + { + gerror("Error starting debugger.", &err); + } +} + + + +void +gdbio_exec_target(gchar * terminal_command) +{ + if (terminal_command) + { + gchar *tty_name = start_xterm(terminal_command); + if (tty_name) + { + gdbio_send_cmd("-inferior-tty-set %s\n", tty_name); + g_free(tty_name); + } + else + return; + } + if (process_token) + { + gdbio_pop_seq(process_token); + } + gdbio_set_starting(TRUE); + gdbio_do_status(GdbStartup); + process_token = gdbio_send_seq_cmd(gdbio_target_started, "-exec-run\n"); +} + + + +void +gdbio_set_target_pid(GPid pid) +{ + gdbio_info_func("Started target process. (pid=%d)\n", pid); + target_pid = pid; +} + + + +GPid +gdbio_get_target_pid() +{ + return target_pid; +}
Added: trunk/geanydebug/src/gdb-io-stack.c =================================================================== --- trunk/geanydebug/src/gdb-io-stack.c (rev 0) +++ trunk/geanydebug/src/gdb-io-stack.c 2008-09-07 20:36:07 UTC (rev 169) @@ -0,0 +1,198 @@ + +/* + * gdb-io-stack.c - Stack information functions for GDB wrapper library. + * + * See the file "gdb-io.h" for license information. + * + */ + +#include <string.h> +#include <glib.h> + +#include "gdb-io-priv.h" + +static GdbListFunc gdbio_stack_list_func = NULL; +static GSList *frame_list = NULL; + +/* + Max number of frames to return in stack list - + you can increase if you want, but too large + value can be *very* slow! +*/ +#define MAX_STACK_RETURN 1024 + + + +static void +free_frame_list() +{ + GSList *p; + for (p = frame_list; p; p = p->next) + { + if (p->data) + { + GdbFrameInfo *f = p->data; + if (f->func) + { + g_free(f->func); + } + if (f->filename) + { + g_free(f->filename); + } + if (f->args) + { + gdbio_free_var_list(f->args); + } + g_free(f); + p->data = NULL; + } + } + g_slist_free(frame_list); + frame_list = NULL; +} + + + +static void +stack_cb(gpointer data, gpointer user_data) +{ + GdbLxValue *v = (GdbLxValue *) data; + if (v && (v->type == vt_HASH)) + { + GHashTable *frame = v->hash; + HSTR(frame, level); + HSTR(frame, addr); + HSTR(frame, func); + HSTR(frame, file); + HSTR(frame, fullname); + HSTR(frame, line); + if (!fullname) + fullname = file; + if (level && addr && func && fullname && line) + { + GdbFrameInfo *frame = g_new0(GdbFrameInfo, 1); + strncpy(frame->level, level, sizeof(frame->level) - 1); + strncpy(frame->addr, addr, sizeof(frame->addr) - 1); + strncpy(frame->line, line, sizeof(frame->line) - 1); + frame->func = g_strdup(func); + frame->filename = g_strdup(fullname); + frame_list = g_slist_append(frame_list, frame); + } + } +} + + + +static void +merge_stack_args_cb(gpointer data, gpointer user_data) +{ + GdbLxValue *v = (GdbLxValue *) data; + if (v && (v->type = vt_HASH)) + { + GHashTable *hash = v->hash; + HSTR(hash, level); + HLST(hash, args); + if (level && args) + { + gchar *tail; + gint n = strtoull(level, &tail, 10); + GdbFrameInfo *frame = NULL; + GSList *p; + for (p = frame_list; p; p = p->next) + { + if (p->data) + { + GdbFrameInfo *f = p->data; + if (gdbio_atoi(f->level) == n) + { + frame = f; + break; + } + } + } + if (frame) + { + for (p = args; p; p = p->next) + { + v = p->data; + if (v && (v->type = vt_HASH)) + { + HSTR(v->hash, name); + HSTR(v->hash, value); + if (name && value) + { + GdbVar *arg = g_new0(GdbVar, 1); + arg->name = g_strdup(name); + arg->value = g_strdup(value); + frame->args = + g_slist_append(frame->args, arg); + } + } + } + } + } + } +} + + + +static void +parse_stack_args(gint seq, gchar ** list, gchar * resp) +{ + GHashTable *h = gdbio_get_results(resp, list); + HLST(h, stack_args); + gdbio_pop_seq(seq); + if (stack_args) + { + if (frame_list) + { + g_slist_foreach(stack_args, merge_stack_args_cb, NULL); + gdbio_stack_list_func(frame_list); + free_frame_list(); + } + } + if (h) + g_hash_table_destroy(h); +} + + + +static void +parse_stack_list(gint seq, gchar ** list, gchar * resp) +{ + GHashTable *h = gdbio_get_results(resp, list); + HLST(h, stack); + gdbio_pop_seq(seq); + if (stack) + { + g_slist_foreach(stack, stack_cb, h); + if (frame_list) + { + gint len = g_slist_length(frame_list); + if (len >= MAX_STACK_RETURN) + { + gdbio_error_func + ("Stack too deep to display!\n(Showing only %d frames)", + len); + } + gdbio_send_seq_cmd(parse_stack_args, "-stack-list-arguments 1 0 %d\n", + len - 1); + } + } + if (h) + g_hash_table_destroy(h); +} + + + +void +gdbio_show_stack(GdbListFunc func) +{ + gdbio_stack_list_func = func; + if (func) + { + gdbio_send_seq_cmd(parse_stack_list, "-stack-list-frames 0 %d\n", + MAX_STACK_RETURN - 1); + } +}
Added: trunk/geanydebug/src/gdb-io.h =================================================================== --- trunk/geanydebug/src/gdb-io.h (rev 0) +++ trunk/geanydebug/src/gdb-io.h 2008-09-07 20:36:07 UTC (rev 169) @@ -0,0 +1,231 @@ +/* + * gdb-io.h - A GLib-based library wrapper for the GNU debugger. + * Copyright 2008 Jeff Pohlmeyer <yetanothergeek(at)gmail(dot)com> + * + * + * 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 <stdio.h> + + +extern ssize_t getline(char **lineptr, size_t * n, FILE * stream); +extern const gchar *basename(const gchar * path); + +gint gdbio_atoi(gchar * str); +gint gdbio_wait(gint ms); + + +typedef enum +{ + GdbDead, + GdbLoaded, + GdbStartup, + GdbRunning, + GdbStopped, + GdbFinished +} GdbStatus; + + +typedef struct +{ + gchar *type; + gchar *name; + gchar *value; + gchar *numchild; +} GdbVar; + + +typedef struct +{ + gchar level[12]; + gchar addr[12]; + gchar line[12]; + gchar *func; + gchar *filename; + GSList *args; +} GdbFrameInfo; + + +typedef struct +{ + gchar *signal_name; + gchar *signal_meaning; + gchar *addr; + gchar *func; + gchar *file; + gchar *fullname; + gchar *line; + gchar *from; +} GdbSignalInfo; + + +typedef struct +{ + gchar *addr; + gchar *disp; + gchar *enabled; + gchar *file; + gchar *fullname; + gchar *func; + gchar *line; + gchar *number; + gchar *times; + gchar *type; + gchar *what; + gchar *cond; + gchar *ignore; +} GdbBreakPointInfo; + + +typedef struct +{ + gchar *cwd; + gchar *path; + gchar *args; + gchar *dirs; +} GdbEnvironInfo; + + +typedef void (*GdbMsgFunc) (const gchar * msg); +typedef void (*GdbListFunc) (const GSList * list); +typedef void (*GdbFrameFunc) (const GdbFrameInfo * frame, const GSList * locals); +typedef void (*GdbSignalFunc) (const GdbSignalInfo * si); +typedef void (*GdbStatusFunc) (GdbStatus status); +typedef void (*GdbStepFunc) (const gchar * filename, const gchar * line, const gchar * reason); +typedef void (*GdbObjectFunc) (const GdbVar * obj, const GSList * list); +typedef void (*GdbEnvironFunc) (const GdbEnvironInfo * env); + + + +/* Load a program into the debugger */ +void gdbio_load(const gchar * exe_name); + +/* Terminate the debugger ( and the target program, if running ) */ +void gdbio_exit(); + +/* Resume execution after a breakpoint or SIGINT, etc... */ +void gdbio_continue(); + +/* Complete the current function */ +void gdbio_finish(); + +/* Return immediately from the current function */ +void gdbio_return(); + +/* + Execute the previously loaded program in the debugger. + If the terminal_command argument is non-null, it will + be started first, and the target program will be run + in the resulting console. +*/ +void gdbio_exec_target(gchar * terminal_command); + + +/* Send SIGINT to target */ +void gdbio_pause_target(); + + +/* Send SIGKILL to target */ +void gdbio_kill_target(); + + +/* Send a command to GDB */ +void gdbio_send_cmd(const gchar * fmt, ...); + + +/* + Pass a GSList of GdbBreakPointInfo pointers to the func callback + Showing the current list of breakpoints and watchpoints +*/ +void gdbio_show_breaks(GdbListFunc func); + + +/* + These 3 functions pass a GSList of GdbBreakPointInfo pointers to + the func callback showing the current list of breakpoints and + watchpoints after the requested change has been completed. +*/ +void gdbio_add_watch(GdbListFunc func, const gchar * option, const gchar * varname); +void gdbio_add_break(GdbListFunc func, const gchar * filename, const gchar * locn); +void gdbio_delete_break(GdbListFunc func, const gchar * number); + + +void gdbio_enable_break(const gchar * number, gboolean enabled); +void gdbio_ignore_break(const gchar * number, const gchar * times); +void gdbio_break_cond(const gchar * number, const gchar * expr); + + + +/* + Pass a GdbEnvironInfo pointer to the callback to show some + information about current GDB settings. +*/ +void gdbio_get_env(GdbEnvironFunc func); + + +/* + Pass a GSList of GdbFrameInfo pointers to the func callback + representing a backtrace of current call stack. +*/ +void gdbio_show_stack(GdbListFunc func); + + +/* + Passes a GdbFrameInfo pointer and a GSList of GdbVar pointers to func + representing the state of the local variables at the specified level. +*/ +void gdbio_show_locals(GdbFrameFunc func, gchar * level); + + +/* + Passes GdbVar pointer containing information about the variable to + the callback along with a GSList of GdbVar pointers containing + information about each array element or struct field. +*/ +void gdbio_show_object(GdbObjectFunc func, const gchar * varname); + + + +/* + The fields of the gdbio_setup struct should be initialized by the + client application before loading the first target program. + + The tty_helper field must point to the full path and filename + of the included "ttyhelper" program (see ttyhelper.c) + + The temp_dir must point to a readable and writeable directory. + + The client is also responsible for allocating/freeing the + string fields. +*/ + +typedef struct _GdbIoSetup +{ + GdbMsgFunc info_func; + GdbMsgFunc error_func; + GdbSignalFunc signal_func; + GdbStatusFunc status_func; + GdbStepFunc step_func; + gchar *tty_helper; + gchar *temp_dir; +} GdbIoSetup; + +extern GdbIoSetup gdbio_setup;
Added: trunk/geanydebug/src/gdb-lex.c =================================================================== --- trunk/geanydebug/src/gdb-lex.c (rev 0) +++ trunk/geanydebug/src/gdb-lex.c 2008-09-07 20:36:07 UTC (rev 169) @@ -0,0 +1,337 @@ + +/* + * gdb-lex.c - A GLib-based parser for GNU debugger machine interface output. + * + * See the file "gdb-lex.h" for license information. + * + */ + +#include <string.h> +#include <glib.h> +#include "gdb-lex.h" + + +static void +free_value(GdbLxValue * v) +{ + if (v) + { + switch (v->type) + { + case vt_STRING: + { + g_free(v->string); + break; + } + case vt_HASH: + { + g_hash_table_destroy(v->hash); + break; + } + case vt_LIST: + { + GSList *p; + for (p = v->list; p; p = p->next) + { + free_value(p->data); + } + g_slist_free(v->list); + break; + } + } + } +} + + +static GdbLxValue * +new_value(GdbLxValueType type, gpointer data) +{ + GdbLxValue *v = g_new0(GdbLxValue, 1); + v->type = type; + v->data = data; + return v; +} + + +static void +scan_error(GScanner * scanner, gchar * message, gboolean error) +{ + g_printerr("\n%s\n", message); +} + + + + +#define ID_NTH G_CSET_a_2_z G_CSET_A_2_Z G_CSET_DIGITS "_-" +static GScanner * +init_scanner() +{ + GScanner *scanner = g_scanner_new(NULL); + scanner->msg_handler = scan_error; + scanner->config->cset_identifier_nth = ID_NTH; + return scanner; +} + + +#define new_hash() g_hash_table_new_full(g_str_hash, g_str_equal, g_free, (GDestroyNotify)free_value) +#define curr ((GdbLxValue*)(g_queue_peek_head(queue))) + + + +static void +add_node(GScanner * scanner, gchar ** key, GdbLxValueType type, gpointer data, GQueue * queue) +{ + GdbLxValue *v = new_value(type, data); + switch (curr->type) + { + case vt_STRING: + { + g_scanner_error(scanner, "***** queue head is a string\n"); + break; + } + case vt_HASH: + { + if (*key) + { + g_hash_table_insert(curr->hash, *key, v); + } + else + { + g_scanner_error(scanner, "***** no key for hash\n"); + } + break; + } + case vt_LIST: + { + curr->list = g_slist_append(curr->list, v); + break; + } + } + *key = NULL; + if (type != vt_STRING) + { + g_queue_push_head(queue, v); + } +} + + +static GScanner *scanner = NULL; + +GHashTable * +gdblx_parse_results(gchar * results) +{ + gchar *key = NULL; + gboolean equals = FALSE; + GHashTable *rv = new_hash(); + GdbLxValue *top = new_value(vt_HASH, rv); + GQueue *queue = g_queue_new(); + g_queue_push_head(queue, top); + GTokenType tt; + if (!scanner) + { + scanner = init_scanner(); + } + g_scanner_input_text(scanner, results, strlen(results)); + do + { + tt = g_scanner_get_next_token(scanner); + switch (tt) + { + case G_TOKEN_LEFT_CURLY: + { + add_node(scanner, &key, vt_HASH, new_hash(), queue); + break; + } + case G_TOKEN_RIGHT_CURLY: + { + g_queue_pop_head(queue); + break; + } + case G_TOKEN_LEFT_BRACE: + { + add_node(scanner, &key, vt_LIST, NULL, queue); + break; + } + case G_TOKEN_RIGHT_BRACE: + { + g_queue_pop_head(queue); + break; + } + case G_TOKEN_STRING: + { + add_node(scanner, &key, vt_STRING, + g_strdup(scanner->value.v_string), queue); + break; + } + + case G_TOKEN_IDENTIFIER: + { + if (g_scanner_peek_next_token(scanner) == + G_TOKEN_EQUAL_SIGN) + { + gchar *p; + if (key) + { + g_scanner_error(scanner, + "multiple keys: found %s and %s\n", + key, + scanner->value. + v_identifier); + g_free(key); + } + key = g_strdup(scanner->value.v_identifier); + for (p = key; *p; p++) + { + if (*p == '-') + { + *p = '_'; + } + } + } + break; + } + default: + { + } + equals = (tt == G_TOKEN_EQUAL_SIGN); + } + } + while ((tt != G_TOKEN_EOF) && (tt != G_TOKEN_ERROR)); + g_queue_free(queue); + return rv; +} + + +void +gdblx_scanner_done() +{ + if (scanner) + { + g_scanner_destroy(scanner); + scanner = NULL; + } +} + + +/* don't print the newline until after the rval of the equal sign is printed. */ +static gboolean dump_value_rval_pending = FALSE; + +#define indent(s) if (dump_value_rval_pending) \ +g_printerr("%s\n", s); \ +else g_printerr("%*c%s\n", depth, ' ', s); \ + dump_value_rval_pending = FALSE; + + +static void dump_rec(GHashTable * h, gint depth); + + +static void dump_list_cb(gpointer data, gpointer user_data); + +static void +dump_value(GdbLxValue * v, gint depth) +{ + switch (v->type) + { + case vt_STRING: + { + indent(v->string); + break; + } + case vt_HASH: + { + indent("{"); + dump_rec(v->hash, depth); + indent("}"); + break; + } + case vt_LIST: + { + indent("["); + g_slist_foreach(v->list, dump_list_cb, GINT_TO_POINTER(depth) + 1); + indent("]"); + break; + } + } +} + + + +static void +dump_list_cb(gpointer data, gpointer user_data) +{ + dump_value(data, GPOINTER_TO_INT(user_data)); +} + + + +static void +dump_rec_cb(gpointer key, gpointer value, gpointer user_data) +{ + g_printerr("%*c%s=", GPOINTER_TO_INT(user_data), ' ', (gchar *) key); + dump_value_rval_pending = TRUE; + dump_value(value, GPOINTER_TO_INT(user_data)); +} + + + +static void +dump_rec(GHashTable * h, gint depth) +{ + if (h) + { + g_hash_table_foreach(h, dump_rec_cb, GINT_TO_POINTER(depth) + 1); + } + else + {
@@ Diff output truncated at 100000 characters. @@
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.