From 9185ddce9648a80c661182dad116648e57a2be31 Mon Sep 17 00:00:00 2001 From: Joel Brobecker Date: Fri, 27 Aug 2004 13:37:42 +0000 Subject: [PATCH] * procfs.c (dbx_link_bpt_addr): New static global variable. (dbx_link_shadow_contents): New static global variable. (procfs_wait, case ): Handle syssgi events. (procfs_wait, case ): Remove the __dbx_link brekapoint if we just hit it. (procfs_init_inferior): Enable syssgi() syscall trace if appropriate. Reset dbx_link_bpt_addr as the address of __dbx_link() may change from run to run. (procfs_create_inferior): Remove syssgi syscall-exit notifications after the inferior has been forked. (remove_dbx_link_breakpoint): New function. (dbx_link_addr): New function. (insert_dbx_link_bpt_in_file): New function. (insert_dbx_link_bpt_in_region): New function. (insert_dbx_link_breakpoint): New function. (proc_trace_syscalls_1): New function, extracted from proc_trace_syscalls. (proc_trace_syscalls): Replace extract code by call to proc_trace_syscalls_1. * solib-irix.c (disable_break): Remove stop_pc assertion, as it is no longer valid. --- gdb/ChangeLog | 24 +++++ gdb/procfs.c | 262 ++++++++++++++++++++++++++++++++++++++++++----- gdb/solib-irix.c | 14 +-- 3 files changed, 266 insertions(+), 34 deletions(-) diff --git a/gdb/ChangeLog b/gdb/ChangeLog index 7decaadd6f2..0ac0540bcec 100644 --- a/gdb/ChangeLog +++ b/gdb/ChangeLog @@ -1,3 +1,27 @@ +2004-08-27 Joel Brobecker + + * procfs.c (dbx_link_bpt_addr): New static global variable. + (dbx_link_shadow_contents): New static global variable. + (procfs_wait, case ): Handle syssgi events. + (procfs_wait, case ): Remove the __dbx_link brekapoint + if we just hit it. + (procfs_init_inferior): Enable syssgi() syscall trace if appropriate. + Reset dbx_link_bpt_addr as the address of __dbx_link() may change + from run to run. + (procfs_create_inferior): Remove syssgi syscall-exit notifications + after the inferior has been forked. + (remove_dbx_link_breakpoint): New function. + (dbx_link_addr): New function. + (insert_dbx_link_bpt_in_file): New function. + (insert_dbx_link_bpt_in_region): New function. + (insert_dbx_link_breakpoint): New function. + (proc_trace_syscalls_1): New function, extracted from + proc_trace_syscalls. + (proc_trace_syscalls): Replace extract code by call to + proc_trace_syscalls_1. + * solib-irix.c (disable_break): Remove stop_pc assertion, as it + is no longer valid. + 2004-08-25 Jim Blandy * gdbtypes.h (TYPE_CODE_ARRAY): Doc fix. diff --git a/gdb/procfs.c b/gdb/procfs.c index 3ac97024028..0a1f1528b3a 100644 --- a/gdb/procfs.c +++ b/gdb/procfs.c @@ -3382,6 +3382,17 @@ proc_iterate_over_threads (procinfo *pi, static ptid_t do_attach (ptid_t ptid); static void do_detach (int signo); static int register_gdb_signals (procinfo *, gdb_sigset_t *); +static void proc_trace_syscalls_1 (procinfo *pi, int syscallnum, + int entry_or_exit, int mode, int from_tty); +static int insert_dbx_link_breakpoint (procinfo *pi); +static void remove_dbx_link_breakpoint (void); + +/* On mips-irix, we need to insert a breakpoint at __dbx_link during + the startup phase. The following two variables are used to record + the address of the breakpoint, and the code that was replaced by + a breakpoint. */ +static int dbx_link_bpt_addr = 0; +static char dbx_link_shadow_contents[BREAKPOINT_MAX]; /* * Function: procfs_debug_inferior @@ -4070,6 +4081,22 @@ wait_again: address. */ wstat = (SIGTRAP << 8) | 0177; } +#ifdef SYS_syssgi + else if (what == SYS_syssgi) + { + /* see if we can break on dbx_link(). If yes, then + we no longer need the SYS_syssgi notifications. */ + if (insert_dbx_link_breakpoint (pi)) + proc_trace_syscalls_1 (pi, SYS_syssgi, PR_SYSEXIT, + FLAG_RESET, 0); + + /* This is an internal event and should be transparent + to wfi, so resume the execution and wait again. See + comment in procfs_init_inferior() for more details. */ + target_resume (ptid, 0, TARGET_SIGNAL_0); + goto wait_again; + } +#endif else if (syscall_is_lwp_create (pi, what)) { /* @@ -4196,6 +4223,13 @@ wait_again: #if (FLTTRACE != FLTBPT) /* avoid "duplicate case" error */ case FLTTRACE: #endif + /* If we hit our __dbx_link() internal breakpoint, + then remove it. See comments in procfs_init_inferior() + for more details. */ + if (dbx_link_bpt_addr != 0 + && dbx_link_bpt_addr == read_pc ()) + remove_dbx_link_breakpoint (); + wstat = (SIGTRAP << 8) | 0177; break; case FLTSTACK: @@ -4847,6 +4881,32 @@ procfs_init_inferior (int pid) /* Typically two, one trap to exec the shell, one to exec the program being debugged. Defined by "inferior.h". */ startup_inferior (START_INFERIOR_TRAPS_EXPECTED); + +#ifdef SYS_syssgi + /* On mips-irix, we need to stop the inferior early enough during + the startup phase in order to be able to load the shared library + symbols and insert the breakpoints that are located in these shared + libraries. Stopping at the program entry point is not good enough + because the -init code is executed before the execution reaches + that point. + + So what we need to do is to insert a breakpoint in the runtime + loader (rld), more precisely in __dbx_link(). This procedure is + called by rld once all shared libraries have been mapped, but before + the -init code is executed. Unfortuantely, this is not straightforward, + as rld is not part of the executable we are running, and thus we need + the inferior to run until rld itself has been mapped in memory. + + For this, we trace all syssgi() syscall exit events. Each time + we detect such an event, we iterate over each text memory maps, + get its associated fd, and scan the symbol table for __dbx_link(). + When found, we know that rld has been mapped, and that we can insert + the breakpoint at the symbol address. Once the dbx_link() breakpoint + has been inserted, the syssgi() notifications are no longer necessary, + so they should be canceled. */ + proc_trace_syscalls_1 (pi, SYS_syssgi, PR_SYSEXIT, FLAG_SET, 0); + dbx_link_bpt_addr = 0; +#endif } /* @@ -5053,6 +5113,16 @@ procfs_create_inferior (char *exec_file, char *allargs, char **env, fork_inferior (exec_file, allargs, env, procfs_set_exec_trap, procfs_init_inferior, NULL, shell_file); +#ifdef SYS_syssgi + /* Make sure to cancel the syssgi() syscall-exit notifications. + They should normally have been removed by now, but they may still + be activated if the inferior doesn't use shared libraries, or if + we didn't locate __dbx_link, or if we never stopped in __dbx_link. + See procfs_init_inferior() for more details. */ + proc_trace_syscalls_1 (find_procinfo_or_die (PIDGET (inferior_ptid), 0), + SYS_syssgi, PR_SYSEXIT, FLAG_RESET, 0); +#endif + /* We are at the first instruction we care about. */ /* Pedal to the metal... */ @@ -5515,6 +5585,131 @@ proc_find_memory_regions (int (*func) (CORE_ADDR, find_memory_regions_callback); } +/* Remove the breakpoint that we inserted in __dbx_link(). + Does nothing if the breakpoint hasn't been inserted or has already + been removed. */ + +static void +remove_dbx_link_breakpoint (void) +{ + if (dbx_link_bpt_addr == 0) + return; + + if (memory_remove_breakpoint (dbx_link_bpt_addr, + dbx_link_shadow_contents) != 0) + warning ("Unable to remove __dbx_link breakpoint."); + + dbx_link_bpt_addr = 0; +} + +/* Return the address of the __dbx_link() function in the file + refernced by ABFD by scanning its symbol table. Return 0 if + the symbol was not found. */ + +static CORE_ADDR +dbx_link_addr (bfd *abfd) +{ + long storage_needed; + asymbol **symbol_table; + long number_of_symbols; + long i; + + storage_needed = bfd_get_symtab_upper_bound (abfd); + if (storage_needed <= 0) + return 0; + + symbol_table = (asymbol **) xmalloc (storage_needed); + make_cleanup (xfree, symbol_table); + + number_of_symbols = bfd_canonicalize_symtab (abfd, symbol_table); + + for (i = 0; i < number_of_symbols; i++) + { + asymbol *sym = symbol_table[i]; + + if ((sym->flags & BSF_GLOBAL) + && sym->name != NULL && strcmp (sym->name, "__dbx_link") == 0) + return (sym->value + sym->section->vma); + } + + /* Symbol not found, return NULL. */ + return 0; +} + +/* Search the symbol table of the file referenced by FD for a symbol + named __dbx_link(). If found, then insert a breakpoint at this location, + and return nonzero. Return zero otherwise. */ + +static int +insert_dbx_link_bpt_in_file (int fd, CORE_ADDR ignored) +{ + bfd *abfd; + long storage_needed; + CORE_ADDR sym_addr; + + abfd = bfd_fdopenr ("unamed", 0, fd); + if (abfd == NULL) + { + warning ("Failed to create a bfd: %s.\n", bfd_errmsg (bfd_get_error ())); + return 0; + } + + if (!bfd_check_format (abfd, bfd_object)) + { + /* Not the correct format, so we can not possibly find the dbx_link + symbol in it. */ + bfd_close (abfd); + return 0; + } + + sym_addr = dbx_link_addr (abfd); + if (sym_addr != 0) + { + /* Insert the breakpoint. */ + dbx_link_bpt_addr = sym_addr; + if (target_insert_breakpoint (sym_addr, dbx_link_shadow_contents) != 0) + { + warning ("Failed to insert dbx_link breakpoint."); + bfd_close (abfd); + return 0; + } + bfd_close (abfd); + return 1; + } + + bfd_close (abfd); + return 0; +} + +/* If the given memory region MAP contains a symbol named __dbx_link, + insert a breakpoint at this location and return nonzero. Return + zero otherwise. */ + +static int +insert_dbx_link_bpt_in_region (struct prmap *map, + int (*child_func) (), + void *data) +{ + procinfo *pi = (procinfo *) data; + + /* We know the symbol we're looking for is in a text region, so + only look for it if the region is a text one. */ + if (map->pr_mflags & MA_EXEC) + return solib_mappings_callback (map, insert_dbx_link_bpt_in_file, pi); + + return 0; +} + +/* Search all memory regions for a symbol named __dbx_link. If found, + insert a breakpoint at its location, and return nonzero. Return zero + otherwise. */ + +static int +insert_dbx_link_breakpoint (procinfo *pi) +{ + return iterate_over_mappings (pi, NULL, pi, insert_dbx_link_bpt_in_region); +} + /* * Function: mappingflags * @@ -5703,12 +5898,50 @@ info_proc_cmd (char *args, int from_tty) do_cleanups (old_chain); } +/* Modify the status of the system call identified by SYSCALLNUM in + the set of syscalls that are currently traced/debugged. + + If ENTRY_OR_EXIT is set to PR_SYSENTRY, then the entry syscalls set + will be updated. Otherwise, the exit syscalls set will be updated. + + If MODE is FLAG_SET, then traces will be enabled. Otherwise, they + will be disabled. */ + +static void +proc_trace_syscalls_1 (procinfo *pi, int syscallnum, int entry_or_exit, + int mode, int from_tty) +{ + sysset_t *sysset; + + if (entry_or_exit == PR_SYSENTRY) + sysset = proc_get_traced_sysentry (pi, NULL); + else + sysset = proc_get_traced_sysexit (pi, NULL); + + if (sysset == NULL) + proc_error (pi, "proc-trace, get_traced_sysset", __LINE__); + + if (mode == FLAG_SET) + gdb_praddsysset (sysset, syscallnum); + else + gdb_prdelsysset (sysset, syscallnum); + + if (entry_or_exit == PR_SYSENTRY) + { + if (!proc_set_traced_sysentry (pi, sysset)) + proc_error (pi, "proc-trace, set_traced_sysentry", __LINE__); + } + else + { + if (!proc_set_traced_sysexit (pi, sysset)) + proc_error (pi, "proc-trace, set_traced_sysexit", __LINE__); + } +} + static void proc_trace_syscalls (char *args, int from_tty, int entry_or_exit, int mode) { procinfo *pi; - sysset_t *sysset; - int syscallnum = 0; if (PIDGET (inferior_ptid) <= 0) error ("you must be debugging a process to use this command."); @@ -5719,30 +5952,9 @@ proc_trace_syscalls (char *args, int from_tty, int entry_or_exit, int mode) pi = find_procinfo_or_die (PIDGET (inferior_ptid), 0); if (isdigit (args[0])) { - syscallnum = atoi (args); - if (entry_or_exit == PR_SYSENTRY) - sysset = proc_get_traced_sysentry (pi, NULL); - else - sysset = proc_get_traced_sysexit (pi, NULL); - - if (sysset == NULL) - proc_error (pi, "proc-trace, get_traced_sysset", __LINE__); - - if (mode == FLAG_SET) - gdb_praddsysset (sysset, syscallnum); - else - gdb_prdelsysset (sysset, syscallnum); + const int syscallnum = atoi (args); - if (entry_or_exit == PR_SYSENTRY) - { - if (!proc_set_traced_sysentry (pi, sysset)) - proc_error (pi, "proc-trace, set_traced_sysentry", __LINE__); - } - else - { - if (!proc_set_traced_sysexit (pi, sysset)) - proc_error (pi, "proc-trace, set_traced_sysexit", __LINE__); - } + proc_trace_syscalls_1 (pi, syscallnum, entry_or_exit, mode, from_tty); } } diff --git a/gdb/solib-irix.c b/gdb/solib-irix.c index aaf8338bb25..5795ecaf0c1 100644 --- a/gdb/solib-irix.c +++ b/gdb/solib-irix.c @@ -324,15 +324,11 @@ disable_break (void) status = 0; } - /* For the SVR4 version, we always know the breakpoint address. For the - SunOS version we don't know it until the above code is executed. - Grumble if we are stopped anywhere besides the breakpoint address. */ - - if (stop_pc != breakpoint_addr) - { - warning - ("stopped at unknown breakpoint while handling shared libraries"); - } + /* Note that it is possible that we have stopped at a location that + is different from the location where we inserted our breakpoint. + On mips-irix, we can actually land in __dbx_init(), so we should + not check the PC against our breakpoint address here. See procfs.c + for more details. */ return (status); } -- 2.30.2