123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486 |
- /* Core dump and executable file functions above target vector, for GDB.
- Copyright (C) 1986-2022 Free Software Foundation, Inc.
- This file is part of GDB.
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 3 of the License, or
- (at your option) any later version.
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
- You should have received a copy of the GNU General Public License
- along with this program. If not, see <http://www.gnu.org/licenses/>. */
- #include "defs.h"
- #include <signal.h>
- #include <fcntl.h>
- #include "inferior.h"
- #include "symtab.h"
- #include "command.h"
- #include "gdbcmd.h"
- #include "bfd.h"
- #include "target.h"
- #include "gdbcore.h"
- #include "dis-asm.h"
- #include <sys/stat.h>
- #include "completer.h"
- #include "observable.h"
- #include "cli/cli-utils.h"
- #include "gdbarch.h"
- /* You can have any number of hooks for `exec_file_command' command to
- call. If there's only one hook, it is set in exec_file_display
- hook. If there are two or more hooks, they are set in
- exec_file_extra_hooks[], and deprecated_exec_file_display_hook is
- set to a function that calls all of them. This extra complexity is
- needed to preserve compatibility with old code that assumed that
- only one hook could be set, and which called
- deprecated_exec_file_display_hook directly. */
- typedef void (*hook_type) (const char *);
- hook_type deprecated_exec_file_display_hook; /* The original hook. */
- static hook_type *exec_file_extra_hooks; /* Array of additional
- hooks. */
- static int exec_file_hook_count = 0; /* Size of array. */
- /* If there are two or more functions that wish to hook into
- exec_file_command, this function will call all of the hook
- functions. */
- static void
- call_extra_exec_file_hooks (const char *filename)
- {
- int i;
- for (i = 0; i < exec_file_hook_count; i++)
- (*exec_file_extra_hooks[i]) (filename);
- }
- /* Call this to specify the hook for exec_file_command to call back.
- This is called from the x-window display code. */
- void
- specify_exec_file_hook (void (*hook) (const char *))
- {
- hook_type *new_array;
- if (deprecated_exec_file_display_hook != NULL)
- {
- /* There's already a hook installed. Arrange to have both it
- and the subsequent hooks called. */
- if (exec_file_hook_count == 0)
- {
- /* If this is the first extra hook, initialize the hook
- array. */
- exec_file_extra_hooks = XNEW (hook_type);
- exec_file_extra_hooks[0] = deprecated_exec_file_display_hook;
- deprecated_exec_file_display_hook = call_extra_exec_file_hooks;
- exec_file_hook_count = 1;
- }
- /* Grow the hook array by one and add the new hook to the end.
- Yes, it's inefficient to grow it by one each time but since
- this is hardly ever called it's not a big deal. */
- exec_file_hook_count++;
- new_array = (hook_type *)
- xrealloc (exec_file_extra_hooks,
- exec_file_hook_count * sizeof (hook_type));
- exec_file_extra_hooks = new_array;
- exec_file_extra_hooks[exec_file_hook_count - 1] = hook;
- }
- else
- deprecated_exec_file_display_hook = hook;
- }
- void
- reopen_exec_file (void)
- {
- int res;
- struct stat st;
- /* Don't do anything if there isn't an exec file. */
- if (current_program_space->exec_bfd () == NULL)
- return;
- /* If the timestamp of the exec file has changed, reopen it. */
- std::string filename = bfd_get_filename (current_program_space->exec_bfd ());
- res = stat (filename.c_str (), &st);
- if (res == 0
- && current_program_space->ebfd_mtime
- && current_program_space->ebfd_mtime != st.st_mtime)
- exec_file_attach (filename.c_str (), 0);
- else
- /* If we accessed the file since last opening it, close it now;
- this stops GDB from holding the executable open after it
- exits. */
- bfd_cache_close_all ();
- }
- /* If we have both a core file and an exec file,
- print a warning if they don't go together. */
- void
- validate_files (void)
- {
- if (current_program_space->exec_bfd () && core_bfd)
- {
- if (!core_file_matches_executable_p (core_bfd,
- current_program_space->exec_bfd ()))
- warning (_("core file may not match specified executable file."));
- else if (bfd_get_mtime (current_program_space->exec_bfd ())
- > bfd_get_mtime (core_bfd))
- warning (_("exec file is newer than core file."));
- }
- }
- /* See gdbsupport/common-inferior.h. */
- const char *
- get_exec_file (int err)
- {
- if (current_program_space->exec_filename != nullptr)
- return current_program_space->exec_filename.get ();
- if (!err)
- return NULL;
- error (_("No executable file specified.\n\
- Use the \"file\" or \"exec-file\" command."));
- }
- std::string
- memory_error_message (enum target_xfer_status err,
- struct gdbarch *gdbarch, CORE_ADDR memaddr)
- {
- switch (err)
- {
- case TARGET_XFER_E_IO:
- /* Actually, address between memaddr and memaddr + len was out of
- bounds. */
- return string_printf (_("Cannot access memory at address %s"),
- paddress (gdbarch, memaddr));
- case TARGET_XFER_UNAVAILABLE:
- return string_printf (_("Memory at address %s unavailable."),
- paddress (gdbarch, memaddr));
- default:
- internal_error (__FILE__, __LINE__,
- "unhandled target_xfer_status: %s (%s)",
- target_xfer_status_to_string (err),
- plongest (err));
- }
- }
- /* Report a memory error by throwing a suitable exception. */
- void
- memory_error (enum target_xfer_status err, CORE_ADDR memaddr)
- {
- enum errors exception = GDB_NO_ERROR;
- /* Build error string. */
- std::string str = memory_error_message (err, target_gdbarch (), memaddr);
- /* Choose the right error to throw. */
- switch (err)
- {
- case TARGET_XFER_E_IO:
- exception = MEMORY_ERROR;
- break;
- case TARGET_XFER_UNAVAILABLE:
- exception = NOT_AVAILABLE_ERROR;
- break;
- }
- /* Throw it. */
- throw_error (exception, ("%s"), str.c_str ());
- }
- /* Helper function. */
- static void
- read_memory_object (enum target_object object, CORE_ADDR memaddr,
- gdb_byte *myaddr, ssize_t len)
- {
- ULONGEST xfered = 0;
- while (xfered < len)
- {
- enum target_xfer_status status;
- ULONGEST xfered_len;
- status = target_xfer_partial (current_inferior ()->top_target (), object,
- NULL, myaddr + xfered, NULL,
- memaddr + xfered, len - xfered,
- &xfered_len);
- if (status != TARGET_XFER_OK)
- memory_error (status == TARGET_XFER_EOF ? TARGET_XFER_E_IO : status,
- memaddr + xfered);
- xfered += xfered_len;
- QUIT;
- }
- }
- /* Same as target_read_memory, but report an error if can't read. */
- void
- read_memory (CORE_ADDR memaddr, gdb_byte *myaddr, ssize_t len)
- {
- read_memory_object (TARGET_OBJECT_MEMORY, memaddr, myaddr, len);
- }
- /* Same as target_read_stack, but report an error if can't read. */
- void
- read_stack (CORE_ADDR memaddr, gdb_byte *myaddr, ssize_t len)
- {
- read_memory_object (TARGET_OBJECT_STACK_MEMORY, memaddr, myaddr, len);
- }
- /* Same as target_read_code, but report an error if can't read. */
- void
- read_code (CORE_ADDR memaddr, gdb_byte *myaddr, ssize_t len)
- {
- read_memory_object (TARGET_OBJECT_CODE_MEMORY, memaddr, myaddr, len);
- }
- /* Read memory at MEMADDR of length LEN and put the contents in
- RETURN_VALUE. Return 0 if MEMADDR couldn't be read and non-zero
- if successful. */
- int
- safe_read_memory_integer (CORE_ADDR memaddr, int len,
- enum bfd_endian byte_order,
- LONGEST *return_value)
- {
- gdb_byte buf[sizeof (LONGEST)];
- if (target_read_memory (memaddr, buf, len))
- return 0;
- *return_value = extract_signed_integer (buf, len, byte_order);
- return 1;
- }
- /* Read memory at MEMADDR of length LEN and put the contents in
- RETURN_VALUE. Return 0 if MEMADDR couldn't be read and non-zero
- if successful. */
- int
- safe_read_memory_unsigned_integer (CORE_ADDR memaddr, int len,
- enum bfd_endian byte_order,
- ULONGEST *return_value)
- {
- gdb_byte buf[sizeof (ULONGEST)];
- if (target_read_memory (memaddr, buf, len))
- return 0;
- *return_value = extract_unsigned_integer (buf, len, byte_order);
- return 1;
- }
- LONGEST
- read_memory_integer (CORE_ADDR memaddr, int len,
- enum bfd_endian byte_order)
- {
- gdb_byte buf[sizeof (LONGEST)];
- read_memory (memaddr, buf, len);
- return extract_signed_integer (buf, len, byte_order);
- }
- ULONGEST
- read_memory_unsigned_integer (CORE_ADDR memaddr, int len,
- enum bfd_endian byte_order)
- {
- gdb_byte buf[sizeof (ULONGEST)];
- read_memory (memaddr, buf, len);
- return extract_unsigned_integer (buf, len, byte_order);
- }
- LONGEST
- read_code_integer (CORE_ADDR memaddr, int len,
- enum bfd_endian byte_order)
- {
- gdb_byte buf[sizeof (LONGEST)];
- read_code (memaddr, buf, len);
- return extract_signed_integer (buf, len, byte_order);
- }
- ULONGEST
- read_code_unsigned_integer (CORE_ADDR memaddr, int len,
- enum bfd_endian byte_order)
- {
- gdb_byte buf[sizeof (ULONGEST)];
- read_code (memaddr, buf, len);
- return extract_unsigned_integer (buf, len, byte_order);
- }
- CORE_ADDR
- read_memory_typed_address (CORE_ADDR addr, struct type *type)
- {
- gdb_byte *buf = (gdb_byte *) alloca (TYPE_LENGTH (type));
- read_memory (addr, buf, TYPE_LENGTH (type));
- return extract_typed_address (buf, type);
- }
- /* See gdbcore.h. */
- void
- write_memory (CORE_ADDR memaddr,
- const bfd_byte *myaddr, ssize_t len)
- {
- int status;
- status = target_write_memory (memaddr, myaddr, len);
- if (status != 0)
- memory_error (TARGET_XFER_E_IO, memaddr);
- }
- /* Same as write_memory, but notify 'memory_changed' observers. */
- void
- write_memory_with_notification (CORE_ADDR memaddr, const bfd_byte *myaddr,
- ssize_t len)
- {
- write_memory (memaddr, myaddr, len);
- gdb::observers::memory_changed.notify (current_inferior (), memaddr, len, myaddr);
- }
- /* Store VALUE at ADDR in the inferior as a LEN-byte unsigned
- integer. */
- void
- write_memory_unsigned_integer (CORE_ADDR addr, int len,
- enum bfd_endian byte_order,
- ULONGEST value)
- {
- gdb_byte *buf = (gdb_byte *) alloca (len);
- store_unsigned_integer (buf, len, byte_order, value);
- write_memory (addr, buf, len);
- }
- /* Store VALUE at ADDR in the inferior as a LEN-byte signed
- integer. */
- void
- write_memory_signed_integer (CORE_ADDR addr, int len,
- enum bfd_endian byte_order,
- LONGEST value)
- {
- gdb_byte *buf = (gdb_byte *) alloca (len);
- store_signed_integer (buf, len, byte_order, value);
- write_memory (addr, buf, len);
- }
- /* The current default bfd target. Points to storage allocated for
- gnutarget_string. */
- const char *gnutarget;
- /* Same thing, except it is "auto" not NULL for the default case. */
- static std::string gnutarget_string;
- static void
- show_gnutarget_string (struct ui_file *file, int from_tty,
- struct cmd_list_element *c,
- const char *value)
- {
- gdb_printf (file,
- _("The current BFD target is \"%s\".\n"), value);
- }
- static void
- set_gnutarget_command (const char *ignore, int from_tty,
- struct cmd_list_element *c)
- {
- const char *gend = gnutarget_string.c_str () + gnutarget_string.size ();
- gend = remove_trailing_whitespace (gnutarget_string.c_str (), gend);
- gnutarget_string
- = gnutarget_string.substr (0, gend - gnutarget_string.data ());
- if (gnutarget_string == "auto")
- gnutarget = NULL;
- else
- gnutarget = gnutarget_string.c_str ();
- }
- /* A completion function for "set gnutarget". */
- static void
- complete_set_gnutarget (struct cmd_list_element *cmd,
- completion_tracker &tracker,
- const char *text, const char *word)
- {
- static const char **bfd_targets;
- if (bfd_targets == NULL)
- {
- int last;
- bfd_targets = bfd_target_list ();
- for (last = 0; bfd_targets[last] != NULL; ++last)
- ;
- bfd_targets = XRESIZEVEC (const char *, bfd_targets, last + 2);
- bfd_targets[last] = "auto";
- bfd_targets[last + 1] = NULL;
- }
- complete_on_enum (tracker, bfd_targets, text, word);
- }
- /* Set the gnutarget. */
- void
- set_gnutarget (const char *newtarget)
- {
- gnutarget_string = newtarget;
- set_gnutarget_command (NULL, 0, NULL);
- }
- void _initialize_core ();
- void
- _initialize_core ()
- {
- cmd_list_element *core_file_cmd
- = add_cmd ("core-file", class_files, core_file_command, _("\
- Use FILE as core dump for examining memory and registers.\n\
- Usage: core-file FILE\n\
- No arg means have no core file. This command has been superseded by the\n\
- `target core' and `detach' commands."), &cmdlist);
- set_cmd_completer (core_file_cmd, filename_completer);
-
- set_show_commands set_show_gnutarget
- = add_setshow_string_noescape_cmd ("gnutarget", class_files,
- &gnutarget_string, _("\
- Set the current BFD target."), _("\
- Show the current BFD target."), _("\
- Use `set gnutarget auto' to specify automatic detection."),
- set_gnutarget_command,
- show_gnutarget_string,
- &setlist, &showlist);
- set_cmd_completer (set_show_gnutarget.set, complete_set_gnutarget);
- add_alias_cmd ("g", set_show_gnutarget.set, class_files, 1, &setlist);
- if (getenv ("GNUTARGET"))
- set_gnutarget (getenv ("GNUTARGET"));
- else
- set_gnutarget ("auto");
- }
|