xref: /dragonfly/contrib/gdb-7/gdb/auxv.c (revision ef5ccd6c)
15796c8dcSSimon Schubert /* Auxiliary vector support for GDB, the GNU debugger.
25796c8dcSSimon Schubert 
3*ef5ccd6cSJohn Marino    Copyright (C) 2004-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 "target.h"
225796c8dcSSimon Schubert #include "gdbtypes.h"
235796c8dcSSimon Schubert #include "command.h"
245796c8dcSSimon Schubert #include "inferior.h"
255796c8dcSSimon Schubert #include "valprint.h"
265796c8dcSSimon Schubert #include "gdb_assert.h"
27cf7f2e2dSJohn Marino #include "gdbcore.h"
28a45ae5f8SJohn Marino #include "observer.h"
295796c8dcSSimon Schubert 
305796c8dcSSimon Schubert #include "auxv.h"
315796c8dcSSimon Schubert #include "elf/common.h"
325796c8dcSSimon Schubert 
335796c8dcSSimon Schubert #include <unistd.h>
345796c8dcSSimon Schubert #include <fcntl.h>
355796c8dcSSimon Schubert 
365796c8dcSSimon Schubert 
37c50c785cSJohn Marino /* This function handles access via /proc/PID/auxv, which is a common
38c50c785cSJohn Marino    method for native targets.  */
395796c8dcSSimon Schubert 
40cf7f2e2dSJohn Marino static LONGEST
procfs_xfer_auxv(gdb_byte * readbuf,const gdb_byte * writebuf,ULONGEST offset,LONGEST len)41cf7f2e2dSJohn Marino procfs_xfer_auxv (gdb_byte *readbuf,
425796c8dcSSimon Schubert 		  const gdb_byte *writebuf,
435796c8dcSSimon Schubert 		  ULONGEST offset,
445796c8dcSSimon Schubert 		  LONGEST len)
455796c8dcSSimon Schubert {
465796c8dcSSimon Schubert   char *pathname;
475796c8dcSSimon Schubert   int fd;
485796c8dcSSimon Schubert   LONGEST n;
495796c8dcSSimon Schubert 
505796c8dcSSimon Schubert   pathname = xstrprintf ("/proc/%d/auxv", PIDGET (inferior_ptid));
515796c8dcSSimon Schubert   fd = open (pathname, writebuf != NULL ? O_WRONLY : O_RDONLY);
525796c8dcSSimon Schubert   xfree (pathname);
535796c8dcSSimon Schubert   if (fd < 0)
545796c8dcSSimon Schubert     return -1;
555796c8dcSSimon Schubert 
565796c8dcSSimon Schubert   if (offset != (ULONGEST) 0
575796c8dcSSimon Schubert       && lseek (fd, (off_t) offset, SEEK_SET) != (off_t) offset)
585796c8dcSSimon Schubert     n = -1;
595796c8dcSSimon Schubert   else if (readbuf != NULL)
605796c8dcSSimon Schubert     n = read (fd, readbuf, len);
615796c8dcSSimon Schubert   else
625796c8dcSSimon Schubert     n = write (fd, writebuf, len);
635796c8dcSSimon Schubert 
645796c8dcSSimon Schubert   (void) close (fd);
655796c8dcSSimon Schubert 
665796c8dcSSimon Schubert   return n;
675796c8dcSSimon Schubert }
685796c8dcSSimon Schubert 
69cf7f2e2dSJohn Marino /* This function handles access via ld.so's symbol `_dl_auxv'.  */
70cf7f2e2dSJohn Marino 
71cf7f2e2dSJohn Marino static LONGEST
ld_so_xfer_auxv(gdb_byte * readbuf,const gdb_byte * writebuf,ULONGEST offset,LONGEST len)72cf7f2e2dSJohn Marino ld_so_xfer_auxv (gdb_byte *readbuf,
73cf7f2e2dSJohn Marino 		 const gdb_byte *writebuf,
74cf7f2e2dSJohn Marino 		 ULONGEST offset,
75cf7f2e2dSJohn Marino 		 LONGEST len)
76cf7f2e2dSJohn Marino {
77cf7f2e2dSJohn Marino   struct minimal_symbol *msym;
78cf7f2e2dSJohn Marino   CORE_ADDR data_address, pointer_address;
79*ef5ccd6cSJohn Marino   struct type *ptr_type = builtin_type (target_gdbarch ())->builtin_data_ptr;
80cf7f2e2dSJohn Marino   size_t ptr_size = TYPE_LENGTH (ptr_type);
81cf7f2e2dSJohn Marino   size_t auxv_pair_size = 2 * ptr_size;
82cf7f2e2dSJohn Marino   gdb_byte *ptr_buf = alloca (ptr_size);
83cf7f2e2dSJohn Marino   LONGEST retval;
84cf7f2e2dSJohn Marino   size_t block;
85cf7f2e2dSJohn Marino 
86cf7f2e2dSJohn Marino   msym = lookup_minimal_symbol ("_dl_auxv", NULL, NULL);
87cf7f2e2dSJohn Marino   if (msym == NULL)
88cf7f2e2dSJohn Marino     return -1;
89cf7f2e2dSJohn Marino 
90cf7f2e2dSJohn Marino   if (MSYMBOL_SIZE (msym) != ptr_size)
91cf7f2e2dSJohn Marino     return -1;
92cf7f2e2dSJohn Marino 
93c50c785cSJohn Marino   /* POINTER_ADDRESS is a location where the `_dl_auxv' variable
94c50c785cSJohn Marino      resides.  DATA_ADDRESS is the inferior value present in
95c50c785cSJohn Marino      `_dl_auxv', therefore the real inferior AUXV address.  */
96cf7f2e2dSJohn Marino 
97cf7f2e2dSJohn Marino   pointer_address = SYMBOL_VALUE_ADDRESS (msym);
98cf7f2e2dSJohn Marino 
99cf7f2e2dSJohn Marino   /* The location of the _dl_auxv symbol may no longer be correct if
100c50c785cSJohn Marino      ld.so runs at a different address than the one present in the
101c50c785cSJohn Marino      file.  This is very common case - for unprelinked ld.so or with a
102c50c785cSJohn Marino      PIE executable.  PIE executable forces random address even for
103c50c785cSJohn Marino      libraries already being prelinked to some address.  PIE
104c50c785cSJohn Marino      executables themselves are never prelinked even on prelinked
105c50c785cSJohn Marino      systems.  Prelinking of a PIE executable would block their
106c50c785cSJohn Marino      purpose of randomizing load of everything including the
107c50c785cSJohn Marino      executable.
108cf7f2e2dSJohn Marino 
109c50c785cSJohn Marino      If the memory read fails, return -1 to fallback on another
110c50c785cSJohn Marino      mechanism for retrieving the AUXV.
111cf7f2e2dSJohn Marino 
112c50c785cSJohn Marino      In most cases of a PIE running under valgrind there is no way to
113c50c785cSJohn Marino      find out the base addresses of any of ld.so, executable or AUXV
114c50c785cSJohn Marino      as everything is randomized and /proc information is not relevant
115c50c785cSJohn Marino      for the virtual executable running under valgrind.  We think that
116c50c785cSJohn Marino      we might need a valgrind extension to make it work.  This is PR
117c50c785cSJohn Marino      11440.  */
118cf7f2e2dSJohn Marino 
119cf7f2e2dSJohn Marino   if (target_read_memory (pointer_address, ptr_buf, ptr_size) != 0)
120cf7f2e2dSJohn Marino     return -1;
121cf7f2e2dSJohn Marino 
122cf7f2e2dSJohn Marino   data_address = extract_typed_address (ptr_buf, ptr_type);
123cf7f2e2dSJohn Marino 
124c50c785cSJohn Marino   /* Possibly still not initialized such as during an inferior
125c50c785cSJohn Marino      startup.  */
126cf7f2e2dSJohn Marino   if (data_address == 0)
127cf7f2e2dSJohn Marino     return -1;
128cf7f2e2dSJohn Marino 
129cf7f2e2dSJohn Marino   data_address += offset;
130cf7f2e2dSJohn Marino 
131cf7f2e2dSJohn Marino   if (writebuf != NULL)
132cf7f2e2dSJohn Marino     {
133cf7f2e2dSJohn Marino       if (target_write_memory (data_address, writebuf, len) == 0)
134cf7f2e2dSJohn Marino 	return len;
135cf7f2e2dSJohn Marino       else
136cf7f2e2dSJohn Marino 	return -1;
137cf7f2e2dSJohn Marino     }
138cf7f2e2dSJohn Marino 
139c50c785cSJohn Marino   /* Stop if trying to read past the existing AUXV block.  The final
140c50c785cSJohn Marino      AT_NULL was already returned before.  */
141cf7f2e2dSJohn Marino 
142cf7f2e2dSJohn Marino   if (offset >= auxv_pair_size)
143cf7f2e2dSJohn Marino     {
144cf7f2e2dSJohn Marino       if (target_read_memory (data_address - auxv_pair_size, ptr_buf,
145cf7f2e2dSJohn Marino 			      ptr_size) != 0)
146cf7f2e2dSJohn Marino 	return -1;
147cf7f2e2dSJohn Marino 
148cf7f2e2dSJohn Marino       if (extract_typed_address (ptr_buf, ptr_type) == AT_NULL)
149cf7f2e2dSJohn Marino 	return 0;
150cf7f2e2dSJohn Marino     }
151cf7f2e2dSJohn Marino 
152cf7f2e2dSJohn Marino   retval = 0;
153cf7f2e2dSJohn Marino   block = 0x400;
154cf7f2e2dSJohn Marino   gdb_assert (block % auxv_pair_size == 0);
155cf7f2e2dSJohn Marino 
156cf7f2e2dSJohn Marino   while (len > 0)
157cf7f2e2dSJohn Marino     {
158cf7f2e2dSJohn Marino       if (block > len)
159cf7f2e2dSJohn Marino 	block = len;
160cf7f2e2dSJohn Marino 
161c50c785cSJohn Marino       /* Reading sizes smaller than AUXV_PAIR_SIZE is not supported.
162c50c785cSJohn Marino 	 Tails unaligned to AUXV_PAIR_SIZE will not be read during a
163c50c785cSJohn Marino 	 call (they should be completed during next read with
164c50c785cSJohn Marino 	 new/extended buffer).  */
165cf7f2e2dSJohn Marino 
166cf7f2e2dSJohn Marino       block &= -auxv_pair_size;
167cf7f2e2dSJohn Marino       if (block == 0)
168cf7f2e2dSJohn Marino 	return retval;
169cf7f2e2dSJohn Marino 
170cf7f2e2dSJohn Marino       if (target_read_memory (data_address, readbuf, block) != 0)
171cf7f2e2dSJohn Marino 	{
172cf7f2e2dSJohn Marino 	  if (block <= auxv_pair_size)
173cf7f2e2dSJohn Marino 	    return retval;
174cf7f2e2dSJohn Marino 
175cf7f2e2dSJohn Marino 	  block = auxv_pair_size;
176cf7f2e2dSJohn Marino 	  continue;
177cf7f2e2dSJohn Marino 	}
178cf7f2e2dSJohn Marino 
179cf7f2e2dSJohn Marino       data_address += block;
180cf7f2e2dSJohn Marino       len -= block;
181cf7f2e2dSJohn Marino 
182c50c785cSJohn Marino       /* Check terminal AT_NULL.  This function is being called
183c50c785cSJohn Marino          indefinitely being extended its READBUF until it returns EOF
184c50c785cSJohn Marino          (0).  */
185cf7f2e2dSJohn Marino 
186cf7f2e2dSJohn Marino       while (block >= auxv_pair_size)
187cf7f2e2dSJohn Marino 	{
188cf7f2e2dSJohn Marino 	  retval += auxv_pair_size;
189cf7f2e2dSJohn Marino 
190cf7f2e2dSJohn Marino 	  if (extract_typed_address (readbuf, ptr_type) == AT_NULL)
191cf7f2e2dSJohn Marino 	    return retval;
192cf7f2e2dSJohn Marino 
193cf7f2e2dSJohn Marino 	  readbuf += auxv_pair_size;
194cf7f2e2dSJohn Marino 	  block -= auxv_pair_size;
195cf7f2e2dSJohn Marino 	}
196cf7f2e2dSJohn Marino     }
197cf7f2e2dSJohn Marino 
198cf7f2e2dSJohn Marino   return retval;
199cf7f2e2dSJohn Marino }
200cf7f2e2dSJohn Marino 
201cf7f2e2dSJohn Marino /* This function is called like a to_xfer_partial hook, but must be
202cf7f2e2dSJohn Marino    called with TARGET_OBJECT_AUXV.  It handles access to AUXV.  */
203cf7f2e2dSJohn Marino 
204cf7f2e2dSJohn Marino LONGEST
memory_xfer_auxv(struct target_ops * ops,enum target_object object,const char * annex,gdb_byte * readbuf,const gdb_byte * writebuf,ULONGEST offset,LONGEST len)205cf7f2e2dSJohn Marino memory_xfer_auxv (struct target_ops *ops,
206cf7f2e2dSJohn Marino 		  enum target_object object,
207cf7f2e2dSJohn Marino 		  const char *annex,
208cf7f2e2dSJohn Marino 		  gdb_byte *readbuf,
209cf7f2e2dSJohn Marino 		  const gdb_byte *writebuf,
210cf7f2e2dSJohn Marino 		  ULONGEST offset,
211cf7f2e2dSJohn Marino 		  LONGEST len)
212cf7f2e2dSJohn Marino {
213cf7f2e2dSJohn Marino   gdb_assert (object == TARGET_OBJECT_AUXV);
214cf7f2e2dSJohn Marino   gdb_assert (readbuf || writebuf);
215cf7f2e2dSJohn Marino 
216c50c785cSJohn Marino    /* ld_so_xfer_auxv is the only function safe for virtual
217c50c785cSJohn Marino       executables being executed by valgrind's memcheck.  Using
218c50c785cSJohn Marino       ld_so_xfer_auxv during inferior startup is problematic, because
219c50c785cSJohn Marino       ld.so symbol tables have not yet been relocated.  So GDB uses
220c50c785cSJohn Marino       this function only when attaching to a process.
221cf7f2e2dSJohn Marino       */
222cf7f2e2dSJohn Marino 
223cf7f2e2dSJohn Marino   if (current_inferior ()->attach_flag != 0)
224cf7f2e2dSJohn Marino     {
225cf7f2e2dSJohn Marino       LONGEST retval;
226cf7f2e2dSJohn Marino 
227cf7f2e2dSJohn Marino       retval = ld_so_xfer_auxv (readbuf, writebuf, offset, len);
228cf7f2e2dSJohn Marino       if (retval != -1)
229cf7f2e2dSJohn Marino 	return retval;
230cf7f2e2dSJohn Marino     }
231cf7f2e2dSJohn Marino 
232cf7f2e2dSJohn Marino   return procfs_xfer_auxv (readbuf, writebuf, offset, len);
233cf7f2e2dSJohn Marino }
234cf7f2e2dSJohn Marino 
2355796c8dcSSimon Schubert /* Read one auxv entry from *READPTR, not reading locations >= ENDPTR.
2365796c8dcSSimon Schubert    Return 0 if *READPTR is already at the end of the buffer.
2375796c8dcSSimon Schubert    Return -1 if there is insufficient buffer for a whole entry.
2385796c8dcSSimon Schubert    Return 1 if an entry was read into *TYPEP and *VALP.  */
2395796c8dcSSimon Schubert static int
default_auxv_parse(struct target_ops * ops,gdb_byte ** readptr,gdb_byte * endptr,CORE_ADDR * typep,CORE_ADDR * valp)2405796c8dcSSimon Schubert default_auxv_parse (struct target_ops *ops, gdb_byte **readptr,
2415796c8dcSSimon Schubert 		   gdb_byte *endptr, CORE_ADDR *typep, CORE_ADDR *valp)
2425796c8dcSSimon Schubert {
243*ef5ccd6cSJohn Marino   const int sizeof_auxv_field = gdbarch_ptr_bit (target_gdbarch ())
2445796c8dcSSimon Schubert 				/ TARGET_CHAR_BIT;
245*ef5ccd6cSJohn Marino   const enum bfd_endian byte_order = gdbarch_byte_order (target_gdbarch ());
2465796c8dcSSimon Schubert   gdb_byte *ptr = *readptr;
2475796c8dcSSimon Schubert 
2485796c8dcSSimon Schubert   if (endptr == ptr)
2495796c8dcSSimon Schubert     return 0;
2505796c8dcSSimon Schubert 
2515796c8dcSSimon Schubert   if (endptr - ptr < sizeof_auxv_field * 2)
2525796c8dcSSimon Schubert     return -1;
2535796c8dcSSimon Schubert 
2545796c8dcSSimon Schubert   *typep = extract_unsigned_integer (ptr, sizeof_auxv_field, byte_order);
2555796c8dcSSimon Schubert   ptr += sizeof_auxv_field;
2565796c8dcSSimon Schubert   *valp = extract_unsigned_integer (ptr, sizeof_auxv_field, byte_order);
2575796c8dcSSimon Schubert   ptr += sizeof_auxv_field;
2585796c8dcSSimon Schubert 
2595796c8dcSSimon Schubert   *readptr = ptr;
2605796c8dcSSimon Schubert   return 1;
2615796c8dcSSimon Schubert }
2625796c8dcSSimon Schubert 
2635796c8dcSSimon Schubert /* Read one auxv entry from *READPTR, not reading locations >= ENDPTR.
2645796c8dcSSimon Schubert    Return 0 if *READPTR is already at the end of the buffer.
2655796c8dcSSimon Schubert    Return -1 if there is insufficient buffer for a whole entry.
2665796c8dcSSimon Schubert    Return 1 if an entry was read into *TYPEP and *VALP.  */
2675796c8dcSSimon Schubert int
target_auxv_parse(struct target_ops * ops,gdb_byte ** readptr,gdb_byte * endptr,CORE_ADDR * typep,CORE_ADDR * valp)2685796c8dcSSimon Schubert target_auxv_parse (struct target_ops *ops, gdb_byte **readptr,
2695796c8dcSSimon Schubert                   gdb_byte *endptr, CORE_ADDR *typep, CORE_ADDR *valp)
2705796c8dcSSimon Schubert {
2715796c8dcSSimon Schubert   struct target_ops *t;
272cf7f2e2dSJohn Marino 
2735796c8dcSSimon Schubert   for (t = ops; t != NULL; t = t->beneath)
2745796c8dcSSimon Schubert     if (t->to_auxv_parse != NULL)
2755796c8dcSSimon Schubert       return t->to_auxv_parse (t, readptr, endptr, typep, valp);
2765796c8dcSSimon Schubert 
2775796c8dcSSimon Schubert   return default_auxv_parse (ops, readptr, endptr, typep, valp);
2785796c8dcSSimon Schubert }
2795796c8dcSSimon Schubert 
280a45ae5f8SJohn Marino 
281a45ae5f8SJohn Marino /* Per-inferior data key for auxv.  */
282a45ae5f8SJohn Marino static const struct inferior_data *auxv_inferior_data;
283a45ae5f8SJohn Marino 
284a45ae5f8SJohn Marino /*  Auxiliary Vector information structure.  This is used by GDB
285a45ae5f8SJohn Marino     for caching purposes for each inferior.  This helps reduce the
286a45ae5f8SJohn Marino     overhead of transfering data from a remote target to the local host.  */
287a45ae5f8SJohn Marino struct auxv_info
288a45ae5f8SJohn Marino {
289a45ae5f8SJohn Marino   LONGEST length;
290a45ae5f8SJohn Marino   gdb_byte *data;
291a45ae5f8SJohn Marino };
292a45ae5f8SJohn Marino 
293a45ae5f8SJohn Marino /* Handles the cleanup of the auxv cache for inferior INF.  ARG is ignored.
294a45ae5f8SJohn Marino    Frees whatever allocated space there is to be freed and sets INF's auxv cache
295a45ae5f8SJohn Marino    data pointer to NULL.
296a45ae5f8SJohn Marino 
297a45ae5f8SJohn Marino    This function is called when the following events occur: inferior_appeared,
298a45ae5f8SJohn Marino    inferior_exit and executable_changed.  */
299a45ae5f8SJohn Marino 
300a45ae5f8SJohn Marino static void
auxv_inferior_data_cleanup(struct inferior * inf,void * arg)301a45ae5f8SJohn Marino auxv_inferior_data_cleanup (struct inferior *inf, void *arg)
302a45ae5f8SJohn Marino {
303a45ae5f8SJohn Marino   struct auxv_info *info;
304a45ae5f8SJohn Marino 
305a45ae5f8SJohn Marino   info = inferior_data (inf, auxv_inferior_data);
306a45ae5f8SJohn Marino   if (info != NULL)
307a45ae5f8SJohn Marino     {
308a45ae5f8SJohn Marino       xfree (info->data);
309a45ae5f8SJohn Marino       xfree (info);
310a45ae5f8SJohn Marino       set_inferior_data (inf, auxv_inferior_data, NULL);
311a45ae5f8SJohn Marino     }
312a45ae5f8SJohn Marino }
313a45ae5f8SJohn Marino 
314a45ae5f8SJohn Marino /* Invalidate INF's auxv cache.  */
315a45ae5f8SJohn Marino 
316a45ae5f8SJohn Marino static void
invalidate_auxv_cache_inf(struct inferior * inf)317a45ae5f8SJohn Marino invalidate_auxv_cache_inf (struct inferior *inf)
318a45ae5f8SJohn Marino {
319a45ae5f8SJohn Marino   auxv_inferior_data_cleanup (inf, NULL);
320a45ae5f8SJohn Marino }
321a45ae5f8SJohn Marino 
322a45ae5f8SJohn Marino /* Invalidate current inferior's auxv cache.  */
323a45ae5f8SJohn Marino 
324a45ae5f8SJohn Marino static void
invalidate_auxv_cache(void)325a45ae5f8SJohn Marino invalidate_auxv_cache (void)
326a45ae5f8SJohn Marino {
327a45ae5f8SJohn Marino   invalidate_auxv_cache_inf (current_inferior ());
328a45ae5f8SJohn Marino }
329a45ae5f8SJohn Marino 
330a45ae5f8SJohn Marino /* Fetch the auxv object from inferior INF.  If auxv is cached already,
331a45ae5f8SJohn Marino    return a pointer to the cache.  If not, fetch the auxv object from the
332a45ae5f8SJohn Marino    target and cache it.  This function always returns a valid INFO pointer.  */
333a45ae5f8SJohn Marino 
334a45ae5f8SJohn Marino static struct auxv_info *
get_auxv_inferior_data(struct target_ops * ops)335a45ae5f8SJohn Marino get_auxv_inferior_data (struct target_ops *ops)
336a45ae5f8SJohn Marino {
337a45ae5f8SJohn Marino   struct auxv_info *info;
338a45ae5f8SJohn Marino   struct inferior *inf = current_inferior ();
339a45ae5f8SJohn Marino 
340a45ae5f8SJohn Marino   info = inferior_data (inf, auxv_inferior_data);
341a45ae5f8SJohn Marino   if (info == NULL)
342a45ae5f8SJohn Marino     {
343a45ae5f8SJohn Marino       info = XZALLOC (struct auxv_info);
344a45ae5f8SJohn Marino       info->length = target_read_alloc (ops, TARGET_OBJECT_AUXV,
345a45ae5f8SJohn Marino 					NULL, &info->data);
346a45ae5f8SJohn Marino       set_inferior_data (inf, auxv_inferior_data, info);
347a45ae5f8SJohn Marino     }
348a45ae5f8SJohn Marino 
349a45ae5f8SJohn Marino   return info;
350a45ae5f8SJohn Marino }
351a45ae5f8SJohn Marino 
3525796c8dcSSimon Schubert /* Extract the auxiliary vector entry with a_type matching MATCH.
3535796c8dcSSimon Schubert    Return zero if no such entry was found, or -1 if there was
3545796c8dcSSimon Schubert    an error getting the information.  On success, return 1 after
3555796c8dcSSimon Schubert    storing the entry's value field in *VALP.  */
3565796c8dcSSimon Schubert int
target_auxv_search(struct target_ops * ops,CORE_ADDR match,CORE_ADDR * valp)3575796c8dcSSimon Schubert target_auxv_search (struct target_ops *ops, CORE_ADDR match, CORE_ADDR *valp)
3585796c8dcSSimon Schubert {
3595796c8dcSSimon Schubert   CORE_ADDR type, val;
3605796c8dcSSimon Schubert   gdb_byte *data;
361a45ae5f8SJohn Marino   gdb_byte *ptr;
362a45ae5f8SJohn Marino   struct auxv_info *info;
3635796c8dcSSimon Schubert 
364a45ae5f8SJohn Marino   info = get_auxv_inferior_data (ops);
365a45ae5f8SJohn Marino 
366a45ae5f8SJohn Marino   data = info->data;
367a45ae5f8SJohn Marino   ptr = data;
368a45ae5f8SJohn Marino 
369a45ae5f8SJohn Marino   if (info->length <= 0)
370a45ae5f8SJohn Marino     return info->length;
3715796c8dcSSimon Schubert 
3725796c8dcSSimon Schubert   while (1)
373a45ae5f8SJohn Marino     switch (target_auxv_parse (ops, &ptr, data + info->length, &type, &val))
3745796c8dcSSimon Schubert       {
3755796c8dcSSimon Schubert       case 1:			/* Here's an entry, check it.  */
3765796c8dcSSimon Schubert 	if (type == match)
3775796c8dcSSimon Schubert 	  {
3785796c8dcSSimon Schubert 	    *valp = val;
3795796c8dcSSimon Schubert 	    return 1;
3805796c8dcSSimon Schubert 	  }
3815796c8dcSSimon Schubert 	break;
3825796c8dcSSimon Schubert       case 0:			/* End of the vector.  */
3835796c8dcSSimon Schubert 	return 0;
3845796c8dcSSimon Schubert       default:			/* Bogosity.  */
3855796c8dcSSimon Schubert 	return -1;
3865796c8dcSSimon Schubert       }
3875796c8dcSSimon Schubert 
3885796c8dcSSimon Schubert   /*NOTREACHED*/
3895796c8dcSSimon Schubert }
3905796c8dcSSimon Schubert 
3915796c8dcSSimon Schubert 
3925796c8dcSSimon Schubert /* Print the contents of the target's AUXV on the specified file.  */
3935796c8dcSSimon Schubert int
fprint_target_auxv(struct ui_file * file,struct target_ops * ops)3945796c8dcSSimon Schubert fprint_target_auxv (struct ui_file *file, struct target_ops *ops)
3955796c8dcSSimon Schubert {
3965796c8dcSSimon Schubert   CORE_ADDR type, val;
3975796c8dcSSimon Schubert   gdb_byte *data;
398a45ae5f8SJohn Marino   gdb_byte *ptr;
399a45ae5f8SJohn Marino   struct auxv_info *info;
4005796c8dcSSimon Schubert   int ents = 0;
4015796c8dcSSimon Schubert 
402a45ae5f8SJohn Marino   info = get_auxv_inferior_data (ops);
4035796c8dcSSimon Schubert 
404a45ae5f8SJohn Marino   data = info->data;
405a45ae5f8SJohn Marino   ptr = data;
406a45ae5f8SJohn Marino   if (info->length <= 0)
407a45ae5f8SJohn Marino     return info->length;
408a45ae5f8SJohn Marino 
409a45ae5f8SJohn Marino   while (target_auxv_parse (ops, &ptr, data + info->length, &type, &val) > 0)
4105796c8dcSSimon Schubert     {
4115796c8dcSSimon Schubert       const char *name = "???";
4125796c8dcSSimon Schubert       const char *description = "";
4135796c8dcSSimon Schubert       enum { dec, hex, str } flavor = hex;
4145796c8dcSSimon Schubert 
4155796c8dcSSimon Schubert       switch (type)
4165796c8dcSSimon Schubert 	{
4175796c8dcSSimon Schubert #define TAG(tag, text, kind) \
4185796c8dcSSimon Schubert 	case tag: name = #tag; description = text; flavor = kind; break
4195796c8dcSSimon Schubert 	  TAG (AT_NULL, _("End of vector"), hex);
4205796c8dcSSimon Schubert 	  TAG (AT_IGNORE, _("Entry should be ignored"), hex);
4215796c8dcSSimon Schubert 	  TAG (AT_EXECFD, _("File descriptor of program"), dec);
4225796c8dcSSimon Schubert 	  TAG (AT_PHDR, _("Program headers for program"), hex);
4235796c8dcSSimon Schubert 	  TAG (AT_PHENT, _("Size of program header entry"), dec);
4245796c8dcSSimon Schubert 	  TAG (AT_PHNUM, _("Number of program headers"), dec);
4255796c8dcSSimon Schubert 	  TAG (AT_PAGESZ, _("System page size"), dec);
4265796c8dcSSimon Schubert 	  TAG (AT_BASE, _("Base address of interpreter"), hex);
4275796c8dcSSimon Schubert 	  TAG (AT_FLAGS, _("Flags"), hex);
4285796c8dcSSimon Schubert 	  TAG (AT_ENTRY, _("Entry point of program"), hex);
4295796c8dcSSimon Schubert 	  TAG (AT_NOTELF, _("Program is not ELF"), dec);
4305796c8dcSSimon Schubert 	  TAG (AT_UID, _("Real user ID"), dec);
4315796c8dcSSimon Schubert 	  TAG (AT_EUID, _("Effective user ID"), dec);
4325796c8dcSSimon Schubert 	  TAG (AT_GID, _("Real group ID"), dec);
4335796c8dcSSimon Schubert 	  TAG (AT_EGID, _("Effective group ID"), dec);
4345796c8dcSSimon Schubert 	  TAG (AT_CLKTCK, _("Frequency of times()"), dec);
4355796c8dcSSimon Schubert 	  TAG (AT_PLATFORM, _("String identifying platform"), str);
4365796c8dcSSimon Schubert 	  TAG (AT_HWCAP, _("Machine-dependent CPU capability hints"), hex);
4375796c8dcSSimon Schubert 	  TAG (AT_FPUCW, _("Used FPU control word"), dec);
4385796c8dcSSimon Schubert 	  TAG (AT_DCACHEBSIZE, _("Data cache block size"), dec);
4395796c8dcSSimon Schubert 	  TAG (AT_ICACHEBSIZE, _("Instruction cache block size"), dec);
4405796c8dcSSimon Schubert 	  TAG (AT_UCACHEBSIZE, _("Unified cache block size"), dec);
4415796c8dcSSimon Schubert 	  TAG (AT_IGNOREPPC, _("Entry should be ignored"), dec);
4425796c8dcSSimon Schubert 	  TAG (AT_BASE_PLATFORM, _("String identifying base platform"), str);
4435796c8dcSSimon Schubert 	  TAG (AT_RANDOM, _("Address of 16 random bytes"), hex);
4445796c8dcSSimon Schubert 	  TAG (AT_EXECFN, _("File name of executable"), str);
4455796c8dcSSimon Schubert 	  TAG (AT_SECURE, _("Boolean, was exec setuid-like?"), dec);
4465796c8dcSSimon Schubert 	  TAG (AT_SYSINFO, _("Special system info/entry points"), hex);
4475796c8dcSSimon Schubert 	  TAG (AT_SYSINFO_EHDR, _("System-supplied DSO's ELF header"), hex);
448*ef5ccd6cSJohn Marino 	  TAG (AT_L1I_CACHESHAPE, _("L1 Instruction cache information"), hex);
449*ef5ccd6cSJohn Marino 	  TAG (AT_L1D_CACHESHAPE, _("L1 Data cache information"), hex);
450*ef5ccd6cSJohn Marino 	  TAG (AT_L2_CACHESHAPE, _("L2 cache information"), hex);
451*ef5ccd6cSJohn Marino 	  TAG (AT_L3_CACHESHAPE, _("L3 cache information"), hex);
4525796c8dcSSimon Schubert 	  TAG (AT_SUN_UID, _("Effective user ID"), dec);
4535796c8dcSSimon Schubert 	  TAG (AT_SUN_RUID, _("Real user ID"), dec);
4545796c8dcSSimon Schubert 	  TAG (AT_SUN_GID, _("Effective group ID"), dec);
4555796c8dcSSimon Schubert 	  TAG (AT_SUN_RGID, _("Real group ID"), dec);
4565796c8dcSSimon Schubert 	  TAG (AT_SUN_LDELF, _("Dynamic linker's ELF header"), hex);
4575796c8dcSSimon Schubert 	  TAG (AT_SUN_LDSHDR, _("Dynamic linker's section headers"), hex);
4585796c8dcSSimon Schubert 	  TAG (AT_SUN_LDNAME, _("String giving name of dynamic linker"), str);
4595796c8dcSSimon Schubert 	  TAG (AT_SUN_LPAGESZ, _("Large pagesize"), dec);
4605796c8dcSSimon Schubert 	  TAG (AT_SUN_PLATFORM, _("Platform name string"), str);
4615796c8dcSSimon Schubert 	  TAG (AT_SUN_HWCAP, _("Machine-dependent CPU capability hints"), hex);
4625796c8dcSSimon Schubert 	  TAG (AT_SUN_IFLUSH, _("Should flush icache?"), dec);
4635796c8dcSSimon Schubert 	  TAG (AT_SUN_CPU, _("CPU name string"), str);
4645796c8dcSSimon Schubert 	  TAG (AT_SUN_EMUL_ENTRY, _("COFF entry point address"), hex);
4655796c8dcSSimon Schubert 	  TAG (AT_SUN_EMUL_EXECFD, _("COFF executable file descriptor"), dec);
4665796c8dcSSimon Schubert 	  TAG (AT_SUN_EXECNAME,
4675796c8dcSSimon Schubert 	       _("Canonicalized file name given to execve"), str);
4685796c8dcSSimon Schubert 	  TAG (AT_SUN_MMU, _("String for name of MMU module"), str);
4695796c8dcSSimon Schubert 	  TAG (AT_SUN_LDDATA, _("Dynamic linker's data segment address"), hex);
4705796c8dcSSimon Schubert 	  TAG (AT_SUN_AUXFLAGS,
4715796c8dcSSimon Schubert 	       _("AF_SUN_ flags passed from the kernel"), hex);
4725796c8dcSSimon Schubert 	}
4735796c8dcSSimon Schubert 
4745796c8dcSSimon Schubert       fprintf_filtered (file, "%-4s %-20s %-30s ",
4755796c8dcSSimon Schubert 			plongest (type), name, description);
4765796c8dcSSimon Schubert       switch (flavor)
4775796c8dcSSimon Schubert 	{
4785796c8dcSSimon Schubert 	case dec:
4795796c8dcSSimon Schubert 	  fprintf_filtered (file, "%s\n", plongest (val));
4805796c8dcSSimon Schubert 	  break;
4815796c8dcSSimon Schubert 	case hex:
482*ef5ccd6cSJohn Marino 	  fprintf_filtered (file, "%s\n", paddress (target_gdbarch (), val));
4835796c8dcSSimon Schubert 	  break;
4845796c8dcSSimon Schubert 	case str:
4855796c8dcSSimon Schubert 	  {
4865796c8dcSSimon Schubert 	    struct value_print_options opts;
487cf7f2e2dSJohn Marino 
4885796c8dcSSimon Schubert 	    get_user_print_options (&opts);
4895796c8dcSSimon Schubert 	    if (opts.addressprint)
490*ef5ccd6cSJohn Marino 	      fprintf_filtered (file, "%s ", paddress (target_gdbarch (), val));
491*ef5ccd6cSJohn Marino 	    val_print_string (builtin_type (target_gdbarch ())->builtin_char,
492c50c785cSJohn Marino 			      NULL, val, -1, file, &opts);
4935796c8dcSSimon Schubert 	    fprintf_filtered (file, "\n");
4945796c8dcSSimon Schubert 	  }
4955796c8dcSSimon Schubert 	  break;
4965796c8dcSSimon Schubert 	}
4975796c8dcSSimon Schubert       ++ents;
4985796c8dcSSimon Schubert       if (type == AT_NULL)
4995796c8dcSSimon Schubert 	break;
5005796c8dcSSimon Schubert     }
5015796c8dcSSimon Schubert 
5025796c8dcSSimon Schubert   return ents;
5035796c8dcSSimon Schubert }
5045796c8dcSSimon Schubert 
5055796c8dcSSimon Schubert static void
info_auxv_command(char * cmd,int from_tty)5065796c8dcSSimon Schubert info_auxv_command (char *cmd, int from_tty)
5075796c8dcSSimon Schubert {
5085796c8dcSSimon Schubert   if (! target_has_stack)
5095796c8dcSSimon Schubert     error (_("The program has no auxiliary information now."));
5105796c8dcSSimon Schubert   else
5115796c8dcSSimon Schubert     {
5125796c8dcSSimon Schubert       int ents = fprint_target_auxv (gdb_stdout, &current_target);
513cf7f2e2dSJohn Marino 
5145796c8dcSSimon Schubert       if (ents < 0)
5155796c8dcSSimon Schubert 	error (_("No auxiliary vector found, or failed reading it."));
5165796c8dcSSimon Schubert       else if (ents == 0)
5175796c8dcSSimon Schubert 	error (_("Auxiliary vector is empty."));
5185796c8dcSSimon Schubert     }
5195796c8dcSSimon Schubert }
5205796c8dcSSimon Schubert 
5215796c8dcSSimon Schubert 
5225796c8dcSSimon Schubert extern initialize_file_ftype _initialize_auxv; /* -Wmissing-prototypes; */
5235796c8dcSSimon Schubert 
5245796c8dcSSimon Schubert void
_initialize_auxv(void)5255796c8dcSSimon Schubert _initialize_auxv (void)
5265796c8dcSSimon Schubert {
5275796c8dcSSimon Schubert   add_info ("auxv", info_auxv_command,
5285796c8dcSSimon Schubert 	    _("Display the inferior's auxiliary vector.\n\
5295796c8dcSSimon Schubert This is information provided by the operating system at program startup."));
530a45ae5f8SJohn Marino 
531a45ae5f8SJohn Marino   /* Set an auxv cache per-inferior.  */
532a45ae5f8SJohn Marino   auxv_inferior_data
533*ef5ccd6cSJohn Marino     = register_inferior_data_with_cleanup (NULL, auxv_inferior_data_cleanup);
534a45ae5f8SJohn Marino 
535a45ae5f8SJohn Marino   /* Observers used to invalidate the auxv cache when needed.  */
536a45ae5f8SJohn Marino   observer_attach_inferior_exit (invalidate_auxv_cache_inf);
537a45ae5f8SJohn Marino   observer_attach_inferior_appeared (invalidate_auxv_cache_inf);
538a45ae5f8SJohn Marino   observer_attach_executable_changed (invalidate_auxv_cache);
5395796c8dcSSimon Schubert }
540