Index: gdb/target.c |
diff --git a/gdb/target.c b/gdb/target.c |
index 9aaa0eac44e084ee1cb9c31116aa48285ea8377b..bb8eae8e8e3808015ed873a251b9f9d932904bf9 100644 |
--- a/gdb/target.c |
+++ b/gdb/target.c |
@@ -29,7 +29,6 @@ |
#include "bfd.h" |
#include "symfile.h" |
#include "objfiles.h" |
-#include "gdb_wait.h" |
#include "dcache.h" |
#include <signal.h> |
#include "regcache.h" |
@@ -42,6 +41,8 @@ |
#include "exec.h" |
#include "inline-frame.h" |
#include "tracepoint.h" |
+#include "gdb/fileio.h" |
+#include "agent.h" |
static void target_info (char *, int); |
@@ -637,6 +638,7 @@ update_current_target (void) |
/* Do not inherit to_mourn_inferior. */ |
INHERIT (to_can_run, t); |
/* Do not inherit to_pass_signals. */ |
+ /* Do not inherit to_program_signals. */ |
/* Do not inherit to_thread_alive. */ |
/* Do not inherit to_find_new_threads. */ |
/* Do not inherit to_pid_to_str. */ |
@@ -697,7 +699,11 @@ update_current_target (void) |
INHERIT (to_static_tracepoint_marker_at, t); |
INHERIT (to_static_tracepoint_markers_by_strid, t); |
INHERIT (to_traceframe_info, t); |
+ INHERIT (to_use_agent, t); |
+ INHERIT (to_can_use_agent, t); |
INHERIT (to_magic, t); |
+ INHERIT (to_supports_evaluation_of_breakpoint_conditions, t); |
+ INHERIT (to_can_run_breakpoint_commands, t); |
/* Do not inherit to_memory_map. */ |
/* Do not inherit to_flash_erase. */ |
/* Do not inherit to_flash_done. */ |
@@ -924,6 +930,18 @@ update_current_target (void) |
de_fault (to_traceframe_info, |
(struct traceframe_info * (*) (void)) |
tcomplain); |
+ de_fault (to_supports_evaluation_of_breakpoint_conditions, |
+ (int (*) (void)) |
+ return_zero); |
+ de_fault (to_can_run_breakpoint_commands, |
+ (int (*) (void)) |
+ return_zero); |
+ de_fault (to_use_agent, |
+ (int (*) (int)) |
+ tcomplain); |
+ de_fault (to_can_use_agent, |
+ (int (*) (void)) |
+ return_zero); |
de_fault (to_execution_direction, default_execution_direction); |
#undef de_fault |
@@ -1010,16 +1028,10 @@ unpush_target (struct target_ops *t) |
break; |
} |
+ /* If we don't find target_ops, quit. Only open targets should be |
+ closed. */ |
if ((*cur) == NULL) |
- return 0; /* Didn't find target_ops, quit now. */ |
- |
- /* NOTE: cagney/2003-12-06: In '94 the close call was made |
- unconditional by moving it to before the above check that the |
- target was in the target stack (something about "Change the way |
- pushing and popping of targets work to support target overlays |
- and inheritance"). This doesn't make much sense - only open |
- targets should be closed. */ |
- target_close (t, 0); |
+ return 0; |
/* Unchain the target. */ |
tmp = (*cur); |
@@ -1028,6 +1040,11 @@ unpush_target (struct target_ops *t) |
update_current_target (); |
+ /* Finally close the target. Note we do this after unchaining, so |
+ any target method calls from within the target_close |
+ implementation don't end up in T anymore. */ |
+ target_close (t, 0); |
+ |
return 1; |
} |
@@ -1743,7 +1760,7 @@ target_xfer_partial (struct target_ops *ops, |
it makes no progress, and then return how much was transferred). */ |
int |
-target_read_memory (CORE_ADDR memaddr, gdb_byte *myaddr, int len) |
+target_read_memory (CORE_ADDR memaddr, gdb_byte *myaddr, ssize_t len) |
{ |
/* Dispatch to the topmost target, not the flattened current_target. |
Memory accesses check target->to_has_(all_)memory, and the |
@@ -1759,7 +1776,7 @@ target_read_memory (CORE_ADDR memaddr, gdb_byte *myaddr, int len) |
the target's stack. This may trigger different cache behavior. */ |
int |
-target_read_stack (CORE_ADDR memaddr, gdb_byte *myaddr, int len) |
+target_read_stack (CORE_ADDR memaddr, gdb_byte *myaddr, ssize_t len) |
{ |
/* Dispatch to the topmost target, not the flattened current_target. |
Memory accesses check target->to_has_(all_)memory, and the |
@@ -1778,7 +1795,7 @@ target_read_stack (CORE_ADDR memaddr, gdb_byte *myaddr, int len) |
Callers that can deal with partial writes should call target_write. */ |
int |
-target_write_memory (CORE_ADDR memaddr, const gdb_byte *myaddr, int len) |
+target_write_memory (CORE_ADDR memaddr, const gdb_byte *myaddr, ssize_t len) |
{ |
/* Dispatch to the topmost target, not the flattened current_target. |
Memory accesses check target->to_has_(all_)memory, and the |
@@ -1797,7 +1814,7 @@ target_write_memory (CORE_ADDR memaddr, const gdb_byte *myaddr, int len) |
should call target_write. */ |
int |
-target_write_raw_memory (CORE_ADDR memaddr, const gdb_byte *myaddr, int len) |
+target_write_raw_memory (CORE_ADDR memaddr, const gdb_byte *myaddr, ssize_t len) |
{ |
/* Dispatch to the topmost target, not the flattened current_target. |
Memory accesses check target->to_has_(all_)memory, and the |
@@ -2345,7 +2362,7 @@ target_read_stralloc (struct target_ops *ops, enum target_object object, |
const char *annex) |
{ |
gdb_byte *buffer; |
- LONGEST transferred; |
+ LONGEST i, transferred; |
transferred = target_read_alloc_1 (ops, object, annex, &buffer, 1); |
@@ -2356,10 +2373,16 @@ target_read_stralloc (struct target_ops *ops, enum target_object object, |
return xstrdup (""); |
buffer[transferred] = 0; |
- if (strlen (buffer) < transferred) |
- warning (_("target object %d, annex %s, " |
- "contained unexpected null characters"), |
- (int) object, annex ? annex : "(none)"); |
+ |
+ /* Check for embedded NUL bytes; but allow trailing NULs. */ |
+ for (i = strlen (buffer); i < transferred; i++) |
+ if (buffer[i] != 0) |
+ { |
+ warning (_("target object %d, annex %s, " |
+ "contained unexpected null characters"), |
+ (int) object, annex ? annex : "(none)"); |
+ break; |
+ } |
return (char *) buffer; |
} |
@@ -2482,6 +2505,8 @@ target_pre_inferior (int from_tty) |
target_clear_description (); |
} |
+ |
+ agent_capability_invalidate (); |
} |
/* Callback for iterate_over_inferiors. Gets rid of the given |
@@ -2649,7 +2674,7 @@ target_thread_name (struct thread_info *info) |
} |
void |
-target_resume (ptid_t ptid, int step, enum target_signal signal) |
+target_resume (ptid_t ptid, int step, enum gdb_signal signal) |
{ |
struct target_ops *t; |
@@ -2664,7 +2689,7 @@ target_resume (ptid_t ptid, int step, enum target_signal signal) |
fprintf_unfiltered (gdb_stdlog, "target_resume (%d, %s, %s)\n", |
PIDGET (ptid), |
step ? "step" : "continue", |
- target_signal_to_name (signal)); |
+ gdb_signal_to_name (signal)); |
registers_changed_ptid (ptid); |
set_executing (ptid, 1); |
@@ -2696,7 +2721,7 @@ target_pass_signals (int numsigs, unsigned char *pass_signals) |
for (i = 0; i < numsigs; i++) |
if (pass_signals[i]) |
fprintf_unfiltered (gdb_stdlog, " %s", |
- target_signal_to_name (i)); |
+ gdb_signal_to_name (i)); |
fprintf_unfiltered (gdb_stdlog, " })\n"); |
} |
@@ -2707,6 +2732,36 @@ target_pass_signals (int numsigs, unsigned char *pass_signals) |
} |
} |
+void |
+target_program_signals (int numsigs, unsigned char *program_signals) |
+{ |
+ struct target_ops *t; |
+ |
+ for (t = current_target.beneath; t != NULL; t = t->beneath) |
+ { |
+ if (t->to_program_signals != NULL) |
+ { |
+ if (targetdebug) |
+ { |
+ int i; |
+ |
+ fprintf_unfiltered (gdb_stdlog, "target_program_signals (%d, {", |
+ numsigs); |
+ |
+ for (i = 0; i < numsigs; i++) |
+ if (program_signals[i]) |
+ fprintf_unfiltered (gdb_stdlog, " %s", |
+ gdb_signal_to_name (i)); |
+ |
+ fprintf_unfiltered (gdb_stdlog, " })\n"); |
+ } |
+ |
+ (*t->to_program_signals) (numsigs, program_signals); |
+ return; |
+ } |
+ } |
+} |
+ |
/* Look through the list of possible targets for a target that can |
follow forks. */ |
@@ -3081,6 +3136,38 @@ target_supports_non_stop (void) |
return 0; |
} |
+/* Implement the "info proc" command. */ |
+ |
+void |
+target_info_proc (char *args, enum info_proc_what what) |
+{ |
+ struct target_ops *t; |
+ |
+ /* If we're already connected to something that can get us OS |
+ related data, use it. Otherwise, try using the native |
+ target. */ |
+ if (current_target.to_stratum >= process_stratum) |
+ t = current_target.beneath; |
+ else |
+ t = find_default_run_target (NULL); |
+ |
+ for (; t != NULL; t = t->beneath) |
+ { |
+ if (t->to_info_proc != NULL) |
+ { |
+ t->to_info_proc (t, args, what); |
+ |
+ if (targetdebug) |
+ fprintf_unfiltered (gdb_stdlog, |
+ "target_info_proc (\"%s\", %d)\n", args, what); |
+ |
+ return; |
+ } |
+ } |
+ |
+ error (_("Not supported on this target.")); |
+} |
+ |
static int |
find_default_supports_disable_randomization (void) |
{ |
@@ -3160,6 +3247,304 @@ target_thread_address_space (ptid_t ptid) |
return inf->aspace; |
} |
+ |
+/* Target file operations. */ |
+ |
+static struct target_ops * |
+default_fileio_target (void) |
+{ |
+ /* If we're already connected to something that can perform |
+ file I/O, use it. Otherwise, try using the native target. */ |
+ if (current_target.to_stratum >= process_stratum) |
+ return current_target.beneath; |
+ else |
+ return find_default_run_target ("file I/O"); |
+} |
+ |
+/* Open FILENAME on the target, using FLAGS and MODE. Return a |
+ target file descriptor, or -1 if an error occurs (and set |
+ *TARGET_ERRNO). */ |
+int |
+target_fileio_open (const char *filename, int flags, int mode, |
+ int *target_errno) |
+{ |
+ struct target_ops *t; |
+ |
+ for (t = default_fileio_target (); t != NULL; t = t->beneath) |
+ { |
+ if (t->to_fileio_open != NULL) |
+ { |
+ int fd = t->to_fileio_open (filename, flags, mode, target_errno); |
+ |
+ if (targetdebug) |
+ fprintf_unfiltered (gdb_stdlog, |
+ "target_fileio_open (%s,0x%x,0%o) = %d (%d)\n", |
+ filename, flags, mode, |
+ fd, fd != -1 ? 0 : *target_errno); |
+ return fd; |
+ } |
+ } |
+ |
+ *target_errno = FILEIO_ENOSYS; |
+ return -1; |
+} |
+ |
+/* Write up to LEN bytes from WRITE_BUF to FD on the target. |
+ Return the number of bytes written, or -1 if an error occurs |
+ (and set *TARGET_ERRNO). */ |
+int |
+target_fileio_pwrite (int fd, const gdb_byte *write_buf, int len, |
+ ULONGEST offset, int *target_errno) |
+{ |
+ struct target_ops *t; |
+ |
+ for (t = default_fileio_target (); t != NULL; t = t->beneath) |
+ { |
+ if (t->to_fileio_pwrite != NULL) |
+ { |
+ int ret = t->to_fileio_pwrite (fd, write_buf, len, offset, |
+ target_errno); |
+ |
+ if (targetdebug) |
+ fprintf_unfiltered (gdb_stdlog, |
+ "target_fileio_pwrite (%d,...,%d,%s) " |
+ "= %d (%d)\n", |
+ fd, len, pulongest (offset), |
+ ret, ret != -1 ? 0 : *target_errno); |
+ return ret; |
+ } |
+ } |
+ |
+ *target_errno = FILEIO_ENOSYS; |
+ return -1; |
+} |
+ |
+/* Read up to LEN bytes FD on the target into READ_BUF. |
+ Return the number of bytes read, or -1 if an error occurs |
+ (and set *TARGET_ERRNO). */ |
+int |
+target_fileio_pread (int fd, gdb_byte *read_buf, int len, |
+ ULONGEST offset, int *target_errno) |
+{ |
+ struct target_ops *t; |
+ |
+ for (t = default_fileio_target (); t != NULL; t = t->beneath) |
+ { |
+ if (t->to_fileio_pread != NULL) |
+ { |
+ int ret = t->to_fileio_pread (fd, read_buf, len, offset, |
+ target_errno); |
+ |
+ if (targetdebug) |
+ fprintf_unfiltered (gdb_stdlog, |
+ "target_fileio_pread (%d,...,%d,%s) " |
+ "= %d (%d)\n", |
+ fd, len, pulongest (offset), |
+ ret, ret != -1 ? 0 : *target_errno); |
+ return ret; |
+ } |
+ } |
+ |
+ *target_errno = FILEIO_ENOSYS; |
+ return -1; |
+} |
+ |
+/* Close FD on the target. Return 0, or -1 if an error occurs |
+ (and set *TARGET_ERRNO). */ |
+int |
+target_fileio_close (int fd, int *target_errno) |
+{ |
+ struct target_ops *t; |
+ |
+ for (t = default_fileio_target (); t != NULL; t = t->beneath) |
+ { |
+ if (t->to_fileio_close != NULL) |
+ { |
+ int ret = t->to_fileio_close (fd, target_errno); |
+ |
+ if (targetdebug) |
+ fprintf_unfiltered (gdb_stdlog, |
+ "target_fileio_close (%d) = %d (%d)\n", |
+ fd, ret, ret != -1 ? 0 : *target_errno); |
+ return ret; |
+ } |
+ } |
+ |
+ *target_errno = FILEIO_ENOSYS; |
+ return -1; |
+} |
+ |
+/* Unlink FILENAME on the target. Return 0, or -1 if an error |
+ occurs (and set *TARGET_ERRNO). */ |
+int |
+target_fileio_unlink (const char *filename, int *target_errno) |
+{ |
+ struct target_ops *t; |
+ |
+ for (t = default_fileio_target (); t != NULL; t = t->beneath) |
+ { |
+ if (t->to_fileio_unlink != NULL) |
+ { |
+ int ret = t->to_fileio_unlink (filename, target_errno); |
+ |
+ if (targetdebug) |
+ fprintf_unfiltered (gdb_stdlog, |
+ "target_fileio_unlink (%s) = %d (%d)\n", |
+ filename, ret, ret != -1 ? 0 : *target_errno); |
+ return ret; |
+ } |
+ } |
+ |
+ *target_errno = FILEIO_ENOSYS; |
+ return -1; |
+} |
+ |
+/* Read value of symbolic link FILENAME on the target. Return a |
+ null-terminated string allocated via xmalloc, or NULL if an error |
+ occurs (and set *TARGET_ERRNO). */ |
+char * |
+target_fileio_readlink (const char *filename, int *target_errno) |
+{ |
+ struct target_ops *t; |
+ |
+ for (t = default_fileio_target (); t != NULL; t = t->beneath) |
+ { |
+ if (t->to_fileio_readlink != NULL) |
+ { |
+ char *ret = t->to_fileio_readlink (filename, target_errno); |
+ |
+ if (targetdebug) |
+ fprintf_unfiltered (gdb_stdlog, |
+ "target_fileio_readlink (%s) = %s (%d)\n", |
+ filename, ret? ret : "(nil)", |
+ ret? 0 : *target_errno); |
+ return ret; |
+ } |
+ } |
+ |
+ *target_errno = FILEIO_ENOSYS; |
+ return NULL; |
+} |
+ |
+static void |
+target_fileio_close_cleanup (void *opaque) |
+{ |
+ int fd = *(int *) opaque; |
+ int target_errno; |
+ |
+ target_fileio_close (fd, &target_errno); |
+} |
+ |
+/* Read target file FILENAME. Store the result in *BUF_P and |
+ return the size of the transferred data. PADDING additional bytes are |
+ available in *BUF_P. This is a helper function for |
+ target_fileio_read_alloc; see the declaration of that function for more |
+ information. */ |
+ |
+static LONGEST |
+target_fileio_read_alloc_1 (const char *filename, |
+ gdb_byte **buf_p, int padding) |
+{ |
+ struct cleanup *close_cleanup; |
+ size_t buf_alloc, buf_pos; |
+ gdb_byte *buf; |
+ LONGEST n; |
+ int fd; |
+ int target_errno; |
+ |
+ fd = target_fileio_open (filename, FILEIO_O_RDONLY, 0700, &target_errno); |
+ if (fd == -1) |
+ return -1; |
+ |
+ close_cleanup = make_cleanup (target_fileio_close_cleanup, &fd); |
+ |
+ /* Start by reading up to 4K at a time. The target will throttle |
+ this number down if necessary. */ |
+ buf_alloc = 4096; |
+ buf = xmalloc (buf_alloc); |
+ buf_pos = 0; |
+ while (1) |
+ { |
+ n = target_fileio_pread (fd, &buf[buf_pos], |
+ buf_alloc - buf_pos - padding, buf_pos, |
+ &target_errno); |
+ if (n < 0) |
+ { |
+ /* An error occurred. */ |
+ do_cleanups (close_cleanup); |
+ xfree (buf); |
+ return -1; |
+ } |
+ else if (n == 0) |
+ { |
+ /* Read all there was. */ |
+ do_cleanups (close_cleanup); |
+ if (buf_pos == 0) |
+ xfree (buf); |
+ else |
+ *buf_p = buf; |
+ return buf_pos; |
+ } |
+ |
+ buf_pos += n; |
+ |
+ /* If the buffer is filling up, expand it. */ |
+ if (buf_alloc < buf_pos * 2) |
+ { |
+ buf_alloc *= 2; |
+ buf = xrealloc (buf, buf_alloc); |
+ } |
+ |
+ QUIT; |
+ } |
+} |
+ |
+/* Read target file FILENAME. Store the result in *BUF_P and return |
+ the size of the transferred data. See the declaration in "target.h" |
+ function for more information about the return value. */ |
+ |
+LONGEST |
+target_fileio_read_alloc (const char *filename, gdb_byte **buf_p) |
+{ |
+ return target_fileio_read_alloc_1 (filename, buf_p, 0); |
+} |
+ |
+/* Read target file FILENAME. The result is NUL-terminated and |
+ returned as a string, allocated using xmalloc. If an error occurs |
+ or the transfer is unsupported, NULL is returned. Empty objects |
+ are returned as allocated but empty strings. A warning is issued |
+ if the result contains any embedded NUL bytes. */ |
+ |
+char * |
+target_fileio_read_stralloc (const char *filename) |
+{ |
+ gdb_byte *buffer; |
+ LONGEST i, transferred; |
+ |
+ transferred = target_fileio_read_alloc_1 (filename, &buffer, 1); |
+ |
+ if (transferred < 0) |
+ return NULL; |
+ |
+ if (transferred == 0) |
+ return xstrdup (""); |
+ |
+ buffer[transferred] = 0; |
+ |
+ /* Check for embedded NUL bytes; but allow trailing NULs. */ |
+ for (i = strlen (buffer); i < transferred; i++) |
+ if (buffer[i] != 0) |
+ { |
+ warning (_("target file %s " |
+ "contained unexpected null characters"), |
+ filename); |
+ break; |
+ } |
+ |
+ return (char *) buffer; |
+} |
+ |
+ |
static int |
default_region_ok_for_hw_watchpoint (CORE_ADDR addr, int len) |
{ |
@@ -3243,13 +3628,22 @@ generic_mourn_inferior (void) |
ptid = inferior_ptid; |
inferior_ptid = null_ptid; |
+ /* Mark breakpoints uninserted in case something tries to delete a |
+ breakpoint while we delete the inferior's threads (which would |
+ fail, since the inferior is long gone). */ |
+ mark_breakpoints_out (); |
+ |
if (!ptid_equal (ptid, null_ptid)) |
{ |
int pid = ptid_get_pid (ptid); |
exit_inferior (pid); |
} |
+ /* Note this wipes step-resume breakpoints, so needs to be done |
+ after exit_inferior, which ends up referencing the step-resume |
+ breakpoints through clear_thread_inferior_resources. */ |
breakpoint_init_inferior (inf_exited); |
+ |
registers_changed (); |
reopen_exec_file (); |
@@ -3259,29 +3653,6 @@ generic_mourn_inferior (void) |
deprecated_detach_hook (); |
} |
-/* Helper function for child_wait and the derivatives of child_wait. |
- HOSTSTATUS is the waitstatus from wait() or the equivalent; store our |
- translation of that in OURSTATUS. */ |
-void |
-store_waitstatus (struct target_waitstatus *ourstatus, int hoststatus) |
-{ |
- if (WIFEXITED (hoststatus)) |
- { |
- ourstatus->kind = TARGET_WAITKIND_EXITED; |
- ourstatus->value.integer = WEXITSTATUS (hoststatus); |
- } |
- else if (!WIFSTOPPED (hoststatus)) |
- { |
- ourstatus->kind = TARGET_WAITKIND_SIGNALLED; |
- ourstatus->value.sig = target_signal_from_host (WTERMSIG (hoststatus)); |
- } |
- else |
- { |
- ourstatus->kind = TARGET_WAITKIND_STOPPED; |
- ourstatus->value.sig = target_signal_from_host (WSTOPSIG (hoststatus)); |
- } |
-} |
- |
/* Convert a normal process ID to a string. Returns the string in a |
static buffer. */ |
@@ -3485,10 +3856,10 @@ target_waitstatus_to_string (const struct target_waitstatus *ws) |
kind_str, ws->value.integer); |
case TARGET_WAITKIND_STOPPED: |
return xstrprintf ("%sstopped, signal = %s", |
- kind_str, target_signal_to_name (ws->value.sig)); |
+ kind_str, gdb_signal_to_name (ws->value.sig)); |
case TARGET_WAITKIND_SIGNALLED: |
return xstrprintf ("%ssignalled, signal = %s", |
- kind_str, target_signal_to_name (ws->value.sig)); |
+ kind_str, gdb_signal_to_name (ws->value.sig)); |
case TARGET_WAITKIND_LOADED: |
return xstrprintf ("%sloaded", kind_str); |
case TARGET_WAITKIND_FORKED: |
@@ -4264,8 +4635,8 @@ int target_async_permitted = 0; |
static int target_async_permitted_1 = 0; |
static void |
-set_maintenance_target_async_permitted (char *args, int from_tty, |
- struct cmd_list_element *c) |
+set_target_async_command (char *args, int from_tty, |
+ struct cmd_list_element *c) |
{ |
if (have_live_inferiors ()) |
{ |
@@ -4277,9 +4648,9 @@ set_maintenance_target_async_permitted (char *args, int from_tty, |
} |
static void |
-show_maintenance_target_async_permitted (struct ui_file *file, int from_tty, |
- struct cmd_list_element *c, |
- const char *value) |
+show_target_async_command (struct ui_file *file, int from_tty, |
+ struct cmd_list_element *c, |
+ const char *value) |
{ |
fprintf_filtered (file, |
_("Controlling the inferior in " |
@@ -4384,8 +4755,8 @@ result in significant performance improvement for remote targets."), |
Set whether gdb controls the inferior in asynchronous mode."), _("\ |
Show whether gdb controls the inferior in asynchronous mode."), _("\ |
Tells gdb whether to control the inferior in asynchronous mode."), |
- set_maintenance_target_async_permitted, |
- show_maintenance_target_async_permitted, |
+ set_target_async_command, |
+ show_target_async_command, |
&setlist, |
&showlist); |