mirror of
https://github.com/bminor/binutils-gdb.git
synced 2025-12-26 09:08:59 +00:00
gdb: add gdbarch method to get execution context from core file
Add a new gdbarch method which can read the execution context from a core file. An execution context, for this commit, means the filename of the executable used to generate the core file and the arguments passed to the executable. In later commits this will be extended further to include the environment in which the executable was run, but this commit is already pretty big, so I've split that part out into a later commit. Initially this new gdbarch method is only implemented for Linux targets, but a later commit will add FreeBSD support too. Currently when GDB opens a core file, GDB reports the command and arguments used to generate the core file. For example: (gdb) core-file ./core.521524 [New LWP 521524] Core was generated by `./gen-core abc def'. However, this information comes from the psinfo structure in the core file, and this struct only allows 80 characters for the command and arguments combined. If the command and arguments exceed this then they are truncated. Additionally, neither the executable nor the arguments are quoted in the psinfo structure, so if, for example, the executable was named 'aaa bbb' (i.e. contains white space) and was run with the arguments 'ccc' and 'ddd', then when this core file was opened by GDB we'd see: (gdb) core-file ./core.521524 [New LWP 521524] Core was generated by `./aaa bbb ccc ddd'. It is impossible to know if 'bbb' is part of the executable filename, or another argument. However, the kernel places the executable command onto the user stack, this is pointed to by the AT_EXECFN entry in the auxv vector. Additionally, the inferior arguments are all available on the user stack. The new gdbarch method added in this commit extracts this information from the user stack and allows GDB to access it. The information on the stack is writable by the user, so a user application can start up, edit the arguments, override the AT_EXECFN string, and then dump core. In this case GDB will report incorrect information, however, it is worth noting that the psinfo structure is also filled (by the kernel) by just copying information from the user stack, so, if the user edits the on stack arguments, the values reported in psinfo will change, so the new approach is no worse than what we currently have. The benefit of this approach is that GDB gets to report the full executable name and all the arguments without the 80 character limit, and GDB is aware which parts are the executable name, and which parts are arguments, so we can, for example, style the executable name. Another benefit is that, now we know all the arguments, we can poke these into the inferior object. This means that after loading a core file a user can 'show args' to see the arguments used. A user could even transition from core file debugging to live inferior debugging using, e.g. 'run', and GDB would restart the inferior with the correct arguments. Now the downside: finding the AT_EXECFN string is easy, the auxv entry points directly too it. However, finding the arguments is a little trickier. There's currently no easy way to get a direct pointer to the arguments. Instead, I've got a heuristic which I believe should find the arguments in most cases. The algorithm is laid out in linux-tdep.c, I'll not repeat it here, but it's basically a search of the user stack, starting from AT_EXECFN. If the new heuristic fails then GDB just falls back to the old approach, asking bfd to read the psinfo structure for us, which gives the old 80 character limited answer. For testing, I've run this series on (all GNU/Linux) x86-64. s390, ppc64le, and the new test passes in each case. I've done some very basic testing on ARM which does things a little different than the other architectures mentioned, see ARM specific notes in linux_corefile_parse_exec_context_1 for details.
This commit is contained in:
@@ -74,6 +74,58 @@ struct bp_manipulation_endian
|
||||
bp_manipulation_endian<sizeof (BREAK_INSN_LITTLE), \
|
||||
BREAK_INSN_LITTLE, BREAK_INSN_BIG>
|
||||
|
||||
/* Structure returned from gdbarch core_parse_exec_context method. Wraps
|
||||
the execfn string and a vector containing the inferior argument. If a
|
||||
gdbarch is unable to parse this information then an empty structure is
|
||||
returned, check the execfn as an indication, if this is nullptr then no
|
||||
other fields should be considered valid. */
|
||||
|
||||
struct core_file_exec_context
|
||||
{
|
||||
/* Constructor, just move everything into place. The EXEC_NAME should
|
||||
never be nullptr. Only call this constructor if all the arguments
|
||||
have been collected successfully, i.e. if the EXEC_NAME could be
|
||||
found but not ARGV then use the no-argument constructor to create an
|
||||
empty context object. */
|
||||
core_file_exec_context (gdb::unique_xmalloc_ptr<char> exec_name,
|
||||
std::vector<gdb::unique_xmalloc_ptr<char>> argv)
|
||||
: m_exec_name (std::move (exec_name)),
|
||||
m_arguments (std::move (argv))
|
||||
{
|
||||
gdb_assert (m_exec_name != nullptr);
|
||||
}
|
||||
|
||||
/* Create a default context object. In its default state a context
|
||||
object holds no useful information, and will return false from its
|
||||
valid() method. */
|
||||
core_file_exec_context () = default;
|
||||
|
||||
/* Return true if this object contains valid context information. */
|
||||
bool valid () const
|
||||
{ return m_exec_name != nullptr; }
|
||||
|
||||
/* Return the execfn string (executable name) as extracted from the core
|
||||
file. Will always return non-nullptr if valid() returns true. */
|
||||
const char *execfn () const
|
||||
{ return m_exec_name.get (); }
|
||||
|
||||
/* Return the vector of inferior arguments as extracted from the core
|
||||
file. This does not include argv[0] (the executable name) for that
|
||||
see the execfn() function. */
|
||||
const std::vector<gdb::unique_xmalloc_ptr<char>> &args () const
|
||||
{ return m_arguments; }
|
||||
|
||||
private:
|
||||
|
||||
/* The executable filename as reported in the core file. Can be nullptr
|
||||
if no executable name is found. */
|
||||
gdb::unique_xmalloc_ptr<char> m_exec_name;
|
||||
|
||||
/* List of arguments. Doesn't include argv[0] which is the executable
|
||||
name, for this look at m_exec_name field. */
|
||||
std::vector<gdb::unique_xmalloc_ptr<char>> m_arguments;
|
||||
};
|
||||
|
||||
/* Default implementation of gdbarch_displaced_hw_singlestep. */
|
||||
extern bool default_displaced_step_hw_singlestep (struct gdbarch *);
|
||||
|
||||
@@ -305,6 +357,11 @@ extern void default_read_core_file_mappings
|
||||
read_core_file_mappings_pre_loop_ftype pre_loop_cb,
|
||||
read_core_file_mappings_loop_ftype loop_cb);
|
||||
|
||||
/* Default implementation of gdbarch_core_parse_exec_context. Returns
|
||||
an empty core_file_exec_context. */
|
||||
extern core_file_exec_context default_core_parse_exec_context
|
||||
(struct gdbarch *gdbarch, bfd *cbfd);
|
||||
|
||||
/* Default implementation of gdbarch
|
||||
use_target_description_from_corefile_notes. */
|
||||
extern bool default_use_target_description_from_corefile_notes
|
||||
|
||||
Reference in New Issue
Block a user