/* Select target systems and architectures at runtime for GDB.
- Copyright (C) 1990-2020 Free Software Foundation, Inc.
+ Copyright (C) 1990-2021 Free Software Foundation, Inc.
Contributed by Cygnus Support.
#include "event-top.h"
#include <algorithm>
#include "gdbsupport/byte-vector.h"
+#include "gdbsupport/search.h"
#include "terminal.h"
#include <unordered_map>
#include "target-connection.h"
+#include "valprint.h"
static void generic_tls_error (void) ATTRIBUTE_NORETURN;
static ptid_t default_get_ada_task_ptid (struct target_ops *self,
long lwp, long tid);
-static int default_follow_fork (struct target_ops *self, int follow_child,
- int detach_fork);
-
static void default_mourn_inferior (struct target_ops *self);
static int default_search_memory (struct target_ops *ops,
find_memory_region_ftype ignore1,
void *ignore2);
-static char *dummy_make_corefile_notes (struct target_ops *self,
- bfd *ignore1, int *ignore2);
+static gdb::unique_xmalloc_ptr<char> dummy_make_corefile_notes
+ (struct target_ops *self, bfd *ignore1, int *ignore2);
static std::string default_pid_to_str (struct target_ops *ops, ptid_t ptid);
fprintf_filtered (file, _("Target debugging is %s.\n"), value);
}
-/* The user just typed 'target' without the name of a target. */
-
-static void
-target_command (const char *arg, int from_tty)
-{
- fputs_filtered ("Argument required (target name). Try `help target'\n",
- gdb_stdout);
-}
-
int
-target_has_all_memory_1 (void)
-{
- for (target_ops *t = current_top_target (); t != NULL; t = t->beneath ())
- if (t->has_all_memory ())
- return 1;
-
- return 0;
-}
-
-int
-target_has_memory_1 (void)
+target_has_memory ()
{
for (target_ops *t = current_top_target (); t != NULL; t = t->beneath ())
if (t->has_memory ())
}
int
-target_has_stack_1 (void)
+target_has_stack ()
{
for (target_ops *t = current_top_target (); t != NULL; t = t->beneath ())
if (t->has_stack ())
}
int
-target_has_registers_1 (void)
+target_has_registers ()
{
for (target_ops *t = current_top_target (); t != NULL; t = t->beneath ())
if (t->has_registers ())
}
bool
-target_has_execution_1 (inferior *inf)
+target_has_execution (inferior *inf)
{
+ if (inf == nullptr)
+ inf = current_inferior ();
+
for (target_ops *t = inf->top_target ();
t != nullptr;
t = inf->find_target_beneath (t))
return false;
}
-int
-target_has_execution_current (void)
-{
- return target_has_execution_1 (current_inferior ());
-}
-
/* This is used to implement the various target commands. */
static void
func_slot = func;
if (targetlist == NULL)
- add_prefix_cmd ("target", class_run, target_command, _("\
+ add_basic_prefix_cmd ("target", class_run, _("\
Connect to a target machine or process.\n\
The first argument is the type or protocol of the target machine.\n\
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);
+ &targetlist, "target ", 0, &cmdlist);
c = add_cmd (t.shortname, no_class, t.doc, &targetlist);
set_cmd_context (c, (void *) &t);
set_cmd_sfunc (c, open_target);
static enum exec_direction_kind
default_execution_direction (struct target_ops *self)
{
- if (!target_can_execute_reverse)
+ if (!target_can_execute_reverse ())
return EXEC_FORWARD;
else if (!target_can_async_p ())
return EXEC_FORWARD;
/* Fetch the load module address for this objfile. */
lm_addr = gdbarch_fetch_tls_load_module_address (gdbarch,
- objfile);
+ objfile);
if (gdbarch_get_thread_local_address_p (gdbarch))
addr = gdbarch_get_thread_local_address (gdbarch, ptid, lm_addr,
addr = target->get_thread_local_address (ptid, lm_addr, offset);
}
/* If an error occurred, print TLS related messages here. Otherwise,
- throw the error to some higher catcher. */
+ throw the error to some higher catcher. */
catch (const gdb_exception &ex)
{
int objfile_is_library = (objfile->flags & OBJF_SHARED);
case TLS_LOAD_MODULE_NOT_FOUND_ERROR:
if (objfile_is_library)
error (_("Cannot find shared library `%s' in dynamic"
- " linker's load module list"), objfile_name (objfile));
+ " linker's load module list"), objfile_name (objfile));
else
error (_("Cannot find executable file `%s' in dynamic"
- " linker's load module list"), objfile_name (objfile));
+ " linker's load module list"), objfile_name (objfile));
break;
case TLS_NOT_ALLOCATED_YET_ERROR:
if (objfile_is_library)
error (_("The inferior has not yet allocated storage for"
- " thread-local variables in\n"
- "the shared library `%s'\n"
- "for %s"),
+ " thread-local variables in\n"
+ "the shared library `%s'\n"
+ "for %s"),
objfile_name (objfile),
target_pid_to_str (ptid).c_str ());
else
error (_("The inferior has not yet allocated storage for"
- " thread-local variables in\n"
- "the executable `%s'\n"
- "for %s"),
+ " thread-local variables in\n"
+ "the executable `%s'\n"
+ "for %s"),
objfile_name (objfile),
target_pid_to_str (ptid).c_str ());
break;
case TLS_GENERIC_ERROR:
if (objfile_is_library)
error (_("Cannot find thread-local storage for %s, "
- "shared library %s:\n%s"),
+ "shared library %s:\n%s"),
target_pid_to_str (ptid).c_str (),
objfile_name (objfile), ex.what ());
else
error (_("Cannot find thread-local storage for %s, "
- "executable file %s:\n%s"),
+ "executable file %s:\n%s"),
target_pid_to_str (ptid).c_str (),
objfile_name (objfile), ex.what ());
break;
};
-#undef MIN
-#define MIN(A, B) (((A) <= (B)) ? (A) : (B))
-
-/* target_read_string -- read a null terminated string, up to LEN bytes,
- from MEMADDR in target. Set *ERRNOP to the errno code, or 0 if successful.
- Set *STRING to a pointer to malloc'd memory containing the data; the caller
- is responsible for freeing it. Return the number of bytes successfully
- read. */
+/* See target.h. */
-int
-target_read_string (CORE_ADDR memaddr, gdb::unique_xmalloc_ptr<char> *string,
- int len, int *errnop)
+gdb::unique_xmalloc_ptr<char>
+target_read_string (CORE_ADDR memaddr, int len, int *bytes_read)
{
- int tlen, offset, i;
- gdb_byte buf[4];
- int errcode = 0;
- char *buffer;
- int buffer_allocated;
- char *bufptr;
- unsigned int nbytes_read = 0;
-
- gdb_assert (string);
+ gdb::unique_xmalloc_ptr<gdb_byte> buffer;
- /* Small for testing. */
- buffer_allocated = 4;
- buffer = (char *) xmalloc (buffer_allocated);
- bufptr = buffer;
+ int ignore;
+ if (bytes_read == nullptr)
+ bytes_read = &ignore;
- while (len > 0)
- {
- tlen = MIN (len, 4 - (memaddr & 3));
- offset = memaddr & 3;
-
- errcode = target_read_memory (memaddr & ~3, buf, sizeof buf);
- if (errcode != 0)
- {
- /* The transfer request might have crossed the boundary to an
- unallocated region of memory. Retry the transfer, requesting
- a single byte. */
- tlen = 1;
- offset = 0;
- errcode = target_read_memory (memaddr, buf, 1);
- if (errcode != 0)
- goto done;
- }
-
- if (bufptr - buffer + tlen > buffer_allocated)
- {
- unsigned int bytes;
-
- bytes = bufptr - buffer;
- buffer_allocated *= 2;
- buffer = (char *) xrealloc (buffer, buffer_allocated);
- bufptr = buffer + bytes;
- }
-
- for (i = 0; i < tlen; i++)
- {
- *bufptr++ = buf[i + offset];
- if (buf[i + offset] == '\000')
- {
- nbytes_read += i + 1;
- goto done;
- }
- }
+ /* Note that the endian-ness does not matter here. */
+ int errcode = read_string (memaddr, -1, 1, len, BFD_ENDIAN_LITTLE,
+ &buffer, bytes_read);
+ if (errcode != 0)
+ return {};
- memaddr += tlen;
- len -= tlen;
- nbytes_read += tlen;
- }
-done:
- string->reset (buffer);
- if (errnop != NULL)
- *errnop = errcode;
- return nbytes_read;
+ return gdb::unique_xmalloc_ptr<char> ((char *) buffer.release ());
}
-struct target_section_table *
+const target_section_table *
target_get_section_table (struct target_ops *target)
{
return target->get_section_table ();
/* Find a section containing ADDR. */
-struct target_section *
+const struct target_section *
target_section_by_addr (struct target_ops *target, CORE_ADDR addr)
{
- struct target_section_table *table = target_get_section_table (target);
- struct target_section *secp;
+ const target_section_table *table = target_get_section_table (target);
if (table == NULL)
return NULL;
- for (secp = table->sections; secp < table->sections_end; secp++)
+ for (const target_section &secp : *table)
{
- if (addr >= secp->addr && addr < secp->endaddr)
- return secp;
+ if (addr >= secp.addr && addr < secp.endaddr)
+ return &secp;
}
return NULL;
}
+/* See target.h. */
+
+const target_section_table *
+default_get_section_table ()
+{
+ return ¤t_program_space->target_sections ();
+}
/* Helper for the memory xfer routines. Checks the attributes of the
memory region of MEMADDR against the read or write being attempted.
if (res == TARGET_XFER_UNAVAILABLE)
break;
- /* We want to continue past core files to executables, but not
- past a running target's memory. */
+ /* Don't continue past targets which have all the memory.
+ At one time, this code was necessary to read data from
+ executables / shared libraries when data for the requested
+ addresses weren't available in the core file. But now the
+ core target handles this case itself. */
if (ops->has_all_memory ())
break;
if (pc_in_unmapped_range (memaddr, section))
{
- struct target_section_table *table
- = target_get_section_table (ops);
+ const target_section_table *table = target_get_section_table (ops);
const char *section_name = section->the_bfd_section->name;
memaddr = overlay_mapped_address (memaddr, section);
+
+ auto match_cb = [=] (const struct target_section *s)
+ {
+ return (strcmp (section_name, s->the_bfd_section->name) == 0);
+ };
+
return section_table_xfer_memory_partial (readbuf, writebuf,
memaddr, len, xfered_len,
- table->sections,
- table->sections_end,
- section_name);
+ *table, match_cb);
}
}
/* Try the executable files, if "trust-readonly-sections" is set. */
if (readbuf != NULL && trust_readonly)
{
- struct target_section *secp;
- struct target_section_table *table;
-
- secp = target_section_by_addr (ops, memaddr);
+ const struct target_section *secp
+ = target_section_by_addr (ops, memaddr);
if (secp != NULL
&& (bfd_section_flags (secp->the_bfd_section) & SEC_READONLY))
{
- table = target_get_section_table (ops);
+ const target_section_table *table = target_get_section_table (ops);
return section_table_xfer_memory_partial (readbuf, writebuf,
memaddr, len, xfered_len,
- table->sections,
- table->sections_end,
- NULL);
+ *table);
}
}
{
int has_all_mem = 0;
- if (symfile_objfile != NULL)
- printf_unfiltered (_("Symbols from \"%s\".\n"),
- objfile_name (symfile_objfile));
+ if (current_program_space->symfile_object_file != NULL)
+ {
+ objfile *objf = current_program_space->symfile_object_file;
+ printf_unfiltered (_("Symbols from \"%s\".\n"),
+ objfile_name (objf));
+ }
for (target_ops *t = current_top_target (); t != NULL; t = t->beneath ())
{
if (current_inferior ()->pid != 0)
{
if (!from_tty
- || !target_has_execution
+ || !target_has_execution ()
|| query (_("A program is being debugged already. Kill it? ")))
{
/* Core inferiors actually should be detached, not
killed. */
- if (target_has_execution)
+ if (target_has_execution ())
target_kill ();
else
target_detach (current_inferior (), 0);
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. */
- ;
- else
- /* If we're in breakpoints-always-inserted mode, have to remove
- breakpoints before detaching. */
- remove_breakpoints_inf (current_inferior ());
-
prepare_for_detach ();
/* Hold a strong reference because detaching may unpush the
/* See target/target.h. */
ptid_t
-target_wait (ptid_t ptid, struct target_waitstatus *status, int options)
+target_wait (ptid_t ptid, struct target_waitstatus *status,
+ target_wait_flags options)
{
- return current_top_target ()->wait (ptid, status, options);
+ target_ops *target = current_top_target ();
+
+ if (!target->can_async_p ())
+ gdb_assert ((options & TARGET_WNOHANG) == 0);
+
+ return target->wait (ptid, status, options);
}
/* See target.h. */
ptid_t
default_target_wait (struct target_ops *ops,
ptid_t ptid, struct target_waitstatus *status,
- int options)
+ target_wait_flags options)
{
status->kind = TARGET_WAITKIND_IGNORE;
return minus_one_ptid;
current_top_target ()->program_signals (program_signals);
}
-static int
-default_follow_fork (struct target_ops *self, int follow_child,
- int detach_fork)
+static bool
+default_follow_fork (struct target_ops *self, bool follow_child,
+ bool detach_fork)
{
/* Some target returned a fork event, but did not know how to follow it. */
internal_error (__FILE__, __LINE__,
/* Look through the list of possible targets for a target that can
follow forks. */
-int
-target_follow_fork (int follow_child, int detach_fork)
+bool
+target_follow_fork (bool follow_child, bool detach_fork)
{
return current_top_target ()->follow_fork (follow_child, detach_fork);
}
void
target_mourn_inferior (ptid_t ptid)
{
- gdb_assert (ptid == inferior_ptid);
+ gdb_assert (ptid.pid () == inferior_ptid.pid ());
current_top_target ()->mourn_inferior ();
/* We no longer need to keep handles on any of the object files.
return target->read_description ();
}
-/* This implements a basic search of memory, reading target memory and
- performing the search here (as opposed to performing the search in on the
- target side with, for example, gdbserver). */
-
-int
-simple_search_memory (struct target_ops *ops,
- CORE_ADDR start_addr, ULONGEST search_space_len,
- const gdb_byte *pattern, ULONGEST pattern_len,
- CORE_ADDR *found_addrp)
-{
- /* NOTE: also defined in find.c testcase. */
-#define SEARCH_CHUNK_SIZE 16000
- const unsigned chunk_size = SEARCH_CHUNK_SIZE;
- /* Buffer to hold memory contents for searching. */
- unsigned search_buf_size;
-
- search_buf_size = chunk_size + pattern_len - 1;
-
- /* No point in trying to allocate a buffer larger than the search space. */
- if (search_space_len < search_buf_size)
- search_buf_size = search_space_len;
-
- gdb::byte_vector search_buf (search_buf_size);
-
- /* Prime the search buffer. */
-
- if (target_read (ops, TARGET_OBJECT_MEMORY, NULL,
- 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));
- return -1;
- }
-
- /* Perform the search.
-
- The loop is kept simple by allocating [N + pattern-length - 1] bytes.
- When we've scanned N bytes we copy the trailing bytes to the start and
- read in another N bytes. */
-
- while (search_space_len >= pattern_len)
- {
- gdb_byte *found_ptr;
- unsigned nr_search_bytes
- = std::min (search_space_len, (ULONGEST) search_buf_size);
-
- 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.data ());
-
- *found_addrp = found_addr;
- return 1;
- }
-
- /* Not found in this chunk, skip to next chunk. */
-
- /* Don't let search_space_len wrap here, it's unsigned. */
- if (search_space_len >= chunk_size)
- search_space_len -= chunk_size;
- else
- search_space_len = 0;
-
- if (search_space_len >= pattern_len)
- {
- unsigned keep_len = search_buf_size - chunk_size;
- CORE_ADDR read_addr = start_addr + chunk_size + keep_len;
- int nr_to_read;
-
- /* 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[0], &search_buf[chunk_size], keep_len);
-
- 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,
- 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));
- return -1;
- }
-
- start_addr += chunk_size;
- }
- }
-
- /* Not found. */
-
- return 0;
-}
/* Default implementation of memory-searching. */
const gdb_byte *pattern, ULONGEST pattern_len,
CORE_ADDR *found_addrp)
{
+ auto read_memory = [=] (CORE_ADDR addr, gdb_byte *result, size_t len)
+ {
+ return target_read (current_top_target (), TARGET_OBJECT_MEMORY, NULL,
+ result, addr, len) == len;
+ };
+
/* Start over from the top of the target stack. */
- return simple_search_memory (current_top_target (),
- start_addr, search_space_len,
+ return simple_search_memory (read_memory, start_addr, search_space_len,
pattern, pattern_len, found_addrp);
}
return {};
}
-/* Helper for target_fileio_open and
- target_fileio_open_warn_if_slow. */
+/* See target.h. */
-static int
-target_fileio_open_1 (struct inferior *inf, const char *filename,
- int flags, int mode, int warn_if_slow,
- int *target_errno)
+int
+target_fileio_open (struct inferior *inf, const char *filename,
+ int flags, int mode, bool warn_if_slow, int *target_errno)
{
for (target_ops *t = default_fileio_target (); t != NULL; t = t->beneath ())
{
/* 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)
int target_errno;
scoped_target_fd fd (target_fileio_open (inf, filename, FILEIO_O_RDONLY,
- 0700, &target_errno));
+ 0700, false, &target_errno));
if (fd.get () == -1)
return -1;
{
inferior *inf = current_inferior ();
- inferior_ptid = null_ptid;
+ switch_to_no_thread ();
/* Mark breakpoints uninserted in case something tries to delete a
breakpoint while we delete the inferior's threads (which would
}
/* Error-catcher for target_make_corefile_notes. */
-static char *
+static gdb::unique_xmalloc_ptr<char>
dummy_make_corefile_notes (struct target_ops *self,
bfd *ignore1, int *ignore2)
{
if (proc_target == NULL)
continue;
- for (thread_info *thr : inf->threads ())
+ for (thread_info *thr : inf->non_exited_threads ())
{
/* A thread can be THREAD_STOPPED and executing, while
running an infcall. */
OPT is removed from TARGET_OPTIONS. */
static void
-do_option (int *target_options, std::string *ret,
- int opt, const char *opt_str)
+do_option (target_wait_flags *target_options, std::string *ret,
+ target_wait_flag opt, const char *opt_str)
{
if ((*target_options & opt) != 0)
{
/* See target.h. */
std::string
-target_options_to_string (int target_options)
+target_options_to_string (target_wait_flags target_options)
{
std::string ret;
{
/* 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);
+ {
+ 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_core_addr ("address", gdbarch, m.lo);
- current_uiout->message (", size = ");
- current_uiout->field_string ("size", hex_string (m.hi - m.lo));
- current_uiout->message ("\n");
- }
+ current_uiout->message (_("Erasing flash memory region at address "));
+ current_uiout->field_core_addr ("address", gdbarch, m.lo);
+ current_uiout->message (", size = ");
+ current_uiout->field_string ("size", hex_string (m.hi - m.lo));
+ current_uiout->message ("\n");
+ }
}
/* Did we do any flash operations? If so, we need to finalize them. */
/* See target.h. */
-int
-target_is_non_stop_p (void)
+bool
+target_is_non_stop_p ()
{
return (non_stop
|| target_non_stop_enabled == AUTO_BOOLEAN_TRUE
&& target_always_non_stop_p ()));
}
+/* See target.h. */
+
+bool
+exists_non_stop_target ()
+{
+ if (target_is_non_stop_p ())
+ return true;
+
+ scoped_restore_current_thread restore_thread;
+
+ for (inferior *inf : all_inferiors ())
+ {
+ switch_to_inferior_no_thread (inf);
+ if (target_is_non_stop_p ())
+ return true;
+ }
+
+ return false;
+}
+
/* 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;
set_target_permissions (const char *args, int from_tty,
struct cmd_list_element *c)
{
- if (target_has_execution)
+ if (target_has_execution ())
{
update_target_permissions ();
error (_("Cannot change this setting while the inferior is running."));
_("Send a command to the remote monitor (remote targets only)."));
add_cmd ("target-stack", class_maintenance, maintenance_print_target_stack,
- _("Print the name of each layer of the internal target stack."),
- &maintenanceprintlist);
+ _("Print the name of each layer of the internal target stack."),
+ &maintenanceprintlist);
add_setshow_boolean_cmd ("target-async", no_class,
&target_async_permitted_1, _("\
&setlist, &showlist);
add_com ("flash-erase", no_class, flash_erase_command,
- _("Erase all flash memory regions."));
+ _("Erase all flash memory regions."));
add_setshow_boolean_cmd ("auto-connect-native-target", class_support,
&auto_connect_native_target, _("\