From 320f93f7149cbeffb23b93e16ddb92e18f577f16 Mon Sep 17 00:00:00 2001 From: Stu Grossman Date: Tue, 28 Jun 1994 23:36:52 +0000 Subject: [PATCH] * dbxread.c, partial-stab.h (near N_SO): SO stabs with blank names mean end of .o file. * infrun.c (wait_for_inferior): Clean up multi-thread logic near top of routine. Handle new thread notification cleanly. * lynx-nat.c (child_wait): General cleanups, handle new LynxOS thread notification scheme. * (child_resume): General cleanups, handle resumption of all threads properly. --- gdb/ChangeLog | 11 +++ gdb/dbxread.c | 44 +++------- gdb/infrun.c | 234 ++++++++++++++++++++++++++++--------------------- gdb/lynx-nat.c | 46 +++++++--- 4 files changed, 186 insertions(+), 149 deletions(-) diff --git a/gdb/ChangeLog b/gdb/ChangeLog index 4d84f37d2b2..2a65fb5b9d2 100644 --- a/gdb/ChangeLog +++ b/gdb/ChangeLog @@ -1,3 +1,14 @@ +Tue Jun 28 15:28:01 1994 Stu Grossman (grossman@cygnus.com) + + * dbxread.c, partial-stab.h (near N_SO): SO stabs with blank + names mean end of .o file. + * infrun.c (wait_for_inferior): Clean up multi-thread logic near + top of routine. Handle new thread notification cleanly. + * lynx-nat.c (child_wait): General cleanups, handle new LynxOS + thread notification scheme. + * (child_resume): General cleanups, handle resumption of all + threads properly. + Mon Jun 27 09:57:23 1994 Steve Chamberlain (sac@cirdan.cygnus.com) * ser-go32.c: Rewrite to run under windows. diff --git a/gdb/dbxread.c b/gdb/dbxread.c index a77f646f107..5445c8a0a5c 100644 --- a/gdb/dbxread.c +++ b/gdb/dbxread.c @@ -1903,11 +1903,16 @@ process_one_symbol (type, desc, valu, name, section_offsets, objfile) end_symtab (valu, 0, 0, objfile, SECT_OFF_TEXT); end_stabs (); } + + /* Null name means this just marks the end of text for this .o file. + Don't start a new symtab in this case. */ + if (*name == '\000') + break; + start_stabs (); start_symtab (name, NULL, valu); break; - case N_SOL: /* This type of symbol indicates the start of data for a sub-source-file, one whose contents were copied or @@ -2358,12 +2363,13 @@ elfstab_build_psymtabs (objfile, section_offsets, mainline, void stabsect_build_psymtabs (objfile, section_offsets, mainline, stab_name, - stabstr_name) + stabstr_name, text_name) struct objfile *objfile; struct section_offsets *section_offsets; int mainline; char *stab_name; char *stabstr_name; + char *text_name; { int val; bfd *sym_bfd = objfile->obfd; @@ -2384,9 +2390,9 @@ stabsect_build_psymtabs (objfile, section_offsets, mainline, stab_name, objfile->sym_stab_info = (PTR) xmalloc (sizeof (struct dbx_symfile_info)); memset (DBX_SYMFILE_INFO (objfile), 0, sizeof (struct dbx_symfile_info)); - DBX_TEXT_SECT (objfile) = bfd_get_section_by_name (sym_bfd, ".text"); + DBX_TEXT_SECT (objfile) = bfd_get_section_by_name (sym_bfd, text_name); if (!DBX_TEXT_SECT (objfile)) - error ("Can't find .text section in symbol file"); + error ("Can't find %s section in symbol file", text_name); DBX_SYMBOL_SIZE (objfile) = sizeof (struct external_nlist); DBX_SYMCOUNT (objfile) = bfd_section_size (sym_bfd, stabsect) @@ -2422,36 +2428,6 @@ stabsect_build_psymtabs (objfile, section_offsets, mainline, stab_name, dbx_symfile_read (objfile, section_offsets, 0); } -/* Scan and build partial symbols for a SOM symbol file. - This SOM file has already been processed to get its minimal symbols. - - OBJFILE is the object file we are reading symbols from. - ADDR is the address relative to which the symbols are (e.g. - the base address of the text segment). - MAINLINE is true if we are reading the main symbol - table (as opposed to a shared lib or dynamically loaded file). - - */ - -void -somstab_build_psymtabs (objfile, section_offsets, mainline) - struct objfile *objfile; - struct section_offsets *section_offsets; - int mainline; -{ - free_header_files (); - init_header_files (); - - /* This is needed to debug objects assembled with gas2. */ - processing_acc_compilation = 1; - - /* In a SOM file, we've already installed the minimal symbols that came - from the SOM (non-stab) symbol table, so always act like an - incremental load here. */ - - dbx_symfile_read (objfile, section_offsets, mainline); -} - /* Parse the user's idea of an offset for dynamic linking, into our idea of how to represent it for fast symbol reading. */ diff --git a/gdb/infrun.c b/gdb/infrun.c index 08e3bfdefde..9a9e35c7e08 100644 --- a/gdb/infrun.c +++ b/gdb/infrun.c @@ -294,6 +294,24 @@ proceed (addr, siggnal, step) else write_pc (addr); +#ifdef PREPARE_TO_PROCEED + /* In a multi-threaded task we may select another thread and then continue. + + In this case the thread that stopped at a breakpoint will immediately + cause another stop, if it is not stepped over first. On the other hand, + if (ADDR != -1) we only want to single step over the breakpoint if we did + switch to another thread. + + If we are single stepping, don't do any of the above. + (Note that in the current implementation single stepping another + thread after a breakpoint and then continuing will cause the original + breakpoint to be hit again, but you can always continue, so it's not + a big deal.) */ + + if (! step && PREPARE_TO_PROCEED && breakpoint_here_p (read_pc ())) + oneproc = 1; +#endif /* PREPARE_TO_PROCEED */ + if (trap_expected_after_continue) { /* If (step == 0), a trap will be automatically generated after @@ -437,11 +455,25 @@ wait_for_inferior () while (1) { + /* We have to invalidate the registers BEFORE calling target_wait because + they can be loaded from the target while in target_wait. This makes + remote debugging a bit more efficient for those targets that provide + critical registers as part of their normal status mechanism. */ + + registers_changed (); + pid = target_wait (-1, &w); - /* Clean up saved state that will become invalid. */ flush_cached_frames (); - registers_changed (); + + /* If it's a new process, add it to the thread database */ + + if (pid != inferior_pid + && !in_thread_list (pid)) + { + fprintf_unfiltered (gdb_stderr, "[New %s]\n", target_pid_to_str (pid)); + add_thread (pid); + } switch (w.kind) { @@ -507,125 +539,104 @@ wait_for_inferior () stop_signal = w.value.sig; - if (pid != inferior_pid) - { - int save_pid = inferior_pid; + stop_pc = read_pc_pid (pid); - inferior_pid = pid; /* Setup for target memory/regs */ - registers_changed (); - stop_pc = read_pc (); - inferior_pid = save_pid; - registers_changed (); - } - else - stop_pc = read_pc (); + /* See if a thread hit a thread-specific breakpoint that was meant for + another thread. If so, then step that thread past the breakpoint, + and continue it. */ if (stop_signal == TARGET_SIGNAL_TRAP + && breakpoints_inserted && breakpoint_here_p (stop_pc - DECR_PC_AFTER_BREAK)) { + random_signal = 0; if (!breakpoint_thread_match (stop_pc - DECR_PC_AFTER_BREAK, pid)) { /* Saw a breakpoint, but it was hit by the wrong thread. Just continue. */ - if (breakpoints_inserted) - { - if (pid != inferior_pid) - { - int save_pid = inferior_pid; - - inferior_pid = pid; - registers_changed (); - write_pc (stop_pc - DECR_PC_AFTER_BREAK); - inferior_pid = save_pid; - registers_changed (); - } - else - write_pc (stop_pc - DECR_PC_AFTER_BREAK); - - remove_breakpoints (); - target_resume (pid, 1, TARGET_SIGNAL_0); /* Single step */ - /* FIXME: What if a signal arrives instead of the single-step - happening? */ - target_wait (pid, &w); - insert_breakpoints (); - } - target_resume (-1, 0, TARGET_SIGNAL_0); + write_pc (stop_pc - DECR_PC_AFTER_BREAK); + + remove_breakpoints (); + target_resume (pid, 1, TARGET_SIGNAL_0); /* Single step */ + /* FIXME: What if a signal arrives instead of the single-step + happening? */ + target_wait (pid, &w); + insert_breakpoints (); + target_resume (pid, 0, TARGET_SIGNAL_0); continue; } - else - if (pid != inferior_pid) - goto switch_thread; } + else + random_signal = 1; + + /* See if something interesting happened to the non-current thread. If + so, then switch to that thread, and eventually give control back to + the user. */ if (pid != inferior_pid) { int printed = 0; - if (!in_thread_list (pid)) + /* If it's a random signal for a non-current thread, notify user + if he's expressed an interest. */ + + if (random_signal + && signal_print[stop_signal]) { - fprintf_unfiltered (gdb_stderr, "[New %s]\n", target_pid_to_str (pid)); - add_thread (pid); + printed = 1; + target_terminal_ours_for_output (); + printf_filtered ("\nProgram received signal %s, %s.\n", + target_signal_to_name (stop_signal), + target_signal_to_string (stop_signal)); + gdb_flush (gdb_stdout); + } + + /* If it's not SIGTRAP and not a signal we want to stop for, then + continue the thread. */ + + if (stop_signal != TARGET_SIGNAL_TRAP + && !signal_stop[stop_signal]) + { + if (printed) + target_terminal_inferior (); - target_resume (-1, 0, TARGET_SIGNAL_0); + /* Clear the signal if it should not be passed. */ + if (signal_program[stop_signal] == 0) + stop_signal = TARGET_SIGNAL_0; + + target_resume (pid, 0, stop_signal); continue; } - else + + /* It's a SIGTRAP or a signal we're interested in. Switch threads, + and fall into the rest of wait_for_inferior(). */ + + inferior_pid = pid; + printf_filtered ("[Switching to %s]\n", target_pid_to_str (pid)); + + flush_cached_frames (); + trap_expected = 0; + if (step_resume_breakpoint) { - if (signal_print[stop_signal]) - { - printed = 1; - target_terminal_ours_for_output (); - printf_filtered ("\nProgram received signal %s, %s.\n", - target_signal_to_name (stop_signal), - target_signal_to_string (stop_signal)); - gdb_flush (gdb_stdout); - } - - if (stop_signal == TARGET_SIGNAL_TRAP - || signal_stop[stop_signal]) - { -switch_thread: - inferior_pid = pid; - printf_filtered ("[Switching to %s]\n", target_pid_to_str (pid)); - - flush_cached_frames (); - registers_changed (); - trap_expected = 0; - if (step_resume_breakpoint) - { - delete_breakpoint (step_resume_breakpoint); - step_resume_breakpoint = NULL; - } - - /* Not sure whether we need to blow this away too, - but probably it is like the step-resume - breakpoint. */ - if (through_sigtramp_breakpoint) - { - delete_breakpoint (through_sigtramp_breakpoint); - through_sigtramp_breakpoint = NULL; - } - prev_pc = 0; - prev_sp = 0; - prev_func_name = NULL; - step_range_start = 0; - step_range_end = 0; - step_frame_address = 0; - handling_longjmp = 0; - another_trap = 0; - } - else - { - if (printed) - target_terminal_inferior (); - - /* Clear the signal if it should not be passed. */ - if (signal_program[stop_signal] == 0) - stop_signal = TARGET_SIGNAL_0; - - target_resume (pid, 0, stop_signal); - continue; - } + delete_breakpoint (step_resume_breakpoint); + step_resume_breakpoint = NULL; } + + /* Not sure whether we need to blow this away too, + but probably it is like the step-resume + breakpoint. */ + if (through_sigtramp_breakpoint) + { + delete_breakpoint (through_sigtramp_breakpoint); + through_sigtramp_breakpoint = NULL; + } + prev_pc = 0; + prev_sp = 0; + prev_func_name = NULL; + step_range_start = 0; + step_range_end = 0; + step_frame_address = 0; + handling_longjmp = 0; + another_trap = 0; } #ifdef NO_SINGLE_STEP @@ -1061,12 +1072,19 @@ switch_thread: goto keep_going; } +#if 1 if (stop_func_start) { + struct symtab *s; + /* Do this after the IN_SIGTRAMP check; it might give an error. */ prologue_pc = stop_func_start; - SKIP_PROLOGUE (prologue_pc); + + /* Don't skip the prologue if this is assembly source */ + s = find_pc_symtab (stop_pc); + if (s && s->language != language_asm) + SKIP_PROLOGUE (prologue_pc); } if ((/* Might be a non-recursive call. If the symbols are missing @@ -1105,6 +1123,14 @@ switch_thread: which can no longer happen here as long as the handling_longjmp stuff is working. */ )) +#else +/* This is experimental code which greatly simplifies the subroutine call + test. I've actually tested on the Alpha, and it works great. -Stu */ + + if (in_prologue (stop_pc, NULL) + || (prev_func_start != 0 + && stop_func_start == 0)) +#endif { /* It's a subroutine call. */ @@ -1166,7 +1192,13 @@ step_over_function: step_into_function: /* Subroutine call with source code we should not step over. Do step to the first line of code in it. */ - SKIP_PROLOGUE (stop_func_start); + { + struct symtab *s; + + s = find_pc_symtab (stop_pc); + if (s && s->language != language_asm) + SKIP_PROLOGUE (stop_func_start); + } sal = find_pc_line (stop_func_start, 0); /* Use the step_resume_break to step until the end of the prologue, even if that involves jumps diff --git a/gdb/lynx-nat.c b/gdb/lynx-nat.c index 49f361d3c2d..3d7c92d9eb3 100644 --- a/gdb/lynx-nat.c +++ b/gdb/lynx-nat.c @@ -597,7 +597,7 @@ child_wait (pid, ourstatus) { int save_errno; int thread; - int status; + union wait status; while (1) { @@ -632,8 +632,7 @@ child_wait (pid, ourstatus) if (pid != PIDGET (inferior_pid)) /* Some other process?!? */ continue; -/* thread = WIFTID (status);*/ - thread = status >> 16; + thread = status.w_tid; /* Get thread id from status */ /* Initial thread value can only be acquired via wait, so we have to resort to this hack. */ @@ -646,7 +645,26 @@ child_wait (pid, ourstatus) pid = BUILDPID (pid, thread); - store_waitstatus (ourstatus, status); + if (WIFSTOPPED(status) + && WSTOPSIG(status) == SIGTRAP + && !in_thread_list (pid)) + { + int realsig; + + realsig = ptrace (PTRACE_GETTRACESIG, pid, 0); + + if (realsig == SIGNEWTHREAD) + { + /* Simply ignore new thread notification, as we can't do anything + useful with such threads. All ptrace calls at this point just + fail for no apparent reason. The thread will eventually get a + real signal when it becomes real. */ + child_resume (pid, 0, TARGET_SIGNAL_0); + continue; + } + } + + store_waitstatus (ourstatus, status.w_status); return pid; } @@ -662,13 +680,18 @@ child_resume (pid, step, signal) int step; enum target_signal signal; { + int func; + errno = 0; if (pid == -1) - /* Resume all threads. */ - /* I think this only gets used in the non-threaded case, where "resume - all threads" and "resume inferior_pid" are the same. */ - pid = inferior_pid; + { + /* Resume all threads. */ + + pid = inferior_pid; + } + + func = step ? PTRACE_SINGLESTEP_ONE : PTRACE_CONT; /* An address of (PTRACE_ARG3_TYPE)1 tells ptrace to continue from where it was. (If GDB wanted it to start some other way, we have already @@ -679,12 +702,7 @@ child_resume (pid, step, signal) continue request (by setting breakpoints on all possible successor instructions), so we don't have to worry about that here. */ - if (step) - ptrace (PTRACE_SINGLESTEP_ONE, pid, (PTRACE_ARG3_TYPE) 1, - target_signal_to_host (signal)); - else - ptrace (PTRACE_CONT_ONE, pid, (PTRACE_ARG3_TYPE) 1, - target_signal_to_host (signal)); + ptrace (func, pid, (PTRACE_ARG3_TYPE) 1, target_signal_to_host (signal)); if (errno) perror_with_name ("ptrace"); -- 2.30.2