1130803Smarcel/* FreeBSD-specific methods for using the /proc file system.
2130803Smarcel
3130803Smarcel   Copyright 2002, 2003 Free Software Foundation, Inc.
4130803Smarcel
5130803Smarcel   This file is part of GDB.
6130803Smarcel
7130803Smarcel   This program is free software; you can redistribute it and/or modify
8130803Smarcel   it under the terms of the GNU General Public License as published by
9130803Smarcel   the Free Software Foundation; either version 2 of the License, or
10130803Smarcel   (at your option) any later version.
11130803Smarcel
12130803Smarcel   This program is distributed in the hope that it will be useful,
13130803Smarcel   but WITHOUT ANY WARRANTY; without even the implied warranty of
14130803Smarcel   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15130803Smarcel   GNU General Public License for more details.
16130803Smarcel
17130803Smarcel   You should have received a copy of the GNU General Public License
18130803Smarcel   along with this program; if not, write to the Free Software
19130803Smarcel   Foundation, Inc., 59 Temple Place - Suite 330,
20130803Smarcel   Boston, MA 02111-1307, USA.  */
21130803Smarcel
22130803Smarcel#include "defs.h"
23130803Smarcel#include "gdbcore.h"
24130803Smarcel#include "inferior.h"
25130803Smarcel#include "gdb_string.h"
26130803Smarcel
27130803Smarcel#include <sys/procfs.h>
28130803Smarcel#include <sys/types.h>
29130803Smarcel
30130803Smarcel#include "elf-bfd.h"
31130803Smarcel
32130803Smarcel#include "gregset.h"
33130803Smarcel
34130803Smarcelchar *
35130803Smarcelchild_pid_to_exec_file (int pid)
36130803Smarcel{
37130803Smarcel  char *path;
38130803Smarcel  char *buf;
39130803Smarcel
40130803Smarcel  xasprintf (&path, "/proc/%d/file", pid);
41130803Smarcel  buf = xcalloc (MAXPATHLEN, sizeof (char));
42130803Smarcel  make_cleanup (xfree, path);
43130803Smarcel  make_cleanup (xfree, buf);
44130803Smarcel
45130803Smarcel  if (readlink (path, buf, MAXPATHLEN) > 0)
46130803Smarcel    return buf;
47130803Smarcel
48130803Smarcel  return NULL;
49130803Smarcel}
50130803Smarcel
51130803Smarcelstatic int
52130803Smarcelread_mapping (FILE *mapfile, unsigned long *start, unsigned long *end,
53130803Smarcel	      char *protection)
54130803Smarcel{
55130803Smarcel  /* FreeBSD 5.1-RELEASE uses a 256-byte buffer.  */
56130803Smarcel  char buf[256];
57130803Smarcel  int resident, privateresident;
58130803Smarcel  unsigned long obj;
59130803Smarcel  int ret = EOF;
60130803Smarcel
61130803Smarcel  /* As of FreeBSD 5.0-RELEASE, the layout is described in
62130803Smarcel     /usr/src/sys/fs/procfs/procfs_map.c.  Somewhere in 5.1-CURRENT a
63130803Smarcel     new column was added to the procfs map.  Therefore we can't use
64130803Smarcel     fscanf since we need to support older releases too.  */
65130803Smarcel  if (fgets (buf, sizeof buf, mapfile) != NULL)
66130803Smarcel    ret = sscanf (buf, "%lx %lx %d %d %lx %s", start, end,
67130803Smarcel		  &resident, &privateresident, &obj, protection);
68130803Smarcel
69130803Smarcel  return (ret != 0 && ret != EOF);
70130803Smarcel}
71130803Smarcel
72130803Smarcelstatic int
73130803Smarcelfbsd_find_memory_regions (int (*func) (CORE_ADDR, unsigned long,
74130803Smarcel				       int, int, int, void *),
75130803Smarcel			  void *obfd)
76130803Smarcel{
77130803Smarcel  pid_t pid = ptid_get_pid (inferior_ptid);
78130803Smarcel  char *mapfilename;
79130803Smarcel  FILE *mapfile;
80130803Smarcel  unsigned long start, end, size;
81130803Smarcel  char protection[4];
82130803Smarcel  int read, write, exec;
83130803Smarcel
84130803Smarcel  xasprintf (&mapfilename, "/proc/%ld/map", (long) pid);
85130803Smarcel  mapfile = fopen (mapfilename, "r");
86130803Smarcel  if (mapfile == NULL)
87130803Smarcel    error ("Couldn't open %s\n", mapfilename);
88130803Smarcel
89130803Smarcel  if (info_verbose)
90130803Smarcel    fprintf_filtered (gdb_stdout,
91130803Smarcel		      "Reading memory regions from %s\n", mapfilename);
92130803Smarcel
93130803Smarcel  /* Now iterate until end-of-file.  */
94130803Smarcel  while (read_mapping (mapfile, &start, &end, &protection[0]))
95130803Smarcel    {
96130803Smarcel      size = end - start;
97130803Smarcel
98130803Smarcel      read = (strchr (protection, 'r') != 0);
99130803Smarcel      write = (strchr (protection, 'w') != 0);
100130803Smarcel      exec = (strchr (protection, 'x') != 0);
101130803Smarcel
102130803Smarcel      if (info_verbose)
103130803Smarcel	{
104130803Smarcel	  fprintf_filtered (gdb_stdout,
105130803Smarcel			    "Save segment, %ld bytes at 0x%s (%c%c%c)\n",
106130803Smarcel			    size, paddr_nz (start),
107130803Smarcel			    read ? 'r' : '-',
108130803Smarcel			    write ? 'w' : '-',
109130803Smarcel			    exec ? 'x' : '-');
110130803Smarcel	}
111130803Smarcel
112130803Smarcel      /* Invoke the callback function to create the corefile segment. */
113130803Smarcel      func (start, size, read, write, exec, obfd);
114130803Smarcel    }
115130803Smarcel
116130803Smarcel  fclose (mapfile);
117130803Smarcel  return 0;
118130803Smarcel}
119130803Smarcel
120130803Smarcelstatic char *
121130803Smarcelfbsd_make_corefile_notes (bfd *obfd, int *note_size)
122130803Smarcel{
123130803Smarcel  gregset_t gregs;
124130803Smarcel  fpregset_t fpregs;
125130803Smarcel  char *note_data = NULL;
126130803Smarcel  Elf_Internal_Ehdr *i_ehdrp;
127215679Sattilio  char fakename;
128130803Smarcel
129130803Smarcel  /* Put a "FreeBSD" label in the ELF header.  */
130130803Smarcel  i_ehdrp = elf_elfheader (obfd);
131130803Smarcel  i_ehdrp->e_ident[EI_OSABI] = ELFOSABI_FREEBSD;
132130803Smarcel
133130803Smarcel  fill_gregset (&gregs, -1);
134130803Smarcel  note_data = elfcore_write_prstatus (obfd, note_data, note_size,
135130803Smarcel				      ptid_get_pid (inferior_ptid),
136130803Smarcel				      stop_signal, &gregs);
137130803Smarcel
138130803Smarcel  fill_fpregset (&fpregs, -1);
139130803Smarcel  note_data = elfcore_write_prfpreg (obfd, note_data, note_size,
140130803Smarcel				     &fpregs, sizeof (fpregs));
141130803Smarcel
142215679Sattilio  fakename = '\0';
143215679Sattilio  note_data = elfcore_write_thrmisc (obfd, note_data, note_size,
144215679Sattilio				     &fakename, sizeof (fakename));
145215679Sattilio
146130803Smarcel  if (get_exec_file (0))
147130803Smarcel    {
148130803Smarcel      char *fname = strrchr (get_exec_file (0), '/') + 1;
149130803Smarcel      char *psargs = xstrdup (fname);
150130803Smarcel
151130803Smarcel      if (get_inferior_args ())
152130803Smarcel	psargs = reconcat (psargs, psargs, " ", get_inferior_args (), NULL);
153130803Smarcel
154130803Smarcel      note_data = elfcore_write_prpsinfo (obfd, note_data, note_size,
155130803Smarcel					  fname, psargs);
156130803Smarcel    }
157130803Smarcel
158130803Smarcel  make_cleanup (xfree, note_data);
159130803Smarcel  return note_data;
160130803Smarcel}
161130803Smarcel
162130803Smarcel
163130803Smarcelvoid
164130803Smarcel_initialize_fbsd_proc (void)
165130803Smarcel{
166130803Smarcel  extern void inftarg_set_find_memory_regions ();
167130803Smarcel  extern void inftarg_set_make_corefile_notes ();
168130803Smarcel
169130803Smarcel  inftarg_set_find_memory_regions (fbsd_find_memory_regions);
170130803Smarcel  inftarg_set_make_corefile_notes (fbsd_make_corefile_notes);
171130803Smarcel}
172