/* Select target systems and architectures at runtime for GDB.
- Copyright (C) 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999,
- 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011
- Free Software Foundation, Inc.
+ Copyright (C) 1990-2012 Free Software Foundation, Inc.
Contributed by Cygnus Support.
#include "exec.h"
#include "inline-frame.h"
#include "tracepoint.h"
+#include "gdb/fileio.h"
+#include "agent.h"
static void target_info (char *, int);
static int default_region_ok_for_hw_watchpoint (CORE_ADDR, int);
-static int nosymbol (char *, CORE_ADDR *);
-
static void tcomplain (void) ATTRIBUTE_NORETURN;
static int nomemory (CORE_ADDR, char *, int, int, struct target_ops *);
static void debug_to_load (char *, int);
-static int debug_to_lookup_symbol (char *, CORE_ADDR *);
-
static int debug_to_can_run (void);
-static void debug_to_notice_signals (ptid_t);
-
static void debug_to_stop (ptid_t);
-/* NOTE: cagney/2004-09-29: Many targets reference this variable in
- wierd and mysterious ways. Putting the variable here lets those
- wierd and mysterious ways keep building while they are being
- converted to the inferior inheritance structure. */
-struct target_ops deprecated_child_ops;
-
/* Pointer to array of target architecture structures; the size of the
array; the current index into the array; the allocated size of the
array. */
}
int
-default_child_has_execution (struct target_ops *ops)
+default_child_has_execution (struct target_ops *ops, ptid_t the_ptid)
{
/* If there's no thread selected, then we can't make it run through
hoops. */
- if (ptid_equal (inferior_ptid, null_ptid))
+ if (ptid_equal (the_ptid, null_ptid))
return 0;
return 1;
}
int
-target_has_execution_1 (void)
+target_has_execution_1 (ptid_t the_ptid)
{
struct target_ops *t;
for (t = current_target.beneath; t != NULL; t = t->beneath)
- if (t->to_has_execution (t))
+ if (t->to_has_execution (t, the_ptid))
return 1;
return 0;
}
+int
+target_has_execution_current (void)
+{
+ return target_has_execution_1 (inferior_ptid);
+}
+
/* Add a possible target architecture to the list. */
void
t->to_has_registers = (int (*) (struct target_ops *)) return_zero;
if (t->to_has_execution == NULL)
- t->to_has_execution = (int (*) (struct target_ops *)) return_zero;
+ t->to_has_execution = (int (*) (struct target_ops *, ptid_t)) return_zero;
if (!target_structs)
{
error (_("You can't do that without a process to debug."));
}
-static int
-nosymbol (char *name, CORE_ADDR *addrp)
-{
- return 1; /* Symbol does not exist in target env. */
-}
-
static void
default_terminal_info (char *args, int from_tty)
{
return ptid_build (ptid_get_pid (inferior_ptid), lwp, tid);
}
+static enum exec_direction_kind
+default_execution_direction (void)
+{
+ if (!target_can_execute_reverse)
+ return EXEC_FORWARD;
+ else if (!target_can_async_p ())
+ return EXEC_FORWARD;
+ else
+ gdb_assert_not_reached ("\
+to_execution_direction must be implemented for reverse async");
+}
+
/* Go through the target stack from top to bottom, copying over zero
entries in current_target, then filling in still empty entries. In
effect, we are doing class inheritance through the pushed target
INHERIT (to_can_use_hw_breakpoint, t);
INHERIT (to_insert_hw_breakpoint, t);
INHERIT (to_remove_hw_breakpoint, t);
+ /* Do not inherit to_ranged_break_num_registers. */
INHERIT (to_insert_watchpoint, t);
INHERIT (to_remove_watchpoint, t);
+ /* Do not inherit to_insert_mask_watchpoint. */
+ /* Do not inherit to_remove_mask_watchpoint. */
INHERIT (to_stopped_data_address, t);
INHERIT (to_have_steppable_watchpoint, t);
INHERIT (to_have_continuable_watchpoint, t);
INHERIT (to_watchpoint_addr_within_range, t);
INHERIT (to_region_ok_for_hw_watchpoint, t);
INHERIT (to_can_accel_watchpoint_condition, t);
+ /* Do not inherit to_masked_watch_num_registers. */
INHERIT (to_terminal_init, t);
INHERIT (to_terminal_inferior, t);
INHERIT (to_terminal_ours_for_output, t);
INHERIT (to_terminal_info, t);
/* Do not inherit to_kill. */
INHERIT (to_load, t);
- INHERIT (to_lookup_symbol, t);
/* Do no inherit to_create_inferior. */
INHERIT (to_post_startup_inferior, t);
INHERIT (to_insert_fork_catchpoint, t);
INHERIT (to_has_exited, t);
/* Do not inherit to_mourn_inferior. */
INHERIT (to_can_run, t);
- INHERIT (to_notice_signals, 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. */
INHERIT (to_extra_thread_info, t);
+ INHERIT (to_thread_name, t);
INHERIT (to_stop, t);
/* Do not inherit to_xfer_partial. */
INHERIT (to_rcmd, t);
INHERIT (to_can_async_p, t);
INHERIT (to_is_async_p, t);
INHERIT (to_async, t);
- INHERIT (to_async_mask, t);
INHERIT (to_find_memory_regions, t);
INHERIT (to_make_corefile_notes, t);
INHERIT (to_get_bookmark, t);
INHERIT (to_goto_bookmark, t);
/* Do not inherit to_get_thread_local_address. */
INHERIT (to_can_execute_reverse, t);
+ INHERIT (to_execution_direction, t);
INHERIT (to_thread_architecture, t);
/* Do not inherit to_read_description. */
INHERIT (to_get_ada_task_ptid, t);
/* Do not inherit to_search_memory. */
INHERIT (to_supports_multi_process, t);
+ INHERIT (to_supports_enable_disable_tracepoint, t);
+ INHERIT (to_supports_string_tracing, t);
INHERIT (to_trace_init, t);
INHERIT (to_download_tracepoint, t);
+ INHERIT (to_can_download_tracepoint, t);
INHERIT (to_download_trace_state_variable, t);
+ INHERIT (to_enable_tracepoint, t);
+ INHERIT (to_disable_tracepoint, t);
INHERIT (to_trace_set_readonly_regions, t);
INHERIT (to_trace_start, t);
INHERIT (to_get_trace_status, t);
+ INHERIT (to_get_tracepoint_status, t);
INHERIT (to_trace_stop, t);
INHERIT (to_trace_find, t);
INHERIT (to_get_trace_state_variable_value, t);
INHERIT (to_upload_tracepoints, t);
INHERIT (to_upload_trace_state_variables, t);
INHERIT (to_get_raw_trace_data, t);
+ INHERIT (to_get_min_fast_tracepoint_insn_len, t);
INHERIT (to_set_disconnected_tracing, t);
INHERIT (to_set_circular_trace_buffer, t);
+ INHERIT (to_set_trace_notes, t);
INHERIT (to_get_tib_address, t);
INHERIT (to_set_permissions, t);
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);
/* Do not inherit to_memory_map. */
/* Do not inherit to_flash_erase. */
/* Do not inherit to_flash_done. */
de_fault (to_load,
(void (*) (char *, int))
tcomplain);
- de_fault (to_lookup_symbol,
- (int (*) (char *, CORE_ADDR *))
- nosymbol);
de_fault (to_post_startup_inferior,
(void (*) (ptid_t))
target_ignore);
return_zero);
de_fault (to_can_run,
return_zero);
- de_fault (to_notice_signals,
- (void (*) (ptid_t))
- target_ignore);
de_fault (to_extra_thread_info,
(char *(*) (struct thread_info *))
return_zero);
+ de_fault (to_thread_name,
+ (char *(*) (struct thread_info *))
+ return_zero);
de_fault (to_stop,
(void (*) (ptid_t))
target_ignore);
de_fault (to_async,
(void (*) (void (*) (enum inferior_event_type, void*), void*))
tcomplain);
- de_fault (to_async_mask,
- (int (*) (int))
- return_one);
de_fault (to_thread_architecture,
default_thread_architecture);
current_target.to_read_description = NULL;
de_fault (to_supports_multi_process,
(int (*) (void))
return_zero);
+ de_fault (to_supports_enable_disable_tracepoint,
+ (int (*) (void))
+ return_zero);
+ de_fault (to_supports_string_tracing,
+ (int (*) (void))
+ return_zero);
de_fault (to_trace_init,
(void (*) (void))
tcomplain);
de_fault (to_download_tracepoint,
- (void (*) (struct breakpoint *))
+ (void (*) (struct bp_location *))
tcomplain);
+ de_fault (to_can_download_tracepoint,
+ (int (*) (void))
+ return_zero);
de_fault (to_download_trace_state_variable,
(void (*) (struct trace_state_variable *))
tcomplain);
+ de_fault (to_enable_tracepoint,
+ (void (*) (struct bp_location *))
+ tcomplain);
+ de_fault (to_disable_tracepoint,
+ (void (*) (struct bp_location *))
+ tcomplain);
de_fault (to_trace_set_readonly_regions,
(void (*) (void))
tcomplain);
de_fault (to_get_trace_status,
(int (*) (struct trace_status *))
return_minus_one);
+ de_fault (to_get_tracepoint_status,
+ (void (*) (struct breakpoint *, struct uploaded_tp *))
+ tcomplain);
de_fault (to_trace_stop,
(void (*) (void))
tcomplain);
de_fault (to_get_raw_trace_data,
(LONGEST (*) (gdb_byte *, ULONGEST, LONGEST))
tcomplain);
+ de_fault (to_get_min_fast_tracepoint_insn_len,
+ (int (*) (void))
+ return_minus_one);
de_fault (to_set_disconnected_tracing,
(void (*) (int))
target_ignore);
de_fault (to_set_circular_trace_buffer,
(void (*) (int))
target_ignore);
+ de_fault (to_set_trace_notes,
+ (int (*) (char *, char *, char *))
+ return_zero);
de_fault (to_get_tib_address,
(int (*) (ptid_t, CORE_ADDR *))
tcomplain);
de_fault (to_static_tracepoint_markers_by_strid,
(VEC(static_tracepoint_marker_p) * (*) (const char *))
tcomplain);
+ 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_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
/* Finally, position the target-stack beneath the squashed
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);
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;
}
return NULL;
}
+/* Read memory from the live target, even if currently inspecting a
+ traceframe. The return is the same as that of target_read. */
+
+static LONGEST
+target_read_live_memory (enum target_object object,
+ ULONGEST memaddr, gdb_byte *myaddr, LONGEST len)
+{
+ int ret;
+ struct cleanup *cleanup;
+
+ /* Switch momentarily out of tfind mode so to access live memory.
+ Note that this must not clear global state, such as the frame
+ cache, which must still remain valid for the previous traceframe.
+ We may be _building_ the frame cache at this point. */
+ cleanup = make_cleanup_restore_traceframe_number ();
+ set_traceframe_number (-1);
+
+ ret = target_read (current_target.beneath, object, NULL,
+ myaddr, memaddr, len);
+
+ do_cleanups (cleanup);
+ return ret;
+}
+
+/* Using the set of read-only target sections of OPS, read live
+ read-only memory. Note that the actual reads start from the
+ top-most target again.
+
+ For interface/parameters/return description see target.h,
+ to_xfer_partial. */
+
+static LONGEST
+memory_xfer_live_readonly_partial (struct target_ops *ops,
+ enum target_object object,
+ gdb_byte *readbuf, ULONGEST memaddr,
+ LONGEST len)
+{
+ struct target_section *secp;
+ struct target_section_table *table;
+
+ secp = target_section_by_addr (ops, memaddr);
+ if (secp != NULL
+ && (bfd_get_section_flags (secp->bfd, secp->the_bfd_section)
+ & SEC_READONLY))
+ {
+ struct target_section *p;
+ ULONGEST memend = memaddr + len;
+
+ table = target_get_section_table (ops);
+
+ for (p = table->sections; p < table->sections_end; p++)
+ {
+ if (memaddr >= p->addr)
+ {
+ if (memend <= p->endaddr)
+ {
+ /* Entire transfer is within this section. */
+ return target_read_live_memory (object, memaddr,
+ readbuf, len);
+ }
+ else if (memaddr >= p->endaddr)
+ {
+ /* This section ends before the transfer starts. */
+ continue;
+ }
+ else
+ {
+ /* This section overlaps the transfer. Just do half. */
+ len = p->endaddr - memaddr;
+ return target_read_live_memory (object, memaddr,
+ readbuf, len);
+ }
+ }
+ }
+ }
+
+ return 0;
+}
+
/* Perform a partial memory transfer.
For docs see target.h, to_xfer_partial. */
static LONGEST
-memory_xfer_partial (struct target_ops *ops, enum target_object object,
- void *readbuf, const void *writebuf, ULONGEST memaddr,
- LONGEST len)
+memory_xfer_partial_1 (struct target_ops *ops, enum target_object object,
+ void *readbuf, const void *writebuf, ULONGEST memaddr,
+ LONGEST len)
{
LONGEST res;
int reg_len;
struct mem_region *region;
struct inferior *inf;
- /* Zero length requests are ok and require no work. */
- if (len == 0)
- return 0;
-
/* For accesses to unmapped overlay sections, read directly from
files. Must do this first, as MEMADDR may need adjustment. */
if (readbuf != NULL && overlay_debugging)
}
}
+ /* If reading unavailable memory in the context of traceframes, and
+ this address falls within a read-only section, fallback to
+ reading from live memory. */
+ if (readbuf != NULL && get_traceframe_number () != -1)
+ {
+ VEC(mem_range_s) *available;
+
+ /* If we fail to get the set of available memory, then the
+ target does not support querying traceframe info, and so we
+ attempt reading from the traceframe anyway (assuming the
+ target implements the old QTro packet then). */
+ if (traceframe_available_memory (&available, memaddr, len))
+ {
+ struct cleanup *old_chain;
+
+ old_chain = make_cleanup (VEC_cleanup(mem_range_s), &available);
+
+ if (VEC_empty (mem_range_s, available)
+ || VEC_index (mem_range_s, available, 0)->start != memaddr)
+ {
+ /* Don't read into the traceframe's available
+ memory. */
+ if (!VEC_empty (mem_range_s, available))
+ {
+ LONGEST oldlen = len;
+
+ len = VEC_index (mem_range_s, available, 0)->start - memaddr;
+ gdb_assert (len <= oldlen);
+ }
+
+ do_cleanups (old_chain);
+
+ /* This goes through the topmost target again. */
+ res = memory_xfer_live_readonly_partial (ops, object,
+ readbuf, memaddr, len);
+ if (res > 0)
+ return res;
+
+ /* No use trying further, we know some memory starting
+ at MEMADDR isn't available. */
+ return -1;
+ }
+
+ /* Don't try to read more than how much is available, in
+ case the target implements the deprecated QTro packet to
+ cater for older GDBs (the target's knowledge of read-only
+ sections may be outdated by now). */
+ len = VEC_index (mem_range_s, available, 0)->length;
+
+ do_cleanups (old_chain);
+ }
+ }
+
/* Try GDB's internal data cache. */
region = lookup_mem_region (memaddr);
/* region->hi == 0 means there's no upper bound. */
if (res <= 0)
return -1;
else
- {
- if (readbuf && !show_memory_breakpoints)
- breakpoint_restore_shadows (readbuf, memaddr, reg_len);
- return res;
- }
+ return res;
}
/* If none of those methods found the memory we wanted, fall back
}
while (ops != NULL);
- if (readbuf && !show_memory_breakpoints)
- breakpoint_restore_shadows (readbuf, memaddr, reg_len);
-
/* Make sure the cache gets updated no matter what - if we are writing
to the stack. Even if this write is not tagged as such, we still need
to update the cache. */
return res;
}
+/* Perform a partial memory transfer. For docs see target.h,
+ to_xfer_partial. */
+
+static LONGEST
+memory_xfer_partial (struct target_ops *ops, enum target_object object,
+ void *readbuf, const void *writebuf, ULONGEST memaddr,
+ LONGEST len)
+{
+ int res;
+
+ /* Zero length requests are ok and require no work. */
+ if (len == 0)
+ return 0;
+
+ /* Fill in READBUF with breakpoint shadows, or WRITEBUF with
+ breakpoint insns, thus hiding out from higher layers whether
+ there are software breakpoints inserted in the code stream. */
+ if (readbuf != NULL)
+ {
+ res = memory_xfer_partial_1 (ops, object, readbuf, NULL, memaddr, len);
+
+ if (res > 0 && !show_memory_breakpoints)
+ breakpoint_xfer_memory (readbuf, NULL, NULL, memaddr, res);
+ }
+ else
+ {
+ void *buf;
+ struct cleanup *old_chain;
+
+ buf = xmalloc (len);
+ old_chain = make_cleanup (xfree, buf);
+ memcpy (buf, writebuf, len);
+
+ breakpoint_xfer_memory (NULL, buf, writebuf, memaddr, len);
+ res = memory_xfer_partial_1 (ops, object, NULL, buf, memaddr, len);
+
+ do_cleanups (old_chain);
+ }
+
+ return res;
+}
+
static void
restore_show_memory_breakpoints (void *arg)
{
return EIO;
}
+/* Write LEN bytes from MYADDR to target raw memory at address
+ MEMADDR. Returns either 0 for success or an errno value if any
+ error occurs. If an error occurs, no guarantee is made about how
+ much data got written. Callers that can deal with partial writes
+ should call target_write. */
+
+int
+target_write_raw_memory (CORE_ADDR memaddr, const gdb_byte *myaddr, int len)
+{
+ /* Dispatch to the topmost target, not the flattened current_target.
+ Memory accesses check target->to_has_(all_)memory, and the
+ flattened target doesn't inherit those. */
+ if (target_write (current_target.beneath, TARGET_OBJECT_RAW_MEMORY, NULL,
+ myaddr, memaddr, len) == len)
+ return 0;
+ else
+ return EIO;
+}
+
/* Fetch the target's memory map. */
VEC(mem_region_s) *
return len;
}
-/** Assuming that the entire [begin, end) range of memory cannot be read,
- try to read whatever subrange is possible to read.
+/* Assuming that the entire [begin, end) range of memory cannot be
+ read, try to read whatever subrange is possible to read.
- The function results, in RESULT, either zero or one memory block.
- If there's a readable subrange at the beginning, it is completely
- read and returned. Any further readable subrange will not be read.
- Otherwise, if there's a readable subrange at the end, it will be
- completely read and returned. Any readable subranges before it (obviously,
- not starting at the beginning), will be ignored. In other cases --
- either no readable subrange, or readable subrange (s) that is neither
- at the beginning, or end, nothing is returned.
+ The function returns, in RESULT, either zero or one memory block.
+ If there's a readable subrange at the beginning, it is completely
+ read and returned. Any further readable subrange will not be read.
+ Otherwise, if there's a readable subrange at the end, it will be
+ completely read and returned. Any readable subranges before it
+ (obviously, not starting at the beginning), will be ignored. In
+ other cases -- either no readable subrange, or readable subrange(s)
+ that is neither at the beginning, or end, nothing is returned.
- The purpose of this function is to handle a read across a boundary of
- accessible memory in a case when memory map is not available. The above
- restrictions are fine for this case, but will give incorrect results if
- the memory is 'patchy'. However, supporting 'patchy' memory would require
- trying to read every single byte, and it seems unacceptable solution.
- Explicit memory map is recommended for this case -- and
- target_read_memory_robust will take care of reading multiple ranges
- then. */
+ The purpose of this function is to handle a read across a boundary
+ of accessible memory in a case when memory map is not available.
+ The above restrictions are fine for this case, but will give
+ incorrect results if the memory is 'patchy'. However, supporting
+ 'patchy' memory would require trying to read every single byte,
+ and it seems unacceptable solution. Explicit memory map is
+ recommended for this case -- and target_read_memory_robust will
+ take care of reading multiple ranges then. */
static void
read_whatever_is_readable (struct target_ops *ops,
ULONGEST begin, ULONGEST end,
VEC(memory_read_result_s) **result)
{
- gdb_byte *buf = xmalloc (end-begin);
+ gdb_byte *buf = xmalloc (end - begin);
ULONGEST current_begin = begin;
ULONGEST current_end = end;
int forward;
/* If we previously failed to read 1 byte, nothing can be done here. */
if (end - begin <= 1)
- return;
+ {
+ xfree (buf);
+ return;
+ }
/* Check that either first or the last byte is readable, and give up
if not. This heuristic is meant to permit reading accessible memory
}
else
{
+ xfree (buf);
return;
}
ULONGEST first_half_begin, first_half_end;
ULONGEST second_half_begin, second_half_end;
LONGEST xfer;
-
ULONGEST middle = current_begin + (current_end - current_begin)/2;
+
if (forward)
{
first_half_begin = current_begin;
{
/* The [current_end, end) range has been read. */
LONGEST rlen = end - current_end;
+
r.data = xmalloc (rlen);
memcpy (r.data, buf + current_end - begin, rlen);
r.begin = current_end;
const char *annex)
{
gdb_byte *buffer;
- LONGEST transferred;
+ LONGEST i, transferred;
transferred = target_read_alloc_1 (ops, object, annex, &buffer, 1);
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;
}
target_clear_description ();
}
+
+ agent_capability_invalidate ();
}
/* Callback for iterate_over_inferiors. Gets rid of the given
return normal_pid_to_str (ptid);
}
+char *
+target_thread_name (struct thread_info *info)
+{
+ struct target_ops *t;
+
+ for (t = current_target.beneath; t != NULL; t = t->beneath)
+ {
+ if (t->to_thread_name != NULL)
+ return (*t->to_thread_name) (info);
+ }
+
+ return NULL;
+}
+
void
target_resume (ptid_t ptid, int step, enum target_signal signal)
{
noprocess ();
}
+
+void
+target_pass_signals (int numsigs, unsigned char *pass_signals)
+{
+ struct target_ops *t;
+
+ for (t = current_target.beneath; t != NULL; t = t->beneath)
+ {
+ if (t->to_pass_signals != NULL)
+ {
+ if (targetdebug)
+ {
+ int i;
+
+ fprintf_unfiltered (gdb_stdlog, "target_pass_signals (%d, {",
+ numsigs);
+
+ for (i = 0; i < numsigs; i++)
+ if (pass_signals[i])
+ fprintf_unfiltered (gdb_stdlog, " %s",
+ target_signal_to_name (i));
+
+ fprintf_unfiltered (gdb_stdlog, " })\n");
+ }
+
+ (*t->to_pass_signals) (numsigs, pass_signals);
+ return;
+ }
+ }
+}
+
+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",
+ target_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. */
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)
+{
+ struct target_ops *t;
+
+ t = find_default_run_target (NULL);
+ if (t && t->to_supports_disable_randomization)
+ return (t->to_supports_disable_randomization) ();
+ return 0;
+}
+
+int
+target_supports_disable_randomization (void)
+{
+ struct target_ops *t;
+
+ for (t = ¤t_target; t != NULL; t = t->beneath)
+ if (t->to_supports_disable_randomization)
+ return t->to_supports_disable_randomization ();
+
+ return 0;
+}
char *
target_get_osdata (const char *type)
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)
{
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 ();
dummy_target.to_can_async_p = find_default_can_async_p;
dummy_target.to_is_async_p = find_default_is_async_p;
dummy_target.to_supports_non_stop = find_default_supports_non_stop;
+ dummy_target.to_supports_disable_randomization
+ = find_default_supports_disable_randomization;
dummy_target.to_pid_to_str = dummy_pid_to_str;
dummy_target.to_stratum = dummy_stratum;
dummy_target.to_find_memory_regions = dummy_find_memory_regions;
dummy_target.to_has_memory = (int (*) (struct target_ops *)) return_zero;
dummy_target.to_has_stack = (int (*) (struct target_ops *)) return_zero;
dummy_target.to_has_registers = (int (*) (struct target_ops *)) return_zero;
- dummy_target.to_has_execution = (int (*) (struct target_ops *)) return_zero;
+ dummy_target.to_has_execution
+ = (int (*) (struct target_ops *, ptid_t)) return_zero;
dummy_target.to_stopped_by_watchpoint = return_zero;
dummy_target.to_stopped_data_address =
(int (*) (struct target_ops *, CORE_ADDR *)) return_zero;
return xstrprintf ("%signore", kind_str);
case TARGET_WAITKIND_NO_HISTORY:
return xstrprintf ("%sno-history", kind_str);
+ case TARGET_WAITKIND_NO_RESUMED:
+ return xstrprintf ("%sno-resumed", kind_str);
default:
return xstrprintf ("%sunknown???", kind_str);
}
tcomplain ();
}
+/* The documentation for this function is in its prototype declaration in
+ target.h. */
+
+int
+target_insert_mask_watchpoint (CORE_ADDR addr, CORE_ADDR mask, int rw)
+{
+ struct target_ops *t;
+
+ for (t = current_target.beneath; t != NULL; t = t->beneath)
+ if (t->to_insert_mask_watchpoint != NULL)
+ {
+ int ret;
+
+ ret = t->to_insert_mask_watchpoint (t, addr, mask, rw);
+
+ if (targetdebug)
+ fprintf_unfiltered (gdb_stdlog, "\
+target_insert_mask_watchpoint (%s, %s, %d) = %d\n",
+ core_addr_to_string (addr),
+ core_addr_to_string (mask), rw, ret);
+
+ return ret;
+ }
+
+ return 1;
+}
+
+/* The documentation for this function is in its prototype declaration in
+ target.h. */
+
+int
+target_remove_mask_watchpoint (CORE_ADDR addr, CORE_ADDR mask, int rw)
+{
+ struct target_ops *t;
+
+ for (t = current_target.beneath; t != NULL; t = t->beneath)
+ if (t->to_remove_mask_watchpoint != NULL)
+ {
+ int ret;
+
+ ret = t->to_remove_mask_watchpoint (t, addr, mask, rw);
+
+ if (targetdebug)
+ fprintf_unfiltered (gdb_stdlog, "\
+target_remove_mask_watchpoint (%s, %s, %d) = %d\n",
+ core_addr_to_string (addr),
+ core_addr_to_string (mask), rw, ret);
+
+ return ret;
+ }
+
+ return 1;
+}
+
+/* The documentation for this function is in its prototype declaration
+ in target.h. */
+
+int
+target_masked_watch_num_registers (CORE_ADDR addr, CORE_ADDR mask)
+{
+ struct target_ops *t;
+
+ for (t = current_target.beneath; t != NULL; t = t->beneath)
+ if (t->to_masked_watch_num_registers != NULL)
+ return t->to_masked_watch_num_registers (t, addr, mask);
+
+ return -1;
+}
+
+/* The documentation for this function is in its prototype declaration
+ in target.h. */
+
+int
+target_ranged_break_num_registers (void)
+{
+ struct target_ops *t;
+
+ for (t = current_target.beneath; t != NULL; t = t->beneath)
+ if (t->to_ranged_break_num_registers != NULL)
+ return t->to_ranged_break_num_registers (t);
+
+ return -1;
+}
+
static void
debug_to_prepare_to_store (struct regcache *regcache)
{
fprintf_unfiltered (gdb_stdlog, "target_load (%s, %d)\n", args, from_tty);
}
-static int
-debug_to_lookup_symbol (char *name, CORE_ADDR *addrp)
-{
- int retval;
-
- retval = debug_target.to_lookup_symbol (name, addrp);
-
- fprintf_unfiltered (gdb_stdlog, "target_lookup_symbol (%s, xxx)\n", name);
-
- return retval;
-}
-
static void
debug_to_post_startup_inferior (ptid_t ptid)
{
return retval;
}
-static void
-debug_to_notice_signals (ptid_t ptid)
-{
- debug_target.to_notice_signals (ptid);
-
- fprintf_unfiltered (gdb_stdlog, "target_notice_signals (%d)\n",
- PIDGET (ptid));
-}
-
static struct gdbarch *
debug_to_thread_architecture (struct target_ops *ops, ptid_t ptid)
{
current_target.to_terminal_save_ours = debug_to_terminal_save_ours;
current_target.to_terminal_info = debug_to_terminal_info;
current_target.to_load = debug_to_load;
- current_target.to_lookup_symbol = debug_to_lookup_symbol;
current_target.to_post_startup_inferior = debug_to_post_startup_inferior;
current_target.to_insert_fork_catchpoint = debug_to_insert_fork_catchpoint;
current_target.to_remove_fork_catchpoint = debug_to_remove_fork_catchpoint;
current_target.to_remove_exec_catchpoint = debug_to_remove_exec_catchpoint;
current_target.to_has_exited = debug_to_has_exited;
current_target.to_can_run = debug_to_can_run;
- current_target.to_notice_signals = debug_to_notice_signals;
current_target.to_stop = debug_to_stop;
current_target.to_rcmd = debug_to_rcmd;
current_target.to_pid_to_exec_file = debug_to_pid_to_exec_file;