| 1 | /* Auxiliary vector support for GDB, the GNU debugger. |
| 2 | |
| 3 | Copyright (C) 2004-2019 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 3 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, see <http://www.gnu.org/licenses/>. */ |
| 19 | |
| 20 | #include "defs.h" |
| 21 | #include "target.h" |
| 22 | #include "gdbtypes.h" |
| 23 | #include "command.h" |
| 24 | #include "inferior.h" |
| 25 | #include "valprint.h" |
| 26 | #include "gdbcore.h" |
| 27 | #include "observable.h" |
| 28 | #include "gdbsupport/filestuff.h" |
| 29 | #include "objfiles.h" |
| 30 | |
| 31 | #include "auxv.h" |
| 32 | #include "elf/common.h" |
| 33 | |
| 34 | #include <unistd.h> |
| 35 | #include <fcntl.h> |
| 36 | |
| 37 | |
| 38 | /* Implement the to_xfer_partial target_ops method. This function |
| 39 | handles access via /proc/PID/auxv, which is a common method for |
| 40 | native targets. */ |
| 41 | |
| 42 | static enum target_xfer_status |
| 43 | procfs_xfer_auxv (gdb_byte *readbuf, |
| 44 | const gdb_byte *writebuf, |
| 45 | ULONGEST offset, |
| 46 | ULONGEST len, |
| 47 | ULONGEST *xfered_len) |
| 48 | { |
| 49 | int fd; |
| 50 | ssize_t l; |
| 51 | |
| 52 | std::string pathname = string_printf ("/proc/%d/auxv", inferior_ptid.pid ()); |
| 53 | fd = gdb_open_cloexec (pathname, writebuf != NULL ? O_WRONLY : O_RDONLY, 0); |
| 54 | if (fd < 0) |
| 55 | return TARGET_XFER_E_IO; |
| 56 | |
| 57 | if (offset != (ULONGEST) 0 |
| 58 | && lseek (fd, (off_t) offset, SEEK_SET) != (off_t) offset) |
| 59 | l = -1; |
| 60 | else if (readbuf != NULL) |
| 61 | l = read (fd, readbuf, (size_t) len); |
| 62 | else |
| 63 | l = write (fd, writebuf, (size_t) len); |
| 64 | |
| 65 | (void) close (fd); |
| 66 | |
| 67 | if (l < 0) |
| 68 | return TARGET_XFER_E_IO; |
| 69 | else if (l == 0) |
| 70 | return TARGET_XFER_EOF; |
| 71 | else |
| 72 | { |
| 73 | *xfered_len = (ULONGEST) l; |
| 74 | return TARGET_XFER_OK; |
| 75 | } |
| 76 | } |
| 77 | |
| 78 | /* This function handles access via ld.so's symbol `_dl_auxv'. */ |
| 79 | |
| 80 | static enum target_xfer_status |
| 81 | ld_so_xfer_auxv (gdb_byte *readbuf, |
| 82 | const gdb_byte *writebuf, |
| 83 | ULONGEST offset, |
| 84 | ULONGEST len, ULONGEST *xfered_len) |
| 85 | { |
| 86 | struct bound_minimal_symbol msym; |
| 87 | CORE_ADDR data_address, pointer_address; |
| 88 | struct type *ptr_type = builtin_type (target_gdbarch ())->builtin_data_ptr; |
| 89 | size_t ptr_size = TYPE_LENGTH (ptr_type); |
| 90 | size_t auxv_pair_size = 2 * ptr_size; |
| 91 | gdb_byte *ptr_buf = (gdb_byte *) alloca (ptr_size); |
| 92 | LONGEST retval; |
| 93 | size_t block; |
| 94 | |
| 95 | msym = lookup_minimal_symbol ("_dl_auxv", NULL, NULL); |
| 96 | if (msym.minsym == NULL) |
| 97 | return TARGET_XFER_E_IO; |
| 98 | |
| 99 | if (MSYMBOL_SIZE (msym.minsym) != ptr_size) |
| 100 | return TARGET_XFER_E_IO; |
| 101 | |
| 102 | /* POINTER_ADDRESS is a location where the `_dl_auxv' variable |
| 103 | resides. DATA_ADDRESS is the inferior value present in |
| 104 | `_dl_auxv', therefore the real inferior AUXV address. */ |
| 105 | |
| 106 | pointer_address = BMSYMBOL_VALUE_ADDRESS (msym); |
| 107 | |
| 108 | /* The location of the _dl_auxv symbol may no longer be correct if |
| 109 | ld.so runs at a different address than the one present in the |
| 110 | file. This is very common case - for unprelinked ld.so or with a |
| 111 | PIE executable. PIE executable forces random address even for |
| 112 | libraries already being prelinked to some address. PIE |
| 113 | executables themselves are never prelinked even on prelinked |
| 114 | systems. Prelinking of a PIE executable would block their |
| 115 | purpose of randomizing load of everything including the |
| 116 | executable. |
| 117 | |
| 118 | If the memory read fails, return -1 to fallback on another |
| 119 | mechanism for retrieving the AUXV. |
| 120 | |
| 121 | In most cases of a PIE running under valgrind there is no way to |
| 122 | find out the base addresses of any of ld.so, executable or AUXV |
| 123 | as everything is randomized and /proc information is not relevant |
| 124 | for the virtual executable running under valgrind. We think that |
| 125 | we might need a valgrind extension to make it work. This is PR |
| 126 | 11440. */ |
| 127 | |
| 128 | if (target_read_memory (pointer_address, ptr_buf, ptr_size) != 0) |
| 129 | return TARGET_XFER_E_IO; |
| 130 | |
| 131 | data_address = extract_typed_address (ptr_buf, ptr_type); |
| 132 | |
| 133 | /* Possibly still not initialized such as during an inferior |
| 134 | startup. */ |
| 135 | if (data_address == 0) |
| 136 | return TARGET_XFER_E_IO; |
| 137 | |
| 138 | data_address += offset; |
| 139 | |
| 140 | if (writebuf != NULL) |
| 141 | { |
| 142 | if (target_write_memory (data_address, writebuf, len) == 0) |
| 143 | { |
| 144 | *xfered_len = (ULONGEST) len; |
| 145 | return TARGET_XFER_OK; |
| 146 | } |
| 147 | else |
| 148 | return TARGET_XFER_E_IO; |
| 149 | } |
| 150 | |
| 151 | /* Stop if trying to read past the existing AUXV block. The final |
| 152 | AT_NULL was already returned before. */ |
| 153 | |
| 154 | if (offset >= auxv_pair_size) |
| 155 | { |
| 156 | if (target_read_memory (data_address - auxv_pair_size, ptr_buf, |
| 157 | ptr_size) != 0) |
| 158 | return TARGET_XFER_E_IO; |
| 159 | |
| 160 | if (extract_typed_address (ptr_buf, ptr_type) == AT_NULL) |
| 161 | return TARGET_XFER_EOF; |
| 162 | } |
| 163 | |
| 164 | retval = 0; |
| 165 | block = 0x400; |
| 166 | gdb_assert (block % auxv_pair_size == 0); |
| 167 | |
| 168 | while (len > 0) |
| 169 | { |
| 170 | if (block > len) |
| 171 | block = len; |
| 172 | |
| 173 | /* Reading sizes smaller than AUXV_PAIR_SIZE is not supported. |
| 174 | Tails unaligned to AUXV_PAIR_SIZE will not be read during a |
| 175 | call (they should be completed during next read with |
| 176 | new/extended buffer). */ |
| 177 | |
| 178 | block &= -auxv_pair_size; |
| 179 | if (block == 0) |
| 180 | break; |
| 181 | |
| 182 | if (target_read_memory (data_address, readbuf, block) != 0) |
| 183 | { |
| 184 | if (block <= auxv_pair_size) |
| 185 | break; |
| 186 | |
| 187 | block = auxv_pair_size; |
| 188 | continue; |
| 189 | } |
| 190 | |
| 191 | data_address += block; |
| 192 | len -= block; |
| 193 | |
| 194 | /* Check terminal AT_NULL. This function is being called |
| 195 | indefinitely being extended its READBUF until it returns EOF |
| 196 | (0). */ |
| 197 | |
| 198 | while (block >= auxv_pair_size) |
| 199 | { |
| 200 | retval += auxv_pair_size; |
| 201 | |
| 202 | if (extract_typed_address (readbuf, ptr_type) == AT_NULL) |
| 203 | { |
| 204 | *xfered_len = (ULONGEST) retval; |
| 205 | return TARGET_XFER_OK; |
| 206 | } |
| 207 | |
| 208 | readbuf += auxv_pair_size; |
| 209 | block -= auxv_pair_size; |
| 210 | } |
| 211 | } |
| 212 | |
| 213 | *xfered_len = (ULONGEST) retval; |
| 214 | return TARGET_XFER_OK; |
| 215 | } |
| 216 | |
| 217 | /* Implement the to_xfer_partial target_ops method for |
| 218 | TARGET_OBJECT_AUXV. It handles access to AUXV. */ |
| 219 | |
| 220 | enum target_xfer_status |
| 221 | memory_xfer_auxv (struct target_ops *ops, |
| 222 | enum target_object object, |
| 223 | const char *annex, |
| 224 | gdb_byte *readbuf, |
| 225 | const gdb_byte *writebuf, |
| 226 | ULONGEST offset, |
| 227 | ULONGEST len, ULONGEST *xfered_len) |
| 228 | { |
| 229 | gdb_assert (object == TARGET_OBJECT_AUXV); |
| 230 | gdb_assert (readbuf || writebuf); |
| 231 | |
| 232 | /* ld_so_xfer_auxv is the only function safe for virtual |
| 233 | executables being executed by valgrind's memcheck. Using |
| 234 | ld_so_xfer_auxv during inferior startup is problematic, because |
| 235 | ld.so symbol tables have not yet been relocated. So GDB uses |
| 236 | this function only when attaching to a process. |
| 237 | */ |
| 238 | |
| 239 | if (current_inferior ()->attach_flag != 0) |
| 240 | { |
| 241 | enum target_xfer_status ret; |
| 242 | |
| 243 | ret = ld_so_xfer_auxv (readbuf, writebuf, offset, len, xfered_len); |
| 244 | if (ret != TARGET_XFER_E_IO) |
| 245 | return ret; |
| 246 | } |
| 247 | |
| 248 | return procfs_xfer_auxv (readbuf, writebuf, offset, len, xfered_len); |
| 249 | } |
| 250 | |
| 251 | /* Read one auxv entry from *READPTR, not reading locations >= ENDPTR. |
| 252 | Return 0 if *READPTR is already at the end of the buffer. |
| 253 | Return -1 if there is insufficient buffer for a whole entry. |
| 254 | Return 1 if an entry was read into *TYPEP and *VALP. */ |
| 255 | int |
| 256 | default_auxv_parse (struct target_ops *ops, gdb_byte **readptr, |
| 257 | gdb_byte *endptr, CORE_ADDR *typep, CORE_ADDR *valp) |
| 258 | { |
| 259 | const int sizeof_auxv_field = gdbarch_ptr_bit (target_gdbarch ()) |
| 260 | / TARGET_CHAR_BIT; |
| 261 | const enum bfd_endian byte_order = gdbarch_byte_order (target_gdbarch ()); |
| 262 | gdb_byte *ptr = *readptr; |
| 263 | |
| 264 | if (endptr == ptr) |
| 265 | return 0; |
| 266 | |
| 267 | if (endptr - ptr < sizeof_auxv_field * 2) |
| 268 | return -1; |
| 269 | |
| 270 | *typep = extract_unsigned_integer (ptr, sizeof_auxv_field, byte_order); |
| 271 | ptr += sizeof_auxv_field; |
| 272 | *valp = extract_unsigned_integer (ptr, sizeof_auxv_field, byte_order); |
| 273 | ptr += sizeof_auxv_field; |
| 274 | |
| 275 | *readptr = ptr; |
| 276 | return 1; |
| 277 | } |
| 278 | |
| 279 | /* Read one auxv entry from *READPTR, not reading locations >= ENDPTR. |
| 280 | Return 0 if *READPTR is already at the end of the buffer. |
| 281 | Return -1 if there is insufficient buffer for a whole entry. |
| 282 | Return 1 if an entry was read into *TYPEP and *VALP. */ |
| 283 | int |
| 284 | target_auxv_parse (gdb_byte **readptr, |
| 285 | gdb_byte *endptr, CORE_ADDR *typep, CORE_ADDR *valp) |
| 286 | { |
| 287 | struct gdbarch *gdbarch = target_gdbarch(); |
| 288 | |
| 289 | if (gdbarch_auxv_parse_p (gdbarch)) |
| 290 | return gdbarch_auxv_parse (gdbarch, readptr, endptr, typep, valp); |
| 291 | |
| 292 | return current_top_target ()->auxv_parse (readptr, endptr, typep, valp); |
| 293 | } |
| 294 | |
| 295 | |
| 296 | /* Auxiliary Vector information structure. This is used by GDB |
| 297 | for caching purposes for each inferior. This helps reduce the |
| 298 | overhead of transfering data from a remote target to the local host. */ |
| 299 | struct auxv_info |
| 300 | { |
| 301 | gdb::optional<gdb::byte_vector> data; |
| 302 | }; |
| 303 | |
| 304 | /* Per-inferior data key for auxv. */ |
| 305 | static const struct inferior_key<auxv_info> auxv_inferior_data; |
| 306 | |
| 307 | /* Invalidate INF's auxv cache. */ |
| 308 | |
| 309 | static void |
| 310 | invalidate_auxv_cache_inf (struct inferior *inf) |
| 311 | { |
| 312 | auxv_inferior_data.clear (inf); |
| 313 | } |
| 314 | |
| 315 | /* Invalidate current inferior's auxv cache. */ |
| 316 | |
| 317 | static void |
| 318 | invalidate_auxv_cache (void) |
| 319 | { |
| 320 | invalidate_auxv_cache_inf (current_inferior ()); |
| 321 | } |
| 322 | |
| 323 | /* Fetch the auxv object from inferior INF. If auxv is cached already, |
| 324 | return a pointer to the cache. If not, fetch the auxv object from the |
| 325 | target and cache it. This function always returns a valid INFO pointer. */ |
| 326 | |
| 327 | static struct auxv_info * |
| 328 | get_auxv_inferior_data (struct target_ops *ops) |
| 329 | { |
| 330 | struct auxv_info *info; |
| 331 | struct inferior *inf = current_inferior (); |
| 332 | |
| 333 | info = auxv_inferior_data.get (inf); |
| 334 | if (info == NULL) |
| 335 | { |
| 336 | info = auxv_inferior_data.emplace (inf); |
| 337 | info->data = target_read_alloc (ops, TARGET_OBJECT_AUXV, NULL); |
| 338 | } |
| 339 | |
| 340 | return info; |
| 341 | } |
| 342 | |
| 343 | /* Extract the auxiliary vector entry with a_type matching MATCH. |
| 344 | Return zero if no such entry was found, or -1 if there was |
| 345 | an error getting the information. On success, return 1 after |
| 346 | storing the entry's value field in *VALP. */ |
| 347 | int |
| 348 | target_auxv_search (struct target_ops *ops, CORE_ADDR match, CORE_ADDR *valp) |
| 349 | { |
| 350 | CORE_ADDR type, val; |
| 351 | auxv_info *info = get_auxv_inferior_data (ops); |
| 352 | |
| 353 | if (!info->data) |
| 354 | return -1; |
| 355 | |
| 356 | gdb_byte *data = info->data->data (); |
| 357 | gdb_byte *ptr = data; |
| 358 | size_t len = info->data->size (); |
| 359 | |
| 360 | while (1) |
| 361 | switch (target_auxv_parse (&ptr, data + len, &type, &val)) |
| 362 | { |
| 363 | case 1: /* Here's an entry, check it. */ |
| 364 | if (type == match) |
| 365 | { |
| 366 | *valp = val; |
| 367 | return 1; |
| 368 | } |
| 369 | break; |
| 370 | case 0: /* End of the vector. */ |
| 371 | return 0; |
| 372 | default: /* Bogosity. */ |
| 373 | return -1; |
| 374 | } |
| 375 | |
| 376 | /*NOTREACHED*/ |
| 377 | } |
| 378 | |
| 379 | |
| 380 | /* Print the description of a single AUXV entry on the specified file. */ |
| 381 | |
| 382 | void |
| 383 | fprint_auxv_entry (struct ui_file *file, const char *name, |
| 384 | const char *description, enum auxv_format format, |
| 385 | CORE_ADDR type, CORE_ADDR val) |
| 386 | { |
| 387 | fprintf_filtered (file, ("%-4s %-20s %-30s "), |
| 388 | plongest (type), name, description); |
| 389 | switch (format) |
| 390 | { |
| 391 | case AUXV_FORMAT_DEC: |
| 392 | fprintf_filtered (file, ("%s\n"), plongest (val)); |
| 393 | break; |
| 394 | case AUXV_FORMAT_HEX: |
| 395 | fprintf_filtered (file, ("%s\n"), paddress (target_gdbarch (), val)); |
| 396 | break; |
| 397 | case AUXV_FORMAT_STR: |
| 398 | { |
| 399 | struct value_print_options opts; |
| 400 | |
| 401 | get_user_print_options (&opts); |
| 402 | if (opts.addressprint) |
| 403 | fprintf_filtered (file, ("%s "), paddress (target_gdbarch (), val)); |
| 404 | val_print_string (builtin_type (target_gdbarch ())->builtin_char, |
| 405 | NULL, val, -1, file, &opts); |
| 406 | fprintf_filtered (file, ("\n")); |
| 407 | } |
| 408 | break; |
| 409 | } |
| 410 | } |
| 411 | |
| 412 | /* The default implementation of gdbarch_print_auxv_entry. */ |
| 413 | |
| 414 | void |
| 415 | default_print_auxv_entry (struct gdbarch *gdbarch, struct ui_file *file, |
| 416 | CORE_ADDR type, CORE_ADDR val) |
| 417 | { |
| 418 | const char *name = "???"; |
| 419 | const char *description = ""; |
| 420 | enum auxv_format format = AUXV_FORMAT_HEX; |
| 421 | |
| 422 | switch (type) |
| 423 | { |
| 424 | #define TAG(tag, text, kind) \ |
| 425 | case tag: name = #tag; description = text; format = kind; break |
| 426 | TAG (AT_NULL, _("End of vector"), AUXV_FORMAT_HEX); |
| 427 | TAG (AT_IGNORE, _("Entry should be ignored"), AUXV_FORMAT_HEX); |
| 428 | TAG (AT_EXECFD, _("File descriptor of program"), AUXV_FORMAT_DEC); |
| 429 | TAG (AT_PHDR, _("Program headers for program"), AUXV_FORMAT_HEX); |
| 430 | TAG (AT_PHENT, _("Size of program header entry"), AUXV_FORMAT_DEC); |
| 431 | TAG (AT_PHNUM, _("Number of program headers"), AUXV_FORMAT_DEC); |
| 432 | TAG (AT_PAGESZ, _("System page size"), AUXV_FORMAT_DEC); |
| 433 | TAG (AT_BASE, _("Base address of interpreter"), AUXV_FORMAT_HEX); |
| 434 | TAG (AT_FLAGS, _("Flags"), AUXV_FORMAT_HEX); |
| 435 | TAG (AT_ENTRY, _("Entry point of program"), AUXV_FORMAT_HEX); |
| 436 | TAG (AT_NOTELF, _("Program is not ELF"), AUXV_FORMAT_DEC); |
| 437 | TAG (AT_UID, _("Real user ID"), AUXV_FORMAT_DEC); |
| 438 | TAG (AT_EUID, _("Effective user ID"), AUXV_FORMAT_DEC); |
| 439 | TAG (AT_GID, _("Real group ID"), AUXV_FORMAT_DEC); |
| 440 | TAG (AT_EGID, _("Effective group ID"), AUXV_FORMAT_DEC); |
| 441 | TAG (AT_CLKTCK, _("Frequency of times()"), AUXV_FORMAT_DEC); |
| 442 | TAG (AT_PLATFORM, _("String identifying platform"), AUXV_FORMAT_STR); |
| 443 | TAG (AT_HWCAP, _("Machine-dependent CPU capability hints"), |
| 444 | AUXV_FORMAT_HEX); |
| 445 | TAG (AT_FPUCW, _("Used FPU control word"), AUXV_FORMAT_DEC); |
| 446 | TAG (AT_DCACHEBSIZE, _("Data cache block size"), AUXV_FORMAT_DEC); |
| 447 | TAG (AT_ICACHEBSIZE, _("Instruction cache block size"), AUXV_FORMAT_DEC); |
| 448 | TAG (AT_UCACHEBSIZE, _("Unified cache block size"), AUXV_FORMAT_DEC); |
| 449 | TAG (AT_IGNOREPPC, _("Entry should be ignored"), AUXV_FORMAT_DEC); |
| 450 | TAG (AT_BASE_PLATFORM, _("String identifying base platform"), |
| 451 | AUXV_FORMAT_STR); |
| 452 | TAG (AT_RANDOM, _("Address of 16 random bytes"), AUXV_FORMAT_HEX); |
| 453 | TAG (AT_HWCAP2, _("Extension of AT_HWCAP"), AUXV_FORMAT_HEX); |
| 454 | TAG (AT_EXECFN, _("File name of executable"), AUXV_FORMAT_STR); |
| 455 | TAG (AT_SECURE, _("Boolean, was exec setuid-like?"), AUXV_FORMAT_DEC); |
| 456 | TAG (AT_SYSINFO, _("Special system info/entry points"), AUXV_FORMAT_HEX); |
| 457 | TAG (AT_SYSINFO_EHDR, _("System-supplied DSO's ELF header"), |
| 458 | AUXV_FORMAT_HEX); |
| 459 | TAG (AT_L1I_CACHESHAPE, _("L1 Instruction cache information"), |
| 460 | AUXV_FORMAT_HEX); |
| 461 | TAG (AT_L1D_CACHESHAPE, _("L1 Data cache information"), AUXV_FORMAT_HEX); |
| 462 | TAG (AT_L2_CACHESHAPE, _("L2 cache information"), AUXV_FORMAT_HEX); |
| 463 | TAG (AT_L3_CACHESHAPE, _("L3 cache information"), AUXV_FORMAT_HEX); |
| 464 | TAG (AT_SUN_UID, _("Effective user ID"), AUXV_FORMAT_DEC); |
| 465 | TAG (AT_SUN_RUID, _("Real user ID"), AUXV_FORMAT_DEC); |
| 466 | TAG (AT_SUN_GID, _("Effective group ID"), AUXV_FORMAT_DEC); |
| 467 | TAG (AT_SUN_RGID, _("Real group ID"), AUXV_FORMAT_DEC); |
| 468 | TAG (AT_SUN_LDELF, _("Dynamic linker's ELF header"), AUXV_FORMAT_HEX); |
| 469 | TAG (AT_SUN_LDSHDR, _("Dynamic linker's section headers"), |
| 470 | AUXV_FORMAT_HEX); |
| 471 | TAG (AT_SUN_LDNAME, _("String giving name of dynamic linker"), |
| 472 | AUXV_FORMAT_STR); |
| 473 | TAG (AT_SUN_LPAGESZ, _("Large pagesize"), AUXV_FORMAT_DEC); |
| 474 | TAG (AT_SUN_PLATFORM, _("Platform name string"), AUXV_FORMAT_STR); |
| 475 | TAG (AT_SUN_CAP_HW1, _("Machine-dependent CPU capability hints"), |
| 476 | AUXV_FORMAT_HEX); |
| 477 | TAG (AT_SUN_IFLUSH, _("Should flush icache?"), AUXV_FORMAT_DEC); |
| 478 | TAG (AT_SUN_CPU, _("CPU name string"), AUXV_FORMAT_STR); |
| 479 | TAG (AT_SUN_EMUL_ENTRY, _("COFF entry point address"), AUXV_FORMAT_HEX); |
| 480 | TAG (AT_SUN_EMUL_EXECFD, _("COFF executable file descriptor"), |
| 481 | AUXV_FORMAT_DEC); |
| 482 | TAG (AT_SUN_EXECNAME, |
| 483 | _("Canonicalized file name given to execve"), AUXV_FORMAT_STR); |
| 484 | TAG (AT_SUN_MMU, _("String for name of MMU module"), AUXV_FORMAT_STR); |
| 485 | TAG (AT_SUN_LDDATA, _("Dynamic linker's data segment address"), |
| 486 | AUXV_FORMAT_HEX); |
| 487 | TAG (AT_SUN_AUXFLAGS, |
| 488 | _("AF_SUN_ flags passed from the kernel"), AUXV_FORMAT_HEX); |
| 489 | TAG (AT_SUN_EMULATOR, _("Name of emulation binary for runtime linker"), |
| 490 | AUXV_FORMAT_STR); |
| 491 | TAG (AT_SUN_BRANDNAME, _("Name of brand library"), AUXV_FORMAT_STR); |
| 492 | TAG (AT_SUN_BRAND_AUX1, _("Aux vector for brand modules 1"), |
| 493 | AUXV_FORMAT_HEX); |
| 494 | TAG (AT_SUN_BRAND_AUX2, _("Aux vector for brand modules 2"), |
| 495 | AUXV_FORMAT_HEX); |
| 496 | TAG (AT_SUN_BRAND_AUX3, _("Aux vector for brand modules 3"), |
| 497 | AUXV_FORMAT_HEX); |
| 498 | TAG (AT_SUN_CAP_HW2, _("Machine-dependent CPU capability hints 2"), |
| 499 | AUXV_FORMAT_HEX); |
| 500 | } |
| 501 | |
| 502 | fprint_auxv_entry (file, name, description, format, type, val); |
| 503 | } |
| 504 | |
| 505 | /* Print the contents of the target's AUXV on the specified file. */ |
| 506 | |
| 507 | int |
| 508 | fprint_target_auxv (struct ui_file *file, struct target_ops *ops) |
| 509 | { |
| 510 | struct gdbarch *gdbarch = target_gdbarch (); |
| 511 | CORE_ADDR type, val; |
| 512 | int ents = 0; |
| 513 | auxv_info *info = get_auxv_inferior_data (ops); |
| 514 | |
| 515 | if (!info->data) |
| 516 | return -1; |
| 517 | |
| 518 | gdb_byte *data = info->data->data (); |
| 519 | gdb_byte *ptr = data; |
| 520 | size_t len = info->data->size (); |
| 521 | |
| 522 | while (target_auxv_parse (&ptr, data + len, &type, &val) > 0) |
| 523 | { |
| 524 | gdbarch_print_auxv_entry (gdbarch, file, type, val); |
| 525 | ++ents; |
| 526 | if (type == AT_NULL) |
| 527 | break; |
| 528 | } |
| 529 | |
| 530 | return ents; |
| 531 | } |
| 532 | |
| 533 | static void |
| 534 | info_auxv_command (const char *cmd, int from_tty) |
| 535 | { |
| 536 | if (! target_has_stack) |
| 537 | error (_("The program has no auxiliary information now.")); |
| 538 | else |
| 539 | { |
| 540 | int ents = fprint_target_auxv (gdb_stdout, current_top_target ()); |
| 541 | |
| 542 | if (ents < 0) |
| 543 | error (_("No auxiliary vector found, or failed reading it.")); |
| 544 | else if (ents == 0) |
| 545 | error (_("Auxiliary vector is empty.")); |
| 546 | } |
| 547 | } |
| 548 | |
| 549 | void |
| 550 | _initialize_auxv (void) |
| 551 | { |
| 552 | add_info ("auxv", info_auxv_command, |
| 553 | _("Display the inferior's auxiliary vector.\n\ |
| 554 | This is information provided by the operating system at program startup.")); |
| 555 | |
| 556 | /* Observers used to invalidate the auxv cache when needed. */ |
| 557 | gdb::observers::inferior_exit.attach (invalidate_auxv_cache_inf); |
| 558 | gdb::observers::inferior_appeared.attach (invalidate_auxv_cache_inf); |
| 559 | gdb::observers::executable_changed.attach (invalidate_auxv_cache); |
| 560 | } |