xref: /dflybsd-src/contrib/gdb-7/gdb/fbsd-nat.c (revision de8e141f24382815c10a4012d209bbbf7abf1112)
15796c8dcSSimon Schubert /* Native-dependent code for FreeBSD.
25796c8dcSSimon Schubert 
3*ef5ccd6cSJohn Marino    Copyright (C) 2002-2013 Free Software Foundation, Inc.
45796c8dcSSimon Schubert 
55796c8dcSSimon Schubert    This file is part of GDB.
65796c8dcSSimon Schubert 
75796c8dcSSimon Schubert    This program is free software; you can redistribute it and/or modify
85796c8dcSSimon Schubert    it under the terms of the GNU General Public License as published by
95796c8dcSSimon Schubert    the Free Software Foundation; either version 3 of the License, or
105796c8dcSSimon Schubert    (at your option) any later version.
115796c8dcSSimon Schubert 
125796c8dcSSimon Schubert    This program is distributed in the hope that it will be useful,
135796c8dcSSimon Schubert    but WITHOUT ANY WARRANTY; without even the implied warranty of
145796c8dcSSimon Schubert    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
155796c8dcSSimon Schubert    GNU General Public License for more details.
165796c8dcSSimon Schubert 
175796c8dcSSimon Schubert    You should have received a copy of the GNU General Public License
185796c8dcSSimon Schubert    along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
195796c8dcSSimon Schubert 
205796c8dcSSimon Schubert #include "defs.h"
215796c8dcSSimon Schubert #include "gdbcore.h"
225796c8dcSSimon Schubert #include "inferior.h"
235796c8dcSSimon Schubert #include "regcache.h"
245796c8dcSSimon Schubert #include "regset.h"
255796c8dcSSimon Schubert #include "gdbthread.h"
265796c8dcSSimon Schubert 
275796c8dcSSimon Schubert #include "gdb_assert.h"
285796c8dcSSimon Schubert #include "gdb_string.h"
295796c8dcSSimon Schubert #include <sys/types.h>
305796c8dcSSimon Schubert #include <sys/procfs.h>
315796c8dcSSimon Schubert #include <sys/sysctl.h>
325796c8dcSSimon Schubert 
335796c8dcSSimon Schubert #include "elf-bfd.h"
345796c8dcSSimon Schubert #include "fbsd-nat.h"
355796c8dcSSimon Schubert 
36c50c785cSJohn Marino /* Return the name of a file that can be opened to get the symbols for
375796c8dcSSimon Schubert    the child process identified by PID.  */
385796c8dcSSimon Schubert 
395796c8dcSSimon Schubert char *
fbsd_pid_to_exec_file(int pid)405796c8dcSSimon Schubert fbsd_pid_to_exec_file (int pid)
415796c8dcSSimon Schubert {
425796c8dcSSimon Schubert   size_t len = MAXPATHLEN;
435796c8dcSSimon Schubert   char *buf = xcalloc (len, sizeof (char));
445796c8dcSSimon Schubert   char *path;
455796c8dcSSimon Schubert 
465796c8dcSSimon Schubert #ifdef KERN_PROC_PATHNAME
475796c8dcSSimon Schubert   int mib[4];
485796c8dcSSimon Schubert 
495796c8dcSSimon Schubert   mib[0] = CTL_KERN;
505796c8dcSSimon Schubert   mib[1] = KERN_PROC;
515796c8dcSSimon Schubert   mib[2] = KERN_PROC_PATHNAME;
525796c8dcSSimon Schubert   mib[3] = pid;
535796c8dcSSimon Schubert   if (sysctl (mib, 4, buf, &len, NULL, 0) == 0)
545796c8dcSSimon Schubert     return buf;
555796c8dcSSimon Schubert #endif
565796c8dcSSimon Schubert 
575796c8dcSSimon Schubert   path = xstrprintf ("/proc/%d/file", pid);
58*ef5ccd6cSJohn Marino   if (readlink (path, buf, MAXPATHLEN - 1) == -1)
595796c8dcSSimon Schubert     {
605796c8dcSSimon Schubert       xfree (buf);
615796c8dcSSimon Schubert       buf = NULL;
625796c8dcSSimon Schubert     }
635796c8dcSSimon Schubert 
645796c8dcSSimon Schubert   xfree (path);
655796c8dcSSimon Schubert   return buf;
665796c8dcSSimon Schubert }
675796c8dcSSimon Schubert 
685796c8dcSSimon Schubert static int
fbsd_read_mapping(FILE * mapfile,unsigned long * start,unsigned long * end,char * protection)695796c8dcSSimon Schubert fbsd_read_mapping (FILE *mapfile, unsigned long *start, unsigned long *end,
705796c8dcSSimon Schubert 		   char *protection)
715796c8dcSSimon Schubert {
725796c8dcSSimon Schubert   /* FreeBSD 5.1-RELEASE uses a 256-byte buffer.  */
735796c8dcSSimon Schubert   char buf[256];
745796c8dcSSimon Schubert   int resident, privateresident;
755796c8dcSSimon Schubert   unsigned long obj;
765796c8dcSSimon Schubert   int ret = EOF;
775796c8dcSSimon Schubert 
785796c8dcSSimon Schubert   /* As of FreeBSD 5.0-RELEASE, the layout is described in
795796c8dcSSimon Schubert      /usr/src/sys/fs/procfs/procfs_map.c.  Somewhere in 5.1-CURRENT a
805796c8dcSSimon Schubert      new column was added to the procfs map.  Therefore we can't use
815796c8dcSSimon Schubert      fscanf since we need to support older releases too.  */
825796c8dcSSimon Schubert   if (fgets (buf, sizeof buf, mapfile) != NULL)
835796c8dcSSimon Schubert     ret = sscanf (buf, "%lx %lx %d %d %lx %s", start, end,
845796c8dcSSimon Schubert 		  &resident, &privateresident, &obj, protection);
855796c8dcSSimon Schubert 
865796c8dcSSimon Schubert   return (ret != 0 && ret != EOF);
875796c8dcSSimon Schubert }
885796c8dcSSimon Schubert 
895796c8dcSSimon Schubert /* Iterate over all the memory regions in the current inferior,
905796c8dcSSimon Schubert    calling FUNC for each memory region.  OBFD is passed as the last
915796c8dcSSimon Schubert    argument to FUNC.  */
925796c8dcSSimon Schubert 
935796c8dcSSimon Schubert int
fbsd_find_memory_regions(find_memory_region_ftype func,void * obfd)94c50c785cSJohn Marino fbsd_find_memory_regions (find_memory_region_ftype func, void *obfd)
955796c8dcSSimon Schubert {
965796c8dcSSimon Schubert   pid_t pid = ptid_get_pid (inferior_ptid);
975796c8dcSSimon Schubert   char *mapfilename;
985796c8dcSSimon Schubert   FILE *mapfile;
995796c8dcSSimon Schubert   unsigned long start, end, size;
1005796c8dcSSimon Schubert   char protection[4];
1015796c8dcSSimon Schubert   int read, write, exec;
1025796c8dcSSimon Schubert   struct cleanup *cleanup;
1035796c8dcSSimon Schubert 
1045796c8dcSSimon Schubert   mapfilename = xstrprintf ("/proc/%ld/map", (long) pid);
1055796c8dcSSimon Schubert   cleanup = make_cleanup (xfree, mapfilename);
1065796c8dcSSimon Schubert   mapfile = fopen (mapfilename, "r");
1075796c8dcSSimon Schubert   if (mapfile == NULL)
1085796c8dcSSimon Schubert     error (_("Couldn't open %s."), mapfilename);
1095796c8dcSSimon Schubert   make_cleanup_fclose (mapfile);
1105796c8dcSSimon Schubert 
1115796c8dcSSimon Schubert   if (info_verbose)
1125796c8dcSSimon Schubert     fprintf_filtered (gdb_stdout,
1135796c8dcSSimon Schubert 		      "Reading memory regions from %s\n", mapfilename);
1145796c8dcSSimon Schubert 
1155796c8dcSSimon Schubert   /* Now iterate until end-of-file.  */
1165796c8dcSSimon Schubert   while (fbsd_read_mapping (mapfile, &start, &end, &protection[0]))
1175796c8dcSSimon Schubert     {
1185796c8dcSSimon Schubert       size = end - start;
1195796c8dcSSimon Schubert 
1205796c8dcSSimon Schubert       read = (strchr (protection, 'r') != 0);
1215796c8dcSSimon Schubert       write = (strchr (protection, 'w') != 0);
1225796c8dcSSimon Schubert       exec = (strchr (protection, 'x') != 0);
1235796c8dcSSimon Schubert 
1245796c8dcSSimon Schubert       if (info_verbose)
1255796c8dcSSimon Schubert 	{
1265796c8dcSSimon Schubert 	  fprintf_filtered (gdb_stdout,
1275796c8dcSSimon Schubert 			    "Save segment, %ld bytes at %s (%c%c%c)\n",
128*ef5ccd6cSJohn Marino 			    size, paddress (target_gdbarch (), start),
1295796c8dcSSimon Schubert 			    read ? 'r' : '-',
1305796c8dcSSimon Schubert 			    write ? 'w' : '-',
1315796c8dcSSimon Schubert 			    exec ? 'x' : '-');
1325796c8dcSSimon Schubert 	}
1335796c8dcSSimon Schubert 
134*ef5ccd6cSJohn Marino       /* Invoke the callback function to create the corefile segment.
135*ef5ccd6cSJohn Marino 	 Pass MODIFIED as true, we do not know the real modification state.  */
136*ef5ccd6cSJohn Marino       func (start, size, read, write, exec, 1, obfd);
1375796c8dcSSimon Schubert     }
1385796c8dcSSimon Schubert 
1395796c8dcSSimon Schubert   do_cleanups (cleanup);
1405796c8dcSSimon Schubert   return 0;
1415796c8dcSSimon Schubert }
1425796c8dcSSimon Schubert 
1435796c8dcSSimon Schubert static int
find_signalled_thread(struct thread_info * info,void * data)1445796c8dcSSimon Schubert find_signalled_thread (struct thread_info *info, void *data)
1455796c8dcSSimon Schubert {
146*ef5ccd6cSJohn Marino   if (info->suspend.stop_signal != GDB_SIGNAL_0
1475796c8dcSSimon Schubert       && ptid_get_pid (info->ptid) == ptid_get_pid (inferior_ptid))
1485796c8dcSSimon Schubert     return 1;
1495796c8dcSSimon Schubert 
1505796c8dcSSimon Schubert   return 0;
1515796c8dcSSimon Schubert }
1525796c8dcSSimon Schubert 
153*ef5ccd6cSJohn Marino static enum gdb_signal
find_stop_signal(void)1545796c8dcSSimon Schubert find_stop_signal (void)
1555796c8dcSSimon Schubert {
1565796c8dcSSimon Schubert   struct thread_info *info =
1575796c8dcSSimon Schubert     iterate_over_threads (find_signalled_thread, NULL);
1585796c8dcSSimon Schubert 
1595796c8dcSSimon Schubert   if (info)
160c50c785cSJohn Marino     return info->suspend.stop_signal;
1615796c8dcSSimon Schubert   else
162*ef5ccd6cSJohn Marino     return GDB_SIGNAL_0;
1635796c8dcSSimon Schubert }
1645796c8dcSSimon Schubert 
1655796c8dcSSimon Schubert /* Create appropriate note sections for a corefile, returning them in
1665796c8dcSSimon Schubert    allocated memory.  */
1675796c8dcSSimon Schubert 
1685796c8dcSSimon Schubert char *
fbsd_make_corefile_notes(bfd * obfd,int * note_size)1695796c8dcSSimon Schubert fbsd_make_corefile_notes (bfd *obfd, int *note_size)
1705796c8dcSSimon Schubert {
1715796c8dcSSimon Schubert   const struct regcache *regcache = get_current_regcache ();
1725796c8dcSSimon Schubert   struct gdbarch *gdbarch = get_regcache_arch (regcache);
1735796c8dcSSimon Schubert   gregset_t gregs;
1745796c8dcSSimon Schubert   fpregset_t fpregs;
1755796c8dcSSimon Schubert   char *note_data = NULL;
1765796c8dcSSimon Schubert   Elf_Internal_Ehdr *i_ehdrp;
1775796c8dcSSimon Schubert   const struct regset *regset;
1785796c8dcSSimon Schubert   size_t size;
1795796c8dcSSimon Schubert 
1805796c8dcSSimon Schubert   /* Put a "FreeBSD" label in the ELF header.  */
1815796c8dcSSimon Schubert   i_ehdrp = elf_elfheader (obfd);
1825796c8dcSSimon Schubert   i_ehdrp->e_ident[EI_OSABI] = ELFOSABI_FREEBSD;
1835796c8dcSSimon Schubert 
1845796c8dcSSimon Schubert   gdb_assert (gdbarch_regset_from_core_section_p (gdbarch));
1855796c8dcSSimon Schubert 
1865796c8dcSSimon Schubert   size = sizeof gregs;
1875796c8dcSSimon Schubert   regset = gdbarch_regset_from_core_section (gdbarch, ".reg", size);
1885796c8dcSSimon Schubert   gdb_assert (regset && regset->collect_regset);
1895796c8dcSSimon Schubert   regset->collect_regset (regset, regcache, -1, &gregs, size);
1905796c8dcSSimon Schubert 
1915796c8dcSSimon Schubert   note_data = elfcore_write_prstatus (obfd, note_data, note_size,
1925796c8dcSSimon Schubert 				      ptid_get_pid (inferior_ptid),
1935796c8dcSSimon Schubert 				      find_stop_signal (), &gregs);
1945796c8dcSSimon Schubert 
1955796c8dcSSimon Schubert   size = sizeof fpregs;
1965796c8dcSSimon Schubert   regset = gdbarch_regset_from_core_section (gdbarch, ".reg2", size);
1975796c8dcSSimon Schubert   gdb_assert (regset && regset->collect_regset);
1985796c8dcSSimon Schubert   regset->collect_regset (regset, regcache, -1, &fpregs, size);
1995796c8dcSSimon Schubert 
2005796c8dcSSimon Schubert   note_data = elfcore_write_prfpreg (obfd, note_data, note_size,
2015796c8dcSSimon Schubert 				     &fpregs, sizeof (fpregs));
2025796c8dcSSimon Schubert 
2035796c8dcSSimon Schubert   if (get_exec_file (0))
2045796c8dcSSimon Schubert     {
205c50c785cSJohn Marino       const char *fname = lbasename (get_exec_file (0));
2065796c8dcSSimon Schubert       char *psargs = xstrdup (fname);
2075796c8dcSSimon Schubert 
2085796c8dcSSimon Schubert       if (get_inferior_args ())
209cf7f2e2dSJohn Marino 	psargs = reconcat (psargs, psargs, " ", get_inferior_args (),
210cf7f2e2dSJohn Marino 			   (char *) NULL);
2115796c8dcSSimon Schubert 
2125796c8dcSSimon Schubert       note_data = elfcore_write_prpsinfo (obfd, note_data, note_size,
2135796c8dcSSimon Schubert 					  fname, psargs);
2145796c8dcSSimon Schubert     }
2155796c8dcSSimon Schubert 
2165796c8dcSSimon Schubert   make_cleanup (xfree, note_data);
2175796c8dcSSimon Schubert   return note_data;
2185796c8dcSSimon Schubert }
219