libGDB architecture - events

Andrew Cagney ac131313@cygnus.com
Thu Aug 26 03:06:00 GMT 1999


Andrew Cagney wrote:

> Event notify
> ------------
> 
>    The next component is the notify mechanism.  When GDB determines
> that a significant event has occurred (memory changed, breakpoint
> changed, target started, target stopped) it advises the target using a
> notify call.
> 
>    For each "object" that GDB can represent symbolically, there is
> notify mechanism that allows GDB to inform the UI that information has
> been invalidated.  The exact mechanism used depends on the type of data
> involved.
> 
>    For instance, looking at the existing GDB CLI:
> 
>      (gdb) disable 1
>      (gdb) info breakpoint
>      Num Type           Disp Enb Address    What
>      1   breakpoint     keep n   0x0000003d in main at hello.c:3
>              breakpoint already hit 1 time
> 
>    After the command `disable 1' has been issued, GDB's internal state
> of breakpoint has been changed.  Consequently, as part of updating the
> breakpoint internal state, libGDB would notify the client that the
> breakpoints state has changed.  The client could then query libGDB for
> the new breakpoint state.

[...]

> Notify
> ======
> 
>    The notify mechanism is based on the hook system already provided to
> GDBtk.  The mechanism would need to be formalized (`gdb-hooks.[hc]')
> (say).
> 
>    The set of notify hooks would be expected to evolve over time as the
> needs of the clients are better understood.

To make this part more tangable I've attached a jumbo patch that
contains a simplified implementation of the event code.  I'll try to
summarize the points of interest below. The patch results in a CLI-GDB
that can be played with.


gdb-events.h/gdb-events.c:

It only handles breakpoints.  It also went slightly overboard and threw
in a simplistic event-queueing mechanism so that I could delay the event
delivery until later (gdb_events_deliver()) :-)

The breakpoint is identified to the client using a breakpoint number and
_not_ GDB's internal breakpoint struct:
    typedef void (gdb_events_breakpoint_create_ftype) (int b);
As a BTW, the old GDBtk had the full breakpoint passed to it.  This
isn't being done here.  The intention is to clearly separate the client
from the server and avoid the risk of the client getting its dirty
little fingers in where it shouldn't.  In addition, since the a pointer
to an internal struct ment that it had to be processed immediatly (think
about the breakpoint delete event :-).

A more fancy event delivery mechanism might do things like merge
duplicate and redundant events (ex: a create followed by a delete).


breakpoints.c:

I've split breakpoint_1() into:
	breakpoint_1() - does just one breakpoint
	breakpoint_n() - does up to N breakpoints
	gdb_ops_breakpoint() - example-only not indicative
		of the real lib-gdb
