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_field = TYPE_LENGTH (builtin_type_void_data_ptr);
125  char *ptr = *readptr;
126
127  if (endptr == ptr)
128    return 0;
129
130  if (endptr - ptr < sizeof_auxv_field * 2)
131    return -1;
132
133  *typep = extract_unsigned_integer (ptr, sizeof_auxv_field);
134  ptr += sizeof_auxv_field;
135  *valp = extract_unsigned_integer (ptr, sizeof_auxv_field);
136  ptr += sizeof_auxv_field;
137
138  *readptr = ptr;
139  return 1;
140}
141
142/* Extract the auxiliary vector entry with a_type matching MATCH.
143   Return zero if no such entry was found, or -1 if there was
144   an error getting the information.  On success, return 1 after
145   storing the entry's value field in *VALP.  */
146int
147target_auxv_search (struct target_ops *ops, CORE_ADDR match, CORE_ADDR *valp)
148{
149  CORE_ADDR type, val;
150  char *data;
151  int n = target_auxv_read (ops, &data);
152  char *ptr = data;
153  int ents = 0;
154
155  if (n <= 0)
156    return n;
157
158  while (1)
159    switch (target_auxv_parse (ops, &ptr, data + n, &type, &val))
160      {
161      case 1:			/* Here's an entry, check it.  */
162	if (type == match)
163	  {
164	    xfree (data);
165	    *valp = val;
166	    return 1;
167	  }
168	break;
169      case 0:			/* End of the vector.  */
170	xfree (data);
171	return 0;
172      default:			/* Bogosity.  */
173	xfree (data);
174	return -1;
175      }
176
177  /*NOTREACHED*/
178}
179
180
181/* Print the contents of the target's AUXV on the specified file. */
182int
183fprint_target_auxv (struct ui_file *file, struct target_ops *ops)
184{
185  CORE_ADDR type, val;
186  char *data;
187  int len = target_auxv_read (ops, &data);
188  char *ptr = data;
189  int ents = 0;
190
191  if (len <= 0)
192    return len;
193
194  while (target_auxv_parse (ops, &ptr, data + len, &type, &val) > 0)
195    {
196      extern int addressprint;
197      const char *name = "???";
198      const char *description = "";
199      enum { dec, hex, str } flavor = hex;
200
201      switch (type)
202	{
203#define TAG(tag, text, kind) \
204	case tag: name = #tag; description = text; flavor = kind; break
205	  TAG (AT_NULL, "End of vector", hex);
206	  TAG (AT_IGNORE, "Entry should be ignored", hex);
207	  TAG (AT_EXECFD, "File descriptor of program", dec);
208	  TAG (AT_PHDR, "Program headers for program", hex);
209	  TAG (AT_PHENT, "Size of program header entry", dec);
210	  TAG (AT_PHNUM, "Number of program headers", dec);
211	  TAG (AT_PAGESZ, "System page size", dec);
212	  TAG (AT_BASE, "Base address of interpreter", hex);
213	  TAG (AT_FLAGS, "Flags", hex);
214	  TAG (AT_ENTRY, "Entry point of program", hex);
215	  TAG (AT_NOTELF, "Program is not ELF", dec);
216	  TAG (AT_UID, "Real user ID", dec);
217	  TAG (AT_EUID, "Effective user ID", dec);
218	  TAG (AT_GID, "Real group ID", dec);
219	  TAG (AT_EGID, "Effective group ID", dec);
220	  TAG (AT_CLKTCK, "Frequency of times()", dec);
221	  TAG (AT_PLATFORM, "String identifying platform", str);
222	  TAG (AT_HWCAP, "Machine-dependent CPU capability hints", hex);
223	  TAG (AT_FPUCW, "Used FPU control word", dec);
224	  TAG (AT_DCACHEBSIZE, "Data cache block size", dec);
225	  TAG (AT_ICACHEBSIZE, "Instruction cache block size", dec);
226	  TAG (AT_UCACHEBSIZE, "Unified cache block size", dec);
227	  TAG (AT_IGNOREPPC, "Entry should be ignored", dec);
228	  TAG (AT_SYSINFO, "Special system info/entry points", hex);
229	  TAG (AT_SYSINFO_EHDR, "System-supplied DSO's ELF header", hex);
230	  TAG (AT_SECURE, "Boolean, was exec setuid-like?", dec);
231	  TAG (AT_SUN_UID, "Effective user ID", dec);
232	  TAG (AT_SUN_RUID, "Real user ID", dec);
233	  TAG (AT_SUN_GID, "Effective group ID", dec);
234	  TAG (AT_SUN_RGID, "Real group ID", dec);
235	  TAG (AT_SUN_LDELF, "Dynamic linker's ELF header", hex);
236	  TAG (AT_SUN_LDSHDR, "Dynamic linker's section headers", hex);
237	  TAG (AT_SUN_LDNAME, "String giving name of dynamic linker", str);
238	  TAG (AT_SUN_LPAGESZ, "Large pagesize", dec);
239	  TAG (AT_SUN_PLATFORM, "Platform name string", str);
240	  TAG (AT_SUN_HWCAP, "Machine-dependent CPU capability hints", hex);
241	  TAG (AT_SUN_IFLUSH, "Should flush icache?", dec);
242	  TAG (AT_SUN_CPU, "CPU name string", str);
243	  TAG (AT_SUN_EMUL_ENTRY, "COFF entry point address", hex);
244	  TAG (AT_SUN_EMUL_EXECFD, "COFF executable file descriptor", dec);
245	  TAG (AT_SUN_EXECNAME,
246	       "Canonicalized file name given to execve", str);
247	  TAG (AT_SUN_MMU, "String for name of MMU module", str);
248	  TAG (AT_SUN_LDDATA, "Dynamic linker's data segment address", hex);
249	}
250
251      fprintf_filtered (file, "%-4s %-20s %-30s ",
252			paddr_d (type), name, description);
253      switch (flavor)
254	{
255	case dec:
256	  fprintf_filtered (file, "%s\n", paddr_d (val));
257	  break;
258	case hex:
259	  fprintf_filtered (file, "0x%s\n", paddr_nz (val));
260	  break;
261	case str:
262	  if (addressprint)
263	    fprintf_filtered (file, "0x%s", paddr_nz (val));
264	  val_print_string (val, -1, 1, file);
265	  fprintf_filtered (file, "\n");
266	  break;
267	}
268      ++ents;
269    }
270
271  xfree (data);
272
273  return ents;
274}
275
276static void
277info_auxv_command (char *cmd, int from_tty)
278{
279  if (! target_has_stack)
280    error ("The program has no auxiliary information now.");
281  else
282    {
283      int ents = fprint_target_auxv (gdb_stdout, &current_target);
284      if (ents < 0)
285	error ("No auxiliary vector found, or failed reading it.");
286      else if (ents == 0)
287	error ("Auxiliary vector is empty.");
288    }
289}
290
291
292extern initialize_file_ftype _initialize_auxv; /* -Wmissing-prototypes; */
293
294void
295_initialize_auxv (void)
296{
297  add_info ("auxv", info_auxv_command,
298	    "Display the inferior's auxiliary vector.\n\
299This is information provided by the operating system at program startup.");
300}
301