X-Git-Url: http://git.efficios.com/?a=blobdiff_plain;f=gdb%2Flinux-tdep.c;h=718dc1ab6620f5ae5099c12f13de654f10c0d87b;hb=f389f6fef76d7cf8e8beb7061edff2155c284898;hp=375730611dd71e23879f0c018617a41b22bfded8;hpb=43564574f1de367f537a37bf6ec83bb4c29627c6;p=deliverable%2Fbinutils-gdb.git diff --git a/gdb/linux-tdep.c b/gdb/linux-tdep.c index 375730611d..718dc1ab66 100644 --- a/gdb/linux-tdep.c +++ b/gdb/linux-tdep.c @@ -243,15 +243,14 @@ get_linux_inferior_data (void) return info; } -/* This function is suitable for architectures that - extend/override the standard siginfo in a specific way. */ +/* See linux-tdep.h. */ -static struct type * +struct type * linux_get_siginfo_type_with_fields (struct gdbarch *gdbarch, linux_siginfo_extra_fields extra_fields) { struct linux_gdbarch_data *linux_gdbarch_data; - struct type *int_type, *uint_type, *long_type, *void_ptr_type; + struct type *int_type, *uint_type, *long_type, *void_ptr_type, *short_type; struct type *uid_type, *pid_type; struct type *sigval_type, *clock_type; struct type *siginfo_type, *sifields_type; @@ -267,6 +266,8 @@ linux_get_siginfo_type_with_fields (struct gdbarch *gdbarch, 1, "unsigned int"); long_type = arch_integer_type (gdbarch, gdbarch_long_bit (gdbarch), 0, "long"); + short_type = arch_integer_type (gdbarch, gdbarch_long_bit (gdbarch), + 0, "short"); void_ptr_type = lookup_pointer_type (builtin_type (gdbarch)->builtin_void); /* sival_t */ @@ -342,6 +343,18 @@ linux_get_siginfo_type_with_fields (struct gdbarch *gdbarch, /* _sigfault */ type = arch_composite_type (gdbarch, NULL, TYPE_CODE_STRUCT); append_composite_type_field (type, "si_addr", void_ptr_type); + + /* Additional bound fields for _sigfault in case they were requested. */ + if ((extra_fields & LINUX_SIGINFO_FIELD_ADDR_BND) != 0) + { + struct type *sigfault_bnd_fields; + + append_composite_type_field (type, "_addr_lsb", short_type); + sigfault_bnd_fields = arch_composite_type (gdbarch, NULL, TYPE_CODE_STRUCT); + append_composite_type_field (sigfault_bnd_fields, "_lower", void_ptr_type); + append_composite_type_field (sigfault_bnd_fields, "_upper", void_ptr_type); + append_composite_type_field (type, "_addr_bnd", sigfault_bnd_fields); + } append_composite_type_field (sifields_type, "_sigfault", type); /* _sigpoll */ @@ -1744,7 +1757,6 @@ linux_fill_prpsinfo (struct elf_internal_linux_prpsinfo *p) int n_fields = 0; /* Cleanups. */ struct cleanup *c; - int i; gdb_assert (p != NULL); @@ -1776,7 +1788,7 @@ linux_fill_prpsinfo (struct elf_internal_linux_prpsinfo *p) psargs = xstrdup (fname); if (infargs != NULL) - psargs = reconcat (psargs, psargs, " ", infargs, NULL); + psargs = reconcat (psargs, psargs, " ", infargs, (char *) NULL); make_cleanup (xfree, psargs); @@ -2265,39 +2277,95 @@ linux_gdb_signal_to_target (struct gdbarch *gdbarch, return -1; } -/* Rummage through mappings to find a mapping's size. */ - -static int -find_mapping_size (CORE_ADDR vaddr, unsigned long size, - int read, int write, int exec, int modified, - void *data) -{ - struct mem_range *range = (struct mem_range *) data; - - if (vaddr == range->start) - { - range->length = size; - return 1; - } - return 0; -} - /* Helper for linux_vsyscall_range that does the real work of finding the vsyscall's address range. */ static int linux_vsyscall_range_raw (struct gdbarch *gdbarch, struct mem_range *range) { + char filename[100]; + long pid; + char *data; + if (target_auxv_search (¤t_target, AT_SYSINFO_EHDR, &range->start) <= 0) return 0; - /* This is installed by linux_init_abi below, so should always be - available. */ - gdb_assert (gdbarch_find_memory_regions_p (target_gdbarch ())); + /* It doesn't make sense to access the host's /proc when debugging a + core file. Instead, look for the PT_LOAD segment that matches + the vDSO. */ + if (!target_has_execution) + { + Elf_Internal_Phdr *phdrs; + long phdrs_size; + int num_phdrs, i; - range->length = 0; - gdbarch_find_memory_regions (gdbarch, find_mapping_size, range); - return 1; + phdrs_size = bfd_get_elf_phdr_upper_bound (core_bfd); + if (phdrs_size == -1) + return 0; + + phdrs = (Elf_Internal_Phdr *) alloca (phdrs_size); + num_phdrs = bfd_get_elf_phdrs (core_bfd, phdrs); + if (num_phdrs == -1) + return 0; + + for (i = 0; i < num_phdrs; i++) + if (phdrs[i].p_type == PT_LOAD + && phdrs[i].p_vaddr == range->start) + { + range->length = phdrs[i].p_memsz; + return 1; + } + + return 0; + } + + /* We need to know the real target PID to access /proc. */ + if (current_inferior ()->fake_pid_p) + return 0; + + pid = current_inferior ()->pid; + + /* Note that reading /proc/PID/task/PID/maps (1) is much faster than + reading /proc/PID/maps (2). The later identifies thread stacks + in the output, which requires scanning every thread in the thread + group to check whether a VMA is actually a thread's stack. With + Linux 4.4 on an Intel i7-4810MQ @ 2.80GHz, with an inferior with + a few thousand threads, (1) takes a few miliseconds, while (2) + takes several seconds. Also note that "smaps", what we read for + determining core dump mappings, is even slower than "maps". */ + xsnprintf (filename, sizeof filename, "/proc/%ld/task/%ld/maps", pid, pid); + data = target_fileio_read_stralloc (NULL, filename); + if (data != NULL) + { + struct cleanup *cleanup = make_cleanup (xfree, data); + char *line; + char *saveptr = NULL; + + for (line = strtok_r (data, "\n", &saveptr); + line != NULL; + line = strtok_r (NULL, "\n", &saveptr)) + { + ULONGEST addr, endaddr; + const char *p = line; + + addr = strtoulst (p, &p, 16); + if (addr == range->start) + { + if (*p == '-') + p++; + endaddr = strtoulst (p, &p, 16); + range->length = endaddr - addr; + do_cleanups (cleanup); + return 1; + } + } + + do_cleanups (cleanup); + } + else + warning (_("unable to open /proc file '%s'"), filename); + + return 0; } /* Implementation of the "vsyscall_range" gdbarch hook. Handles @@ -2413,7 +2481,8 @@ linux_displaced_step_location (struct gdbarch *gdbarch) location. The auxiliary vector gets us the PowerPC-side entry point address instead. */ if (target_auxv_search (¤t_target, AT_ENTRY, &addr) <= 0) - error (_("Cannot find AT_ENTRY auxiliary vector entry.")); + throw_error (NOT_SUPPORTED_ERROR, + _("Cannot find AT_ENTRY auxiliary vector entry.")); /* Make certain that the address points at real code, and not a function descriptor. */