diff options
author | Joel Brobecker <brobecker@gnat.com> | 2004-08-27 13:37:42 +0000 |
---|---|---|
committer | Joel Brobecker <brobecker@gnat.com> | 2004-08-27 13:37:42 +0000 |
commit | 9185ddce9648a80c661182dad116648e57a2be31 (patch) | |
tree | 8f51f2eaadd4a0fb0a6a0725d8ea26428e76c297 /gdb/procfs.c | |
parent | e5b2549632217988c5fc4ef40c779e4089962f66 (diff) | |
download | gdb-9185ddce9648a80c661182dad116648e57a2be31.zip gdb-9185ddce9648a80c661182dad116648e57a2be31.tar.gz gdb-9185ddce9648a80c661182dad116648e57a2be31.tar.bz2 |
* procfs.c (dbx_link_bpt_addr): New static global variable.
(dbx_link_shadow_contents): New static global variable.
(procfs_wait, case <PR_SYSEXIT>): Handle syssgi events.
(procfs_wait, case <FLTBPT>): 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.
Diffstat (limited to 'gdb/procfs.c')
-rw-r--r-- | gdb/procfs.c | 262 |
1 files changed, 237 insertions, 25 deletions
diff --git a/gdb/procfs.c b/gdb/procfs.c index 3ac9702..0a1f152 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); } } |