1130803Smarcel/* Auxiliary vector support for GDB, the GNU debugger.
2130803Smarcel
3130803Smarcel   Copyright 2004 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 "target.h"
24130803Smarcel#include "gdbtypes.h"
25130803Smarcel#include "command.h"
26130803Smarcel#include "inferior.h"
27130803Smarcel#include "valprint.h"
28130803Smarcel#include "gdb_assert.h"
29130803Smarcel
30130803Smarcel#include "auxv.h"
31130803Smarcel#include "elf/common.h"
32130803Smarcel
33130803Smarcel#include <unistd.h>
34130803Smarcel#include <fcntl.h>
35130803Smarcel
36130803Smarcel
37130803Smarcel/* This function is called like a to_xfer_partial hook,
38130803Smarcel   but must be called with TARGET_OBJECT_AUXV.
39130803Smarcel   It handles access via /proc/PID/auxv, which is the common method.
40130803Smarcel   This function is appropriate for doing:
41130803Smarcel	   #define NATIVE_XFER_AUXV	procfs_xfer_auxv
42130803Smarcel   for a native target that uses inftarg.c's child_xfer_partial hook.  */
43130803Smarcel
44130803SmarcelLONGEST
45130803Smarcelprocfs_xfer_auxv (struct target_ops *ops,
46130803Smarcel		  int /* enum target_object */ object,
47130803Smarcel		  const char *annex,
48130803Smarcel		  void *readbuf,
49130803Smarcel		  const void *writebuf,
50130803Smarcel		  ULONGEST offset,
51130803Smarcel		  LONGEST len)
52130803Smarcel{
53130803Smarcel  char *pathname;
54130803Smarcel  int fd;
55130803Smarcel  LONGEST n;
56130803Smarcel
57130803Smarcel  gdb_assert (object == TARGET_OBJECT_AUXV);
58130803Smarcel  gdb_assert (readbuf || writebuf);
59130803Smarcel
60130803Smarcel  pathname = xstrprintf ("/proc/%d/auxv", PIDGET (inferior_ptid));
61130803Smarcel  fd = open (pathname, writebuf != NULL ? O_WRONLY : O_RDONLY);
62130803Smarcel  xfree (pathname);
63130803Smarcel  if (fd < 0)
64130803Smarcel    return -1;
65130803Smarcel
66130803Smarcel  if (offset != (ULONGEST) 0
67130803Smarcel      && lseek (fd, (off_t) offset, SEEK_SET) != (off_t) offset)
68130803Smarcel    n = -1;
69130803Smarcel  else if (readbuf != NULL)
70130803Smarcel    n = read (fd, readbuf, len);
71130803Smarcel  else
72130803Smarcel    n = write (fd, writebuf, len);
73130803Smarcel
74130803Smarcel  (void) close (fd);
75130803Smarcel
76130803Smarcel  return n;
77130803Smarcel}
78130803Smarcel
79130803Smarcel/* Read all the auxv data into a contiguous xmalloc'd buffer,
80130803Smarcel   stored in *DATA.  Return the size in bytes of this data.
81130803Smarcel   If zero, there is no data and *DATA is null.
82130803Smarcel   if < 0, there was an error and *DATA is null.  */
83130803SmarcelLONGEST
84130803Smarceltarget_auxv_read (struct target_ops *ops, char **data)
85130803Smarcel{
86130803Smarcel  size_t auxv_alloc = 512, auxv_pos = 0;
87130803Smarcel  char *auxv = xmalloc (auxv_alloc);
88130803Smarcel  int n;
89130803Smarcel
90130803Smarcel  while (1)
91130803Smarcel    {
92130803Smarcel      n = target_read_partial (ops, TARGET_OBJECT_AUXV,
93130803Smarcel			       NULL, &auxv[auxv_pos], 0,
94130803Smarcel			       auxv_alloc - auxv_pos);
95130803Smarcel      if (n <= 0)
96130803Smarcel	break;
97130803Smarcel      auxv_pos += n;
98130803Smarcel      if (auxv_pos < auxv_alloc) /* Read all there was.  */
99130803Smarcel	break;
100130803Smarcel      gdb_assert (auxv_pos == auxv_alloc);
101130803Smarcel      auxv_alloc *= 2;
102130803Smarcel      auxv = xrealloc (auxv, auxv_alloc);
103130803Smarcel    }
104130803Smarcel
105130803Smarcel  if (auxv_pos == 0)
106130803Smarcel    {
107130803Smarcel      xfree (auxv);
108130803Smarcel      *data = NULL;
109130803Smarcel      return n;
110130803Smarcel    }
111130803Smarcel
112130803Smarcel  *data = auxv;
113130803Smarcel  return auxv_pos;
114130803Smarcel}
115130803Smarcel
116130803Smarcel/* Read one auxv entry from *READPTR, not reading locations >= ENDPTR.
117130803Smarcel   Return 0 if *READPTR is already at the end of the buffer.
118130803Smarcel   Return -1 if there is insufficient buffer for a whole entry.
119130803Smarcel   Return 1 if an entry was read into *TYPEP and *VALP.  */
120130803Smarcelint
121130803Smarceltarget_auxv_parse (struct target_ops *ops, char **readptr, char *endptr,
122130803Smarcel		   CORE_ADDR *typep, CORE_ADDR *valp)
123130803Smarcel{
124130803Smarcel  const int sizeof_auxv_field = TYPE_LENGTH (builtin_type_void_data_ptr);
125130803Smarcel  char *ptr = *readptr;
126130803Smarcel
127130803Smarcel  if (endptr == ptr)
128130803Smarcel    return 0;
129130803Smarcel
130130803Smarcel  if (endptr - ptr < sizeof_auxv_field * 2)
131130803Smarcel    return -1;
132130803Smarcel
133130803Smarcel  *typep = extract_unsigned_integer (ptr, sizeof_auxv_field);
134130803Smarcel  ptr += sizeof_auxv_field;
135130803Smarcel  *valp = extract_unsigned_integer (ptr, sizeof_auxv_field);
136130803Smarcel  ptr += sizeof_auxv_field;
137130803Smarcel
138130803Smarcel  *readptr = ptr;
139130803Smarcel  return 1;
140130803Smarcel}
141130803Smarcel
142130803Smarcel/* Extract the auxiliary vector entry with a_type matching MATCH.
143130803Smarcel   Return zero if no such entry was found, or -1 if there was
144130803Smarcel   an error getting the information.  On success, return 1 after
145130803Smarcel   storing the entry's value field in *VALP.  */
146130803Smarcelint
147130803Smarceltarget_auxv_search (struct target_ops *ops, CORE_ADDR match, CORE_ADDR *valp)
148130803Smarcel{
149130803Smarcel  CORE_ADDR type, val;
150130803Smarcel  char *data;
151130803Smarcel  int n = target_auxv_read (ops, &data);
152130803Smarcel  char *ptr = data;
153130803Smarcel  int ents = 0;
154130803Smarcel
155130803Smarcel  if (n <= 0)
156130803Smarcel    return n;
157130803Smarcel
158130803Smarcel  while (1)
159130803Smarcel    switch (target_auxv_parse (ops, &ptr, data + n, &type, &val))
160130803Smarcel      {
161130803Smarcel      case 1:			/* Here's an entry, check it.  */
162130803Smarcel	if (type == match)
163130803Smarcel	  {
164130803Smarcel	    xfree (data);
165130803Smarcel	    *valp = val;
166130803Smarcel	    return 1;
167130803Smarcel	  }
168130803Smarcel	break;
169130803Smarcel      case 0:			/* End of the vector.  */
170130803Smarcel	xfree (data);
171130803Smarcel	return 0;
172130803Smarcel      default:			/* Bogosity.  */
173130803Smarcel	xfree (data);
174130803Smarcel	return -1;
175130803Smarcel      }
176130803Smarcel
177130803Smarcel  /*NOTREACHED*/
178130803Smarcel}
179130803Smarcel
180130803Smarcel
181130803Smarcel/* Print the contents of the target's AUXV on the specified file. */
182130803Smarcelint
183130803Smarcelfprint_target_auxv (struct ui_file *file, struct target_ops *ops)
184130803Smarcel{
185130803Smarcel  CORE_ADDR type, val;
186130803Smarcel  char *data;
187130803Smarcel  int len = target_auxv_read (ops, &data);
188130803Smarcel  char *ptr = data;
189130803Smarcel  int ents = 0;
190130803Smarcel
191130803Smarcel  if (len <= 0)
192130803Smarcel    return len;
193130803Smarcel
194130803Smarcel  while (target_auxv_parse (ops, &ptr, data + len, &type, &val) > 0)
195130803Smarcel    {
196130803Smarcel      extern int addressprint;
197130803Smarcel      const char *name = "???";
198130803Smarcel      const char *description = "";
199130803Smarcel      enum { dec, hex, str } flavor = hex;
200130803Smarcel
201130803Smarcel      switch (type)
202130803Smarcel	{
203130803Smarcel#define TAG(tag, text, kind) \
204130803Smarcel	case tag: name = #tag; description = text; flavor = kind; break
205130803Smarcel	  TAG (AT_NULL, "End of vector", hex);
206130803Smarcel	  TAG (AT_IGNORE, "Entry should be ignored", hex);
207130803Smarcel	  TAG (AT_EXECFD, "File descriptor of program", dec);
208130803Smarcel	  TAG (AT_PHDR, "Program headers for program", hex);
209130803Smarcel	  TAG (AT_PHENT, "Size of program header entry", dec);
210130803Smarcel	  TAG (AT_PHNUM, "Number of program headers", dec);
211130803Smarcel	  TAG (AT_PAGESZ, "System page size", dec);
212130803Smarcel	  TAG (AT_BASE, "Base address of interpreter", hex);
213130803Smarcel	  TAG (AT_FLAGS, "Flags", hex);
214130803Smarcel	  TAG (AT_ENTRY, "Entry point of program", hex);
215130803Smarcel	  TAG (AT_NOTELF, "Program is not ELF", dec);
216130803Smarcel	  TAG (AT_UID, "Real user ID", dec);
217130803Smarcel	  TAG (AT_EUID, "Effective user ID", dec);
218130803Smarcel	  TAG (AT_GID, "Real group ID", dec);
219130803Smarcel	  TAG (AT_EGID, "Effective group ID", dec);
220130803Smarcel	  TAG (AT_CLKTCK, "Frequency of times()", dec);
221130803Smarcel	  TAG (AT_PLATFORM, "String identifying platform", str);
222130803Smarcel	  TAG (AT_HWCAP, "Machine-dependent CPU capability hints", hex);
223130803Smarcel	  TAG (AT_FPUCW, "Used FPU control word", dec);
224130803Smarcel	  TAG (AT_DCACHEBSIZE, "Data cache block size", dec);
225130803Smarcel	  TAG (AT_ICACHEBSIZE, "Instruction cache block size", dec);
226130803Smarcel	  TAG (AT_UCACHEBSIZE, "Unified cache block size", dec);
227130803Smarcel	  TAG (AT_IGNOREPPC, "Entry should be ignored", dec);
228130803Smarcel	  TAG (AT_SYSINFO, "Special system info/entry points", hex);
229130803Smarcel	  TAG (AT_SYSINFO_EHDR, "System-supplied DSO's ELF header", hex);
230130803Smarcel	  TAG (AT_SECURE, "Boolean, was exec setuid-like?", dec);
231130803Smarcel	  TAG (AT_SUN_UID, "Effective user ID", dec);
232130803Smarcel	  TAG (AT_SUN_RUID, "Real user ID", dec);
233130803Smarcel	  TAG (AT_SUN_GID, "Effective group ID", dec);
234130803Smarcel	  TAG (AT_SUN_RGID, "Real group ID", dec);
235130803Smarcel	  TAG (AT_SUN_LDELF, "Dynamic linker's ELF header", hex);
236130803Smarcel	  TAG (AT_SUN_LDSHDR, "Dynamic linker's section headers", hex);
237130803Smarcel	  TAG (AT_SUN_LDNAME, "String giving name of dynamic linker", str);
238130803Smarcel	  TAG (AT_SUN_LPAGESZ, "Large pagesize", dec);
239130803Smarcel	  TAG (AT_SUN_PLATFORM, "Platform name string", str);
240130803Smarcel	  TAG (AT_SUN_HWCAP, "Machine-dependent CPU capability hints", hex);
241130803Smarcel	  TAG (AT_SUN_IFLUSH, "Should flush icache?", dec);
242130803Smarcel	  TAG (AT_SUN_CPU, "CPU name string", str);
243130803Smarcel	  TAG (AT_SUN_EMUL_ENTRY, "COFF entry point address", hex);
244130803Smarcel	  TAG (AT_SUN_EMUL_EXECFD, "COFF executable file descriptor", dec);
245130803Smarcel	  TAG (AT_SUN_EXECNAME,
246130803Smarcel	       "Canonicalized file name given to execve", str);
247130803Smarcel	  TAG (AT_SUN_MMU, "String for name of MMU module", str);
248130803Smarcel	  TAG (AT_SUN_LDDATA, "Dynamic linker's data segment address", hex);
249130803Smarcel	}
250130803Smarcel
251130803Smarcel      fprintf_filtered (file, "%-4s %-20s %-30s ",
252130803Smarcel			paddr_d (type), name, description);
253130803Smarcel      switch (flavor)
254130803Smarcel	{
255130803Smarcel	case dec:
256130803Smarcel	  fprintf_filtered (file, "%s\n", paddr_d (val));
257130803Smarcel	  break;
258130803Smarcel	case hex:
259130803Smarcel	  fprintf_filtered (file, "0x%s\n", paddr_nz (val));
260130803Smarcel	  break;
261130803Smarcel	case str:
262130803Smarcel	  if (addressprint)
263130803Smarcel	    fprintf_filtered (file, "0x%s", paddr_nz (val));
264130803Smarcel	  val_print_string (val, -1, 1, file);
265130803Smarcel	  fprintf_filtered (file, "\n");
266130803Smarcel	  break;
267130803Smarcel	}
268130803Smarcel      ++ents;
269130803Smarcel    }
270130803Smarcel
271130803Smarcel  xfree (data);
272130803Smarcel
273130803Smarcel  return ents;
274130803Smarcel}
275130803Smarcel
276130803Smarcelstatic void
277130803Smarcelinfo_auxv_command (char *cmd, int from_tty)
278130803Smarcel{
279130803Smarcel  if (! target_has_stack)
280130803Smarcel    error ("The program has no auxiliary information now.");
281130803Smarcel  else
282130803Smarcel    {
283130803Smarcel      int ents = fprint_target_auxv (gdb_stdout, &current_target);
284130803Smarcel      if (ents < 0)
285130803Smarcel	error ("No auxiliary vector found, or failed reading it.");
286130803Smarcel      else if (ents == 0)
287130803Smarcel	error ("Auxiliary vector is empty.");
288130803Smarcel    }
289130803Smarcel}
290130803Smarcel
291130803Smarcel
292130803Smarcelextern initialize_file_ftype _initialize_auxv; /* -Wmissing-prototypes; */
293130803Smarcel
294130803Smarcelvoid
295130803Smarcel_initialize_auxv (void)
296130803Smarcel{
297130803Smarcel  add_info ("auxv", info_auxv_command,
298130803Smarcel	    "Display the inferior's auxiliary vector.\n\
299130803SmarcelThis is information provided by the operating system at program startup.");
300130803Smarcel}
301