#include "exceptions.h"
#include "cli/cli-decode.h"
#include "gdbthread.h"
+#include "valprint.h"
/* Functions exported for general use, in inferior.h: */
static void float_info (char *, int);
-static void detach_command (char *, int);
-
static void disconnect_command (char *, int);
static void unset_environment_command (char *, int);
/* We over-compute the size. It shouldn't matter. */
for (i = 0; i < argc; ++i)
- length += 2 * strlen (argv[i]) + 1 + 2 * (argv[i][0] == '\0');
+ length += 3 * strlen (argv[i]) + 1 + 2 * (argv[i][0] == '\0');
result = (char *) xmalloc (length);
out = result;
{
for (cp = argv[i]; *cp; ++cp)
{
- if (strchr (special, *cp) != NULL)
- *out++ = '\\';
- *out++ = *cp;
+ if (*cp == '\n')
+ {
+ /* A newline cannot be quoted with a backslash (it
+ just disappears), only by putting it inside
+ quotes. */
+ *out++ = '\'';
+ *out++ = '\n';
+ *out++ = '\'';
+ }
+ else
+ {
+ if (strchr (special, *cp) != NULL)
+ *out++ = '\\';
+ *out++ = *cp;
+ }
}
}
}
don't need to. */
target_find_description ();
- if (exec_bfd)
+ /* If the solist is global across processes, there's no need to
+ refetch it here. */
+ if (exec_bfd && !gdbarch_has_global_solist (target_gdbarch))
{
/* Sometimes the platform-specific hook loads initial shared
libraries, and sometimes it doesn't. Try to do so first, so
#else
solib_add (NULL, from_tty, target, auto_solib_add);
#endif
+ }
+ if (exec_bfd)
+ {
/* Create the hooks to handle shared library load and unload
events. */
#ifdef SOLIB_CREATE_INFERIOR_HOOK
static int
proceed_thread_callback (struct thread_info *thread, void *arg)
{
+ /* We go through all threads individually instead of compressing
+ into a single target `resume_all' request, because some threads
+ may be stopped in internal breakpoints/events, or stopped waiting
+ for its turn in the displaced stepping queue (that is, they are
+ running && !executing). The target side has no idea about why
+ the thread is stopped, so a `resume_all' command would resume too
+ much. If/when GDB gains a way to tell the target `hold this
+ thread stopped until I say otherwise', then we can optimize
+ this. */
if (!is_stopped (thread->ptid))
return 0;
make_cleanup (delete_longjmp_breakpoint_cleanup, &thread);
}
- /* In synchronous case, all is well, just use the regular for loop. */
+ /* In synchronous case, all is well; each step_once call will step once. */
if (!target_can_async_p ())
{
for (; count > 0; count--)
{
- struct thread_info *tp = inferior_thread ();
- clear_proceed_status ();
-
- frame = get_current_frame ();
- tp->step_frame_id = get_frame_id (frame);
+ struct thread_info *tp;
+ step_once (skip_subroutines, single_inst, count, thread);
- if (!single_inst)
- {
- find_pc_line_pc_range (stop_pc,
- &tp->step_range_start, &tp->step_range_end);
- if (tp->step_range_end == 0)
- {
- char *name;
- if (find_pc_partial_function (stop_pc, &name,
- &tp->step_range_start,
- &tp->step_range_end) == 0)
- error (_("Cannot find bounds of current function"));
-
- target_terminal_ours ();
- printf_filtered (_("\
-Single stepping until exit from function %s, \n\
-which has no line number information.\n"), name);
- }
- }
+ if (target_has_execution
+ && !ptid_equal (inferior_ptid, null_ptid))
+ tp = inferior_thread ();
else
+ tp = NULL;
+
+ if (!tp || !tp->stop_step || !tp->step_multi)
{
- /* Say we are stepping, but stop after one insn whatever it does. */
- tp->step_range_start = tp->step_range_end = 1;
- if (!skip_subroutines)
- /* It is stepi.
- Don't step over function calls, not even to functions lacking
- line numbers. */
- tp->step_over_calls = STEP_OVER_NONE;
+ /* If we stopped for some reason that is not stepping
+ there are no further steps to make. */
+ if (tp)
+ tp->step_multi = 0;
+ break;
}
-
- if (skip_subroutines)
- tp->step_over_calls = STEP_OVER_ALL;
-
- tp->step_multi = (count > 1);
- proceed ((CORE_ADDR) -1, TARGET_SIGNAL_DEFAULT, 1);
-
- if (!target_has_execution
- || !inferior_thread ()->stop_step)
- break;
}
do_cleanups (cleanups);
- return;
}
- /* In case of asynchronous target things get complicated, do only
- one step for now, before returning control to the event loop. Let
- the continuation figure out how many other steps we need to do,
- and handle them one at the time, through step_once(). */
else
{
+ /* In the case of an asynchronous target things get complicated;
+ do only one step for now, before returning control to the
+ event loop. Let the continuation figure out how many other
+ steps we need to do, and handle them one at the time, through
+ step_once. */
step_once (skip_subroutines, single_inst, count, thread);
+
/* We are running, and the continuation is installed. It will
disable the longjmp breakpoint as appropriate. */
discard_cleanups (cleanups);
{
/* There are more steps to make, and we did stop due to
ending a stepping range. Do another step. */
- step_once (a->skip_subroutines, a->single_inst, a->count - 1, a->thread);
+ step_once (a->skip_subroutines, a->single_inst,
+ a->count - 1, a->thread);
return;
}
tp->step_multi = 0;
delete_longjmp_breakpoint (a->thread);
}
-/* Do just one step operation. If count >1 we will have to set up a
- continuation to be done after the target stops (after this one
- step). This is useful to implement the 'step n' kind of commands, in
- case of asynchronous targets. We had to split step_1 into two parts,
- one to be done before proceed() and one afterwards. This function is
- called in case of step n with n>1, after the first step operation has
- been completed.*/
-static void
+/* Do just one step operation. This is useful to implement the 'step
+ n' kind of commands. In case of asynchronous targets, we will have
+ to set up a continuation to be done after the target stops (after
+ this one step). For synch targets, the caller handles further
+ stepping. */
+
+static void
step_once (int skip_subroutines, int single_inst, int count, int thread)
{
struct frame_info *frame;
- struct step_1_continuation_args *args;
if (count > 0)
{
clear_proceed_status ();
frame = get_current_frame ();
- if (!frame) /* Avoid coredump here. Why tho? */
- error (_("No current frame"));
tp->step_frame_id = get_frame_id (frame);
if (!single_inst)
{
- find_pc_line_pc_range (stop_pc,
+ CORE_ADDR pc;
+
+ pc = get_frame_pc (frame);
+ find_pc_line_pc_range (pc,
&tp->step_range_start, &tp->step_range_end);
/* If we have no line info, switch to stepi mode. */
else if (tp->step_range_end == 0)
{
char *name;
- if (find_pc_partial_function (stop_pc, &name,
+ if (find_pc_partial_function (pc, &name,
&tp->step_range_start,
&tp->step_range_end) == 0)
error (_("Cannot find bounds of current function"));
tp->step_multi = (count > 1);
proceed ((CORE_ADDR) -1, TARGET_SIGNAL_DEFAULT, 1);
- args = xmalloc (sizeof (*args));
- args->skip_subroutines = skip_subroutines;
- args->single_inst = single_inst;
- args->count = count;
- args->thread = thread;
- add_intermediate_continuation (tp, step_1_continuation, args, xfree);
+ /* For async targets, register a continuation to do any
+ additional steps. For sync targets, the caller will handle
+ further stepping. */
+ if (target_can_async_p ())
+ {
+ struct step_1_continuation_args *args;
+
+ args = xmalloc (sizeof (*args));
+ args->skip_subroutines = skip_subroutines;
+ args->single_inst = single_inst;
+ args->count = count;
+ args->thread = thread;
+
+ add_intermediate_continuation (tp, step_1_continuation, args, xfree);
+ }
}
}
than the current line (if in symbolic section) or pc (if
not). */
- pc = read_pc ();
+ pc = get_frame_pc (frame);
func = find_pc_function (pc);
if (!func)
if (value)
{
+ struct value_print_options opts;
+
/* Print it. */
stb = ui_out_stream_new (uiout);
old_chain = make_cleanup_ui_out_stream_delete (stb);
ui_out_field_fmt (uiout, "gdb-result-var", "$%d",
record_latest_value (value));
ui_out_text (uiout, " = ");
- value_print (value, stb->stream, 0, Val_no_prettyprint);
+ get_raw_print_options (&opts);
+ value_print (value, stb->stream, &opts);
ui_out_field_stream (uiout, "return-value", stb);
ui_out_text (uiout, "\n");
do_cleanups (old_chain);
struct thread_info *tp = inferior_thread ();
struct breakpoint *breakpoint;
struct cleanup *old_chain;
+ CORE_ADDR pc;
CORE_ADDR func_addr;
int back_up;
- if (find_pc_partial_function (get_frame_pc (get_current_frame ()),
- NULL, &func_addr, NULL) == 0)
+ pc = get_frame_pc (get_current_frame ());
+
+ if (find_pc_partial_function (pc, NULL, &func_addr, NULL) == 0)
internal_error (__FILE__, __LINE__,
_("Finish: couldn't find function."));
no way that a function up the stack can have a return address
that's equal to its entry point. */
- if (sal.pc != read_pc ())
+ if (sal.pc != pc)
{
/* Set breakpoint and continue. */
breakpoint =
|| TYPE_CODE (register_type (gdbarch, i)) == TYPE_CODE_DECFLOAT)
{
int j;
+ struct value_print_options opts;
+ get_user_print_options (&opts);
+ opts.deref_ref = 1;
val_print (register_type (gdbarch, i), buffer, 0, 0,
- file, 0, 1, 0, Val_pretty_default, current_language);
+ file, 0, &opts, current_language);
fprintf_filtered (file, "\t(raw 0x");
for (j = 0; j < register_size (gdbarch, i); j++)
}
else
{
+ struct value_print_options opts;
+
/* Print the register in hex. */
+ get_formatted_print_options (&opts, 'x');
+ opts.deref_ref = 1;
val_print (register_type (gdbarch, i), buffer, 0, 0,
- file, 'x', 1, 0, Val_pretty_default, current_language);
+ file, 0, &opts,
+ current_language);
/* If not a vector register, print it also according to its
natural format. */
if (TYPE_VECTOR (register_type (gdbarch, i)) == 0)
{
+ get_user_print_options (&opts);
+ opts.deref_ref = 1;
fprintf_filtered (file, "\t");
val_print (register_type (gdbarch, i), buffer, 0, 0,
- file, 0, 1, 0, Val_pretty_default, current_language);
+ file, 0, &opts, current_language);
}
}
if (regnum >= gdbarch_num_regs (gdbarch)
+ gdbarch_num_pseudo_regs (gdbarch))
{
+ struct value_print_options opts;
struct value *val = value_of_user_reg (regnum, frame);
printf_filtered ("%s: ", start);
+ get_formatted_print_options (&opts, 'x');
print_scalar_formatted (value_contents (val),
check_typedef (value_type (val)),
- 'x', 0, gdb_stdout);
+ &opts, 0, gdb_stdout);
printf_filtered ("\n");
}
else
}
\f
+/* Used in `attach&' command. ARG is a point to an integer
+ representing a process id. Proceed threads of this process iff
+ they stopped due to debugger request, and when they did, they
+ reported a clean stop (TARGET_SIGNAL_0). Do not proceed threads
+ that have been explicitly been told to stop. */
+
+static int
+proceed_after_attach_callback (struct thread_info *thread,
+ void *arg)
+{
+ int pid = * (int *) arg;
+
+ if (ptid_get_pid (thread->ptid) == pid
+ && !is_exited (thread->ptid)
+ && !is_executing (thread->ptid)
+ && !thread->stop_requested
+ && thread->stop_signal == TARGET_SIGNAL_0)
+ {
+ switch_to_thread (thread->ptid);
+ clear_proceed_status ();
+ proceed ((CORE_ADDR) -1, TARGET_SIGNAL_DEFAULT, 0);
+ }
+
+ return 0;
+}
+
+static void
+proceed_after_attach (int pid)
+{
+ /* Don't error out if the current thread is running, because
+ there may be other stopped threads. */
+ struct cleanup *old_chain;
+
+ /* Backup current thread and selected frame. */
+ old_chain = make_cleanup_restore_current_thread ();
+
+ iterate_over_threads (proceed_after_attach_callback, &pid);
+
+ /* Restore selected ptid. */
+ do_cleanups (old_chain);
+}
+
/*
* TODO:
* Should save/restore the tty state since it might be that the
target_terminal_inferior ();
if (async_exec)
- proceed ((CORE_ADDR) -1, TARGET_SIGNAL_0, 0);
+ {
+ /* The user requested an `attach&', so be sure to leave threads
+ that didn't get a signal running. */
+
+ /* Immediatelly resume all suspended threads of this inferior,
+ and this inferior only. This should have no effect on
+ already running threads. If a thread has been stopped with a
+ signal, leave it be. */
+ if (non_stop)
+ proceed_after_attach (inferior->pid);
+ else
+ {
+ if (inferior_thread ()->stop_signal == TARGET_SIGNAL_0)
+ {
+ clear_proceed_status ();
+ proceed ((CORE_ADDR) -1, TARGET_SIGNAL_DEFAULT, 0);
+ }
+ }
+ }
else
{
+ /* The user requested a plain `attach', so be sure to leave
+ the inferior stopped. */
+
if (target_can_async_p ())
async_enable_stdin ();
+
+ /* At least the current thread is already stopped. */
+
+ /* In all-stop, by definition, all threads have to be already
+ stopped at this point. In non-stop, however, although the
+ selected thread is stopped, others may still be executing.
+ Be sure to explicitly stop all threads of the process. This
+ should have no effect on already stopped threads. */
+ if (non_stop)
+ target_stop (pid_to_ptid (inferior->pid));
+
+ /* Tell the user/frontend where we're stopped. */
normal_stop ();
if (deprecated_attach_hook)
deprecated_attach_hook ();
char *exec_file;
char *full_exec_path = NULL;
int async_exec = 0;
+ struct cleanup *back_to = make_cleanup (null_cleanup, NULL);
dont_repeat (); /* Not for the faint of heart */
- if (target_has_execution)
+ if (target_supports_multi_process ())
+ /* Don't complain if we can be attached to multiple processes. */
+ ;
+ else if (target_has_execution)
{
if (query ("A program is being debugged already. Kill it? "))
target_kill ();
{
/* Simulate synchronous execution */
async_disable_stdin ();
+ make_cleanup ((make_cleanup_ftype *)async_enable_stdin, NULL);
}
target_attach (args, from_tty);
init_wait_for_inferior ();
clear_proceed_status ();
+ if (non_stop)
+ {
+ /* If we find that the current thread isn't stopped, explicitly
+ do so now, because we're going to install breakpoints and
+ poke at memory. */
+
+ if (async_exec)
+ /* The user requested an `attach&'; stop just one thread. */
+ target_stop (inferior_ptid);
+ else
+ /* The user requested an `attach', so stop all threads of this
+ inferior. */
+ target_stop (pid_to_ptid (ptid_get_pid (inferior_ptid)));
+ }
+
/* Some system don't generate traps when attaching to inferior.
E.g. Mach 3 or GNU hurd. */
if (!target_attach_no_wait)
a->args = xstrdup (args);
a->from_tty = from_tty;
a->async_exec = async_exec;
- add_continuation (inferior_thread (),
- attach_command_continuation, a,
- attach_command_continuation_free_args);
+ add_inferior_continuation (attach_command_continuation, a,
+ attach_command_continuation_free_args);
+ discard_cleanups (back_to);
return;
}
}
attach_command_post_wait (args, from_tty, async_exec);
+ discard_cleanups (back_to);
}
/*
* started via the normal ptrace (PTRACE_TRACEME).
*/
-static void
+void
detach_command (char *args, int from_tty)
{
dont_repeat (); /* Not for the faint of heart. */
target_detach (args, from_tty);
- no_shared_libraries (NULL, from_tty);
- init_thread_list ();
+
+ /* If the solist is global across inferiors, don't clear it when we
+ detach from a single inferior. */
+ if (!gdbarch_has_global_solist (target_gdbarch))
+ no_shared_libraries (NULL, from_tty);
+
+ /* If the current target interface claims there's still execution,
+ then don't mess with threads of other processes. */
+ if (!target_has_execution)
+ init_thread_list ();
+
if (deprecated_detach_hook)
deprecated_detach_hook ();
}