diff options
Diffstat (limited to 'gnu/usr.bin/binutils/gdb/procfs.c')
-rw-r--r-- | gnu/usr.bin/binutils/gdb/procfs.c | 324 |
1 files changed, 266 insertions, 58 deletions
diff --git a/gnu/usr.bin/binutils/gdb/procfs.c b/gnu/usr.bin/binutils/gdb/procfs.c index 352b735c868..7e31a7ffcb6 100644 --- a/gnu/usr.bin/binutils/gdb/procfs.c +++ b/gnu/usr.bin/binutils/gdb/procfs.c @@ -124,7 +124,7 @@ static void procfs_notice_signals (ptid_t); static void procfs_prepare_to_store (void); static void procfs_kill_inferior (void); static void procfs_mourn_inferior (void); -static void procfs_create_inferior (char *, char *, char **); +static void procfs_create_inferior (char *, char *, char **, int); static ptid_t procfs_wait (ptid_t, struct target_waitstatus *); static int procfs_xfer_memory (CORE_ADDR, char *, int, int, struct mem_attrib *attrib, @@ -172,7 +172,7 @@ init_procfs_ops (void) procfs_ops.to_fetch_registers = procfs_fetch_registers; procfs_ops.to_store_registers = procfs_store_registers; procfs_ops.to_xfer_partial = procfs_xfer_partial; - procfs_ops.to_xfer_memory = procfs_xfer_memory; + procfs_ops.deprecated_xfer_memory = procfs_xfer_memory; procfs_ops.to_insert_breakpoint = memory_insert_breakpoint; procfs_ops.to_remove_breakpoint = memory_remove_breakpoint; procfs_ops.to_notice_signals = procfs_notice_signals; @@ -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 @@ -3545,24 +3556,29 @@ procfs_attach (char *args, int from_tty) static void procfs_detach (char *args, int from_tty) { - char *exec_file; - int signo = 0; + int sig = 0; + + if (args) + sig = atoi (args); if (from_tty) { + int pid = PIDGET (inferior_ptid); + char *exec_file; + exec_file = get_exec_file (0); - if (exec_file == 0) + if (exec_file == NULL) exec_file = ""; - printf_filtered ("Detaching from program: %s %s\n", - exec_file, target_pid_to_str (inferior_ptid)); - fflush (stdout); + + printf_filtered ("Detaching from program: %s, %s\n", exec_file, + target_pid_to_str (pid_to_ptid (pid))); + gdb_flush (gdb_stdout); } - if (args) - signo = atoi (args); - do_detach (signo); + do_detach (sig); + inferior_ptid = null_ptid; - unpush_target (&procfs_ops); /* Pop out of handling an inferior */ + unpush_target (&procfs_ops); } static ptid_t @@ -4065,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)) { /* @@ -4191,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: @@ -4287,11 +4326,11 @@ procfs_xfer_partial (struct target_ops *ops, enum target_object object, { case TARGET_OBJECT_MEMORY: if (readbuf) - return (*ops->to_xfer_memory) (offset, readbuf, len, 0/*write*/, - NULL, ops); + return (*ops->deprecated_xfer_memory) (offset, readbuf, len, + 0/*write*/, NULL, ops); if (writebuf) - return (*ops->to_xfer_memory) (offset, readbuf, len, 1/*write*/, - NULL, ops); + return (*ops->deprecated_xfer_memory) (offset, writebuf, len, + 1/*write*/, NULL, ops); return -1; #ifdef NEW_PROC_API @@ -4842,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 } /* @@ -4972,7 +5037,8 @@ procfs_set_exec_trap (void) */ static void -procfs_create_inferior (char *exec_file, char *allargs, char **env) +procfs_create_inferior (char *exec_file, char *allargs, char **env, + int from_tty) { char *shell_file = getenv ("SHELL"); char *tryname; @@ -5047,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... */ @@ -5121,29 +5197,19 @@ procfs_thread_alive (ptid_t ptid) return 1; } -/* - * Function: target_pid_to_str - * - * Return a string to be used to identify the thread in - * the "info threads" display. - */ +/* Convert PTID to a string. Returns the string in a static buffer. */ char * procfs_pid_to_str (ptid_t ptid) { static char buf[80]; - int proc, thread; - procinfo *pi; - proc = PIDGET (ptid); - thread = TIDGET (ptid); - pi = find_procinfo (proc, thread); - - if (thread == 0) - sprintf (buf, "Process %d", proc); + if (TIDGET (ptid) == 0) + sprintf (buf, "process %d", PIDGET (ptid)); else - sprintf (buf, "LWP %d", thread); - return &buf[0]; + sprintf (buf, "LWP %ld", TIDGET (ptid)); + + return buf; } /* @@ -5519,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 * @@ -5707,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."); @@ -5723,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); } } |