From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 1537 invoked by alias); 6 Aug 2010 13:55:02 -0000 Received: (qmail 1513 invoked by uid 22791); 6 Aug 2010 13:54:59 -0000 X-SWARE-Spam-Status: No, hits=-5.4 required=5.0 tests=AWL,BAYES_00,RCVD_IN_DNSWL_HI,SPF_HELO_PASS,T_RP_MATCHES_RCVD X-Spam-Check-By: sourceware.org Received: from mx1.redhat.com (HELO mx1.redhat.com) (209.132.183.28) by sourceware.org (qpsmtpd/0.43rc1) with ESMTP; Fri, 06 Aug 2010 13:54:52 +0000 Received: from int-mx08.intmail.prod.int.phx2.redhat.com (int-mx08.intmail.prod.int.phx2.redhat.com [10.5.11.21]) by mx1.redhat.com (8.13.8/8.13.8) with ESMTP id o76DsXds028515 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=OK); Fri, 6 Aug 2010 09:54:34 -0400 Received: from Phil-THINK.home (ovpn01.gateway.prod.ext.phx2.redhat.com [10.5.9.1]) by int-mx08.intmail.prod.int.phx2.redhat.com (8.13.8/8.13.8) with ESMTP id o76DsWaM005755; Fri, 6 Aug 2010 09:54:32 -0400 Message-ID: <4C5C1418.7030607@redhat.com> Date: Fri, 06 Aug 2010 13:55:00 -0000 From: Phil Muldoon User-Agent: Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9.2.7) Gecko/20100720 Fedora/3.1.1-1.fc13 Thunderbird/3.1.1 MIME-Version: 1.0 To: Tom Tromey CC: Joel Brobecker , gdb-patches ml Subject: Re: [patch] Add solib_address and decode_line Python functionality References: <4C44728D.4040408@redhat.com> <20100727162545.GF13267@adacore.com> <4C5015E2.4000205@redhat.com> In-Reply-To: Content-Type: text/plain; charset=ISO-8859-1 Content-Transfer-Encoding: 7bit X-IsSubscribed: yes Mailing-List: contact gdb-patches-help@sourceware.org; run by ezmlm Precedence: bulk List-Id: List-Subscribe: List-Archive: List-Post: List-Help: , Sender: gdb-patches-owner@sourceware.org X-SW-Source: 2010-08/txt/msg00063.txt.bz2 On 29/07/10 21:38, Tom Tromey wrote: >>>>>> "Phil" == Phil Muldoon writes: > > Phil> +static PyObject * > Phil> +gdbpy_solib_name (PyObject *self, PyObject *args) > Phil> +{ > Phil> + unsigned long long pc; > > I don't think it is ok to use 'long long'. > Maybe you can use `unsigned PY_LONG_LONG', but see the Python API > manual; it seems that is not always available. If it is not available > then I think this function could probably revert to 'unsigned long' and > the 'k' format. I looked at the documentation and PY_LONG_LONG is only available on some platforms (namely, 64 bit platforms). I used unsigned long, and 'k' instead. > > Phil> + TRY_CATCH (except, RETURN_MASK_ALL) > Phil> + { > Phil> + if (arg) > Phil> + { > Phil> + char *copy; > Phil> + > Phil> + arg = strdup (arg); > > Needs xstrdup and a cleanup. > > I think we may want this function to also return the unparsed part of > the argument string. For example we could return a tuple whose first > element is a string and whose second element is the return value as in > this patch. I've modified this function to return the tuple as you requested, and updated the documentation and testsuite accordingly. What do you think? Cheers, Phil -- diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo index 03b59a3..fbe1d47 100644 --- a/gdb/doc/gdb.texinfo +++ b/gdb/doc/gdb.texinfo @@ -20562,6 +20562,26 @@ Return the name of the current target wide character set never returned. @end defun +@findex gdb.solib_name +@defun solib_name address +Return the name of the shared library holding the given @var{address} +as a string, or @code{None}. +@end defun + +@findex gdb.decode_line +@defun decode_line @r{[}expression@r{]} +Decode the optional argument @var{expression} the way that +@value{GDBN}'s inbuilt @code{break} or @code{edit} commands do +(@pxref{Specify Location}). This function returns a Python tuple +containing two elements. The first element contains a string holding +any unparsed section of @var{expression} (or @code{None} if the +expression has been fully parsed). The second element contains either +@code{None} or another tuple that contains all the locations that +match the expression represented as @code{gdb.Symtab_and_line} objects +(@pxref{Symbol Tables In Python}). If @var{expression} is not +provided, the current location is returned. +@end defun + @node Exception Handling @subsubsection Exception Handling @cindex python exceptions diff --git a/gdb/python/python.c b/gdb/python/python.c index 6680126..d4f782d 100644 --- a/gdb/python/python.c +++ b/gdb/python/python.c @@ -42,7 +42,10 @@ static int gdbpy_should_print_stack = 1; #include "cli/cli-decode.h" #include "charset.h" #include "top.h" +#include "solib.h" #include "python-internal.h" +#include "linespec.h" +#include "source.h" #include "version.h" #include "target.h" #include "gdbthread.h" @@ -413,6 +416,131 @@ execute_gdb_command (PyObject *self, PyObject *args, PyObject *kw) Py_RETURN_NONE; } +/* Implementation of gdb.solib_name (Long) -> String. + Returns the name of the shared library holding a given address, or None. */ + +static PyObject * +gdbpy_solib_name (PyObject *self, PyObject *args) +{ + unsigned long pc; + char *soname; + PyObject *str_obj; + + if (!PyArg_ParseTuple (args, "k", &pc)) + return NULL; + + soname = solib_name_from_address (current_program_space, pc); + if (soname) + str_obj = PyString_Decode (soname, strlen (soname), host_charset (), NULL); + else + { + str_obj = Py_None; + Py_INCREF (Py_None); + } + + return str_obj; +} + +/* A Python function which is a wrapper for decode_line_1. */ + +static PyObject * +gdbpy_decode_line (PyObject *self, PyObject *args) +{ + struct symtabs_and_lines sals = { NULL, 0 }; /* Initialize to appease gcc. */ + struct symtab_and_line sal; + char *arg = NULL; + char *copy = NULL; + struct cleanup *cleanups; + PyObject *result = NULL; + PyObject *return_result = NULL; + PyObject *unparsed = NULL; + volatile struct gdb_exception except; + + if (! PyArg_ParseTuple (args, "|s", &arg)) + return NULL; + + cleanups = ensure_python_env (get_current_arch (), current_language); + + TRY_CATCH (except, RETURN_MASK_ALL) + { + if (arg) + { + arg = xstrdup (arg); + make_cleanup (xfree, arg); + copy = arg; + sals = decode_line_1 (©, 0, 0, 0, 0, 0); + make_cleanup (xfree, sals.sals); + } + else + { + set_default_source_symtab_and_line (); + sal = get_current_source_symtab_and_line (); + sals.sals = &sal; + sals.nelts = 1; + } + } + if (except.reason < 0) + { + do_cleanups (cleanups); + /* We know this will always throw. */ + GDB_PY_HANDLE_EXCEPTION (except); + } + + if (sals.nelts) + { + int i; + + result = PyTuple_New (sals.nelts); + if (! result) + goto error; + for (i = 0; i < sals.nelts; ++i) + { + PyObject *obj; + char *str; + + obj = symtab_and_line_to_sal_object (sals.sals[i]); + if (! obj) + { + Py_DECREF (result); + goto error; + } + + PyTuple_SetItem (result, i, obj); + } + } + else + { + result = Py_None; + Py_INCREF (Py_None); + } + + return_result = PyTuple_New (2); + if (! return_result) + { + Py_DECREF (result); + goto error; + } + + if (copy && strlen (copy) > 0) + unparsed = PyString_FromString (copy); + else + { + unparsed = Py_None; + Py_INCREF (Py_None); + } + + PyTuple_SetItem (return_result, 0, unparsed); + PyTuple_SetItem (return_result, 1, result); + + do_cleanups (cleanups); + + return return_result; + + error: + do_cleanups (cleanups); + return NULL; +} + /* Parse a string and evaluate it as an expression. */ static PyObject * gdbpy_parse_and_eval (PyObject *self, PyObject *args) @@ -864,6 +992,16 @@ a boolean indicating if name is a field of the current implied argument\n\ `this' (when the current language is object-oriented)." }, { "block_for_pc", gdbpy_block_for_pc, METH_VARARGS, "Return the block containing the given pc value, or None." }, + { "solib_name", gdbpy_solib_name, METH_VARARGS, + "solib_name (Long) -> String.\n\ +Return the name of the shared library holding a given address, or None." }, + { "decode_line", gdbpy_decode_line, METH_VARARGS, + "decode_line (String) -> Tuple. Decode a string argument the way\n\ +that 'break' or 'edit' does. Return a tuple containing two elements.\n\ +The first element contains any unparsed portion of the String parameter\n\ +(or None if the string was fully parsed). The second element contains\n\ +a tuple that contains all the locations that match, represented as\n\ +gdb.Symtab_and_line objects (or None)."}, { "parse_and_eval", gdbpy_parse_and_eval, METH_VARARGS, "parse_and_eval (String) -> Value.\n\ Parse String as an expression, evaluate it, and return the result as a Value." diff --git a/gdb/testsuite/gdb.python/python-sl.c b/gdb/testsuite/gdb.python/python-sl.c new file mode 100644 index 0000000..579a74e --- /dev/null +++ b/gdb/testsuite/gdb.python/python-sl.c @@ -0,0 +1,26 @@ +/* This testcase is part of GDB, the GNU debugger. + + Copyright 2010 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 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, see . */ + +void func1 () +{ + return; +} + +int func2 () +{ + return 0; +} diff --git a/gdb/testsuite/gdb.python/python.c b/gdb/testsuite/gdb.python/python.c new file mode 100644 index 0000000..750a90a --- /dev/null +++ b/gdb/testsuite/gdb.python/python.c @@ -0,0 +1,28 @@ +/* This testcase is part of GDB, the GNU debugger. + + Copyright 2010 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 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, see . */ + +/* Shared library function */ +extern void func1 (void); +extern int func2 (void); + +int +main (int argc, char *argv[]) +{ + func1 (); + func2 (); + return 0; /* Break to end. */ +} diff --git a/gdb/testsuite/gdb.python/python.exp b/gdb/testsuite/gdb.python/python.exp index d0e6c63..9c5bb6e 100644 --- a/gdb/testsuite/gdb.python/python.exp +++ b/gdb/testsuite/gdb.python/python.exp @@ -20,12 +20,44 @@ if $tracelevel then { strace $tracelevel } -# Start with a fresh gdb. +set testfile "python" +set srcfile ${testfile}.c +set libfile "python-sl" +set libsrc ${libfile}.c +set library ${objdir}/${subdir}/${libfile}.sl +set binfile ${objdir}/${subdir}/${testfile} + +if { [gdb_compile_shlib ${srcdir}/${subdir}/${libsrc} ${library} "debug"] != "" } { + untested "Could not compile shared library." + return -1 +} + +set exec_opts [list debug shlib=${library}] +if { [gdb_compile ${srcdir}/${subdir}/${srcfile} ${binfile} executable $exec_opts] != "" } { + untested "Could not compile $binfile." + return -1 +} + +# Start with a fresh gdb. gdb_exit gdb_start gdb_reinitialize_dir $srcdir/$subdir +# Skip all tests if Python scripting is not enabled. +if { [skip_python_tests] } { continue } + +# Run a command in GDB, and report a failure if a Python exception is thrown. +# If report_pass is true, report a pass if no exception is thrown. +proc gdb_py_test_silent_cmd {cmd name report_pass} { + global gdb_prompt + + gdb_test_multiple $cmd $name { + -re "Traceback.*$gdb_prompt $" { fail $name } + -re "$gdb_prompt $" { if $report_pass { pass $name } } + } +} + gdb_test_multiple "python print 23" "verify python support" { -re "not supported.*$gdb_prompt $" { unsupported "python support is disabled" @@ -87,3 +119,50 @@ gdb_test "python import itertools; print 'IMPOR'+'TED'" "IMPORTED" "pythonX.Y/li gdb_test_no_output \ "python x = gdb.execute('printf \"%d\", 23', to_string = True)" gdb_test "python print x" "23" + +# Start with a fresh gdb. +clean_restart ${testfile} + +# The following tests require execution. + +if ![runto_main] then { + fail "Can't run to main" + return 0 +} + +runto [gdb_get_line_number "Break to end."] + +# Test gdb.decode_line. +gdb_test "python gdb.decode_line(\"main.c:43\")" \ + "RuntimeError: No source file named main.c.*" "test decode_line no source named main" + +gdb_py_test_silent_cmd "python symtab = gdb.decode_line()" "test decode_line current location" 1 +gdb_test "python print len(symtab)" "2" "Test decode_line current location" +gdb_test "python print symtab\[0\]" "None" "Test decode_line expression parse" +gdb_test "python print len(symtab\[1\])" "1" "Test decode_line current location" +gdb_test "python print symtab\[1\]\[0\].symtab" "gdb/testsuite/gdb.python/python.c.*" "Test decode_line current locationn filename" +gdb_test "python print symtab\[1\]\[0\].line" "22" "Test decode_line current location line number" + +gdb_py_test_silent_cmd "python symtab = gdb.decode_line(\"python.c:26 if foo\")" "test decode_line python.c:26" 1 +gdb_test "python print len(symtab)" "2" "Test decode_line python.c:26 length" +gdb_test "python print symtab\[0\]" "if foo" "Test decode_line expression parse" +gdb_test "python print len(symtab\[1\])" "1" "Test decode_line python.c:26 length" +gdb_test "python print symtab\[1\]\[0\].symtab" "gdb/testsuite/gdb.python/python.c.*" "Test decode_line python.c:26 filename" +gdb_test "python print symtab\[1\]\[0\].line" "26" "Test decode_line python.c:26 line number" + +gdb_test "python gdb.decode_line(\"randomfunc\")" \ + "RuntimeError: Function \"randomfunc\" not defined.*" "test decode_line randomfunc" +gdb_py_test_silent_cmd "python symtab = gdb.decode_line(\"func1\")" "test decode_line func1()" 1 +gdb_test "python print len(symtab)" "2" "Test decode_line func1 length" +gdb_test "python print len(symtab\[1\])" "1" "Test decode_line func1 length" +gdb_test "python print symtab\[1\]\[0\].symtab" "gdb/testsuite/gdb.python/python-sl.c.*" "Test decode_line func1 filename" +gdb_test "python print symtab\[1\]\[0\].line" "19" "Test decode_line func1 line number" + +# Test gdb.solib_name +gdb_test "p &func1" "" "func1 address" +gdb_py_test_silent_cmd "python func1 = gdb.history(0)" "Aquire func1 address" 1 +gdb_test "python print gdb.solib_name(long(func1))" "gdb/testsuite/gdb.python/python-sl.sl" "test func1 solib location" + +gdb_test "p &main" "" "main address" +gdb_py_test_silent_cmd "python main = gdb.history(0)" "Aquire main address" 1 +gdb_test "python print gdb.solib_name(long(main))" "None" "test main solib location"