From patchwork Sun Aug 9 18:50:31 2015 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Doug Evans X-Patchwork-Id: 8099 Received: (qmail 15537 invoked by alias); 9 Aug 2015 18:50:37 -0000 Mailing-List: contact gdb-patches-help@sourceware.org; run by ezmlm Precedence: bulk List-Id: List-Unsubscribe: List-Subscribe: List-Archive: List-Post: List-Help: , Sender: gdb-patches-owner@sourceware.org Delivered-To: mailing list gdb-patches@sourceware.org Received: (qmail 15525 invoked by uid 89); 9 Aug 2015 18:50:36 -0000 Authentication-Results: sourceware.org; auth=none X-Virus-Found: No X-Spam-SWARE-Status: No, score=-1.3 required=5.0 tests=AWL, BAYES_50, MIME_BASE64_BLANKS, RCVD_IN_DNSWL_LOW, RP_MATCHES_RCVD, SPF_PASS autolearn=ham version=3.3.2 X-HELO: mail-pd0-f201.google.com Received: from mail-pd0-f201.google.com (HELO mail-pd0-f201.google.com) (209.85.192.201) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with (AES128-GCM-SHA256 encrypted) ESMTPS; Sun, 09 Aug 2015 18:50:33 +0000 Received: by pdav4 with SMTP id v4so12600193pda.0 for ; Sun, 09 Aug 2015 11:50:31 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20130820; h=x-gm-message-state:mime-version:message-id:date:subject:from:to :content-type:content-transfer-encoding; bh=8ynJXv5wy1kTgTaGGmxNQgbUy2bQh/Pjvr7WlO6CUJg=; b=ZRhth6FUJwinae+J/oaMeHKvhrY+eo+FYRpVybZ1VLZzihoGksjYh1ehQHpsnehyQM zKW/5s8iLxu1hPhOBy3WArhZZHReWOU9qS0312kvDuYchrSXmFvlck4rBur/a2PkKKK6 G3WE8a38pEzDZ9CoHe2pusXTEN+7EmCHLMJaJu/MxulISPaV7/F7PUPSXGC9kkK56AlE S+T79746iuIcjkQhosTeWiWB4vEN5Hf2x64lcrhoDWID5iHDSOZQuwsmHowXyNCvFXlM kApe2SVZMO91zOt1zeg9nAQyLYGgbf7xK6TrOqb/sVo4J7U+smy4/VcjQTait79hOIxz jsEg== X-Gm-Message-State: ALoCoQl2snruf8l7+mNbL/C7fj9V6lryEZgYeVi6phdYF/xfhnItY+yVbGNX1ZAxFx/00fLiZyOL1236W3fYaAtVyffkC33gFJtoKTqq1/80PFI/9HAgchMcE17ZSMpN4PZ7a7pEOFX9gpQhXqwrooBd00oF7eSNeWwghyDHOxk6cKqCoLUA+yk= MIME-Version: 1.0 X-Received: by 10.67.11.97 with SMTP id eh1mr6223167pad.16.1439146231846; Sun, 09 Aug 2015 11:50:31 -0700 (PDT) Message-ID: <047d7b15b28fee2e17051ce557fd@google.com> Date: Sun, 09 Aug 2015 18:50:31 +0000 Subject: [PATCH, doc RFA] New feature: extension language post-initializers From: Doug Evans To: gdb-patches@sourceware.org, eliz@gnu.org X-IsSubscribed: yes Hi. I have a need to run some python code from system.gdbinit after options -ix, -iex, -cd are processed and before the inferior program is loaded. Regression tested on amd64-linux. 2015-08-09 Doug Evans * NEWS: Document new post-initializer support for Python. * extension-priv.h (extension_language_ops) : New member. * extension.c (post_ext_lang_initialization): New function. * extension.h (post_ext_lang_initialization): Declare. * main.c: #include "extension.h". (captured_main): Call post_ext_lang_initialization. * python/lib/gdb/__init__.py (post_initializers): Define. * python/python.c (python_extension_ops): Update. (gdbpy_post_initialization): New function. * guile/guile.c (guile_extension_ops): Update. doc/ * python.texi (Python API): Add entry for Startup Post-Initialization. (Startup Post-Initialization): New node. testsuite/ * gdb.python/py-post-init.c: New file. * gdb.python/py-post-init.exp: New file. * gdb.python/py-post-init.py: New file. diff --git a/gdb/NEWS b/gdb/NEWS index 3fe6036..a8d1bff 100644 --- a/gdb/NEWS +++ b/gdb/NEWS @@ -3,6 +3,11 @@ *** Changes since GDB 7.10 +* Python Scripting + + ** Python code can now be run after -ix/-iex processing and before any + program is loaded by appending functions to gdb.post_initializers. + * Support for tracepoints on aarch64-linux was added in GDBserver. * The 'record instruction-history' command now indicates speculative execution diff --git a/gdb/doc/python.texi b/gdb/doc/python.texi index a2df254..d9e68a8 100644 --- a/gdb/doc/python.texi +++ b/gdb/doc/python.texi @@ -135,6 +135,7 @@ optional arguments while skipping others. Example: @menu * Basic Python:: Basic Python Functions. * Exception Handling:: How Python exceptions are translated. +* Startup Post-Initialization:: Running python at the end of GDB startup. * Values From Inferior:: Python representation of values. * Types In Python:: Python representation of types. * Pretty Printing API:: Pretty-printing values. @@ -512,6 +513,48 @@ to handle this case. Example: hello-world takes no arguments @end smallexample +@node Startup Post-Initialization +@subsubsection Startup Post-Initialization +@cindex running python at the end of GDB startup + +@value{GDBN} provides a way to run Python code at the end of startup, +after @code{-iex}, @code{-ix}, and @code{-cd} option processing, +and before it loads any specified program. +Such initialization may depend on various startup options thus we want +to defer it until after all such options are processed. + +The Python list @code{gdb.post_initializers} contains an array of +functions or callable objects that have been registered. +Registration is done via appending to the list. + +As an example, suppose the @file{system.gdbinit} file provides a set of +features that are loaded, if present, from the current directory. +The features must be loaded before the program is loaded, +and must take into account the @code{-cd} option. +Thus loading must be delayed until after processing the @code{-cd} +option but before the inferior program is loaded. +This is achieved with a ``post-initializer'' function. +The function is registered by @file{system.gdbinit} and is called +at the correct time by @value{GDBN}. + +Here is a small example: + +@smallexample +$ cd $HOME +$ cat post-init.py +def post_init(): + print "Hi, this is post_init." + gdb.execute("pwd") +import gdb +gdb.post_initializers.append(post_init) +$ gdb -quiet -cd /tmp -iex pwd -ix post-init.py $HOME/myprogram +Working directory /home/user. +Hi, this is post_init. +Working directory /tmp. +Reading symbols from /home/user/myprogram...done. +(gdb) +@end smallexample + @node Values From Inferior @subsubsection Values From Inferior @cindex values from inferior, with Python diff --git a/gdb/extension-priv.h b/gdb/extension-priv.h index d0242e2..b785432 100644 --- a/gdb/extension-priv.h +++ b/gdb/extension-priv.h @@ -136,6 +136,10 @@ struct extension_language_ops This method is required. */ int (*initialized) (const struct extension_language_defn *); + /* Called after -iex, -ix, -cd and -d options are processed to perform + any final user-specified initialization prior to loading the binary. */ + void (*post_initialization) (const struct extension_language_defn *); + /* Process a sequence of commands embedded in GDB's own scripting language. E.g., python diff --git a/gdb/extension.c b/gdb/extension.c index dac203b..bd7eea0 100644 --- a/gdb/extension.c +++ b/gdb/extension.c @@ -337,6 +337,22 @@ finish_ext_lang_initialization (void) } } +/* Wrapper to call the extension_language_ops.post_initialization "method" + for each compiled-in extension language. */ + +void +post_ext_lang_initialization (void) +{ + int i; + const struct extension_language_defn *extlang; + + ALL_ENABLED_EXTENSION_LANGUAGES (i, extlang) + { + if (extlang->ops->post_initialization != NULL) + extlang->ops->post_initialization (extlang); + } +} + /* Invoke the appropriate extension_language_ops.eval_from_control_command method to perform CMD, which is a list of commands in an extension language. diff --git a/gdb/extension.h b/gdb/extension.h index ea30035..7f9ac7a 100644 --- a/gdb/extension.h +++ b/gdb/extension.h @@ -213,6 +213,8 @@ extern int ext_lang_auto_load_enabled (const struct extension_language_defn *); extern void finish_ext_lang_initialization (void); +extern void post_ext_lang_initialization (void); + extern void eval_ext_lang_from_control_command (struct command_line *cmd); extern void auto_load_ext_lang_scripts_for_objfile (struct objfile *); diff --git a/gdb/guile/guile.c b/gdb/guile/guile.c index 4abf5c5..dbb2836 100644 --- a/gdb/guile/guile.c +++ b/gdb/guile/guile.c @@ -138,6 +138,7 @@ const struct extension_language_ops guile_extension_ops = { gdbscm_finish_initialization, gdbscm_initialized, + NULL, /* gdbscm_post_initialization */ gdbscm_eval_from_control_command, diff --git a/gdb/main.c b/gdb/main.c index aecd60a..084a1f5 100644 --- a/gdb/main.c +++ b/gdb/main.c @@ -44,6 +44,7 @@ #include #include "event-top.h" #include "infrun.h" +#include "extension.h" /* The selected interpreter. This will be used as a set command variable, so it should always be malloc'ed - since @@ -1035,6 +1036,12 @@ captured_main (void *data) catch_command_errors (directory_switch, dirarg[i], 0); xfree (dirarg); + /* We're about to load the program (if specified). + Given extension languages a chance to do any final preprocessing, + after -ix, -iex, -cd, and -d parameters are processed, and prior to + the program being loaded. */ + post_ext_lang_initialization (); + /* Skip auto-loading section-specified scripts until we've sourced local_gdbinit (which is often used to augment the source search path). */ diff --git a/gdb/python/lib/gdb/__init__.py b/gdb/python/lib/gdb/__init__.py index 81789e5..03f9b18 100644 --- a/gdb/python/lib/gdb/__init__.py +++ b/gdb/python/lib/gdb/__init__.py @@ -62,6 +62,9 @@ prompt_hook = None # We do not use PySys_SetArgvEx because it did not appear until 2.6.6. sys.argv = [''] +# Initial post-initializers. +post_initializers = [] + # Initial pretty printers. pretty_printers = [] diff --git a/gdb/python/python.c b/gdb/python/python.c index 4f88b0e..7c839b9 100644 --- a/gdb/python/python.c +++ b/gdb/python/python.c @@ -135,6 +135,8 @@ static objfile_script_executor_func gdbpy_execute_objfile_script; static void gdbpy_finish_initialization (const struct extension_language_defn *); static int gdbpy_initialized (const struct extension_language_defn *); +static void gdbpy_post_initialization + (const struct extension_language_defn *); static void gdbpy_eval_from_control_command (const struct extension_language_defn *, struct command_line *cmd); static void gdbpy_start_type_printers (const struct extension_language_defn *, @@ -166,6 +168,7 @@ const struct extension_language_ops python_extension_ops = { gdbpy_finish_initialization, gdbpy_initialized, + gdbpy_post_initialization, gdbpy_eval_from_control_command, @@ -1967,6 +1970,54 @@ gdbpy_initialized (const struct extension_language_defn *extlang) return gdb_python_initialized; } +/* Called after -iex, -ix, -cd and -d options are processed to perform + any final user-specified initialization prior to loading the binary. */ + +static void +gdbpy_post_initialization (const struct extension_language_defn *extlang) +{ + PyObject *pi_list, *function, *result; + Py_ssize_t pi_list_size, list_index; + struct cleanup *cleanup; + + cleanup = ensure_python_env (get_current_arch (), current_language); + + /* Fetch the global post-initializer list. */ + if (gdb_python_module == NULL + || ! PyObject_HasAttrString (gdb_python_module, "post_initializers")) + { + do_cleanups (cleanup); + return; + } + pi_list = PyObject_GetAttrString (gdb_python_module, "post_initializers"); + if (pi_list == NULL || ! PyList_Check (pi_list)) + { + Py_XDECREF (pi_list); + do_cleanups (cleanup); + return; + } + + pi_list_size = PyList_Size (pi_list); + for (list_index = 0; list_index < pi_list_size; list_index++) + { + function = PyList_GetItem (pi_list, list_index); + result = NULL; + if (function != NULL) + result = PyObject_CallFunctionObjArgs (function, NULL); + if (result == NULL) + { + /* Print the trace here, but keep going -- we want to + call all of the callbacks even if one is broken. */ + gdbpy_print_stack (); + } + Py_XDECREF (function); + Py_XDECREF (result); + } + + Py_DECREF (pi_list); + do_cleanups (cleanup); +} + #endif /* HAVE_PYTHON */ diff --git a/gdb/testsuite/gdb.python/py-post-init.c b/gdb/testsuite/gdb.python/py-post-init.c new file mode 100644 index 0000000..d4206cb --- /dev/null +++ b/gdb/testsuite/gdb.python/py-post-init.c @@ -0,0 +1,22 @@ +/* This testcase is part of GDB, the GNU debugger. + + Copyright 2015 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 . */ + +int +main () +{ + return 0; +} diff --git a/gdb/testsuite/gdb.python/py-post-init.exp b/gdb/testsuite/gdb.python/py-post-init.exp new file mode 100644 index 0000000..5b575af --- /dev/null +++ b/gdb/testsuite/gdb.python/py-post-init.exp @@ -0,0 +1,58 @@ +# Copyright (C) 2015 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 . + +# This file is part of the GDB testsuite. It tests the post_initializers +# mechanism. + +load_lib gdb-python.exp + +standard_testfile + +if {[build_executable ${testfile}.exp ${testfile} ${srcfile} debug] == -1} { + return -1 +} + +# Start with a fresh gdb. +gdb_exit +gdb_start + +# Skip all tests if Python scripting is not enabled. +# Note that this requires a running gdb. +if { [skip_python_tests] } { continue } + +gdb_exit + +# Make the program and python scripts available to gdb +# (in case it is remote). +set program_file \ + [gdb_remote_download host ${binfile}] +set post_init_script \ + [gdb_remote_download host ${srcdir}/${subdir}/${testfile}.py] + +# We want to pass the program to gdb at startup so that we can test that +# post_init functions are called after -iex options (and -ix and others) +# and before the program is loaded by gdb. + +set options "--ix ${post_init_script}" +append options " -iex \"py post_init_test = 0\"" +append options " ${program_file}" +set res [gdb_spawn_with_cmdline_opts $options] +set test "starting with post-init script" +gdb_test_multiple "" $test { + -re "Hi, I'm post_init.*Reading symbols from.*$gdb_prompt $" { + pass "$test" + } +} +gdb_test "py print post_init_test" "10" diff --git a/gdb/testsuite/gdb.python/py-post-init.py b/gdb/testsuite/gdb.python/py-post-init.py new file mode 100644 index 0000000..013aa8e --- /dev/null +++ b/gdb/testsuite/gdb.python/py-post-init.py @@ -0,0 +1,23 @@ +# Copyright (C) 2015 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 . + +import gdb + +def post_init(): + print "Hi, I'm post_init." + global post_init_test + post_init_test += 10 + +gdb.post_initializers.append(post_init)