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
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;
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)
dbx_symfile_read (objfile, section_offsets, 0);
}
\f
-/* 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);
-}
-\f
/* Parse the user's idea of an offset for dynamic linking, into our idea
of how to represent it for fast symbol reading. */
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
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)
{
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
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
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. */
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
{
int save_errno;
int thread;
- int status;
+ union wait status;
while (1)
{
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. */
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;
}
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
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");