X-Git-Url: http://drtracing.org/?a=blobdiff_plain;f=gdb%2Ftarget.c;h=e8d4ae7ea8e906a55a112001dbca8cb296e42345;hb=632e107b32c0fe8aede62e070b00756e9fdd2c01;hp=dd2393af7b0823077f7b45d06df4c4c38e7b1090;hpb=279a6fed95275b480d50f6f1d80a4f3970a9c5bc;p=deliverable%2Fbinutils-gdb.git diff --git a/gdb/target.c b/gdb/target.c index dd2393af7b..e8d4ae7ea8 100644 --- a/gdb/target.c +++ b/gdb/target.c @@ -1,6 +1,6 @@ /* Select target systems and architectures at runtime for GDB. - Copyright (C) 1990-2015 Free Software Foundation, Inc. + Copyright (C) 1990-2018 Free Software Foundation, Inc. Contributed by Cygnus Support. @@ -43,8 +43,12 @@ #include "agent.h" #include "auxv.h" #include "target-debug.h" - -static void target_info (char *, int); +#include "top.h" +#include "event-top.h" +#include +#include "byte-vector.h" +#include "terminal.h" +#include static void generic_tls_error (void) ATTRIBUTE_NORETURN; @@ -86,9 +90,7 @@ static int return_zero (struct target_ops *); static int return_zero_has_execution (struct target_ops *, ptid_t); -static void target_command (char *, int); - -static struct target_ops *find_default_run_target (char *); +static struct target_ops *find_default_run_target (const char *); static struct gdbarch *default_thread_architecture (struct target_ops *ops, ptid_t ptid); @@ -100,7 +102,7 @@ static int dummy_find_memory_regions (struct target_ops *self, static char *dummy_make_corefile_notes (struct target_ops *self, bfd *ignore1, int *ignore2); -static char *default_pid_to_str (struct target_ops *ops, ptid_t ptid); +static const char *default_pid_to_str (struct target_ops *ops, ptid_t ptid); static enum exec_direction_kind default_execution_direction (struct target_ops *self); @@ -167,7 +169,7 @@ int may_stop = 1; static unsigned int targetdebug = 0; static void -set_targetdebug (char *args, int from_tty, struct cmd_list_element *c) +set_targetdebug (const char *args, int from_tty, struct cmd_list_element *c) { update_current_target (); } @@ -184,7 +186,7 @@ static void setup_target_debug (void); /* The user just typed 'target' without the name of a target. */ static void -target_command (char *arg, int from_tty) +target_command (const char *arg, int from_tty) { fputs_filtered ("Argument required (target name). Try `help target'\n", gdb_stdout); @@ -345,9 +347,9 @@ complete_target_initialization (struct target_ops *t) /* This is used to implement the various target commands. */ static void -open_target (char *args, int from_tty, struct cmd_list_element *command) +open_target (const char *args, int from_tty, struct cmd_list_element *command) { - struct target_ops *ops = get_cmd_context (command); + struct target_ops *ops = (struct target_ops *) get_cmd_context (command); if (targetdebug) fprintf_unfiltered (gdb_stdlog, "-> %s->to_open (...)\n", @@ -382,7 +384,7 @@ Remaining arguments are interpreted by the target protocol. For more\n\ information on the arguments for a particular protocol, type\n\ `help target ' followed by the protocol name."), &targetlist, "target ", 0, &cmdlist); - c = add_cmd (t->to_shortname, no_class, NULL, t->to_doc, &targetlist); + c = add_cmd (t->to_shortname, no_class, t->to_doc, &targetlist); set_cmd_sfunc (c, open_target); set_cmd_context (c, t); if (completer != NULL) @@ -400,14 +402,14 @@ add_target (struct target_ops *t) /* See target.h. */ void -add_deprecated_target_alias (struct target_ops *t, char *alias) +add_deprecated_target_alias (struct target_ops *t, const char *alias) { struct cmd_list_element *c; char *alt; /* If we use add_alias_cmd, here, we do not get the deprecated warning, see PR cli/15104. */ - c = add_cmd (alias, no_class, NULL, t->to_doc, &targetlist); + c = add_cmd (alias, no_class, t->to_doc, &targetlist); set_cmd_sfunc (c, open_target); set_cmd_context (c, t); alt = xstrprintf ("target %s", t->to_shortname); @@ -429,83 +431,183 @@ target_load (const char *arg, int from_tty) (*current_target.to_load) (¤t_target, arg, from_tty); } -/* Possible terminal states. */ +/* Define it. */ -enum terminal_state - { - /* The inferior's terminal settings are in effect. */ - terminal_is_inferior = 0, +target_terminal_state target_terminal::m_terminal_state + = target_terminal_state::is_ours; - /* Some of our terminal settings are in effect, enough to get - proper output. */ - terminal_is_ours_for_output = 1, +/* See target/target.h. */ - /* Our terminal settings are in effect, for output and input. */ - terminal_is_ours = 2 - }; +void +target_terminal::init (void) +{ + (*current_target.to_terminal_init) (¤t_target); -static enum terminal_state terminal_state; + m_terminal_state = target_terminal_state::is_ours; +} -/* See target.h. */ +/* See target/target.h. */ void -target_terminal_init (void) +target_terminal::inferior (void) { - (*current_target.to_terminal_init) (¤t_target); + struct ui *ui = current_ui; - terminal_state = terminal_is_ours; + /* A background resume (``run&'') should leave GDB in control of the + terminal. */ + if (ui->prompt_state != PROMPT_BLOCKED) + return; + + /* Since we always run the inferior in the main console (unless "set + inferior-tty" is in effect), when some UI other than the main one + calls target_terminal::inferior, then we leave the main UI's + terminal settings as is. */ + if (ui != main_ui) + return; + + /* If GDB is resuming the inferior in the foreground, install + inferior's terminal modes. */ + + struct inferior *inf = current_inferior (); + + if (inf->terminal_state != target_terminal_state::is_inferior) + { + (*current_target.to_terminal_inferior) (¤t_target); + inf->terminal_state = target_terminal_state::is_inferior; + } + + m_terminal_state = target_terminal_state::is_inferior; + + /* If the user hit C-c before, pretend that it was hit right + here. */ + if (check_quit_flag ()) + target_pass_ctrlc (); } -/* See target.h. */ +/* See target/target.h. */ -int -target_terminal_is_inferior (void) +void +target_terminal::restore_inferior (void) +{ + struct ui *ui = current_ui; + + /* See target_terminal::inferior(). */ + if (ui->prompt_state != PROMPT_BLOCKED || ui != main_ui) + return; + + /* Restore the terminal settings of inferiors that were in the + foreground but are now ours_for_output due to a temporary + target_target::ours_for_output() call. */ + + { + scoped_restore_current_inferior restore_inferior; + struct inferior *inf; + + ALL_INFERIORS (inf) + { + if (inf->terminal_state == target_terminal_state::is_ours_for_output) + { + set_current_inferior (inf); + (*current_target.to_terminal_inferior) (¤t_target); + inf->terminal_state = target_terminal_state::is_inferior; + } + } + } + + m_terminal_state = target_terminal_state::is_inferior; + + /* If the user hit C-c before, pretend that it was hit right + here. */ + if (check_quit_flag ()) + target_pass_ctrlc (); +} + +/* Switch terminal state to DESIRED_STATE, either is_ours, or + is_ours_for_output. */ + +static void +target_terminal_is_ours_kind (target_terminal_state desired_state) { - return (terminal_state == terminal_is_inferior); + scoped_restore_current_inferior restore_inferior; + struct inferior *inf; + + /* Must do this in two passes. First, have all inferiors save the + current terminal settings. Then, after all inferiors have add a + chance to safely save the terminal settings, restore GDB's + terminal settings. */ + + ALL_INFERIORS (inf) + { + if (inf->terminal_state == target_terminal_state::is_inferior) + { + set_current_inferior (inf); + (*current_target.to_terminal_save_inferior) (¤t_target); + } + } + + ALL_INFERIORS (inf) + { + /* Note we don't check is_inferior here like above because we + need to handle 'is_ours_for_output -> is_ours' too. Careful + to never transition from 'is_ours' to 'is_ours_for_output', + though. */ + if (inf->terminal_state != target_terminal_state::is_ours + && inf->terminal_state != desired_state) + { + set_current_inferior (inf); + if (desired_state == target_terminal_state::is_ours) + (*current_target.to_terminal_ours) (¤t_target); + else if (desired_state == target_terminal_state::is_ours_for_output) + (*current_target.to_terminal_ours_for_output) (¤t_target); + else + gdb_assert_not_reached ("unhandled desired state"); + inf->terminal_state = desired_state; + } + } } -/* See target.h. */ +/* See target/target.h. */ void -target_terminal_inferior (void) +target_terminal::ours () { - /* A background resume (``run&'') should leave GDB in control of the - terminal. Use target_can_async_p, not target_is_async_p, since at - this point the target is not async yet. However, if sync_execution - is not set, we know it will become async prior to resume. */ - if (target_can_async_p () && !sync_execution) + struct ui *ui = current_ui; + + /* See target_terminal::inferior. */ + if (ui != main_ui) return; - if (terminal_state == terminal_is_inferior) + if (m_terminal_state == target_terminal_state::is_ours) 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; + target_terminal_is_ours_kind (target_terminal_state::is_ours); + m_terminal_state = target_terminal_state::is_ours; } -/* See target.h. */ +/* See target/target.h. */ void -target_terminal_ours (void) +target_terminal::ours_for_output () { - if (terminal_state == terminal_is_ours) + struct ui *ui = current_ui; + + /* See target_terminal::inferior. */ + if (ui != main_ui) return; - (*current_target.to_terminal_ours) (¤t_target); - terminal_state = terminal_is_ours; + if (!target_terminal::is_inferior ()) + return; + + target_terminal_is_ours_kind (target_terminal_state::is_ours_for_output); + target_terminal::m_terminal_state = target_terminal_state::is_ours_for_output; } -/* See target.h. */ +/* See target/target.h. */ void -target_terminal_ours_for_output (void) +target_terminal::info (const char *arg, int from_tty) { - if (terminal_state != terminal_is_inferior) - return; - (*current_target.to_terminal_ours_for_output) (¤t_target); - terminal_state = terminal_is_ours_for_output; + (*current_target.to_terminal_info) (¤t_target, arg, from_tty); } /* See target.h. */ @@ -525,40 +627,6 @@ target_supports_terminal_ours (void) 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) { @@ -746,21 +814,35 @@ unpush_target (struct target_ops *t) return 1; } +/* Unpush TARGET and assert that it worked. */ + +static void +unpush_target_and_assert (struct target_ops *target) +{ + if (!unpush_target (target)) + { + fprintf_unfiltered (gdb_stderr, + "pop_all_targets couldn't find target %s\n", + target->to_shortname); + internal_error (__FILE__, __LINE__, + _("failed internal consistency check")); + } +} + void pop_all_targets_above (enum strata above_stratum) { while ((int) (current_target.to_stratum) > (int) above_stratum) - { - if (!unpush_target (target_stack)) - { - fprintf_unfiltered (gdb_stderr, - "pop_all_targets couldn't find target %s\n", - target_stack->to_shortname); - internal_error (__FILE__, __LINE__, - _("failed internal consistency check")); - break; - } - } + unpush_target_and_assert (target_stack); +} + +/* See target.h. */ + +void +pop_all_targets_at_and_above (enum strata stratum) +{ + while ((int) (current_target.to_stratum) >= (int) stratum) + unpush_target_and_assert (target_stack); } void @@ -912,7 +994,8 @@ target_xfer_status_to_string (enum target_xfer_status status) read. */ int -target_read_string (CORE_ADDR memaddr, char **string, int len, int *errnop) +target_read_string (CORE_ADDR memaddr, gdb::unique_xmalloc_ptr *string, + int len, int *errnop) { int tlen, offset, i; gdb_byte buf[4]; @@ -926,7 +1009,7 @@ target_read_string (CORE_ADDR memaddr, char **string, int len, int *errnop) /* Small for testing. */ buffer_allocated = 4; - buffer = xmalloc (buffer_allocated); + buffer = (char *) xmalloc (buffer_allocated); bufptr = buffer; while (len > 0) @@ -953,7 +1036,7 @@ target_read_string (CORE_ADDR memaddr, char **string, int len, int *errnop) bytes = bufptr - buffer; buffer_allocated *= 2; - buffer = xrealloc (buffer, buffer_allocated); + buffer = (char *) xrealloc (buffer, buffer_allocated); bufptr = buffer + bytes; } @@ -972,7 +1055,7 @@ target_read_string (CORE_ADDR memaddr, char **string, int len, int *errnop) nbytes_read += tlen; } done: - *string = buffer; + string->reset (buffer); if (errnop != NULL) *errnop = errcode; return nbytes_read; @@ -1060,7 +1143,7 @@ memory_xfer_check_region (gdb_byte *readbuf, const gdb_byte *writebuf, instance, could have some of memory but delegate other bits to the target below it. So, we must manually try all targets. */ -static enum target_xfer_status +enum target_xfer_status raw_memory_xfer_partial (struct target_ops *ops, gdb_byte *readbuf, const gdb_byte *writebuf, ULONGEST memaddr, LONGEST len, ULONGEST *xfered_len) @@ -1222,6 +1305,8 @@ memory_xfer_partial (struct target_ops *ops, enum target_object object, if (len == 0) return TARGET_XFER_EOF; + memaddr = address_significant (target_gdbarch (), memaddr); + /* 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. */ @@ -1235,44 +1320,27 @@ memory_xfer_partial (struct target_ops *ops, enum target_object object, } else { - void *buf; - struct cleanup *old_chain; - /* A large write request is likely to be partially satisfied by memory_xfer_partial_1. We will continually malloc and free a copy of the entire write request for breakpoint shadow handling even though we only end up writing a small - subset of it. Cap writes to 4KB to mitigate this. */ - len = min (4096, len); + subset of it. Cap writes to a limit specified by the target + to mitigate this. */ + len = std::min (ops->to_get_memory_xfer_limit (ops), len); - 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, + gdb::byte_vector buf (writebuf, writebuf + len); + breakpoint_xfer_memory (NULL, buf.data (), writebuf, memaddr, len); + res = memory_xfer_partial_1 (ops, object, NULL, buf.data (), memaddr, len, xfered_len); - - do_cleanups (old_chain); } return res; } -static void -restore_show_memory_breakpoints (void *arg) -{ - show_memory_breakpoints = (uintptr_t) arg; -} - -struct cleanup * -make_show_memory_breakpoints_cleanup (int show) +scoped_restore_tmpl +make_scoped_restore_show_memory_breakpoints (int show) { - int current = show_memory_breakpoints; - - show_memory_breakpoints = show; - return make_cleanup (restore_show_memory_breakpoints, - (void *) (uintptr_t) current); + return make_scoped_restore (&show_memory_breakpoints, show); } /* For docs see target.h, to_xfer_partial. */ @@ -1380,7 +1448,7 @@ target_xfer_partial (struct target_ops *ops, /* Read LEN bytes of target memory at address MEMADDR, placing the results in GDB's memory at MYADDR. Returns either 0 for success or - TARGET_XFER_E_IO if any error occurs. + -1 if any error occurs. If an error occurs, no guarantee is made about the contents of the data at MYADDR. In particular, the caller should not depend upon partial reads @@ -1399,7 +1467,7 @@ target_read_memory (CORE_ADDR memaddr, gdb_byte *myaddr, ssize_t len) myaddr, memaddr, len) == len) return 0; else - return TARGET_XFER_E_IO; + return -1; } /* See target/target.h. */ @@ -1431,7 +1499,7 @@ target_read_raw_memory (CORE_ADDR memaddr, gdb_byte *myaddr, ssize_t len) myaddr, memaddr, len) == len) return 0; else - return TARGET_XFER_E_IO; + return -1; } /* Like target_read_memory, but specify explicitly that this is a read from @@ -1446,7 +1514,7 @@ target_read_stack (CORE_ADDR memaddr, gdb_byte *myaddr, ssize_t len) myaddr, memaddr, len) == len) return 0; else - return TARGET_XFER_E_IO; + return -1; } /* Like target_read_memory, but specify explicitly that this is a read from @@ -1461,14 +1529,14 @@ target_read_code (CORE_ADDR memaddr, gdb_byte *myaddr, ssize_t len) myaddr, memaddr, len) == len) return 0; else - return TARGET_XFER_E_IO; + return -1; } /* Write LEN bytes from MYADDR to target memory at address MEMADDR. - Returns either 0 for success or TARGET_XFER_E_IO 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. */ + Returns either 0 for success or -1 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_memory (CORE_ADDR memaddr, const gdb_byte *myaddr, ssize_t len) @@ -1479,14 +1547,14 @@ target_write_memory (CORE_ADDR memaddr, const gdb_byte *myaddr, ssize_t len) myaddr, memaddr, len) == len) return 0; else - return TARGET_XFER_E_IO; + return -1; } /* Write LEN bytes from MYADDR to target raw memory at address - MEMADDR. Returns either 0 for success or TARGET_XFER_E_IO - 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. */ + MEMADDR. Returns either 0 for success or -1 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, ssize_t len) @@ -1497,41 +1565,36 @@ target_write_raw_memory (CORE_ADDR memaddr, const gdb_byte *myaddr, ssize_t len) myaddr, memaddr, len) == len) return 0; else - return TARGET_XFER_E_IO; + return -1; } /* Fetch the target's memory map. */ -VEC(mem_region_s) * +std::vector target_memory_map (void) { - VEC(mem_region_s) *result; - struct mem_region *last_one, *this_one; - int ix; - struct target_ops *t; + std::vector result + = current_target.to_memory_map (¤t_target); + if (result.empty ()) + return result; - result = current_target.to_memory_map (¤t_target); - if (result == NULL) - return NULL; - - qsort (VEC_address (mem_region_s, result), - VEC_length (mem_region_s, result), - sizeof (struct mem_region), mem_region_cmp); + std::sort (result.begin (), result.end ()); /* Check that regions do not overlap. Simultaneously assign a numbering for the "mem" commands to use to refer to each region. */ - last_one = NULL; - for (ix = 0; VEC_iterate (mem_region_s, result, ix, this_one); ix++) + mem_region *last_one = NULL; + for (size_t ix = 0; ix < result.size (); ix++) { + mem_region *this_one = &result[ix]; this_one->number = ix; - if (last_one && last_one->hi > this_one->lo) + if (last_one != NULL && last_one->hi > this_one->lo) { warning (_("Overlapping regions in memory map: ignoring")); - VEC_free (mem_region_s, result); - return NULL; + return std::vector (); } + last_one = this_one; } @@ -1593,6 +1656,15 @@ target_read (struct target_ops *ops, ULONGEST offset, LONGEST len) { LONGEST xfered_total = 0; + int unit_size = 1; + + /* If we are reading from a memory object, find the length of an addressable + unit for that architecture. */ + if (object == TARGET_OBJECT_MEMORY + || object == TARGET_OBJECT_STACK_MEMORY + || object == TARGET_OBJECT_CODE_MEMORY + || object == TARGET_OBJECT_RAW_MEMORY) + unit_size = gdbarch_addressable_memory_unit_size (target_gdbarch ()); while (xfered_total < len) { @@ -1600,7 +1672,7 @@ target_read (struct target_ops *ops, enum target_xfer_status status; status = target_read_partial (ops, object, annex, - buf + xfered_total, + buf + xfered_total * unit_size, offset + xfered_total, len - xfered_total, &xfered_partial); @@ -1643,43 +1715,38 @@ target_read (struct target_ops *ops, static void read_whatever_is_readable (struct target_ops *ops, const ULONGEST begin, const ULONGEST end, - VEC(memory_read_result_s) **result) + int unit_size, + std::vector *result) { - gdb_byte *buf = xmalloc (end - begin); ULONGEST current_begin = begin; ULONGEST current_end = end; int forward; - memory_read_result_s r; ULONGEST xfered_len; /* If we previously failed to read 1 byte, nothing can be done here. */ if (end - begin <= 1) - { - xfree (buf); - return; - } + return; + + gdb::unique_xmalloc_ptr buf ((gdb_byte *) xmalloc (end - begin)); /* Check that either first or the last byte is readable, and give up if not. This heuristic is meant to permit reading accessible memory at the boundary of accessible region. */ if (target_read_partial (ops, TARGET_OBJECT_MEMORY, NULL, - buf, begin, 1, &xfered_len) == TARGET_XFER_OK) + buf.get (), begin, 1, &xfered_len) == TARGET_XFER_OK) { forward = 1; ++current_begin; } else if (target_read_partial (ops, TARGET_OBJECT_MEMORY, NULL, - buf + (end - begin) - 1, end - 1, 1, + buf.get () + (end - begin) - 1, end - 1, 1, &xfered_len) == TARGET_XFER_OK) { forward = 0; --current_end; } else - { - xfree (buf); - return; - } + return; /* Loop invariant is that the [current_begin, current_end) was previously found to be not readable as a whole. @@ -1709,7 +1776,7 @@ read_whatever_is_readable (struct target_ops *ops, } xfer = target_read (ops, TARGET_OBJECT_MEMORY, NULL, - buf + (first_half_begin - begin), + buf.get () + (first_half_begin - begin) * unit_size, first_half_begin, first_half_end - first_half_begin); @@ -1736,43 +1803,27 @@ read_whatever_is_readable (struct target_ops *ops, if (forward) { /* The [begin, current_begin) range has been read. */ - r.begin = begin; - r.end = current_begin; - r.data = buf; + result->emplace_back (begin, current_end, std::move (buf)); } else { /* The [current_end, end) range has been read. */ LONGEST region_len = end - current_end; - r.data = xmalloc (region_len); - memcpy (r.data, buf + current_end - begin, region_len); - r.begin = current_end; - r.end = end; - xfree (buf); - } - VEC_safe_push(memory_read_result_s, (*result), &r); -} - -void -free_memory_read_result_vector (void *x) -{ - VEC(memory_read_result_s) *v = x; - memory_read_result_s *current; - int ix; - - for (ix = 0; VEC_iterate (memory_read_result_s, v, ix, current); ++ix) - { - xfree (current->data); + gdb::unique_xmalloc_ptr data + ((gdb_byte *) xmalloc (region_len * unit_size)); + memcpy (data.get (), buf.get () + (current_end - begin) * unit_size, + region_len * unit_size); + result->emplace_back (current_end, end, std::move (data)); } - VEC_free (memory_read_result_s, v); } -VEC(memory_read_result_s) * +std::vector read_memory_robust (struct target_ops *ops, const ULONGEST offset, const LONGEST len) { - VEC(memory_read_result_s) *result = 0; + std::vector result; + int unit_size = gdbarch_addressable_memory_unit_size (target_gdbarch ()); LONGEST xfered_total = 0; while (xfered_total < len) @@ -1797,35 +1848,34 @@ read_memory_robust (struct target_ops *ops, } else { - LONGEST to_read = min (len - xfered_total, region_len); - gdb_byte *buffer = (gdb_byte *)xmalloc (to_read); + LONGEST to_read = std::min (len - xfered_total, region_len); + gdb::unique_xmalloc_ptr buffer + ((gdb_byte *) xmalloc (to_read * unit_size)); LONGEST xfered_partial = - target_read (ops, TARGET_OBJECT_MEMORY, NULL, - (gdb_byte *) buffer, + target_read (ops, TARGET_OBJECT_MEMORY, NULL, buffer.get (), offset + xfered_total, to_read); /* Call an observer, notifying them of the xfer progress? */ if (xfered_partial <= 0) { /* Got an error reading full chunk. See if maybe we can read some subrange. */ - xfree (buffer); read_whatever_is_readable (ops, offset + xfered_total, - offset + xfered_total + to_read, &result); + offset + xfered_total + to_read, + unit_size, &result); xfered_total += to_read; } else { - struct memory_read_result r; - r.data = buffer; - r.begin = offset + xfered_total; - r.end = r.begin + xfered_partial; - VEC_safe_push (memory_read_result_s, result, &r); + result.emplace_back (offset + xfered_total, + offset + xfered_total + xfered_partial, + std::move (buffer)); xfered_total += xfered_partial; } QUIT; } } + return result; } @@ -1840,6 +1890,15 @@ target_write_with_progress (struct target_ops *ops, void (*progress) (ULONGEST, void *), void *baton) { LONGEST xfered_total = 0; + int unit_size = 1; + + /* If we are writing to a memory object, find the length of an addressable + unit for that architecture. */ + if (object == TARGET_OBJECT_MEMORY + || object == TARGET_OBJECT_STACK_MEMORY + || object == TARGET_OBJECT_CODE_MEMORY + || object == TARGET_OBJECT_RAW_MEMORY) + unit_size = gdbarch_addressable_memory_unit_size (target_gdbarch ()); /* Give the progress callback a chance to set up. */ if (progress) @@ -1851,7 +1910,7 @@ target_write_with_progress (struct target_ops *ops, enum target_xfer_status status; status = target_write_partial (ops, object, annex, - (gdb_byte *) buf + xfered_total, + buf + xfered_total * unit_size, offset + xfered_total, len - xfered_total, &xfered_partial); @@ -1879,18 +1938,17 @@ target_write (struct target_ops *ops, NULL, NULL); } -/* Read OBJECT/ANNEX using OPS. 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_read_alloc; see the declaration of that function for more - information. */ +/* Help for target_read_alloc and target_read_stralloc. See their comments + for details. */ -static LONGEST +template +gdb::optional> target_read_alloc_1 (struct target_ops *ops, enum target_object object, - const char *annex, gdb_byte **buf_p, int padding) + const char *annex) { - size_t buf_alloc, buf_pos; - gdb_byte *buf; + gdb::def_vector buf; + size_t buf_pos = 0; + const int chunk = 4096; /* This function does not have a length parameter; it reads the entire OBJECT). Also, it doesn't support objects fetched partly @@ -1901,86 +1959,64 @@ target_read_alloc_1 (struct target_ops *ops, enum target_object object, /* 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) { ULONGEST xfered_len; enum target_xfer_status status; - status = target_read_partial (ops, object, annex, &buf[buf_pos], - buf_pos, buf_alloc - buf_pos - padding, + buf.resize (buf_pos + chunk); + + status = target_read_partial (ops, object, annex, + (gdb_byte *) &buf[buf_pos], + buf_pos, chunk, &xfered_len); if (status == TARGET_XFER_EOF) { /* Read all there was. */ - if (buf_pos == 0) - xfree (buf); - else - *buf_p = buf; - return buf_pos; + buf.resize (buf_pos); + return buf; } else if (status != TARGET_XFER_OK) { /* An error occurred. */ - xfree (buf); - return TARGET_XFER_E_IO; + return {}; } buf_pos += xfered_len; - /* If the buffer is filling up, expand it. */ - if (buf_alloc < buf_pos * 2) - { - buf_alloc *= 2; - buf = xrealloc (buf, buf_alloc); - } - QUIT; } } -/* Read OBJECT/ANNEX using OPS. 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. */ +/* See target.h */ -LONGEST +gdb::optional target_read_alloc (struct target_ops *ops, enum target_object object, - const char *annex, gdb_byte **buf_p) + const char *annex) { - return target_read_alloc_1 (ops, object, annex, buf_p, 0); + return target_read_alloc_1 (ops, object, annex); } -/* Read OBJECT/ANNEX using OPS. 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. */ +/* See target.h. */ -char * +gdb::optional target_read_stralloc (struct target_ops *ops, enum target_object object, const char *annex) { - gdb_byte *buffer; - char *bufstr; - LONGEST i, transferred; + gdb::optional buf + = target_read_alloc_1 (ops, object, annex); - transferred = target_read_alloc_1 (ops, object, annex, &buffer, 1); - bufstr = (char *) buffer; + if (!buf) + return {}; - if (transferred < 0) - return NULL; - - if (transferred == 0) - return xstrdup (""); - - bufstr[transferred] = 0; + if (buf->back () != '\0') + buf->push_back ('\0'); /* Check for embedded NUL bytes; but allow trailing NULs. */ - for (i = strlen (bufstr); i < transferred; i++) - if (bufstr[i] != 0) + for (auto it = std::find (buf->begin (), buf->end (), '\0'); + it != buf->end (); it++) + if (*it != '\0') { warning (_("target object %d, annex %s, " "contained unexpected null characters"), @@ -1988,7 +2024,7 @@ target_read_stralloc (struct target_ops *ops, enum target_object object, break; } - return bufstr; + return buf; } /* Memory transfer methods. */ @@ -2037,7 +2073,8 @@ target_insert_breakpoint (struct gdbarch *gdbarch, int target_remove_breakpoint (struct gdbarch *gdbarch, - struct bp_target_info *bp_tgt) + struct bp_target_info *bp_tgt, + enum remove_bp_reason reason) { /* This is kind of a weird case to handle, but the permission might have been changed after breakpoints were inserted - in which case @@ -2050,11 +2087,11 @@ target_remove_breakpoint (struct gdbarch *gdbarch, } return current_target.to_remove_breakpoint (¤t_target, - gdbarch, bp_tgt); + gdbarch, bp_tgt, reason); } static void -target_info (char *args, int from_tty) +info_target_command (const char *args, int from_tty) { struct target_ops *t; int has_all_mem = 0; @@ -2117,6 +2154,12 @@ target_pre_inferior (int from_tty) target_clear_description (); } + /* attach_flag may be set if the previous process associated with + the inferior was attached to. */ + current_inferior ()->attach_flag = 0; + + current_inferior ()->highest_thread_num = 0; + agent_capability_invalidate (); } @@ -2137,7 +2180,7 @@ dispose_inferior (struct inferior *inf, void *args) if (target_has_execution) target_kill (); else - target_detach (NULL, 0); + target_detach (inf, 0); } return 0; @@ -2170,13 +2213,18 @@ target_preopen (int from_tty) target_pre_inferior (from_tty); } -/* Detach a target after doing deferred register stores. */ +/* See target.h. */ void -target_detach (const char *args, int from_tty) +target_detach (inferior *inf, int from_tty) { - struct target_ops* t; - + /* As long as some to_detach implementations rely on the current_inferior + (either directly, or indirectly, like through target_gdbarch or by + reading memory), INF needs to be the current inferior. When that + requirement will become no longer true, then we can remove this + assertion. */ + gdb_assert (inf == current_inferior ()); + if (gdbarch_has_global_breakpoints (target_gdbarch ())) /* Don't remove global breakpoints here. They're removed on disconnection from the target. */ @@ -2188,7 +2236,7 @@ target_detach (const char *args, int from_tty) prepare_for_detach (); - current_target.to_detach (¤t_target, args, from_tty); + current_target.to_detach (¤t_target, inf, from_tty); } void @@ -2202,29 +2250,49 @@ target_disconnect (const char *args, int from_tty) current_target.to_disconnect (¤t_target, args, from_tty); } +/* See target/target.h. */ + ptid_t target_wait (ptid_t ptid, struct target_waitstatus *status, int options) { return (current_target.to_wait) (¤t_target, ptid, status, options); } -char * +/* See target.h. */ + +ptid_t +default_target_wait (struct target_ops *ops, + ptid_t ptid, struct target_waitstatus *status, + int options) +{ + status->kind = TARGET_WAITKIND_IGNORE; + return minus_one_ptid; +} + +const char * target_pid_to_str (ptid_t ptid) { return (*current_target.to_pid_to_str) (¤t_target, ptid); } -char * +const char * target_thread_name (struct thread_info *info) { return current_target.to_thread_name (¤t_target, info); } +struct thread_info * +target_thread_handle_to_thread_info (const gdb_byte *thread_handle, + int handle_len, + struct inferior *inf) +{ + return current_target.to_thread_handle_to_thread_info + (¤t_target, thread_handle, handle_len, inf); +} + void target_resume (ptid_t ptid, int step, enum gdb_signal signal) { - struct target_ops *t; - target_dcache_invalidate (); current_target.to_resume (¤t_target, ptid, step, signal); @@ -2236,6 +2304,28 @@ target_resume (ptid_t ptid, int step, enum gdb_signal signal) clear_inline_frame_state (ptid); } +/* If true, target_commit_resume is a nop. */ +static int defer_target_commit_resume; + +/* See target.h. */ + +void +target_commit_resume (void) +{ + if (defer_target_commit_resume) + return; + + current_target.to_commit_resume (¤t_target); +} + +/* See target.h. */ + +scoped_restore_tmpl +make_scoped_defer_target_commit_resume () +{ + return make_scoped_restore (&defer_target_commit_resume, 1); +} + void target_pass_signals (int numsigs, unsigned char *pass_signals) { @@ -2268,6 +2358,14 @@ target_follow_fork (int follow_child, int detach_fork) follow_child, detach_fork); } +/* Target wrapper for follow exec hook. */ + +void +target_follow_exec (struct inferior *inf, char *execd_pathname) +{ + current_target.to_follow_exec (¤t_target, inf, execd_pathname); +} + static void default_mourn_inferior (struct target_ops *self) { @@ -2276,8 +2374,9 @@ default_mourn_inferior (struct target_ops *self) } void -target_mourn_inferior (void) +target_mourn_inferior (ptid_t ptid) { + gdb_assert (ptid_equal (ptid, inferior_ptid)); current_target.to_mourn_inferior (¤t_target); /* We no longer need to keep handles on any of the object files. @@ -2309,9 +2408,7 @@ simple_search_memory (struct target_ops *ops, #define SEARCH_CHUNK_SIZE 16000 const unsigned chunk_size = SEARCH_CHUNK_SIZE; /* Buffer to hold memory contents for searching. */ - gdb_byte *search_buf; unsigned search_buf_size; - struct cleanup *old_cleanups; search_buf_size = chunk_size + pattern_len - 1; @@ -2319,20 +2416,17 @@ simple_search_memory (struct target_ops *ops, if (search_space_len < search_buf_size) search_buf_size = search_space_len; - search_buf = malloc (search_buf_size); - if (search_buf == NULL) - error (_("Unable to allocate memory to perform the search.")); - old_cleanups = make_cleanup (free_current_contents, &search_buf); + gdb::byte_vector search_buf (search_buf_size); /* Prime the search buffer. */ if (target_read (ops, TARGET_OBJECT_MEMORY, NULL, - search_buf, start_addr, search_buf_size) != search_buf_size) + search_buf.data (), start_addr, search_buf_size) + != search_buf_size) { warning (_("Unable to access %s bytes of target " "memory at %s, halting search."), pulongest (search_buf_size), hex_string (start_addr)); - do_cleanups (old_cleanups); return -1; } @@ -2345,17 +2439,17 @@ simple_search_memory (struct target_ops *ops, while (search_space_len >= pattern_len) { gdb_byte *found_ptr; - unsigned nr_search_bytes = min (search_space_len, search_buf_size); + unsigned nr_search_bytes + = std::min (search_space_len, (ULONGEST) search_buf_size); - found_ptr = memmem (search_buf, nr_search_bytes, - pattern, pattern_len); + found_ptr = (gdb_byte *) memmem (search_buf.data (), nr_search_bytes, + pattern, pattern_len); if (found_ptr != NULL) { - CORE_ADDR found_addr = start_addr + (found_ptr - search_buf); + CORE_ADDR found_addr = start_addr + (found_ptr - search_buf.data ()); *found_addrp = found_addr; - do_cleanups (old_cleanups); return 1; } @@ -2376,19 +2470,19 @@ simple_search_memory (struct target_ops *ops, /* Copy the trailing part of the previous iteration to the front of the buffer for the next iteration. */ gdb_assert (keep_len == pattern_len - 1); - memcpy (search_buf, search_buf + chunk_size, keep_len); + memcpy (&search_buf[0], &search_buf[chunk_size], keep_len); - nr_to_read = min (search_space_len - keep_len, chunk_size); + nr_to_read = std::min (search_space_len - keep_len, + (ULONGEST) chunk_size); if (target_read (ops, TARGET_OBJECT_MEMORY, NULL, - search_buf + keep_len, read_addr, + &search_buf[keep_len], read_addr, nr_to_read) != nr_to_read) { warning (_("Unable to access %s bytes of target " "memory at %s, halting search."), plongest (nr_to_read), hex_string (read_addr)); - do_cleanups (old_cleanups); return -1; } @@ -2398,7 +2492,6 @@ simple_search_memory (struct target_ops *ops, /* Not found. */ - do_cleanups (old_cleanups); return 0; } @@ -2492,7 +2585,7 @@ show_auto_connect_native_target (struct ui_file *file, int from_tty, called for errors); else, return NULL on error. */ static struct target_ops * -find_default_run_target (char *do_mesg) +find_default_run_target (const char *do_mesg) { struct target_ops *runable = NULL; @@ -2623,7 +2716,17 @@ target_supports_disable_randomization (void) return 0; } -char * +/* See target/target.h. */ + +int +target_supports_multi_process (void) +{ + return (*current_target.to_supports_multi_process) (¤t_target); +} + +/* See target.h. */ + +gdb::optional target_get_osdata (const char *type) { struct target_ops *t; @@ -2637,7 +2740,7 @@ target_get_osdata (const char *type) t = find_default_run_target ("get OS data"); if (!t) - return NULL; + return {}; return target_read_stralloc (t, TARGET_OBJECT_OSDATA, type); } @@ -2688,56 +2791,70 @@ default_fileio_target (void) /* File handle for target file operations. */ -typedef struct +struct fileio_fh_t { - /* The target on which this file is open. */ - struct target_ops *t; + /* The target on which this file is open. NULL if the target is + meanwhile closed while the handle is open. */ + target_ops *target; /* The file descriptor on the target. */ - int fd; -} fileio_fh_t; + int target_fd; -DEF_VEC_O (fileio_fh_t); + /* Check whether this fileio_fh_t represents a closed file. */ + bool is_closed () + { + return target_fd < 0; + } +}; /* Vector of currently open file handles. The value returned by target_fileio_open and passed as the FD argument to other target_fileio_* functions is an index into this vector. This vector's entries are never freed; instead, files are marked as closed, and the handle becomes available for reuse. */ -static VEC (fileio_fh_t) *fileio_fhandles; - -/* Macro to check whether a fileio_fh_t represents a closed file. */ -#define is_closed_fileio_fh(fd) ((fd) < 0) +static std::vector fileio_fhandles; /* Index into fileio_fhandles of the lowest handle that might be closed. This permits handle reuse without searching the whole list each time a new file is opened. */ static int lowest_closed_fd; -/* Acquire a target fileio file descriptor. */ +/* Invalidate the target associated with open handles that were open + on target TARG, since we're about to close (and maybe destroy) the + target. The handles remain open from the client's perspective, but + trying to do anything with them other than closing them will fail + with EIO. */ -static int -acquire_fileio_fd (struct target_ops *t, int fd) +static void +fileio_handles_invalidate_target (target_ops *targ) { - fileio_fh_t *fh, buf; + for (fileio_fh_t &fh : fileio_fhandles) + if (fh.target == targ) + fh.target = NULL; +} - gdb_assert (!is_closed_fileio_fh (fd)); +/* Acquire a target fileio file descriptor. */ +static int +acquire_fileio_fd (target_ops *target, int target_fd) +{ /* Search for closed handles to reuse. */ - for (; - VEC_iterate (fileio_fh_t, fileio_fhandles, - lowest_closed_fd, fh); - lowest_closed_fd++) - if (is_closed_fileio_fh (fh->fd)) - break; + for (; lowest_closed_fd < fileio_fhandles.size (); lowest_closed_fd++) + { + fileio_fh_t &fh = fileio_fhandles[lowest_closed_fd]; + + if (fh.is_closed ()) + break; + } /* Push a new handle if no closed handles were found. */ - if (lowest_closed_fd == VEC_length (fileio_fh_t, fileio_fhandles)) - fh = VEC_safe_push (fileio_fh_t, fileio_fhandles, NULL); + if (lowest_closed_fd == fileio_fhandles.size ()) + fileio_fhandles.push_back (fileio_fh_t {target, target_fd}); + else + fileio_fhandles[lowest_closed_fd] = {target, target_fd}; - /* Fill in the handle. */ - fh->t = t; - fh->fd = fd; + /* Should no longer be marked closed. */ + gdb_assert (!fileio_fhandles[lowest_closed_fd].is_closed ()); /* Return its index, and start the next lookup at the next index. */ @@ -2749,20 +2866,25 @@ acquire_fileio_fd (struct target_ops *t, int fd) static void release_fileio_fd (int fd, fileio_fh_t *fh) { - fh->fd = -1; - lowest_closed_fd = min (lowest_closed_fd, fd); + fh->target_fd = -1; + lowest_closed_fd = std::min (lowest_closed_fd, fd); } /* Return a pointer to the fileio_fhandle_t corresponding to FD. */ -#define fileio_fd_to_fh(fd) \ - VEC_index (fileio_fh_t, fileio_fhandles, (fd)) +static fileio_fh_t * +fileio_fd_to_fh (int fd) +{ + return &fileio_fhandles[fd]; +} -/* See target.h. */ +/* Helper for target_fileio_open and + target_fileio_open_warn_if_slow. */ -int -target_fileio_open (struct inferior *inf, const char *filename, - int flags, int mode, int *target_errno) +static int +target_fileio_open_1 (struct inferior *inf, const char *filename, + int flags, int mode, int warn_if_slow, + int *target_errno) { struct target_ops *t; @@ -2771,7 +2893,7 @@ target_fileio_open (struct inferior *inf, const char *filename, if (t->to_fileio_open != NULL) { int fd = t->to_fileio_open (t, inf, filename, flags, mode, - target_errno); + warn_if_slow, target_errno); if (fd < 0) fd = -1; @@ -2780,11 +2902,12 @@ target_fileio_open (struct inferior *inf, const char *filename, if (targetdebug) fprintf_unfiltered (gdb_stdlog, - "target_fileio_open (%d,%s,0x%x,0%o)" + "target_fileio_open (%d,%s,0x%x,0%o,%d)" " = %d (%d)\n", inf == NULL ? 0 : inf->num, filename, flags, mode, - fd, fd != -1 ? 0 : *target_errno); + warn_if_slow, fd, + fd != -1 ? 0 : *target_errno); return fd; } } @@ -2795,6 +2918,27 @@ target_fileio_open (struct inferior *inf, const char *filename, /* See target.h. */ +int +target_fileio_open (struct inferior *inf, const char *filename, + int flags, int mode, int *target_errno) +{ + return target_fileio_open_1 (inf, filename, flags, mode, 0, + target_errno); +} + +/* See target.h. */ + +int +target_fileio_open_warn_if_slow (struct inferior *inf, + const char *filename, + int flags, int mode, int *target_errno) +{ + return target_fileio_open_1 (inf, filename, flags, mode, 1, + target_errno); +} + +/* See target.h. */ + int target_fileio_pwrite (int fd, const gdb_byte *write_buf, int len, ULONGEST offset, int *target_errno) @@ -2802,11 +2946,13 @@ target_fileio_pwrite (int fd, const gdb_byte *write_buf, int len, fileio_fh_t *fh = fileio_fd_to_fh (fd); int ret = -1; - if (is_closed_fileio_fh (fh->fd)) + if (fh->is_closed ()) *target_errno = EBADF; + else if (fh->target == NULL) + *target_errno = EIO; else - ret = fh->t->to_fileio_pwrite (fh->t, fh->fd, write_buf, - len, offset, target_errno); + ret = fh->target->to_fileio_pwrite (fh->target, fh->target_fd, write_buf, + len, offset, target_errno); if (targetdebug) fprintf_unfiltered (gdb_stdlog, @@ -2826,11 +2972,13 @@ target_fileio_pread (int fd, gdb_byte *read_buf, int len, fileio_fh_t *fh = fileio_fd_to_fh (fd); int ret = -1; - if (is_closed_fileio_fh (fh->fd)) + if (fh->is_closed ()) *target_errno = EBADF; + else if (fh->target == NULL) + *target_errno = EIO; else - ret = fh->t->to_fileio_pread (fh->t, fh->fd, read_buf, - len, offset, target_errno); + ret = fh->target->to_fileio_pread (fh->target, fh->target_fd, read_buf, + len, offset, target_errno); if (targetdebug) fprintf_unfiltered (gdb_stdlog, @@ -2849,10 +2997,13 @@ target_fileio_fstat (int fd, struct stat *sb, int *target_errno) fileio_fh_t *fh = fileio_fd_to_fh (fd); int ret = -1; - if (is_closed_fileio_fh (fh->fd)) + if (fh->is_closed ()) *target_errno = EBADF; + else if (fh->target == NULL) + *target_errno = EIO; else - ret = fh->t->to_fileio_fstat (fh->t, fh->fd, sb, target_errno); + ret = fh->target->to_fileio_fstat (fh->target, fh->target_fd, + sb, target_errno); if (targetdebug) fprintf_unfiltered (gdb_stdlog, @@ -2869,11 +3020,15 @@ target_fileio_close (int fd, int *target_errno) fileio_fh_t *fh = fileio_fd_to_fh (fd); int ret = -1; - if (is_closed_fileio_fh (fh->fd)) + if (fh->is_closed ()) *target_errno = EBADF; else { - ret = fh->t->to_fileio_close (fh->t, fh->fd, target_errno); + if (fh->target != NULL) + ret = fh->target->to_fileio_close (fh->target, fh->target_fd, + target_errno); + else + ret = 0; release_fileio_fd (fd, fh); } @@ -2915,7 +3070,7 @@ target_fileio_unlink (struct inferior *inf, const char *filename, /* See target.h. */ -char * +gdb::optional target_fileio_readlink (struct inferior *inf, const char *filename, int *target_errno) { @@ -2925,32 +3080,54 @@ target_fileio_readlink (struct inferior *inf, const char *filename, { if (t->to_fileio_readlink != NULL) { - char *ret = t->to_fileio_readlink (t, inf, filename, - target_errno); + gdb::optional ret + = t->to_fileio_readlink (t, inf, filename, target_errno); if (targetdebug) fprintf_unfiltered (gdb_stdlog, "target_fileio_readlink (%d,%s)" " = %s (%d)\n", inf == NULL ? 0 : inf->num, - filename, ret? ret : "(nil)", - ret? 0 : *target_errno); + filename, ret ? ret->c_str () : "(nil)", + ret ? 0 : *target_errno); return ret; } } *target_errno = FILEIO_ENOSYS; - return NULL; + return {}; } -static void -target_fileio_close_cleanup (void *opaque) +/* Like scoped_fd, but specific to target fileio. */ + +class scoped_target_fd { - int fd = *(int *) opaque; - int target_errno; +public: + explicit scoped_target_fd (int fd) noexcept + : m_fd (fd) + { + } - target_fileio_close (fd, &target_errno); -} + ~scoped_target_fd () + { + if (m_fd >= 0) + { + int target_errno; + + target_fileio_close (m_fd, &target_errno); + } + } + + DISABLE_COPY_AND_ASSIGN (scoped_target_fd); + + int get () const noexcept + { + return m_fd; + } + +private: + int m_fd; +}; /* Read target file FILENAME, in the filesystem as seen by INF. If INF is NULL, use the filesystem seen by the debugger (GDB or, for @@ -2964,41 +3141,35 @@ static LONGEST target_fileio_read_alloc_1 (struct inferior *inf, 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 (inf, filename, FILEIO_O_RDONLY, 0700, - &target_errno); - if (fd == -1) + scoped_target_fd fd (target_fileio_open (inf, filename, FILEIO_O_RDONLY, + 0700, &target_errno)); + if (fd.get () == -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 = (gdb_byte *) xmalloc (buf_alloc); buf_pos = 0; while (1) { - n = target_fileio_pread (fd, &buf[buf_pos], + n = target_fileio_pread (fd.get (), &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 @@ -3012,7 +3183,7 @@ target_fileio_read_alloc_1 (struct inferior *inf, const char *filename, if (buf_alloc < buf_pos * 2) { buf_alloc *= 2; - buf = xrealloc (buf, buf_alloc); + buf = (gdb_byte *) xrealloc (buf, buf_alloc); } QUIT; @@ -3030,7 +3201,7 @@ target_fileio_read_alloc (struct inferior *inf, const char *filename, /* See target.h. */ -char * +gdb::unique_xmalloc_ptr target_fileio_read_stralloc (struct inferior *inf, const char *filename) { gdb_byte *buffer; @@ -3041,10 +3212,10 @@ target_fileio_read_stralloc (struct inferior *inf, const char *filename) bufstr = (char *) buffer; if (transferred < 0) - return NULL; + return gdb::unique_xmalloc_ptr (nullptr); if (transferred == 0) - return xstrdup (""); + return gdb::unique_xmalloc_ptr (xstrdup ("")); bufstr[transferred] = 0; @@ -3058,7 +3229,7 @@ target_fileio_read_stralloc (struct inferior *inf, const char *filename) break; } - return bufstr; + return gdb::unique_xmalloc_ptr (bufstr); } @@ -3080,7 +3251,9 @@ default_watchpoint_addr_within_range (struct target_ops *target, static struct gdbarch * default_thread_architecture (struct target_ops *ops, ptid_t ptid) { - return target_gdbarch (); + inferior *inf = find_inferior_ptid (ptid); + gdb_assert (inf != NULL); + return inf->gdbarch; } static int @@ -3120,6 +3293,28 @@ find_target_at (enum strata stratum) } + +/* See target.h */ + +void +target_announce_detach (int from_tty) +{ + pid_t pid; + const char *exec_file; + + if (!from_tty) + return; + + exec_file = get_exec_file (0); + if (exec_file == NULL) + exec_file = ""; + + pid = ptid_get_pid (inferior_ptid); + printf_unfiltered (_("Detaching from program: %s, %s\n"), exec_file, + target_pid_to_str (pid_to_ptid (pid))); + gdb_flush (gdb_stdout); +} + /* The inferior process has died. Long live the inferior! */ void @@ -3158,7 +3353,7 @@ generic_mourn_inferior (void) /* Convert a normal process ID to a string. Returns the string in a static buffer. */ -char * +const char * normal_pid_to_str (ptid_t ptid) { static char buf[32]; @@ -3167,7 +3362,7 @@ normal_pid_to_str (ptid_t ptid) return buf; } -static char * +static const char * default_pid_to_str (struct target_ops *ops, ptid_t ptid) { return normal_pid_to_str (ptid); @@ -3219,6 +3414,8 @@ target_close (struct target_ops *targ) { gdb_assert (!target_is_pushed (targ)); + fileio_handles_invalidate_target (targ); + if (targ->to_xclose != NULL) targ->to_xclose (targ); else if (targ->to_close != NULL) @@ -3252,6 +3449,34 @@ target_stop (ptid_t ptid) (*current_target.to_stop) (¤t_target, ptid); } +void +target_interrupt () +{ + if (!may_stop) + { + warning (_("May not interrupt or stop the target, ignoring attempt")); + return; + } + + (*current_target.to_interrupt) (¤t_target); +} + +/* See target.h. */ + +void +target_pass_ctrlc (void) +{ + (*current_target.to_pass_ctrlc) (¤t_target); +} + +/* See target.h. */ + +void +default_target_pass_ctrlc (struct target_ops *ops) +{ + target_interrupt (); +} + /* See target/target.h. */ void @@ -3277,6 +3502,14 @@ target_continue_no_signal (ptid_t ptid) target_resume (ptid, 0, GDB_SIGNAL_0); } +/* See target/target.h. */ + +void +target_continue (ptid_t ptid, enum gdb_signal signal) +{ + target_resume (ptid, 0, signal); +} + /* Concatenate ELEM to LIST, a comma separate list, and return the result. The LIST incoming argument is released. */ @@ -3296,7 +3529,7 @@ str_comma_list_concat_elem (char *list, const char *elem) static char * do_option (int *target_options, char *ret, - int opt, char *opt_str) + int opt, const char *opt_str) { if ((*target_options & opt) != 0) { @@ -3325,63 +3558,24 @@ target_options_to_string (int target_options) return ret; } -static void -debug_print_register (const char * func, - struct regcache *regcache, int regno) -{ - struct gdbarch *gdbarch = get_regcache_arch (regcache); - - fprintf_unfiltered (gdb_stdlog, "%s ", func); - if (regno >= 0 && regno < gdbarch_num_regs (gdbarch) - && gdbarch_register_name (gdbarch, regno) != NULL - && gdbarch_register_name (gdbarch, regno)[0] != '\0') - fprintf_unfiltered (gdb_stdlog, "(%s)", - gdbarch_register_name (gdbarch, regno)); - else - fprintf_unfiltered (gdb_stdlog, "(%d)", regno); - if (regno >= 0 && regno < gdbarch_num_regs (gdbarch)) - { - enum bfd_endian byte_order = gdbarch_byte_order (gdbarch); - int i, size = register_size (gdbarch, regno); - gdb_byte buf[MAX_REGISTER_SIZE]; - - regcache_raw_collect (regcache, regno, buf); - fprintf_unfiltered (gdb_stdlog, " = "); - for (i = 0; i < size; i++) - { - fprintf_unfiltered (gdb_stdlog, "%02x", buf[i]); - } - if (size <= sizeof (LONGEST)) - { - ULONGEST val = extract_unsigned_integer (buf, size, byte_order); - - fprintf_unfiltered (gdb_stdlog, " %s %s", - core_addr_to_string_nz (val), plongest (val)); - } - } - fprintf_unfiltered (gdb_stdlog, "\n"); -} - void target_fetch_registers (struct regcache *regcache, int regno) { current_target.to_fetch_registers (¤t_target, regcache, regno); if (targetdebug) - debug_print_register ("target_fetch_registers", regcache, regno); + regcache->debug_print_register ("target_fetch_registers", regno); } void target_store_registers (struct regcache *regcache, int regno) { - struct target_ops *t; - if (!may_write_registers) error (_("Writing to registers is not allowed (regno %d)"), regno); current_target.to_store_registers (¤t_target, regcache, regno); if (targetdebug) { - debug_print_register ("target_store_registers", regcache, regno); + regcache->debug_print_register ("target_store_registers", regno); } } @@ -3402,7 +3596,7 @@ simple_verify_memory (struct target_ops *ops, ULONGEST xfered_len; enum target_xfer_status status; gdb_byte buf[1024]; - ULONGEST howmuch = min (sizeof (buf), size - total_xfered); + ULONGEST howmuch = std::min (sizeof (buf), size - total_xfered); status = target_xfer_partial (ops, TARGET_OBJECT_MEMORY, NULL, buf, NULL, lma + total_xfered, howmuch, @@ -3441,7 +3635,8 @@ target_verify_memory (const gdb_byte *data, CORE_ADDR memaddr, ULONGEST size) target.h. */ int -target_insert_mask_watchpoint (CORE_ADDR addr, CORE_ADDR mask, int rw) +target_insert_mask_watchpoint (CORE_ADDR addr, CORE_ADDR mask, + enum target_hw_bp_type rw) { return current_target.to_insert_mask_watchpoint (¤t_target, addr, mask, rw); @@ -3451,7 +3646,8 @@ target_insert_mask_watchpoint (CORE_ADDR addr, CORE_ADDR mask, int rw) target.h. */ int -target_remove_mask_watchpoint (CORE_ADDR addr, CORE_ADDR mask, int rw) +target_remove_mask_watchpoint (CORE_ADDR addr, CORE_ADDR mask, + enum target_hw_bp_type rw) { return current_target.to_remove_mask_watchpoint (¤t_target, addr, mask, rw); @@ -3478,14 +3674,6 @@ target_ranged_break_num_registers (void) /* 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, const struct btrace_config *conf) { @@ -3567,10 +3755,34 @@ target_delete_record (void) /* See target.h. */ +enum record_method +target_record_method (ptid_t ptid) +{ + return current_target.to_record_method (¤t_target, ptid); +} + +/* See target.h. */ + +int +target_record_is_replaying (ptid_t ptid) +{ + return current_target.to_record_is_replaying (¤t_target, ptid); +} + +/* See target.h. */ + int -target_record_is_replaying (void) +target_record_will_replay (ptid_t ptid, int dir) +{ + return current_target.to_record_will_replay (¤t_target, ptid, dir); +} + +/* See target.h. */ + +void +target_record_stop_replaying (void) { - return current_target.to_record_is_replaying (¤t_target); + current_target.to_record_stop_replaying (¤t_target); } /* See target.h. */ @@ -3600,7 +3812,7 @@ target_goto_record (ULONGEST insn) /* See target.h. */ void -target_insn_history (int size, int flags) +target_insn_history (int size, gdb_disassembly_flags flags) { current_target.to_insn_history (¤t_target, size, flags); } @@ -3608,7 +3820,8 @@ target_insn_history (int size, int flags) /* See target.h. */ void -target_insn_history_from (ULONGEST from, int size, int flags) +target_insn_history_from (ULONGEST from, int size, + gdb_disassembly_flags flags) { current_target.to_insn_history_from (¤t_target, from, size, flags); } @@ -3616,7 +3829,8 @@ target_insn_history_from (ULONGEST from, int size, int flags) /* See target.h. */ void -target_insn_history_range (ULONGEST begin, ULONGEST end, int flags) +target_insn_history_range (ULONGEST begin, ULONGEST end, + gdb_disassembly_flags flags) { current_target.to_insn_history_range (¤t_target, begin, end, flags); } @@ -3624,7 +3838,7 @@ target_insn_history_range (ULONGEST begin, ULONGEST end, int flags) /* See target.h. */ void -target_call_history (int size, int flags) +target_call_history (int size, record_print_flags flags) { current_target.to_call_history (¤t_target, size, flags); } @@ -3632,7 +3846,7 @@ target_call_history (int size, int flags) /* See target.h. */ void -target_call_history_from (ULONGEST begin, int size, int flags) +target_call_history_from (ULONGEST begin, int size, record_print_flags flags) { current_target.to_call_history_from (¤t_target, begin, size, flags); } @@ -3640,7 +3854,7 @@ target_call_history_from (ULONGEST begin, int size, int flags) /* See target.h. */ void -target_call_history_range (ULONGEST begin, ULONGEST end, int flags) +target_call_history_range (ULONGEST begin, ULONGEST end, record_print_flags flags) { current_target.to_call_history_range (¤t_target, begin, end, flags); } @@ -3699,16 +3913,53 @@ default_rcmd (struct target_ops *self, const char *command, } static void -do_monitor_command (char *cmd, - int from_tty) +do_monitor_command (const char *cmd, int from_tty) { target_rcmd (cmd, gdb_stdtarg); } +/* Erases all the memory regions marked as flash. CMD and FROM_TTY are + ignored. */ + +void +flash_erase_command (const char *cmd, int from_tty) +{ + /* Used to communicate termination of flash operations to the target. */ + bool found_flash_region = false; + struct gdbarch *gdbarch = target_gdbarch (); + + std::vector mem_regions = target_memory_map (); + + /* Iterate over all memory regions. */ + for (const mem_region &m : mem_regions) + { + /* Is this a flash memory region? */ + if (m.attrib.mode == MEM_FLASH) + { + found_flash_region = true; + target_flash_erase (m.lo, m.hi - m.lo); + + ui_out_emit_tuple tuple_emitter (current_uiout, "erased-regions"); + + current_uiout->message (_("Erasing flash memory region at address ")); + current_uiout->field_fmt ("address", "%s", paddress (gdbarch, m.lo)); + current_uiout->message (", size = "); + current_uiout->field_fmt ("size", "%s", hex_string (m.hi - m.lo)); + current_uiout->message ("\n"); + } + } + + /* Did we do any flash operations? If so, we need to finalize them. */ + if (found_flash_region) + target_flash_done (); + else + current_uiout->message (_("No flash memory regions found.\n")); +} + /* Print the name of each layers of our target stack. */ static void -maintenance_print_target_stack (char *cmd, int from_tty) +maintenance_print_target_stack (const char *cmd, int from_tty) { struct target_ops *t; @@ -3720,6 +3971,23 @@ maintenance_print_target_stack (char *cmd, int from_tty) } } +/* See target.h. */ + +void +target_async (int enable) +{ + infrun_async (enable); + current_target.to_async (¤t_target, enable); +} + +/* See target.h. */ + +void +target_thread_events (int enable) +{ + current_target.to_thread_events (¤t_target, enable); +} + /* Controls if targets can report that they can/are async. This is just for maintainers to use when debugging gdb. */ int target_async_permitted = 1; @@ -3729,7 +3997,7 @@ int target_async_permitted = 1; static int target_async_permitted_1 = 1; static void -maint_set_target_async_command (char *args, int from_tty, +maint_set_target_async_command (const char *args, int from_tty, struct cmd_list_element *c) { if (have_live_inferiors ()) @@ -3751,6 +4019,67 @@ maint_show_target_async_command (struct ui_file *file, int from_tty, "asynchronous mode is %s.\n"), value); } +/* Return true if the target operates in non-stop mode even with "set + non-stop off". */ + +static int +target_always_non_stop_p (void) +{ + return current_target.to_always_non_stop_p (¤t_target); +} + +/* See target.h. */ + +int +target_is_non_stop_p (void) +{ + return (non_stop + || target_non_stop_enabled == AUTO_BOOLEAN_TRUE + || (target_non_stop_enabled == AUTO_BOOLEAN_AUTO + && target_always_non_stop_p ())); +} + +/* Controls if targets can report that they always run in non-stop + mode. This is just for maintainers to use when debugging gdb. */ +enum auto_boolean target_non_stop_enabled = AUTO_BOOLEAN_AUTO; + +/* The set command writes to this variable. If the inferior is + executing, target_non_stop_enabled is *not* updated. */ +static enum auto_boolean target_non_stop_enabled_1 = AUTO_BOOLEAN_AUTO; + +/* Implementation of "maint set target-non-stop". */ + +static void +maint_set_target_non_stop_command (const char *args, int from_tty, + struct cmd_list_element *c) +{ + if (have_live_inferiors ()) + { + target_non_stop_enabled_1 = target_non_stop_enabled; + error (_("Cannot change this setting while the inferior is running.")); + } + + target_non_stop_enabled = target_non_stop_enabled_1; +} + +/* Implementation of "maint show target-non-stop". */ + +static void +maint_show_target_non_stop_command (struct ui_file *file, int from_tty, + struct cmd_list_element *c, + const char *value) +{ + if (target_non_stop_enabled == AUTO_BOOLEAN_AUTO) + fprintf_filtered (file, + _("Whether the target is always in non-stop mode " + "is %s (currently %s).\n"), value, + target_always_non_stop_p () ? "on" : "off"); + else + fprintf_filtered (file, + _("Whether the target is always in non-stop mode " + "is %s.\n"), value); +} + /* Temporary copies of permission settings. */ static int may_write_registers_1 = 1; @@ -3777,7 +4106,7 @@ update_target_permissions (void) way. */ static void -set_target_permissions (char *args, int from_tty, +set_target_permissions (const char *args, int from_tty, struct cmd_list_element *c) { if (target_has_execution) @@ -3798,7 +4127,7 @@ set_target_permissions (char *args, int from_tty, /* Set memory write permission independently of observer mode. */ static void -set_write_memory_permission (char *args, int from_tty, +set_write_memory_permission (const char *args, int from_tty, struct cmd_list_element *c) { /* Make the real values match the user-changed values. */ @@ -3806,6 +4135,53 @@ set_write_memory_permission (char *args, int from_tty, update_observer_mode (); } +#if GDB_SELF_TEST +namespace selftests { + +static int +test_target_has_registers (target_ops *self) +{ + return 1; +} + +static int +test_target_has_stack (target_ops *self) +{ + return 1; +} + +static int +test_target_has_memory (target_ops *self) +{ + return 1; +} + +static void +test_target_prepare_to_store (target_ops *self, regcache *regs) +{ +} + +static void +test_target_store_registers (target_ops *self, regcache *regs, int regno) +{ +} + +test_target_ops::test_target_ops () + : target_ops {} +{ + to_magic = OPS_MAGIC; + to_stratum = process_stratum; + to_has_memory = test_target_has_memory; + to_has_stack = test_target_has_stack; + to_has_registers = test_target_has_registers; + to_prepare_to_store = test_target_prepare_to_store; + to_store_registers = test_target_store_registers; + + complete_target_initialization (this); +} + +} // namespace selftests +#endif /* GDB_SELF_TEST */ void initialize_targets (void) @@ -3813,8 +4189,8 @@ initialize_targets (void) init_dummy_target (); push_target (&dummy_target); - add_info ("target", target_info, targ_desc); - add_info ("files", target_info, targ_desc); + add_info ("target", info_target_command, targ_desc); + add_info ("files", info_target_command, targ_desc); add_setshow_zuinteger_cmd ("target", class_maintenance, &targetdebug, _("\ Set target debugging."), _("\ @@ -3853,6 +4229,16 @@ Tells gdb whether to control the inferior in asynchronous mode."), &maintenance_set_cmdlist, &maintenance_show_cmdlist); + add_setshow_auto_boolean_cmd ("target-non-stop", no_class, + &target_non_stop_enabled_1, _("\ +Set whether gdb always controls the inferior in non-stop mode."), _("\ +Show whether gdb always controls the inferior in non-stop mode."), _("\ +Tells gdb whether to control the inferior in non-stop mode."), + maint_set_target_non_stop_command, + maint_show_target_non_stop_command, + &maintenance_set_cmdlist, + &maintenance_show_cmdlist); + add_setshow_boolean_cmd ("may-write-registers", class_support, &may_write_registers_1, _("\ Set permission to write into registers."), _("\ @@ -3907,6 +4293,9 @@ Otherwise, any attempt to interrupt or stop will be ignored."), set_target_permissions, NULL, &setlist, &showlist); + add_com ("flash-erase", no_class, flash_erase_command, + _("Erase all flash memory regions.")); + add_setshow_boolean_cmd ("auto-connect-native-target", class_support, &auto_connect_native_target, _("\ Set whether GDB may automatically connect to the native target."), _("\