| /* Reading symbol files from memory. | 
 |  | 
 |    Copyright (C) 1986-2024 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/>.  */ | 
 |  | 
 | /* This file defines functions (and commands to exercise those | 
 |    functions) for reading debugging information from object files | 
 |    whose images are mapped directly into the inferior's memory.  For | 
 |    example, the Linux kernel maps a "syscall DSO" into each process's | 
 |    address space; this DSO provides kernel-specific code for some | 
 |    system calls. | 
 |  | 
 |    At the moment, BFD only has functions for parsing object files from | 
 |    memory for the ELF format, even though the general idea isn't | 
 |    ELF-specific.  This means that BFD only provides the functions GDB | 
 |    needs when configured for ELF-based targets.  So these functions | 
 |    may only be compiled on ELF-based targets. | 
 |  | 
 |    GDB has no idea whether it has been configured for an ELF-based | 
 |    target or not: it just tries to handle whatever files it is given. | 
 |    But this means there are no preprocessor symbols on which we could | 
 |    make these functions' compilation conditional. | 
 |  | 
 |    So, for the time being, we put these functions alone in this file, | 
 |    and have .mt files reference them as appropriate.  In the future, I | 
 |    hope BFD will provide a format-independent bfd_from_remote_memory | 
 |    entry point.  */ | 
 |  | 
 |  | 
 | #include "exceptions.h" | 
 | #include "symtab.h" | 
 | #include "gdbcore.h" | 
 | #include "objfiles.h" | 
 | #include "cli/cli-cmds.h" | 
 | #include "target.h" | 
 | #include "value.h" | 
 | #include "symfile.h" | 
 | #include "observable.h" | 
 | #include "auxv.h" | 
 | #include "elf/common.h" | 
 | #include "gdb_bfd.h" | 
 | #include "inferior.h" | 
 |  | 
 | /* Verify parameters of target_read_memory_bfd and target_read_memory are | 
 |    compatible.  */ | 
 |  | 
 | static_assert (sizeof (CORE_ADDR) >= sizeof (bfd_vma)); | 
 | static_assert (sizeof (gdb_byte) == sizeof (bfd_byte)); | 
 | static_assert (sizeof (ssize_t) <= sizeof (bfd_size_type)); | 
 |  | 
 | /* Provide bfd/ compatible prototype for target_read_memory.  Casting would not | 
 |    be enough as LEN width may differ.  */ | 
 |  | 
 | static int | 
 | target_read_memory_bfd (bfd_vma memaddr, bfd_byte *myaddr, bfd_size_type len) | 
 | { | 
 |   /* MYADDR must be already allocated for the LEN size so it has to fit in | 
 |      ssize_t.  */ | 
 |   gdb_assert ((ssize_t) len == len); | 
 |  | 
 |   return target_read_memory (memaddr, myaddr, len); | 
 | } | 
 |  | 
 | /* Read inferior memory at ADDR to find the header of a loaded object file | 
 |    and read its in-core symbols out of inferior memory.  SIZE, if | 
 |    non-zero, is the known size of the object.  TEMPL is a bfd | 
 |    representing the target's format.  NAME is the name to use for this | 
 |    symbol file in messages; it can be NULL.  */ | 
 | static struct objfile * | 
 | symbol_file_add_from_memory (struct bfd *templ, CORE_ADDR addr, | 
 | 			     size_t size, const char *name, int from_tty) | 
 | { | 
 |   struct objfile *objf; | 
 |   struct bfd *nbfd; | 
 |   struct bfd_section *sec; | 
 |   bfd_vma loadbase; | 
 |   symfile_add_flags add_flags = SYMFILE_NOT_FILENAME; | 
 |  | 
 |   if (bfd_get_flavour (templ) != bfd_target_elf_flavour) | 
 |     error (_("add-symbol-file-from-memory not supported for this target")); | 
 |  | 
 |   nbfd = bfd_elf_bfd_from_remote_memory (templ, addr, size, &loadbase, | 
 | 					 target_read_memory_bfd); | 
 |   if (nbfd == NULL) | 
 |     error (_("Failed to read a valid object file image from memory.")); | 
 |  | 
 |   /* Manage the new reference for the duration of this function.  */ | 
 |   gdb_bfd_ref_ptr nbfd_holder = gdb_bfd_ref_ptr::new_reference (nbfd); | 
 |  | 
 |   if (name == NULL) | 
 |     name = "shared object read from target memory"; | 
 |   bfd_set_filename (nbfd, name); | 
 |  | 
 |   if (!bfd_check_format (nbfd, bfd_object)) | 
 |     error (_("Got object file from memory but can't read symbols: %s."), | 
 | 	   bfd_errmsg (bfd_get_error ())); | 
 |  | 
 |   section_addr_info sai; | 
 |   for (sec = nbfd->sections; sec != NULL; sec = sec->next) | 
 |     if ((bfd_section_flags (sec) & (SEC_ALLOC|SEC_LOAD)) != 0) | 
 |       sai.emplace_back (bfd_section_vma (sec) + loadbase, | 
 | 			bfd_section_name (sec), | 
 | 			sec->index); | 
 |  | 
 |   if (from_tty) | 
 |     add_flags |= SYMFILE_VERBOSE; | 
 |  | 
 |   objf = symbol_file_add_from_bfd (nbfd_holder, bfd_get_filename (nbfd), | 
 | 				   add_flags, &sai, OBJF_SHARED, NULL); | 
 |  | 
 |   current_program_space->add_target_sections (objf); | 
 |  | 
 |   /* This might change our ideas about frames already looked at.  */ | 
 |   reinit_frame_cache (); | 
 |  | 
 |   return objf; | 
 | } | 
 |  | 
 |  | 
 | static void | 
 | add_symbol_file_from_memory_command (const char *args, int from_tty) | 
 | { | 
 |   CORE_ADDR addr; | 
 |   struct bfd *templ; | 
 |  | 
 |   if (args == NULL) | 
 |     error (_("add-symbol-file-from-memory requires an expression argument")); | 
 |  | 
 |   addr = parse_and_eval_address (args); | 
 |  | 
 |   /* We need some representative bfd to know the target we are looking at.  */ | 
 |   if (current_program_space->symfile_object_file != NULL) | 
 |     templ = current_program_space->symfile_object_file->obfd.get (); | 
 |   else | 
 |     templ = current_program_space->exec_bfd (); | 
 |   if (templ == NULL) | 
 |     error (_("Must use symbol-file or exec-file " | 
 | 	     "before add-symbol-file-from-memory.")); | 
 |  | 
 |   symbol_file_add_from_memory (templ, addr, 0, NULL, from_tty); | 
 | } | 
 |  | 
 | /* Try to add the symbols for the vsyscall page, if there is one. | 
 |    This function is called via the inferior_created observer.  */ | 
 |  | 
 | static void | 
 | add_vsyscall_page (inferior *inf) | 
 | { | 
 |   struct mem_range vsyscall_range; | 
 |  | 
 |   if (gdbarch_vsyscall_range (inf->arch (), &vsyscall_range)) | 
 |     { | 
 |       struct bfd *bfd; | 
 |  | 
 |       if (current_program_space->core_bfd () != nullptr) | 
 | 	bfd = current_program_space->core_bfd (); | 
 |       else if (current_program_space->exec_bfd () != nullptr) | 
 | 	bfd = current_program_space->exec_bfd (); | 
 |       else | 
 |        /* FIXME: cagney/2004-05-06: Should not require an existing | 
 | 	  BFD when trying to create a run-time BFD of the VSYSCALL | 
 | 	  page in the inferior.  Unfortunately that's the current | 
 | 	  interface so for the moment bail.  Introducing a | 
 | 	  ``bfd_runtime'' (a BFD created using the loaded image) file | 
 | 	  format should fix this.  */ | 
 | 	{ | 
 | 	  warning (_("Could not load vsyscall page " | 
 | 		     "because no executable was specified")); | 
 | 	  return; | 
 | 	} | 
 |  | 
 |       std::string name = string_printf ("system-supplied DSO at %s", | 
 | 					paddress (current_inferior ()->arch (), | 
 | 						  vsyscall_range.start)); | 
 |       try | 
 | 	{ | 
 | 	  /* Pass zero for FROM_TTY, because the action of loading the | 
 | 	     vsyscall DSO was not triggered by the user, even if the | 
 | 	     user typed "run" at the TTY.  */ | 
 | 	  symbol_file_add_from_memory (bfd, | 
 | 				       vsyscall_range.start, | 
 | 				       vsyscall_range.length, | 
 | 				       name.c_str (), | 
 | 				       0 /* from_tty */); | 
 | 	} | 
 |       catch (const gdb_exception_error &ex) | 
 | 	{ | 
 | 	  exception_print (gdb_stderr, ex); | 
 | 	} | 
 |     } | 
 | } | 
 |  | 
 | void _initialize_symfile_mem (); | 
 | void | 
 | _initialize_symfile_mem () | 
 | { | 
 |   add_cmd ("add-symbol-file-from-memory", class_files, | 
 | 	   add_symbol_file_from_memory_command, | 
 | 	   _("Load the symbols out of memory from a " | 
 | 	     "dynamically loaded object file.\n" | 
 | 	     "Give an expression for the address " | 
 | 	     "of the file's shared object file header."), | 
 | 	   &cmdlist); | 
 |  | 
 |   /* Want to know of each new inferior so that its vsyscall info can | 
 |      be extracted.  */ | 
 |   gdb::observers::inferior_created.attach (add_vsyscall_page, "symfile-mem"); | 
 | } |