The client is able to use gdb_ops_breakpoint() (parameterized here with
both the breakpoint number and a `struct gdb_file') to ``collect'' the
result of the query.  As noted in the proposal the real code would have
a more fancy builder.  The idea is however, the same.  (Mumble something
about error handling, this was example only).


event-loop.c:

Hack, hack, hack....
The command line event loop (sorry Elena) has been attacked and a call
to deliver any outdanding events (gdb_events_deliver()) added.  In this
example, the details of a changed/modified breakpoint are displayed
after being retreived from GDB using gdb_ops_breakpoint().


Looking at an example interaction with a patched GDB:

cagney@b1.cygnus.com$ ./gdb/gdb ~/tmp/hello.mn103 
GNU gdb 19990823
Copyright 1998 Free Software Foundation, Inc.
GDB is free software, covered by the GNU General Public License, and you
are
welcome to change it and/or distribute copies of it under certain
conditions.
Type "show copying" to see the conditions.
There is absolutely no warranty for GDB.  Type "show warranty" for
details.
This GDB was configured as "--host=i386-unknown-freebsdelf3.2
--target=mn10300-elf"...
(gdb) target sim
Connected to the simulator.
(gdb) load
Loading section .text, size 0xcb2 lma 0x0
Loading section .rodata, size 0x29 lma 0xcb2
Loading section .data, size 0x738 lma 0xcdc
Start address 0x0
Transfer rate: 41112 bits in <1 sec.

To make life easier we can watch the event queue in action (Mumble
something about how ``set debug events 1'' would be nice :-):

(gdb) set eventdebug 1

We set a breakpoint.  Gdb reports ``Breakpoint 1 at 0x3d: file hello.c,
line 3.'' which is incomplete information, fortunatly a
breakpoint-create event was queued.  Once the command has finished
(indicated by the ``(gdb) '' prompt) the pending events are processed. 
In the example below the *full* breakpoint details are displayed on the
screen.  A real GUI client might do something more intelegent like pump
the up-dated information into an internal data structure.

  (gdb) b main
  breakpoint_create_event
  Breakpoint 1 at 0x3d: file hello.c, line 3.
  (gdb) Breapoint create: 1   breakpoint     keep y   0x0000003d in main
at hello.c:3

Continuing with our example.  The breakpoint is deleted.  The
``-1077949100 '' is bogus.  In the attached version ``1'' is printed. 
(Mumble something about needing to get builds with -Werror -Wformat
working - printf with missing argument :-)

  delete 1
  breakpoint_delete_event
  (gdb) Breapoint delete: Breakpoint -1077949100 deleted

A second breakpoint is then created and modified.  At each stage.  After
the command has been processed, the up-to-date breakpoint details are
reported.

  b main
  breakpoint_create_event
  Breakpoint 2 at 0x3d: file hello.c, line 3.
  (gdb) Breapoint create: 2   breakpoint     keep y   0x0000003d in main
at hello.c:3
  disable 2
  breakpoint_modify_event
  (gdb) 2   breakpoint     keep n   0x0000003d in main at hello.c:3
  quit

	Andrew
Index: Makefile.in
===================================================================
RCS file: /cvs/gdb/gdb/gdb/Makefile.in,v
retrieving revision 1.1.1.20
diff -p -r1.1.1.20 Makefile.in
*** Makefile.in	1999/08/23 22:34:45	1.1.1.20
--- Makefile.in	1999/08/26 09:13:14
*************** COMMON_OBS = version.o blockframe.o brea
*** 510,515 ****
--- 510,516 ----
  	gdbarch.o gdbtypes.o copying.o $(DEPFILES) \
  	mem-break.o target.o parse.o language.o $(YYOBJ) buildsym.o \
  	kod.o kod-cisco.o \
+ 	gdb-events.o \
  	exec.o bcache.o objfiles.o minsyms.o maint.o demangle.o \
  	dbxread.o coffread.o elfread.o \
  	dwarfread.o dwarf2read.o mipsread.o stabsread.o corefile.o \
*************** m2-exp.tab.o: m2-exp.tab.c $(defs_h) $(e
*** 1663,1667 ****
--- 1664,1669 ----
  	language.h m2-lang.h parser-defs.h $(symtab_h) $(value_h) \
  	$(bfd_h) objfiles.h symfile.h
  
+ gdb-events.o: gdb-events.c gdb-events.h $(defs_h) $(gdbcmd_h)
  
  ### end of the gdb Makefile.in.
Index: breakpoint.c
===================================================================
RCS file: /cvs/gdb/gdb/gdb/breakpoint.c,v
retrieving revision 1.1.1.8
diff -p -r1.1.1.8 breakpoint.c
*** breakpoint.c	1999/08/23 22:34:46	1.1.1.8
--- breakpoint.c	1999/08/26 09:13:27
***************
*** 40,45 ****
--- 40,48 ----
  #include "symfile.h"
  #include "objfiles.h"
  
+ #include "gdb-ops.h"
+ #include "gdb-events.h"
+ 
  /* Prototypes for local functions. */
  
  static void
*************** describe_other_breakpoints PARAMS ((CORE
*** 115,122 ****
  static void
  breakpoints_info PARAMS ((char *, int));
  
! static void
! breakpoint_1 PARAMS ((int, int));
  
  static bpstat
    bpstat_alloc PARAMS ((struct breakpoint *, bpstat));
--- 118,125 ----
  static void
  breakpoints_info PARAMS ((char *, int));
  
! static void breakpoint_1 (struct breakpoint *b, struct gdb_file *out, CORE_ADDR *last_addr);
! static void breakpoint_n (int, int);
  
  static bpstat
    bpstat_alloc PARAMS ((struct breakpoint *, bpstat));
*************** typedef struct
*** 2802,2815 ****
  ep_type_description_t;
  
  static void
! breakpoint_1 (bnum, allflag)
!      int bnum;
!      int allflag;
  {
-   register struct breakpoint *b;
    register struct command_line *l;
    register struct symbol *sym;
-   CORE_ADDR last_addr = (CORE_ADDR) - 1;
    int found_a_breakpoint = 0;
    static ep_type_description_t bptypes[] =
    {
--- 2805,2816 ----
  ep_type_description_t;
  
  static void
! breakpoint_1 (struct breakpoint *b,
! 	      struct gdb_file *out,
! 	      CORE_ADDR *last_addr)
  {
    register struct command_line *l;
    register struct symbol *sym;
    int found_a_breakpoint = 0;
    static ep_type_description_t bptypes[] =
    {
*************** breakpoint_1 (bnum, allflag)
*** 2843,2855 ****
    static char bpenables[] = "nyn";
    char wrap_indent[80];
  
  
  
    ALL_BREAKPOINTS (b)
      if (bnum == -1
  	|| bnum == b->number)
      {
! /*  We only print out user settable breakpoints unless the allflag is set. */
        if (!allflag
  	  && b->type != bp_breakpoint
  	  && b->type != bp_catch_load
--- 2844,3043 ----
    static char bpenables[] = "nyn";
    char wrap_indent[80];
  
+   annotate_record ();
+   annotate_field (0);
+   printf_filtered ("%-3d ", b->number);
+   annotate_field (1);
+   if ((int) b->type > (sizeof (bptypes) / sizeof (bptypes[0])))
+     error ("bptypes table does not describe type #%d.", (int) b->type);
+   if ((int) b->type != bptypes[(int) b->type].type)
+     error ("bptypes table does not describe type #%d?", (int) b->type);
+   printf_filtered ("%-14s ", bptypes[(int) b->type].description);
+   annotate_field (2);
+   printf_filtered ("%-4s ", bpdisps[(int) b->disposition]);
+   annotate_field (3);
+   printf_filtered ("%-3c ", bpenables[(int) b->enable]);
+   
+   strcpy (wrap_indent, "                           ");
+   if (addressprint)
+     strcat (wrap_indent, "           ");
+   switch (b->type)
+     {
+     case bp_watchpoint:
+     case bp_hardware_watchpoint:
+     case bp_read_watchpoint:
+     case bp_access_watchpoint:
+       /* Field 4, the address, is omitted (which makes the columns
+ 	 not line up too nicely with the headers, but the effect
+ 	 is relatively readable).  */
+       annotate_field (5);
+       print_expression (b->exp, gdb_stdout);
+       break;
+       
+     case bp_catch_load:
+     case bp_catch_unload:
+       /* Field 4, the address, is omitted (which makes the columns
+ 	 not line up too nicely with the headers, but the effect
+ 	 is relatively readable).  */
+       annotate_field (5);
+       if (b->dll_pathname == NULL)
+ 	printf_filtered ("<any library> ");
+       else
+ 	printf_filtered ("library \"%s\" ", b->dll_pathname);
+       break;
+       
+     case bp_catch_fork:
+     case bp_catch_vfork:
+       /* Field 4, the address, is omitted (which makes the columns
+ 	 not line up too nicely with the headers, but the effect
+ 	 is relatively readable).  */
+       annotate_field (5);
+       if (b->forked_inferior_pid != 0)
+ 	printf_filtered ("process %d ", b->forked_inferior_pid);
+       break;
+       
+     case bp_catch_exec:
+       /* Field 4, the address, is omitted (which makes the columns
+ 	 not line up too nicely with the headers, but the effect
+ 	 is relatively readable).  */
+       annotate_field (5);
+       if (b->exec_pathname != NULL)
+ 	printf_filtered ("program \"%s\" ", b->exec_pathname);
+       break;
+     case bp_catch_catch:
+       /* Field 4, the address, is omitted (which makes the columns
+ 	 not line up too nicely with the headers, but the effect
+ 	 is relatively readable).  */
+       annotate_field (5);
+       printf_filtered ("exception catch ");
+       break;
+     case bp_catch_throw:
+       /* Field 4, the address, is omitted (which makes the columns
+ 	 not line up too nicely with the headers, but the effect
+ 	 is relatively readable).  */
+       annotate_field (5);
+       printf_filtered ("exception throw ");
+       break;
+       
+     case bp_breakpoint:
+     case bp_hardware_breakpoint:
+     case bp_until:
+     case bp_finish:
+     case bp_longjmp:
+     case bp_longjmp_resume:
+     case bp_step_resume:
+     case bp_through_sigtramp:
+     case bp_watchpoint_scope:
+     case bp_call_dummy:
+     case bp_shlib_event:
+       if (addressprint)
+ 	{
+ 	  annotate_field (4);
+ 	  /* FIXME-32x64: need a print_address_numeric with
+ 	     field width */
+ 	  printf_filtered
+ 	    ("%s ",
+ 	     local_hex_string_custom
+ 	     ((unsigned long) b->address, "08l"));
+ 	}
+       
+       annotate_field (5);
+       
+       (*last_addr) = b->address;
+       if (b->source_file)
+ 	{
+ 	  sym = find_pc_sect_function (b->address, b->section);
+ 	  if (sym)
+ 	    {
+ 	      fputs_filtered ("in ", gdb_stdout);
+ 	      fputs_filtered (SYMBOL_SOURCE_NAME (sym), gdb_stdout);
+ 	      wrap_here (wrap_indent);
+ 	      fputs_filtered (" at ", gdb_stdout);
+ 	    }
+ 	  fputs_filtered (b->source_file, gdb_stdout);
+ 	  printf_filtered (":%d", b->line_number);
+ 	}
+       else
+ 	print_address_symbolic (b->address, gdb_stdout, demangle, " ");
+       break;
+     }
+   
+   if (b->thread != -1)
+     printf_filtered (" thread %d", b->thread);
+   
+   printf_filtered ("\n");
+   
+   if (b->frame)
+     {
+       annotate_field (6);
+       
+       printf_filtered ("\tstop only in stack frame at ");
+       print_address_numeric (b->frame, 1, gdb_stdout);
+       printf_filtered ("\n");
+     }
+   
+   if (b->cond)
+     {
+       annotate_field (7);
+       
+       printf_filtered ("\tstop only if ");
+       print_expression (b->cond, gdb_stdout);
+       printf_filtered ("\n");
+     }
+   
+   if (b->thread != -1)
+     {
+       /* FIXME should make an annotation for this */
+       printf_filtered ("\tstop only in thread %d\n", b->thread);
+     }
+   
+   if (show_breakpoint_hit_counts && b->hit_count)
+     {
+       /* FIXME should make an annotation for this */
+       if (ep_is_catchpoint (b))
+ 	printf_filtered ("\tcatchpoint");
+       else
+ 	printf_filtered ("\tbreakpoint");
+       printf_filtered (" already hit %d time%s\n",
+ 		       b->hit_count, (b->hit_count == 1 ? "" : "s"));
+     }
+   
+   if (b->ignore_count)
+     {
+       annotate_field (8);
+       
+       printf_filtered ("\tignore next %d hits\n", b->ignore_count);
+     }
+   
+   if ((l = b->commands))
+     {
+       annotate_field (9);
+       
+       while (l)
+ 	{
+ 	  print_command_line (l, 4, gdb_stdout);
+ 	  l = l->next;
+ 	}
+     }
+ }
  
+ static void
+ breakpoint_n (bnum, allflag)
+      int bnum;
+      int allflag;
+ {
+   register struct breakpoint *b;
+   register struct command_line *l;
+   register struct symbol *sym;
+   CORE_ADDR last_addr = (CORE_ADDR) - 1;
+   int found_a_breakpoint = 0;
  
    ALL_BREAKPOINTS (b)
      if (bnum == -1
  	|| bnum == b->number)
      {
!       /* We only print out user settable breakpoints unless the
!           allflag is set. */
        if (!allflag
  	  && b->type != bp_breakpoint
  	  && b->type != bp_catch_load
*************** breakpoint_1 (bnum, allflag)
*** 2888,3069 ****
  
  	  annotate_breakpoints_table ();
  	}
- 
-       annotate_record ();
-       annotate_field (0);
-       printf_filtered ("%-3d ", b->number);
-       annotate_field (1);
-       if ((int) b->type > (sizeof (bptypes) / sizeof (bptypes[0])))
- 	error ("bptypes table does not describe type #%d.", (int) b->type);
-       if ((int) b->type != bptypes[(int) b->type].type)
- 	error ("bptypes table does not describe type #%d?", (int) b->type);
-       printf_filtered ("%-14s ", bptypes[(int) b->type].description);
-       annotate_field (2);
-       printf_filtered ("%-4s ", bpdisps[(int) b->disposition]);
-       annotate_field (3);
-       printf_filtered ("%-3c ", bpenables[(int) b->enable]);
  
!       strcpy (wrap_indent, "                           ");
!       if (addressprint)
! 	strcat (wrap_indent, "           ");
!       switch (b->type)
! 	{
! 	case bp_watchpoint:
! 	case bp_hardware_watchpoint:
! 	case bp_read_watchpoint:
! 	case bp_access_watchpoint:
! 	  /* Field 4, the address, is omitted (which makes the columns
! 	     not line up too nicely with the headers, but the effect
! 	     is relatively readable).  */
! 	  annotate_field (5);
! 	  print_expression (b->exp, gdb_stdout);
! 	  break;
! 
! 	case bp_catch_load:
! 	case bp_catch_unload:
! 	  /* Field 4, the address, is omitted (which makes the columns
! 	     not line up too nicely with the headers, but the effect
! 	     is relatively readable).  */
! 	  annotate_field (5);
! 	  if (b->dll_pathname == NULL)
! 	    printf_filtered ("<any library> ");
! 	  else
! 	    printf_filtered ("library \"%s\" ", b->dll_pathname);
! 	  break;
! 
! 	case bp_catch_fork:
! 	case bp_catch_vfork:
! 	  /* Field 4, the address, is omitted (which makes the columns
! 	     not line up too nicely with the headers, but the effect
! 	     is relatively readable).  */
! 	  annotate_field (5);
! 	  if (b->forked_inferior_pid != 0)
! 	    printf_filtered ("process %d ", b->forked_inferior_pid);
! 	  break;
! 
! 	case bp_catch_exec:
! 	  /* Field 4, the address, is omitted (which makes the columns
! 	     not line up too nicely with the headers, but the effect
! 	     is relatively readable).  */
! 	  annotate_field (5);
! 	  if (b->exec_pathname != NULL)
! 	    printf_filtered ("program \"%s\" ", b->exec_pathname);
! 	  break;
! 	case bp_catch_catch:
! 	  /* Field 4, the address, is omitted (which makes the columns
! 	     not line up too nicely with the headers, but the effect
! 	     is relatively readable).  */
! 	  annotate_field (5);
! 	  printf_filtered ("exception catch ");
! 	  break;
! 	case bp_catch_throw:
! 	  /* Field 4, the address, is omitted (which makes the columns
! 	     not line up too nicely with the headers, but the effect
! 	     is relatively readable).  */
! 	  annotate_field (5);
! 	  printf_filtered ("exception throw ");
! 	  break;
! 
! 	case bp_breakpoint:
! 	case bp_hardware_breakpoint:
! 	case bp_until:
! 	case bp_finish:
! 	case bp_longjmp:
! 	case bp_longjmp_resume:
! 	case bp_step_resume:
! 	case bp_through_sigtramp:
! 	case bp_watchpoint_scope:
! 	case bp_call_dummy:
! 	case bp_shlib_event:
! 	  if (addressprint)
! 	    {
! 	      annotate_field (4);
! 	      /* FIXME-32x64: need a print_address_numeric with
! 	         field width */
! 	      printf_filtered
! 		("%s ",
! 		 local_hex_string_custom
! 		 ((unsigned long) b->address, "08l"));
! 	    }
! 
! 	  annotate_field (5);
! 
! 	  last_addr = b->address;
! 	  if (b->source_file)
! 	    {
! 	      sym = find_pc_sect_function (b->address, b->section);
! 	      if (sym)
! 		{
! 		  fputs_filtered ("in ", gdb_stdout);
! 		  fputs_filtered (SYMBOL_SOURCE_NAME (sym), gdb_stdout);
! 		  wrap_here (wrap_indent);
! 		  fputs_filtered (" at ", gdb_stdout);
! 		}
! 	      fputs_filtered (b->source_file, gdb_stdout);
! 	      printf_filtered (":%d", b->line_number);
! 	    }
! 	  else
! 	    print_address_symbolic (b->address, gdb_stdout, demangle, " ");
! 	  break;
! 	}
! 
!       if (b->thread != -1)
! 	printf_filtered (" thread %d", b->thread);
! 
!       printf_filtered ("\n");
! 
!       if (b->frame)
! 	{
! 	  annotate_field (6);
! 
! 	  printf_filtered ("\tstop only in stack frame at ");
! 	  print_address_numeric (b->frame, 1, gdb_stdout);
! 	  printf_filtered ("\n");
! 	}
! 
!       if (b->cond)
! 	{
! 	  annotate_field (7);
! 
! 	  printf_filtered ("\tstop only if ");
! 	  print_expression (b->cond, gdb_stdout);
! 	  printf_filtered ("\n");
! 	}
! 
!       if (b->thread != -1)
! 	{
! 	  /* FIXME should make an annotation for this */
! 	  printf_filtered ("\tstop only in thread %d\n", b->thread);
! 	}
! 
!       if (show_breakpoint_hit_counts && b->hit_count)
! 	{
! 	  /* FIXME should make an annotation for this */
! 	  if (ep_is_catchpoint (b))
! 	    printf_filtered ("\tcatchpoint");
! 	  else
! 	    printf_filtered ("\tbreakpoint");
! 	  printf_filtered (" already hit %d time%s\n",
! 			   b->hit_count, (b->hit_count == 1 ? "" : "s"));
! 	}
! 
!       if (b->ignore_count)
! 	{
! 	  annotate_field (8);
! 
! 	  printf_filtered ("\tignore next %d hits\n", b->ignore_count);
! 	}
! 
!       if ((l = b->commands))
! 	{
! 	  annotate_field (9);
! 
! 	  while (l)
! 	    {
! 	      print_command_line (l, 4, gdb_stdout);
! 	      l = l->next;
! 	    }
! 	}
      }
  
    if (!found_a_breakpoint)
--- 3076,3083 ----
  
  	  annotate_breakpoints_table ();
  	}
  
!       breakpoint_1 (b, gdb_stdout, &last_addr);
      }
  
    if (!found_a_breakpoint)
*************** breakpoint_1 (bnum, allflag)
*** 3082,3087 ****
--- 3096,3115 ----
    annotate_breakpoints_table_end ();
  }
  
+ void
+ gdb_ops_breakpoint (int bnum,
+ 		    struct gdb_file *out)
+ {
+   register struct breakpoint *b;
+   CORE_ADDR last_addr;
+   ALL_BREAKPOINTS (b)
+     if (bnum == -1
+ 	|| bnum == b->number)
+       {
+ 	breakpoint_1 (b, out, &last_addr);
+       }
+ }
+   
  /* ARGSUSED */
  static void
  breakpoints_info (bnum_exp, from_tty)
*************** breakpoints_info (bnum_exp, from_tty)
*** 3093,3099 ****
    if (bnum_exp)
      bnum = parse_and_eval_address (bnum_exp);
  
!   breakpoint_1 (bnum, 0);
  }
  
  /* ARGSUSED */
--- 3121,3127 ----
    if (bnum_exp)
      bnum = parse_and_eval_address (bnum_exp);
  
!   breakpoint_n (bnum, 0);
  }
  
  /* ARGSUSED */
*************** maintenance_info_breakpoints (bnum_exp, 
*** 3107,3113 ****
    if (bnum_exp)
      bnum = parse_and_eval_address (bnum_exp);
  
!   breakpoint_1 (bnum, 1);
  }
  
  /* Print a message describing any breakpoints set at PC.  */
--- 3135,3141 ----
    if (bnum_exp)
      bnum = parse_and_eval_address (bnum_exp);
  
!   breakpoint_n (bnum, 1);
  }
  
  /* Print a message describing any breakpoints set at PC.  */
*************** mention (b)
*** 3736,3741 ****
--- 3764,3770 ----
       delete_breakpoint_hook and so on.  */
    if (create_breakpoint_hook)
      create_breakpoint_hook (b);
+   breakpoint_create_event (b->number);
  
    switch (b->type)
      {
*************** delete_breakpoint (bpt)
*** 5850,5855 ****
--- 5879,5885 ----
  
    if (delete_breakpoint_hook)
      delete_breakpoint_hook (bpt);
+   breakpoint_delete_event (bpt->number);
  
    if (bpt->inserted)
      remove_breakpoint (bpt, mark_uninserted);
*************** disable_breakpoint (bpt)
*** 6381,6386 ****
--- 6411,6417 ----
  
    if (modify_breakpoint_hook)
      modify_breakpoint_hook (bpt);
+   breakpoint_modify_event (bpt->number);
  }
  
  /* ARGSUSED */
*************** have been allocated for other watchpoint
*** 6513,6518 ****
--- 6544,6550 ----
      }
    if (modify_breakpoint_hook)
      modify_breakpoint_hook (bpt);
+   breakpoint_modify_event (bpt->number);
  }
  
  void
Index: event-loop.c
===================================================================
RCS file: /cvs/gdb/gdb/gdb/event-loop.c,v
retrieving revision 1.1.1.9
diff -p -r1.1.1.9 event-loop.c
*** event-loop.c	1999/08/16 19:52:29	1.1.1.9
--- event-loop.c	1999/08/26 09:13:29
***************
*** 30,35 ****
--- 30,38 ----
  #include <errno.h>
  #include <setjmp.h>
  
+ #include "gdb-events.h"
+ #include "gdb-ops.h"
+ 
  /* Event queue:  
     - the first event in the queue is the head of the queue. 
     It will be the next to be serviced.
*************** gdb_do_one_event ()
*** 293,309 ****
  }
  
  
  /* Start up the event loop. This is the entry point to the event loop
     from the command loop. */
  void
  start_event_loop ()
  {
    /* Loop until there is something to do. This is the entry point to
       the event loop engine. gdb_do_one_event will process one event
       for each invocation.  It always returns 1, unless there are no
       more event sources registered. In this case it returns 0.  */
    while (gdb_do_one_event () != 0)
!     ;
  
    /* We are done with the event loop. There are no more event sources
       to listen to.  So we exit GDB. */
--- 296,343 ----
  }
  
  
+ #include "gdb-events.h"
+ 
+ struct gdb_events hacked_events;
+ 
+ void
+ hacked_breakpoint_create (int b)
+ {
+   fprintf_unfiltered (gdb_stdout, "Breapoint create: ");
+   gdb_ops_breakpoint (b, gdb_stdlog);
+ }
+ 
+ void
+ hacked_breakpoint_delete (int b)
+ {
+   fprintf_unfiltered (gdb_stdout, "Breapoint delete: ");
+   fprintf_unfiltered (gdb_stdlog, "Breakpoint %d deleted\n", b);
+ }
+ 
+ void
+ hacked_breakpoint_modify (int b)
+ {
+   gdb_ops_breakpoint (b, gdb_stdlog);
+ }
+ 
  /* Start up the event loop. This is the entry point to the event loop
     from the command loop. */
  void
  start_event_loop ()
  {
+   hacked_events.breakpoint_create = hacked_breakpoint_create;
+   hacked_events.breakpoint_delete = hacked_breakpoint_delete;
+   hacked_events.breakpoint_modify = hacked_breakpoint_modify;
+   /* force the event queue into delayed delivery mode. */
+   set_gdb_event_hooks (NULL);
+ 
    /* Loop until there is something to do. This is the entry point to
       the event loop engine. gdb_do_one_event will process one event
       for each invocation.  It always returns 1, unless there are no
       more event sources registered. In this case it returns 0.  */
    while (gdb_do_one_event () != 0)
!     /* FIXME: what about flushing any events and error handling. */
!     gdb_events_deliver (&hacked_events);
  
    /* We are done with the event loop. There are no more event sources
       to listen to.  So we exit GDB. */
*** /dev/null	Thu Aug 26 19:00:28 1999
--- gdb-events.h	Thu Aug 26 18:26:14 1999
***************
*** 0 ****
--- 1,84 ----
+ /* User Interface Events.
+    Copyright 1999 Free Software Foundation, Inc.
+ 
+    Contributed by Cygnus Solutions.
+ 
+ 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 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
+ 
+ /* Work in progress */
+ 
+ #ifndef GDB_EVENTS_H
+ #define GDB_EVENTS_H
+ 
+ #ifndef WITH_GDB_EVENTS
+ #define WITH_GDB_EVENTS 1
+ #endif
+ 
+ 
+ /* COMPAT: pointer variables for old, unconverted events.
+    A call to set_gdb_events() will automatically update these. */
+ 
+ 
+ 
+ /* Type definition of all hook functions.
+    Recommended pratice is to first declare each hook function using
+    the below ftype and then define it. */
+ 
+ typedef void (gdb_events_breakpoint_create_ftype) (int b);
+ typedef void (gdb_events_breakpoint_delete_ftype) (int b);
+ typedef void (gdb_events_breakpoint_modify_ftype) (int b);
+ 
+ 
+ /* gdb-events: object. */
+ 
+ struct gdb_events
+   {
+     gdb_events_breakpoint_create_ftype *breakpoint_create;
+     gdb_events_breakpoint_delete_ftype *breakpoint_delete;
+     gdb_events_breakpoint_modify_ftype *breakpoint_modify;
+   };
+ 
+ 
+ /* Interface into events functions.
+    Where a *_p() predicate is present, it must called before calling
+    the hook proper. */
+ extern void breakpoint_create_event (int b);
+ extern void breakpoint_delete_event (int b);
+ extern void breakpoint_modify_event (int b);
+ 
+ 
+ /* When GDB_EVENTS are not being used, completly disable them. */
+ 
+ #if !WITH_GDB_EVENTS
+ #define breakpoint_create_event(b) 0
+ #define breakpoint_delete_event(b) 0
+ #define breakpoint_modify_event(b) 0
+ #endif
+ 
+ /* Install custom gdb-events hooks. */
+ extern void set_gdb_event_hooks (struct gdb_events *vector);
+ 
+ /* Deliver any pending events. */
+ extern void gdb_events_deliver (struct gdb_events *vector);
+ 
+ #if !WITH_GDB_EVENTS
+ #define set_gdb_events(x) 0
+ #define set_gdb_event_hooks(x) 0
+ #define gdb_events_deliver(x) 0
+ #endif
+ 
+ #endif
*** /dev/null	Thu Aug 26 19:00:28 1999
--- gdb-events.c	Thu Aug 26 18:26:14 1999
***************
*** 0 ****
--- 1,214 ----
+ /* User Interface Events.
+    Copyright 1999 Free Software Foundation, Inc.
+ 
+    Contributed by Cygnus Solutions.
+ 
+ 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 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
+ 
+ /* Work in progress */
+ 
+ #include "defs.h"
+ #include "gdb-events.h"
+ #include "gdbcmd.h"
+ 
+ #undef XMALLOC
+ #define XMALLOC(TYPE) ((TYPE*) xmalloc (sizeof (TYPE)))
+ 
+ #if WITH_GDB_EVENTS
+ static struct gdb_events null_event_hooks;
+ static struct gdb_events queue_event_hooks;
+ static struct gdb_events *current_event_hooks = &null_event_hooks;
+ #endif
+ 
+ int gdb_events_debug;
+ 
+ #if WITH_GDB_EVENTS
+ 
+ void
+ breakpoint_create_event (int b)
+ {
+   if (gdb_events_debug)
+     fprintf_unfiltered (gdb_stdlog, "breakpoint_create_event\n");
+   if (!current_event_hooks->breakpoint_create)
+     return;
+   current_event_hooks->breakpoint_create (b);
+ }
+ 
+ void
+ breakpoint_delete_event (int b)
+ {
+   if (gdb_events_debug)
+     fprintf_unfiltered (gdb_stdlog, "breakpoint_delete_event\n");
+   if (!current_event_hooks->breakpoint_delete)
+     return;
+   current_event_hooks->breakpoint_delete (b);
+ }
+ 
+ void
+ breakpoint_modify_event (int b)
+ {
+   if (gdb_events_debug)
+     fprintf_unfiltered (gdb_stdlog, "breakpoint_modify_event\n");
+   if (!current_event_hooks->breakpoint_modify)
+     return;
+   current_event_hooks->breakpoint_modify (b);
+ }
+ 
+ #endif
+ 
+ #if WITH_GDB_EVENTS
+ void
+ set_gdb_event_hooks (struct gdb_events *vector)
+ {
+   if (vector == NULL)
+     current_event_hooks = &queue_event_hooks;
+   else
+     current_event_hooks = vector;
+ }
+ #endif
+ 
+ enum gdb_event
+   {
+     breakpoint_create,
+     breakpoint_delete,
+     breakpoint_modify,
+     nr_gdb_events
+   };
+ 
+ struct breakpoint_create
+   {
+     int b;
+   };
+ 
+ struct breakpoint_delete
+   {
+     int b;
+   };
+ 
+ struct breakpoint_modify
+   {
+     int b;
+   };
+ 
+ struct event
+   {
+     enum gdb_event type;
+     struct event *next;
+     union
+       {
+         struct breakpoint_create breakpoint_create;
+         struct breakpoint_delete breakpoint_delete;
+         struct breakpoint_modify breakpoint_modify;
+       }
+     data;
+   };
+ struct event *pending_events;
+ struct event *delivering_events;
+ 
+ static void
+ append (struct event *new_event)
+ {
+   struct event **event = &pending_events;
+   while ((*event) != NULL)
+     event = &((*event)->next);
+   (*event) = new_event;
+   (*event)->next = NULL;
+ }
+ 
+ static void
+ queue_breakpoint_create (int b)
+ {
+   struct event *event = XMALLOC (struct event);
+   event->type = breakpoint_create;
+   event->data.breakpoint_create.b = b;
+   append (event);
+ }
+ 
+ static void
+ queue_breakpoint_delete (int b)
+ {
+   struct event *event = XMALLOC (struct event);
+   event->type = breakpoint_delete;
+   event->data.breakpoint_delete.b = b;
+   append (event);
+ }
+ 
+ static void
+ queue_breakpoint_modify (int b)
+ {
+   struct event *event = XMALLOC (struct event);
+   event->type = breakpoint_modify;
+   event->data.breakpoint_modify.b = b;
+   append (event);
+ }
+ 
+ void
+ gdb_events_deliver (struct gdb_events *vector)
+ {
+   /* Just zap any events left around from last time. */
+   while (delivering_events != NULL)
+     {
+       struct event *event = delivering_events;
+       delivering_events = event->next;
+       free (event);
+     }
+   /* Process any pending events.  Because one of the deliveries could
+      bail out we move everything off of the pending queue onto an
+      in-progress queue where it can, later, be cleaned up if
+      necessary. */
+   delivering_events = pending_events;
+   pending_events = NULL;
+   while (delivering_events != NULL)
+     {
+       struct event *event = delivering_events;
+       switch (event->type)
+         {
+         case breakpoint_create:
+           vector->breakpoint_create
+             (event->data.breakpoint_create.b);
+           break;
+         case breakpoint_delete:
+           vector->breakpoint_delete
+             (event->data.breakpoint_delete.b);
+           break;
+         case breakpoint_modify:
+           vector->breakpoint_modify
+             (event->data.breakpoint_modify.b);
+           break;
+         }
+       delivering_events = event->next;
+       free (event);
+     }
+ }
+ 
+ void _initialize_gdb_events (void);
+ void
+ _initialize_gdb_events (void)
+ {
+ #if WITH_GDB_EVENTS
+   queue_event_hooks.breakpoint_create = queue_breakpoint_create;
+   queue_event_hooks.breakpoint_delete = queue_breakpoint_delete;
+   queue_event_hooks.breakpoint_modify = queue_breakpoint_modify;
+ #endif
+   add_show_from_set (add_set_cmd ("eventdebug",
+                                   class_maintenance,
+                                   var_zinteger,
+                                   (char *)&gdb_events_debug,
+                                   "Set event debugging.\n\
+ When non-zero, event/notify debugging is enabled.", &setlist),
+                      &showlist);
+ }
*** /dev/null	Thu Aug 26 19:00:28 1999
--- gdb-ops.h	Thu Aug 26 18:59:31 1999
***************
*** 0 ****
--- 1 ----
+ extern void gdb_ops_breakpoint (int bnum, struct gdb_file *out);


More information about the Gdb mailing list