1/* Auxiliary vector support for GDB, the GNU debugger.
2
3   Copyright 2004 Free Software Foundation, Inc.
4
5   This file is part of GDB.
6
7   This program is free software; you can redistribute it and/or modify
8   it under the terms of the GNU General Public License as published by
9   the Free Software Foundation; either version 2 of the License, or
10   (at your option) any later version.
11
12   This program is distributed in the hope that it will be useful,
13   but WITHOUT ANY WARRANTY; without even the implied warranty of
14   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15   GNU General Public License for more details.
16
17   You should have received a copy of the GNU General Public License
18   along with this program; if not, write to the Free Software
19   Foundation, Inc., 59 Temple Place - Suite 330,
20   Boston, MA 02111-1307, USA.  */
21
22#include "defs.h"
23#include "target.h"
24#include "gdbtypes.h"
25#include "command.h"
26#include "inferior.h"
27#include "valprint.h"
28#include "gdb_assert.h"
29
30#include "auxv.h"
31#include "elf/common.h"
32
33#include <unistd.h>
34#include <fcntl.h>
35
36
37/* This function is called like a to_xfer_partial hook,
38   but must be called with TARGET_OBJECT_AUXV.
39   It handles access via /proc/PID/auxv, which is the common method.
40   This function is appropriate for doing:
41	   #define NATIVE_XFER_AUXV	procfs_xfer_auxv
42   for a native target that uses inftarg.c's child_xfer_partial hook.  */
43
44LONGEST
45procfs_xfer_auxv (struct target_ops *ops,
46		  int /* enum target_object */ object,
47		  const char *annex,
48		  void *readbuf,
49		  const void *writebuf,
50		  ULONGEST offset,
51		  LONGEST len)
52{
53  char *pathname;
54  int fd;
55  LONGEST n;
56
57  gdb_assert (object == TARGET_OBJECT_AUXV);
58  gdb_assert (readbuf || writebuf);
59
60  pathname = xstrprintf ("/proc/%d/auxv", PIDGET (inferior_ptid));
61  fd = open (pathname, writebuf != NULL ? O_WRONLY : O_RDONLY);
62  xfree (pathname);
63  if (fd < 0)
64    return -1;
65
66  if (offset != (ULONGEST) 0
67      && lseek (fd, (off_t) offset, SEEK_SET) != (off_t) offset)
68    n = -1;
69  else if (readbuf != NULL)
70    n = read (fd, readbuf, len);
71  else
72    n = write (fd, writebuf, len);
73
74  (void) close (fd);
75
76  return n;
77}
78
79/* Read all the auxv data into a contiguous xmalloc'd buffer,
80   stored in *DATA.  Return the size in bytes of this data.
81   If zero, there is no data and *DATA is null.
82   if < 0, there was an error and *DATA is null.  */
83LONGEST
84target_auxv_read (struct target_ops *ops, char **data)
85{
86  size_t auxv_alloc = 512, auxv_pos = 0;
87  char *auxv = xmalloc (auxv_alloc);
88  int n;
89
90  while (1)
91    {
92      n = target_read_partial (ops, TARGET_OBJECT_AUXV,
93			       NULL, &auxv[auxv_pos], 0,
94			       auxv_alloc - auxv_pos);
95      if (n <= 0)
96	break;
97      auxv_pos += n;
98      if (auxv_pos < auxv_alloc) /* Read all there was.  */
99	break;
100      gdb_assert (auxv_pos == auxv_alloc);
101      auxv_alloc *= 2;
102      auxv = xrealloc (auxv, auxv_alloc);
103    }
104
105  if (auxv_pos == 0)
106    {
107      xfree (auxv);
108      *data = NULL;
109      return n;
110    }
111
112  *data = auxv;
113  return auxv_pos;
114}
115
116/* Read one auxv entry from *READPTR, not reading locations >= ENDPTR.
117   Return 0 if *READPTR is already at the end of the buffer.
118   Return -1 if there is insufficient buffer for a whole entry.
119   Return 1 if an entry was read into *TYPEP and *VALP.  */
120int
121target_auxv_parse (struct target_ops *ops, char **readptr, char *endptr,
122		   CORE_ADDR *typep, CORE_ADDR *valp)
123{
124  const int sizeof_auxv_type = TYPE_LENGTH (builtin_type_int);
125  const int sizeof_auxv_val = TYPE_LENGTH (builtin_type_void_data_ptr);
126  char *ptr = *readptr;
127
128  if (endptr == ptr)
129    return 0;
130
131  if (endptr - ptr < (sizeof_auxv_type + sizeof_auxv_val))
132    return -1;
133
134  *typep = extract_unsigned_integer (ptr, sizeof_auxv_type);
135  ptr += sizeof_auxv_val;	/* Alignment. */
136  *valp = extract_unsigned_integer (ptr, sizeof_auxv_val);
137  ptr += sizeof_auxv_val;
138
139  *readptr = ptr;
140  return 1;
141}
142
143/* Extract the auxiliary vector entry with a_type matching MATCH.
144   Return zero if no such entry was found, or -1 if there was
145   an error getting the information.  On success, return 1 after
146   storing the entry's value field in *VALP.  */
147int
148target_auxv_search (struct target_ops *ops, CORE_ADDR match, CORE_ADDR *valp)
149{
150  CORE_ADDR type, val;
151  char *data;
152  int n = target_auxv_read (ops, &data);
153  char *ptr = data;
154  int ents = 0;
155
156  if (n <= 0)
157    return n;
158
159  while (1)
160    switch (target_auxv_parse (ops, &ptr, data + n, &type, &val))
161      {
162      case 1:			/* Here's an entry, check it.  */
163	if (type == match)
164	  {
165	    xfree (data);
166	    *valp = val;
167	    return 1;
168	  }
169	break;
170      case 0:			/* End of the vector.  */
171	xfree (data);
172	return 0;
173      default:			/* Bogosity.  */
174	xfree (data);
175	return -1;
176      }
177
178  /*NOTREACHED*/
179}
180
181
182/* Print the contents of the target's AUXV on the specified file. */
183int
184fprint_target_auxv (struct ui_file *file, struct target_ops *ops)
185{
186  CORE_ADDR type, val;
187  char *data;
188  int len = target_auxv_read (ops, &data);
189  char *ptr = data;
190  int ents = 0;
191
192  if (len <= 0)
193    return len;
194
195  while (target_auxv_parse (ops, &ptr, data + len, &type, &val) > 0)
196    {
197      extern int addressprint;
198      const char *name = "???";
199      const char *description = "";
200      enum { dec, hex, str } flavor = hex;
201
202      switch (type)
203	{
204#define TAG(tag, text, kind) \
205	case tag: name = #tag; description = text; flavor = kind; break
206	  TAG (AT_NULL, "End of vector", hex);
207	  TAG (AT_IGNORE, "Entry should be ignored", hex);
208	  TAG (AT_EXECFD, "File descriptor of program", dec);
209	  TAG (AT_PHDR, "Program headers for program", hex);
210	  TAG (AT_PHENT, "Size of program header entry", dec);
211	  TAG (AT_PHNUM, "Number of program headers", dec);
212	  TAG (AT_PAGESZ, "System page size", dec);
213	  TAG (AT_BASE, "Base address of interpreter", hex);
214	  TAG (AT_FLAGS, "Flags", hex);
215	  TAG (AT_ENTRY, "Entry point of program", hex);
216	  TAG (AT_NOTELF, "Program is not ELF", dec);
217	  TAG (AT_UID, "Real user ID", dec);
218	  TAG (AT_EUID, "Effective user ID", dec);
219	  TAG (AT_GID, "Real group ID", dec);
220	  TAG (AT_EGID, "Effective group ID", dec);
221	  TAG (AT_CLKTCK, "Frequency of times()", dec);
222	  TAG (AT_PLATFORM, "String identifying platform", str);
223	  TAG (AT_HWCAP, "Machine-dependent CPU capability hints", hex);
224	  TAG (AT_FPUCW, "Used FPU control word", dec);
225	  TAG (AT_DCACHEBSIZE, "Data cache block size", dec);
226	  TAG (AT_ICACHEBSIZE, "Instruction cache block size", dec);
227	  TAG (AT_UCACHEBSIZE, "Unified cache block size", dec);
228	  TAG (AT_IGNOREPPC, "Entry should be ignored", dec);
229	  TAG (AT_SYSINFO, "Special system info/entry points", hex);
230	  TAG (AT_SYSINFO_EHDR, "System-supplied DSO's ELF header", hex);
231	  TAG (AT_SECURE, "Boolean, was exec setuid-like?", dec);
232	  TAG (AT_SUN_UID, "Effective user ID", dec);
233	  TAG (AT_SUN_RUID, "Real user ID", dec);
234	  TAG (AT_SUN_GID, "Effective group ID", dec);
235	  TAG (AT_SUN_RGID, "Real group ID", dec);
236	  TAG (AT_SUN_LDELF, "Dynamic linker's ELF header", hex);
237	  TAG (AT_SUN_LDSHDR, "Dynamic linker's section headers", hex);
238	  TAG (AT_SUN_LDNAME, "String giving name of dynamic linker", str);
239	  TAG (AT_SUN_LPAGESZ, "Large pagesize", dec);
240	  TAG (AT_SUN_PLATFORM, "Platform name string", str);
241	  TAG (AT_SUN_HWCAP, "Machine-dependent CPU capability hints", hex);
242	  TAG (AT_SUN_IFLUSH, "Should flush icache?", dec);
243	  TAG (AT_SUN_CPU, "CPU name string", str);
244	  TAG (AT_SUN_EMUL_ENTRY, "COFF entry point address", hex);
245	  TAG (AT_SUN_EMUL_EXECFD, "COFF executable file descriptor", dec);
246	  TAG (AT_SUN_EXECNAME,
247	       "Canonicalized file name given to execve", str);
248	  TAG (AT_SUN_MMU, "String for name of MMU module", str);
249	  TAG (AT_SUN_LDDATA, "Dynamic linker's data segment address", hex);
250	}
251
252      fprintf_filtered (file, "%-4s %-20s %-30s ",
253			paddr_d (type), name, description);
254      switch (flavor)
255	{
256	case dec:
257	  fprintf_filtered (file, "%s\n", paddr_d (val));
258	  break;
259	case hex:
260	  fprintf_filtered (file, "0x%s\n", paddr_nz (val));
261	  break;
262	case str:
263	  if (addressprint)
264	    fprintf_filtered (file, "0x%s", paddr_nz (val));
265	  val_print_string (val, -1, 1, file);
266	  fprintf_filtered (file, "\n");
267	  break;
268	}
269      ++ents;
270      if (type == AT_NULL)
271	break;
272    }
273
274  xfree (data);
275
276  return ents;
277}
278
279static void
280info_auxv_command (char *cmd, int from_tty)
281{
282  if (! target_has_stack)
283    error ("The program has no auxiliary information now.");
284  else
285    {
286      int ents = fprint_target_auxv (gdb_stdout, &current_target);
287      if (ents < 0)
288	error ("No auxiliary vector found, or failed reading it.");
289      else if (ents == 0)
290	error ("Auxiliary vector is empty.");
291    }
292}
293
294
295extern initialize_file_ftype _initialize_auxv; /* -Wmissing-prototypes; */
296
297void
298_initialize_auxv (void)
299{
300  add_info ("auxv", info_auxv_command,
301	    "Display the inferior's auxiliary vector.\n\
302This is information provided by the operating system at program startup.");
303}
304