X-Git-Url: https://git.libre-soc.org/?a=blobdiff_plain;f=gdb%2Fauxv.c;h=593b0c8059b545dec8d5312b970721909b55dd25;hb=91158a569dc571a9916dfad98c6c95ce789ad18d;hp=292a0d6fa717e853c5d3365c537919b82bc901c7;hpb=c47ffbe3b159da69fcc66cb7ad3a69077641b384;p=binutils-gdb.git diff --git a/gdb/auxv.c b/gdb/auxv.c index 292a0d6fa71..593b0c8059b 100644 --- a/gdb/auxv.c +++ b/gdb/auxv.c @@ -1,6 +1,7 @@ /* Auxiliary vector support for GDB, the GNU debugger. - Copyright (C) 2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc. + Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009, 2010 + Free Software Foundation, Inc. This file is part of GDB. @@ -24,6 +25,7 @@ #include "inferior.h" #include "valprint.h" #include "gdb_assert.h" +#include "gdbcore.h" #include "auxv.h" #include "elf/common.h" @@ -32,18 +34,11 @@ #include -/* This function is called like a to_xfer_partial hook, - but must be called with TARGET_OBJECT_AUXV. - It handles access via /proc/PID/auxv, which is the common method. - This function is appropriate for doing: - #define NATIVE_XFER_AUXV procfs_xfer_auxv - for a native target that uses inftarg.c's child_xfer_partial hook. */ +/* This function handles access via /proc/PID/auxv, which is a common method + for native targets. */ -LONGEST -procfs_xfer_auxv (struct target_ops *ops, - int /* enum target_object */ object, - const char *annex, - gdb_byte *readbuf, +static LONGEST +procfs_xfer_auxv (gdb_byte *readbuf, const gdb_byte *writebuf, ULONGEST offset, LONGEST len) @@ -52,9 +47,6 @@ procfs_xfer_auxv (struct target_ops *ops, int fd; LONGEST n; - gdb_assert (object == TARGET_OBJECT_AUXV); - gdb_assert (readbuf || writebuf); - pathname = xstrprintf ("/proc/%d/auxv", PIDGET (inferior_ptid)); fd = open (pathname, writebuf != NULL ? O_WRONLY : O_RDONLY); xfree (pathname); @@ -74,15 +66,176 @@ procfs_xfer_auxv (struct target_ops *ops, return n; } +/* This function handles access via ld.so's symbol `_dl_auxv'. */ + +static LONGEST +ld_so_xfer_auxv (gdb_byte *readbuf, + const gdb_byte *writebuf, + ULONGEST offset, + LONGEST len) +{ + struct minimal_symbol *msym; + CORE_ADDR data_address, pointer_address; + struct type *ptr_type = builtin_type (target_gdbarch)->builtin_data_ptr; + size_t ptr_size = TYPE_LENGTH (ptr_type); + size_t auxv_pair_size = 2 * ptr_size; + gdb_byte *ptr_buf = alloca (ptr_size); + LONGEST retval; + size_t block; + + msym = lookup_minimal_symbol ("_dl_auxv", NULL, NULL); + if (msym == NULL) + return -1; + + if (MSYMBOL_SIZE (msym) != ptr_size) + return -1; + + /* POINTER_ADDRESS is a location where the `_dl_auxv' variable resides. + DATA_ADDRESS is the inferior value present in `_dl_auxv', therefore the + real inferior AUXV address. */ + + pointer_address = SYMBOL_VALUE_ADDRESS (msym); + + /* The location of the _dl_auxv symbol may no longer be correct if + ld.so runs at a different address than the one present in the file. + This is very common case - for unprelinked ld.so or with a PIE executable. + PIE executable forces random address even for libraries already being + prelinked to some address. PIE executables themselves are never prelinked + even on prelinked systems. Prelinking of a PIE executable would block + their purpose of randomizing load of everything including the executable. + + If the memory read fails, return -1 to fallback on another mechanism for + retrieving the AUXV. + + In most cases of a PIE running under valgrind there is no way to find + out the base addresses of any of ld.so, executable or AUXV as everything + is randomized and /proc information is not relevant for the virtual + executable running under valgrind. We think that we might need a valgrind + extension to make it work. This is PR 11440. */ + + if (target_read_memory (pointer_address, ptr_buf, ptr_size) != 0) + return -1; + + data_address = extract_typed_address (ptr_buf, ptr_type); + + /* Possibly still not initialized such as during an inferior startup. */ + if (data_address == 0) + return -1; + + data_address += offset; + + if (writebuf != NULL) + { + if (target_write_memory (data_address, writebuf, len) == 0) + return len; + else + return -1; + } + + /* Stop if trying to read past the existing AUXV block. The final AT_NULL + was already returned before. */ + + if (offset >= auxv_pair_size) + { + if (target_read_memory (data_address - auxv_pair_size, ptr_buf, + ptr_size) != 0) + return -1; + + if (extract_typed_address (ptr_buf, ptr_type) == AT_NULL) + return 0; + } + + retval = 0; + block = 0x400; + gdb_assert (block % auxv_pair_size == 0); + + while (len > 0) + { + if (block > len) + block = len; + + /* Reading sizes smaller than AUXV_PAIR_SIZE is not supported. Tails + unaligned to AUXV_PAIR_SIZE will not be read during a call (they + should be completed during next read with new/extended buffer). */ + + block &= -auxv_pair_size; + if (block == 0) + return retval; + + if (target_read_memory (data_address, readbuf, block) != 0) + { + if (block <= auxv_pair_size) + return retval; + + block = auxv_pair_size; + continue; + } + + data_address += block; + len -= block; + + /* Check terminal AT_NULL. This function is being called indefinitely + being extended its READBUF until it returns EOF (0). */ + + while (block >= auxv_pair_size) + { + retval += auxv_pair_size; + + if (extract_typed_address (readbuf, ptr_type) == AT_NULL) + return retval; + + readbuf += auxv_pair_size; + block -= auxv_pair_size; + } + } + + return retval; +} + +/* This function is called like a to_xfer_partial hook, but must be + called with TARGET_OBJECT_AUXV. It handles access to AUXV. */ + +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) +{ + gdb_assert (object == TARGET_OBJECT_AUXV); + gdb_assert (readbuf || writebuf); + + /* ld_so_xfer_auxv is the only function safe for virtual executables being + executed by valgrind's memcheck. Using ld_so_xfer_auxv during inferior + startup is problematic, because ld.so symbol tables have not yet been + relocated. So GDB uses this function only when attaching to a process. + */ + + if (current_inferior ()->attach_flag != 0) + { + LONGEST retval; + + retval = ld_so_xfer_auxv (readbuf, writebuf, offset, len); + if (retval != -1) + return retval; + } + + return procfs_xfer_auxv (readbuf, writebuf, offset, len); +} + /* Read one auxv entry from *READPTR, not reading locations >= ENDPTR. Return 0 if *READPTR is already at the end of the buffer. Return -1 if there is insufficient buffer for a whole entry. Return 1 if an entry was read into *TYPEP and *VALP. */ -int +static int default_auxv_parse (struct target_ops *ops, gdb_byte **readptr, gdb_byte *endptr, CORE_ADDR *typep, CORE_ADDR *valp) { - const int sizeof_auxv_field = TYPE_LENGTH (builtin_type_void_data_ptr); + const int sizeof_auxv_field = gdbarch_ptr_bit (target_gdbarch) + / TARGET_CHAR_BIT; + const enum bfd_endian byte_order = gdbarch_byte_order (target_gdbarch); gdb_byte *ptr = *readptr; if (endptr == ptr) @@ -91,9 +244,9 @@ default_auxv_parse (struct target_ops *ops, gdb_byte **readptr, if (endptr - ptr < sizeof_auxv_field * 2) return -1; - *typep = extract_unsigned_integer (ptr, sizeof_auxv_field); + *typep = extract_unsigned_integer (ptr, sizeof_auxv_field, byte_order); ptr += sizeof_auxv_field; - *valp = extract_unsigned_integer (ptr, sizeof_auxv_field); + *valp = extract_unsigned_integer (ptr, sizeof_auxv_field, byte_order); ptr += sizeof_auxv_field; *readptr = ptr; @@ -109,6 +262,7 @@ target_auxv_parse (struct target_ops *ops, gdb_byte **readptr, gdb_byte *endptr, CORE_ADDR *typep, CORE_ADDR *valp) { struct target_ops *t; + for (t = ops; t != NULL; t = t->beneath) if (t->to_auxv_parse != NULL) return t->to_auxv_parse (t, readptr, endptr, typep, valp); @@ -127,7 +281,6 @@ target_auxv_search (struct target_ops *ops, CORE_ADDR match, CORE_ADDR *valp) gdb_byte *data; LONGEST n = target_read_alloc (ops, TARGET_OBJECT_AUXV, NULL, &data); gdb_byte *ptr = data; - int ents = 0; if (n <= 0) return n; @@ -171,7 +324,6 @@ fprint_target_auxv (struct ui_file *file, struct target_ops *ops) while (target_auxv_parse (ops, &ptr, data + len, &type, &val) > 0) { - extern int addressprint; const char *name = "???"; const char *description = ""; enum { dec, hex, str } flavor = hex; @@ -203,9 +355,12 @@ fprint_target_auxv (struct ui_file *file, struct target_ops *ops) TAG (AT_ICACHEBSIZE, _("Instruction cache block size"), dec); TAG (AT_UCACHEBSIZE, _("Unified cache block size"), dec); TAG (AT_IGNOREPPC, _("Entry should be ignored"), dec); + TAG (AT_BASE_PLATFORM, _("String identifying base platform"), str); + TAG (AT_RANDOM, _("Address of 16 random bytes"), hex); + TAG (AT_EXECFN, _("File name of executable"), str); + TAG (AT_SECURE, _("Boolean, was exec setuid-like?"), dec); TAG (AT_SYSINFO, _("Special system info/entry points"), hex); TAG (AT_SYSINFO_EHDR, _("System-supplied DSO's ELF header"), hex); - TAG (AT_SECURE, _("Boolean, was exec setuid-like?"), dec); TAG (AT_SUN_UID, _("Effective user ID"), dec); TAG (AT_SUN_RUID, _("Real user ID"), dec); TAG (AT_SUN_GID, _("Effective group ID"), dec); @@ -229,23 +384,31 @@ fprint_target_auxv (struct ui_file *file, struct target_ops *ops) } fprintf_filtered (file, "%-4s %-20s %-30s ", - paddr_d (type), name, description); + plongest (type), name, description); switch (flavor) { case dec: - fprintf_filtered (file, "%s\n", paddr_d (val)); + fprintf_filtered (file, "%s\n", plongest (val)); break; case hex: - fprintf_filtered (file, "0x%s\n", paddr_nz (val)); + fprintf_filtered (file, "%s\n", paddress (target_gdbarch, val)); break; case str: - if (addressprint) - fprintf_filtered (file, "0x%s", paddr_nz (val)); - val_print_string (val, -1, 1, file); - fprintf_filtered (file, "\n"); + { + struct value_print_options opts; + + get_user_print_options (&opts); + if (opts.addressprint) + fprintf_filtered (file, "%s", paddress (target_gdbarch, val)); + val_print_string (builtin_type (target_gdbarch)->builtin_char, + val, -1, file, &opts); + fprintf_filtered (file, "\n"); + } break; } ++ents; + if (type == AT_NULL) + break; } xfree (data); @@ -261,6 +424,7 @@ info_auxv_command (char *cmd, int from_tty) else { int ents = fprint_target_auxv (gdb_stdout, ¤t_target); + if (ents < 0) error (_("No auxiliary vector found, or failed reading it.")); else if (ents == 0)