From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 25347 invoked by alias); 29 Mar 2011 08:22:23 -0000 Received: (qmail 25328 invoked by uid 22791); 29 Mar 2011 08:22:17 -0000 X-SWARE-Spam-Status: No, hits=-1.5 required=5.0 tests=AWL,BAYES_00,DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,FREEMAIL_FROM,RCVD_IN_DNSWL_LOW,TW_BJ X-Spam-Check-By: sourceware.org Received: from mail-vw0-f41.google.com (HELO mail-vw0-f41.google.com) (209.85.212.41) by sourceware.org (qpsmtpd/0.43rc1) with ESMTP; Tue, 29 Mar 2011 08:22:10 +0000 Received: by vws4 with SMTP id 4so3829218vws.0 for ; Tue, 29 Mar 2011 01:22:09 -0700 (PDT) Received: by 10.220.178.139 with SMTP id bm11mr1413207vcb.62.1301386929122; Tue, 29 Mar 2011 01:22:09 -0700 (PDT) MIME-Version: 1.0 Received: by 10.220.200.3 with HTTP; Tue, 29 Mar 2011 01:21:49 -0700 (PDT) In-Reply-To: References: From: Kevin Pouget Date: Tue, 29 Mar 2011 11:11:00 -0000 Message-ID: Subject: Re: [RFC - Python] New ObjFile event To: Tom Tromey Cc: gdb-patches@sourceware.org Content-Type: text/plain; charset=ISO-8859-1 Content-Transfer-Encoding: quoted-printable 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: 2011-03/txt/msg01163.txt.bz2 Hello, > Do you have copyright assignment paperwork in place? =A0If not, let me > know and I can get you started. =A0This is a requirement before we can > accept a non-trivial patch. No, not yet, what I am supposed to ? > Kevin> and, likewise, allows Python's "gdb.current_objfile ()" to return > Kevin> the current object file. > > I'm ambivalent about this part. > > It seems to me that the objfile should be an attribute of the event. > Also setting it globally is ok, if you really want that, but it isn't a > necessity. I was ambivalent about this point too; I chose "gdb.current_objfile ()" because autoloading (http://sourceware.org/gdb/current/onlinedocs/gdb/Auto_002dloading.html) already does it this way, and the two features are pretty similar. I felt that it would have been strange to access "gdb.current_objfile ()" in one case, and sth like "event.new_objfile" in the other case let me know if you agree with this perspective; it wouldn't be a big deal to flip to the other solution otherwise > Kevin> There is still one thing I'm not happy with in the code, it's how = to > Kevin> 'properly' access "gdbpy_current_objfile" ? I commented out "stati= c" > Kevin> and declared it "extern" when I needed it, but that's certainly not > Kevin> the best way: > > Dropping the `static' is ok. =A0GDB is already full of this kind of thing. > > Kevin> +extern struct objfile *gdbpy_current_objfile; > > Should be in python-internal.h. fixed > Kevin> +static void > Kevin> +python_new_objfile (struct objfile *objfile) > > New functions need an introductory comment. > > Kevin> + =A0/* Will be NULL when clearing the symtab. */ > Kevin> + =A0if (objfile) > Kevin> + =A0 =A0cleanup =3D ensure_python_env (get_objfile_arch (objfile)= , current_language); > > Is this comment stale? =A0It doesn't seem relevant. =A0When can objfile= =3D=3DNULL? I've been _once_ notified with NULL objfiles, coming from >> gdb/symfile.c:clear_symtab_users "observer_notify_new_objfile (NULL);" that's why I added the null-checking, but I didn't investigate what's behind this 'clear_symtab_users' and assumed 'observer_notify_new_objfile (NULL)' justifies the verification by itself is it okay for you? > Kevin> - > Kevin> + =A0observer_attach_new_objfile (python_new_objfile); > Kevin> + > > Gratuitous whitespace change. removed > Kevin> int > Kevin> emit_new_objfile_event (struct objfile *objfile) > Kevin> { > Kevin> =A0 PyObject *event; > [...] > Kevin> =A0 event =3D create_new_objfile_event_object (); > Kevin> =A0 if (event) > Kevin> =A0 =A0 return evpy_emit_event (event, gdb_py_events.newobjfile); > Kevin> =A0 return -1; > > I think this should attach the objfile to the event object. that's discussed above, I'm waiting for your point of view * I added to the patch a few lines of documentation and updated the python event test-case. The exec is now linked with a shared-library automatically created, so that we know that the new objfile observers have to be notified. I'm not 100% confident about the test-case protocol, please don't hesitate to tell me if it's not resilient enough * I don't know how to add gdb/python/py-newobjfileevent.c and gdb/testsuite/gdb.python/py-events-shlib.c to the CVS diff, I'll move to git today so it should be fixed for the next patchs I send ; they are at the bottom of the mail, separated with '----' * I don't know if there is an 'automatic' way to update the ChangeLog (based on CVS/GIT), or if I should do it manually ? Cheers, Kevin ---- ? gdb/python/py-newobjfileevent.c ? gdb/testsuite/gdb.python/py-events-shlib.c Index: gdb/Makefile.in =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D RCS file: /cvs/src/src/gdb/Makefile.in,v retrieving revision 1.1163 diff -u -r1.1163 Makefile.in --- gdb/Makefile.in 9 Mar 2011 06:10:37 -0000 1.1163 +++ gdb/Makefile.in 29 Mar 2011 08:08:41 -0000 @@ -296,7 +296,8 @@ py-threadevent.o \ py-type.o \ py-utils.o \ - py-value.o + py-value.o \ + py-newobjfileevent.o SUBDIR_PYTHON_SRCS =3D \ python/python.c \ @@ -326,7 +327,8 @@ python/py-threadevent.c \ python/py-type.c \ python/py-utils.c \ - python/py-value.c + python/py-value.c \ + python/py-newobjfileevent.c SUBDIR_PYTHON_DEPS =3D SUBDIR_PYTHON_LDFLAGS=3D SUBDIR_PYTHON_CFLAGS=3D @@ -2110,6 +2112,11 @@ $(COMPILE) $(PYTHON_CFLAGS) $(srcdir)/python/py-value.c $(POSTCOMPILE) +py-newobjfileevent.o: $(srcdir)/python/py-newobjfileevent.c + $(COMPILE) $(PYTHON_CFLAGS) $(srcdir)/python/py-newobjfileevent.c + $(POSTCOMPILE) + + # # Dependency tracking. Most of this is conditional on GNU Make being # found by configure; if GNU Make is not found, we fall back to a Index: gdb/doc/gdb.texinfo =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D RCS file: /cvs/src/src/gdb/doc/gdb.texinfo,v retrieving revision 1.814 diff -u -r1.814 gdb.texinfo --- gdb/doc/gdb.texinfo 18 Mar 2011 08:44:46 -0000 1.814 +++ gdb/doc/gdb.texinfo 29 Mar 2011 08:08:45 -0000 @@ -22054,6 +22054,12 @@ This event indicates that the inferior or one of its threads has received = as signal. @code{gdb.SignalEvent} has the following attributes: +@item events.newobjfile +Emits @code{gdb.NewObjFileEvent} which indicates that a new object-file has +been loaded in the inferior. + +During the callback, ``current objfile'' will be set to the new object fil= e. + @table @code @defivar SignalEvent stop_signal A string representing the signal received by the inferior. A list of poss= ible @@ -22696,10 +22702,10 @@ @findex gdb.current_objfile @defun current_objfile -When auto-loading a Python script (@pxref{Auto-loading}), @value{GDBN} -sets the ``current objfile'' to the corresponding objfile. This -function returns the current objfile. If there is no current objfile, -this function returns @code{None}. +When auto-loading a Python script (@pxref{Auto-loading}) and during new +object-file callbacks, @value{GDBN} sets the ``current objfile'' to the +corresponding objfile. This function returns the current objfile. If +there is no current objfile, this function returns @code{None}. @end defun @findex gdb.objfiles Index: gdb/python/py-event.h =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D RCS file: /cvs/src/src/gdb/python/py-event.h,v retrieving revision 1.1 diff -u -r1.1 py-event.h --- gdb/python/py-event.h 5 Feb 2011 05:27:23 -0000 1.1 +++ gdb/python/py-event.h 29 Mar 2011 08:08:46 -0000 @@ -105,6 +105,7 @@ extern int emit_continue_event (ptid_t ptid); extern int emit_exited_event (LONGEST exit_code); +extern int emit_new_objfile_event (struct objfile *objfile); extern int evpy_emit_event (PyObject *event, eventregistry_object *registry); Index: gdb/python/py-events.h =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D RCS file: /cvs/src/src/gdb/python/py-events.h,v retrieving revision 1.1 diff -u -r1.1 py-events.h --- gdb/python/py-events.h 5 Feb 2011 05:27:23 -0000 1.1 +++ gdb/python/py-events.h 29 Mar 2011 08:08:46 -0000 @@ -45,6 +45,7 @@ eventregistry_object *stop; eventregistry_object *cont; eventregistry_object *exited; + eventregistry_object *newobjfile; PyObject *module; Index: gdb/python/py-evts.c =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D RCS file: /cvs/src/src/gdb/python/py-evts.c,v retrieving revision 1.2 diff -u -r1.2 py-evts.c --- gdb/python/py-evts.c 14 Mar 2011 15:43:51 -0000 1.2 +++ gdb/python/py-evts.c 29 Mar 2011 08:08:46 -0000 @@ -57,6 +57,9 @@ if (add_new_registry (&gdb_py_events.exited, "exited") < 0) goto fail; + + if (add_new_registry (&gdb_py_events.newobjfile, "newobjfile") < 0) + goto fail; Py_INCREF (gdb_py_events.module); if (PyModule_AddObject (gdb_module, Index: gdb/python/py-inferior.c =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D RCS file: /cvs/src/src/gdb/python/py-inferior.c,v retrieving revision 1.7 diff -u -r1.7 py-inferior.c --- gdb/python/py-inferior.c 17 Mar 2011 09:36:16 -0000 1.7 +++ gdb/python/py-inferior.c 29 Mar 2011 08:08:46 -0000 @@ -22,6 +22,7 @@ #include "gdbcore.h" #include "gdbthread.h" #include "inferior.h" +#include "objfiles.h" #include "observer.h" #include "python-internal.h" #include "arch-utils.h" @@ -129,6 +130,31 @@ do_cleanups (cleanup); } +/* Callback used to notify Python listeners about new objfiles loaded in t= he + inferior. Python global variable 'gdb.current_objfile ()' will be set + during the notifications. + */ + +static void +python_new_objfile (struct objfile *objfile) +{ + struct cleanup *cleanup; + + /* Will be NULL when clearing the symtab. */ + if (objfile) + cleanup =3D ensure_python_env (get_objfile_arch (objfile), current_lan= guage); + else + cleanup =3D ensure_python_env (get_current_arch (), current_language); + + gdbpy_current_objfile =3D objfile; + + if (emit_new_objfile_event (objfile) < 0) + gdbpy_print_stack (); + + do_cleanups (cleanup); + gdbpy_current_objfile =3D NULL; +} + /* Return a borrowed reference to the Python object of type Inferior representing INFERIOR. If the object has already been created, return it, otherwise, create it. Return NULL on failure. */ @@ -669,6 +695,7 @@ observer_attach_normal_stop (python_on_normal_stop); observer_attach_target_resumed (python_on_resume); observer_attach_inferior_exit (python_inferior_exit); + observer_attach_new_objfile (python_new_objfile); if (PyType_Ready (&membuf_object_type) < 0) return; Index: gdb/python/python-internal.h =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D RCS file: /cvs/src/src/gdb/python/python-internal.h,v retrieving revision 1.44 diff -u -r1.44 python-internal.h --- gdb/python/python-internal.h 28 Feb 2011 19:38:34 -0000 1.44 +++ gdb/python/python-internal.h 29 Mar 2011 08:08:46 -0000 @@ -207,6 +207,7 @@ void gdbpy_initialize_continue_event (void); void gdbpy_initialize_exited_event (void); void gdbpy_initialize_thread_event (void); +void gdbpy_initialize_new_objfile_event (void); struct cleanup *make_cleanup_py_decref (PyObject *py); @@ -215,6 +216,7 @@ extern struct gdbarch *python_gdbarch; extern const struct language_defn *python_language; +extern struct objfile *gdbpy_current_objfile; /* Use this after a TRY_EXCEPT to throw the appropriate Python exception. */ Index: gdb/python/python.c =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D RCS file: /cvs/src/src/gdb/python/python.c,v retrieving revision 1.63 diff -u -r1.63 python.c --- gdb/python/python.c 18 Mar 2011 08:44:47 -0000 1.63 +++ gdb/python/python.c 29 Mar 2011 08:08:46 -0000 @@ -811,8 +811,9 @@ /* The "current" objfile. This is set when gdb detects that a new objfile has been loaded. It is only set for the duration of a call to - source_python_script_for_objfile; it is NULL at other times. */ -static struct objfile *gdbpy_current_objfile; + source_python_script_for_objfile and new_objfile callbacks; it is NULL = at + other times. */ +struct objfile *gdbpy_current_objfile; /* Set the current objfile to OBJFILE and then read STREAM,FILE as Python code. */ @@ -1074,6 +1075,7 @@ gdbpy_initialize_continue_event (); gdbpy_initialize_exited_event (); gdbpy_initialize_thread_event (); + gdbpy_initialize_new_objfile_event () ; PyRun_SimpleString ("import gdb"); PyRun_SimpleString ("gdb.pretty_printers =3D []"); Index: gdb/testsuite/gdb.python/py-events.c =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D RCS file: /cvs/src/src/gdb/testsuite/gdb.python/py-events.c,v retrieving revision 1.1 diff -u -r1.1 py-events.c --- gdb/testsuite/gdb.python/py-events.c 5 Feb 2011 05:27:23 -0000 1.1 +++ gdb/testsuite/gdb.python/py-events.c 29 Mar 2011 08:08:46 -0000 @@ -16,6 +16,8 @@ along with this program. If not, see . */ +extern void do_nothing (void) ; + int second(){ return 12; } @@ -25,5 +27,6 @@ } int main (){ + do_nothing() ; return first(); } Index: gdb/testsuite/gdb.python/py-events.exp =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D RCS file: /cvs/src/src/gdb/testsuite/gdb.python/py-events.exp,v retrieving revision 1.1 diff -u -r1.1 py-events.exp --- gdb/testsuite/gdb.python/py-events.exp 5 Feb 2011 05:27:23 -0000 1.1 +++ gdb/testsuite/gdb.python/py-events.exp 29 Mar 2011 08:08:46 -0000 @@ -24,23 +24,45 @@ load_lib gdb-python.exp +set libfile "py-events-shlib" +set libsrc $srcdir/$subdir/$libfile.c +set lib_sl $objdir/$subdir/$libfile.so +set lib_opts debug + set testfile "py-events" set srcfile ${testfile}.c set binfile ${objdir}/${subdir}/${testfile} +set exec_opts [list debug shlib=3D$lib_sl] set pyfile ${srcdir}/${subdir}/${testfile}.py -if { [prepare_for_testing ${testfile}.exp ${testfile} ${srcfile}] } { +if [get_compiler_info ${binfile}] { + return -1 +} + +if { [gdb_compile_shlib $libsrc $lib_sl $lib_opts] !=3D "" + || [gdb_compile $srcdir/$subdir/$srcfile $binfile executable $exec_opts] !=3D ""} { + untested "Could not compile either $libsrc or $srcdir/$subdir/$srcfile= ." return -1 } +# Start with a fresh gdb. + +gdb_exit +gdb_start + if { [skip_python_tests] } { continue } +gdb_reinitialize_dir $srcdir/$subdir +gdb_load ${binfile} + gdb_test_no_output "python execfile ('${pyfile}')" "" -if ![runto_main ] then { - fail "Can't run to main" - return -1 -} +gdb_test "Test_Newobj_Events" "New ObjectFile Event tester registered." + +gdb_breakpoint "main" {temporary} + +gdb_test "run" ".*event type: new_objfile.* +.*new objfile name.*" gdb_test "Test_Events" "Event testers registered." Index: gdb/testsuite/gdb.python/py-events.py =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D RCS file: /cvs/src/src/gdb/testsuite/gdb.python/py-events.py,v retrieving revision 1.1 diff -u -r1.1 py-events.py --- gdb/testsuite/gdb.python/py-events.py 5 Feb 2011 05:27:23 -0000 1.1 +++ gdb/testsuite/gdb.python/py-events.py 29 Mar 2011 08:08:46 -0000 @@ -48,6 +48,14 @@ if ( event.inferior_thread is not None) : print "thread num: %s" % (event.inferior_thread.num); +def new_objfile_handler (event): + if (isinstance (event, gdb.NewObjFileEvent)): + print "event type: new_objfile" + if (gdb.current_objfile () is not None): + print "new objfile name: %s" % (gdb.current_objfile ().filename) + else: + print "new objfile is None" + class test_events (gdb.Command): """Test events.""" @@ -62,3 +70,15 @@ print "Event testers registered." test_events () + +class test_newobj_events (gdb.Command): + """NewObj events.""" + + def __init__ (self): + gdb.Command.__init__ (self, "test_newobj_events", gdb.COMMAND_STAC= K) + + def invoke (self, arg, from_tty): + gdb.events.newobjfile.connect (new_objfile_handler) + print "New ObjectFile Event tester registered." + +test_newobj_events () ---- /* Python interface to new object file loading events. Copyright (C) 2011 Free Software Foundation, Inc. This file is part of GDB. 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 . */ #include "py-event.h" static PyTypeObject new_objfile_event_object_type; PyObject * create_new_objfile_event_object (void) { return create_event_object (&new_objfile_event_object_type); } /* Callback function which notifies observers when a new objfile event occu= rs. This function will create a new Python new_objfile event object. Return -1 if emit fails. */ int emit_new_objfile_event (struct objfile *objfile) { PyObject *event; if (evregpy_no_listeners_p (gdb_py_events.newobjfile)) return 0; event =3D create_new_objfile_event_object (); if (event) return evpy_emit_event (event, gdb_py_events.newobjfile); return -1; } GDBPY_NEW_EVENT_TYPE (new_objfile, "gdb.NewObjFileEvent", "NewObjFileEvent", "GDB new object file event object", event_object_type, static); ---- /* This testcase is part of GDB, the GNU debugger. Copyright 2011 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 do_nothing (void) {}