/* Select target systems and architectures at runtime for GDB.
- Copyright (C) 1990-2014 Free Software Foundation, Inc.
+ Copyright (C) 1990-2015 Free Software Foundation, Inc.
Contributed by Cygnus Support.
#include <signal.h>
#include "regcache.h"
#include "gdbcore.h"
-#include "exceptions.h"
#include "target-descriptions.h"
#include "gdbthread.h"
#include "solib.h"
static enum exec_direction_kind default_execution_direction
(struct target_ops *self);
-static CORE_ADDR default_target_decr_pc_after_break (struct target_ops *ops,
- struct gdbarch *gdbarch);
-
static struct target_ops debug_target;
#include "target-delegates.c"
(*current_target.to_load) (¤t_target, arg, from_tty);
}
+/* Possible terminal states. */
+
+enum terminal_state
+ {
+ /* The inferior's terminal settings are in effect. */
+ terminal_is_inferior = 0,
+
+ /* Some of our terminal settings are in effect, enough to get
+ proper output. */
+ terminal_is_ours_for_output = 1,
+
+ /* Our terminal settings are in effect, for output and input. */
+ terminal_is_ours = 2
+ };
+
+static enum terminal_state terminal_state;
+
+/* See target.h. */
+
+void
+target_terminal_init (void)
+{
+ (*current_target.to_terminal_init) (¤t_target);
+
+ terminal_state = terminal_is_ours;
+}
+
+/* See target.h. */
+
+int
+target_terminal_is_inferior (void)
+{
+ return (terminal_state == terminal_is_inferior);
+}
+
+/* See target.h. */
+
void
target_terminal_inferior (void)
{
if (target_can_async_p () && !sync_execution)
return;
+ if (terminal_state == terminal_is_inferior)
+ return;
+
/* If GDB is resuming the inferior in the foreground, install
inferior's terminal modes. */
(*current_target.to_terminal_inferior) (¤t_target);
+ terminal_state = terminal_is_inferior;
+}
+
+/* See target.h. */
+
+void
+target_terminal_ours (void)
+{
+ if (terminal_state == terminal_is_ours)
+ return;
+
+ (*current_target.to_terminal_ours) (¤t_target);
+ terminal_state = terminal_is_ours;
+}
+
+/* See target.h. */
+
+void
+target_terminal_ours_for_output (void)
+{
+ if (terminal_state != terminal_is_inferior)
+ return;
+ (*current_target.to_terminal_ours_for_output) (¤t_target);
+ terminal_state = terminal_is_ours_for_output;
}
/* See target.h. */
return 0;
}
+/* Restore the terminal to its previous state (helper for
+ make_cleanup_restore_target_terminal). */
+
+static void
+cleanup_restore_target_terminal (void *arg)
+{
+ enum terminal_state *previous_state = arg;
+
+ switch (*previous_state)
+ {
+ case terminal_is_ours:
+ target_terminal_ours ();
+ break;
+ case terminal_is_ours_for_output:
+ target_terminal_ours_for_output ();
+ break;
+ case terminal_is_inferior:
+ target_terminal_inferior ();
+ break;
+ }
+}
+
+/* See target.h. */
+
+struct cleanup *
+make_cleanup_restore_target_terminal (void)
+{
+ enum terminal_state *ts = xmalloc (sizeof (*ts));
+
+ *ts = terminal_state;
+
+ return make_cleanup_dtor (cleanup_restore_target_terminal, ts, xfree);
+}
+
static void
tcomplain (void)
{
if (gdbarch_fetch_tls_load_module_address_p (target_gdbarch ()))
{
ptid_t ptid = inferior_ptid;
- volatile struct gdb_exception ex;
- TRY_CATCH (ex, RETURN_MASK_ALL)
+ TRY
{
CORE_ADDR lm_addr;
}
/* If an error occurred, print TLS related messages here. Otherwise,
throw the error to some higher catcher. */
- if (ex.reason < 0)
+ CATCH (ex, RETURN_MASK_ALL)
{
int objfile_is_library = (objfile->flags & OBJF_SHARED);
break;
}
}
+ END_CATCH
}
/* It wouldn't be wrong here to try a gdbarch method, too; finding
TLS is an ABI-specific thing. But we don't do that yet. */
return NULL;
}
+
+/* Helper for the memory xfer routines. Checks the attributes of the
+ memory region of MEMADDR against the read or write being attempted.
+ If the access is permitted returns true, otherwise returns false.
+ REGION_P is an optional output parameter. If not-NULL, it is
+ filled with a pointer to the memory region of MEMADDR. REG_LEN
+ returns LEN trimmed to the end of the region. This is how much the
+ caller can continue requesting, if the access is permitted. A
+ single xfer request must not straddle memory region boundaries. */
+
+static int
+memory_xfer_check_region (gdb_byte *readbuf, const gdb_byte *writebuf,
+ ULONGEST memaddr, ULONGEST len, ULONGEST *reg_len,
+ struct mem_region **region_p)
+{
+ struct mem_region *region;
+
+ region = lookup_mem_region (memaddr);
+
+ if (region_p != NULL)
+ *region_p = region;
+
+ switch (region->attrib.mode)
+ {
+ case MEM_RO:
+ if (writebuf != NULL)
+ return 0;
+ break;
+
+ case MEM_WO:
+ if (readbuf != NULL)
+ return 0;
+ break;
+
+ case MEM_FLASH:
+ /* We only support writing to flash during "load" for now. */
+ if (writebuf != NULL)
+ error (_("Writing to flash memory forbidden in this context"));
+ break;
+
+ case MEM_NONE:
+ return 0;
+ }
+
+ /* region->hi == 0 means there's no upper bound. */
+ if (memaddr + len < region->hi || region->hi == 0)
+ *reg_len = len;
+ else
+ *reg_len = region->hi - memaddr;
+
+ return 1;
+}
+
/* Read memory from more than one valid target. A core file, for
instance, could have some of memory but delegate other bits to
the target below it. So, we must manually try all targets. */
ULONGEST len, ULONGEST *xfered_len)
{
enum target_xfer_status res;
- int reg_len;
+ ULONGEST reg_len;
struct mem_region *region;
struct inferior *inf;
}
/* Try GDB's internal data cache. */
- region = lookup_mem_region (memaddr);
- /* region->hi == 0 means there's no upper bound. */
- if (memaddr + len < region->hi || region->hi == 0)
- reg_len = len;
- else
- reg_len = region->hi - memaddr;
- switch (region->attrib.mode)
- {
- case MEM_RO:
- if (writebuf != NULL)
- return TARGET_XFER_E_IO;
- break;
-
- case MEM_WO:
- if (readbuf != NULL)
- return TARGET_XFER_E_IO;
- break;
-
- case MEM_FLASH:
- /* We only support writing to flash during "load" for now. */
- if (writebuf != NULL)
- error (_("Writing to flash memory forbidden in this context"));
- break;
-
- case MEM_NONE:
- return TARGET_XFER_E_IO;
- }
+ if (!memory_xfer_check_region (readbuf, writebuf, memaddr, len, ®_len,
+ ®ion))
+ return TARGET_XFER_E_IO;
if (!ptid_equal (inferior_ptid, null_ptid))
- inf = find_inferior_pid (ptid_get_pid (inferior_ptid));
+ inf = find_inferior_ptid (inferior_ptid);
else
inf = NULL;
writebuf, offset, len, xfered_len);
else if (object == TARGET_OBJECT_RAW_MEMORY)
{
+ /* Skip/avoid accessing the target if the memory region
+ attributes block the access. Check this here instead of in
+ raw_memory_xfer_partial as otherwise we'd end up checking
+ this twice in the case of the memory_xfer_partial path is
+ taken; once before checking the dcache, and another in the
+ tail call to raw_memory_xfer_partial. */
+ if (!memory_xfer_check_region (readbuf, writebuf, offset, len, &len,
+ NULL))
+ return TARGET_XFER_E_IO;
+
/* Request the normal memory object from other layers. */
retval = raw_memory_xfer_partial (ops, readbuf, writebuf, offset, len,
xfered_len);
struct inferior *inf;
/* Fall-back to the "main" address space of the inferior. */
- inf = find_inferior_pid (ptid_get_pid (ptid));
+ inf = find_inferior_ptid (ptid);
if (inf == NULL || inf->aspace == NULL)
internal_error (__FILE__, __LINE__,
}
void
-target_find_new_threads (void)
+target_update_thread_list (void)
{
- current_target.to_find_new_threads (¤t_target);
+ current_target.to_update_thread_list (¤t_target);
}
void
(*current_target.to_stop) (¤t_target, ptid);
}
+/* See target/target.h. */
+
+void
+target_stop_and_wait (ptid_t ptid)
+{
+ struct target_waitstatus status;
+ int was_non_stop = non_stop;
+
+ non_stop = 1;
+ target_stop (ptid);
+
+ memset (&status, 0, sizeof (status));
+ target_wait (ptid, &status, 0);
+
+ non_stop = was_non_stop;
+}
+
+/* See target/target.h. */
+
+void
+target_continue_no_signal (ptid_t ptid)
+{
+ target_resume (ptid, 0, GDB_SIGNAL_0);
+}
+
/* Concatenate ELEM to LIST, a comma separate list, and return the
result. The LIST incoming argument is released. */
/* See target.h. */
+int
+target_supports_btrace (enum btrace_format format)
+{
+ return current_target.to_supports_btrace (¤t_target, format);
+}
+
+/* See target.h. */
+
struct btrace_target_info *
-target_enable_btrace (ptid_t ptid)
+target_enable_btrace (ptid_t ptid, const struct btrace_config *conf)
{
- return current_target.to_enable_btrace (¤t_target, ptid);
+ return current_target.to_enable_btrace (¤t_target, ptid, conf);
}
/* See target.h. */
/* See target.h. */
enum btrace_error
-target_read_btrace (VEC (btrace_block_s) **btrace,
+target_read_btrace (struct btrace_data *btrace,
struct btrace_target_info *btinfo,
enum btrace_read_type type)
{
/* See target.h. */
+const struct btrace_config *
+target_btrace_conf (const struct btrace_target_info *btinfo)
+{
+ return current_target.to_btrace_conf (¤t_target, btinfo);
+}
+
+/* See target.h. */
+
void
target_stop_recording (void)
{
return current_target.to_get_tailcall_unwinder (¤t_target);
}
-/* Default implementation of to_decr_pc_after_break. */
-
-static CORE_ADDR
-default_target_decr_pc_after_break (struct target_ops *ops,
- struct gdbarch *gdbarch)
-{
- return gdbarch_decr_pc_after_break (gdbarch);
-}
-
-/* See target.h. */
-
-CORE_ADDR
-target_decr_pc_after_break (struct gdbarch *gdbarch)
-{
- return current_target.to_decr_pc_after_break (¤t_target, gdbarch);
-}
-
/* See target.h. */
void