/* Target-dependent code for GNU/Linux, architecture independent.
- Copyright (C) 2009-2015 Free Software Foundation, Inc.
+ Copyright (C) 2009-2016 Free Software Foundation, Inc.
This file is part of GDB.
#include "infcall.h"
#include "gdbcmd.h"
#include "gdb_regex.h"
+#include "common/enum-flags.h"
#include <ctype.h>
Documentation/filesystems/proc.txt, inside the Linux kernel
tree. */
-enum filterflags
+enum filter_flag
{
COREFILTER_ANON_PRIVATE = 1 << 0,
COREFILTER_ANON_SHARED = 1 << 1,
COREFILTER_HUGETLB_PRIVATE = 1 << 5,
COREFILTER_HUGETLB_SHARED = 1 << 6,
};
+DEF_ENUM_FLAGS_TYPE (enum filter_flag, filter_flags);
/* This struct is used to map flags found in the "VmFlags:" field (in
the /proc/<PID>/smaps file). */
static struct linux_gdbarch_data *
get_linux_gdbarch_data (struct gdbarch *gdbarch)
{
- return gdbarch_data (gdbarch, linux_gdbarch_data_handle);
+ return ((struct linux_gdbarch_data *)
+ gdbarch_data (gdbarch, linux_gdbarch_data_handle));
}
/* Per-inferior data key. */
{
struct linux_info *info;
- info = inferior_data (inf, linux_inferior_data);
+ info = (struct linux_info *) inferior_data (inf, linux_inferior_data);
if (info != NULL)
{
xfree (info);
struct linux_info *info;
struct inferior *inf = current_inferior ();
- info = inferior_data (inf, linux_inferior_data);
+ info = (struct linux_info *) inferior_data (inf, linux_inferior_data);
if (info == NULL)
{
info = XCNEW (struct linux_info);
return info;
}
-/* This function is suitable for architectures that don't
- extend/override the standard siginfo structure. */
+/* See linux-tdep.h. */
struct type *
-linux_get_siginfo_type (struct gdbarch *gdbarch)
+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;
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 */
/* _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 */
return siginfo_type;
}
+/* This function is suitable for architectures that don't
+ extend/override the standard siginfo structure. */
+
+static struct type *
+linux_get_siginfo_type (struct gdbarch *gdbarch)
+{
+ return linux_get_siginfo_type_with_fields (gdbarch, 0);
+}
+
/* Return true if the target is running on uClinux instead of normal
Linux kernel. */
This should work OK enough, however. */
static int
-dump_mapping_p (enum filterflags filterflags, const struct smaps_vmflags *v,
+dump_mapping_p (filter_flags filterflags, const struct smaps_vmflags *v,
int maybe_private_p, int mapping_anon_p, int mapping_file_p,
const char *filename)
{
if (note_size < 2 * addr_size)
error (_("malformed core note - too short for header"));
- contents = xmalloc (note_size);
+ contents = (unsigned char *) xmalloc (note_size);
cleanup = make_cleanup (xfree, contents);
if (!bfd_get_section_contents (core_bfd, section, contents, 0, note_size))
error (_("could not get core note contents"));
/* Default dump behavior of coredump_filter (0x33), according to
Documentation/filesystems/proc.txt from the Linux kernel
tree. */
- enum filterflags filterflags = (COREFILTER_ANON_PRIVATE
- | COREFILTER_ANON_SHARED
- | COREFILTER_ELF_HEADERS
- | COREFILTER_HUGETLB_PRIVATE);
+ filter_flags filterflags = (COREFILTER_ANON_PRIVATE
+ | COREFILTER_ANON_SHARED
+ | COREFILTER_ELF_HEADERS
+ | COREFILTER_HUGETLB_PRIVATE);
/* We need to know the real target PID to access /proc. */
if (current_inferior ()->fake_pid_p)
coredumpfilter_name);
if (coredumpfilterdata != NULL)
{
- sscanf (coredumpfilterdata, "%x", &filterflags);
+ unsigned int flags;
+
+ sscanf (coredumpfilterdata, "%x", &flags);
+ filterflags = (enum filter_flag) flags;
xfree (coredumpfilterdata);
}
}
int read, int write, int exec, int modified,
const char *filename, void *arg)
{
- struct linux_find_memory_regions_data *data = arg;
+ struct linux_find_memory_regions_data *data
+ = (struct linux_find_memory_regions_data *) arg;
return data->func (vaddr, size, read, write, exec, modified, data->obfd);
}
return 0;
}
-static enum gdb_signal
-find_stop_signal (void)
-{
- struct thread_info *info =
- iterate_over_threads (find_signalled_thread, NULL);
-
- if (info)
- return info->suspend.stop_signal;
- else
- return GDB_SIGNAL_0;
-}
-
/* Generate corefile notes for SPU contexts. */
static char *
int read, int write, int exec, int modified,
const char *filename, void *data)
{
- struct linux_make_mappings_data *map_data = data;
+ struct linux_make_mappings_data *map_data
+ = (struct linux_make_mappings_data *) data;
gdb_byte buf[sizeof (ULONGEST)];
if (*filename == '\0' || inode == 0)
const char *human_name, void *cb_data)
{
char *buf;
- struct linux_collect_regset_section_cb_data *data = cb_data;
+ struct linux_collect_regset_section_cb_data *data
+ = (struct linux_collect_regset_section_cb_data *) cb_data;
if (data->abort_iteration)
return;
gdb_assert (regset && regset->collect_regset);
- buf = xmalloc (size);
+ buf = (char *) xmalloc (size);
regset->collect_regset (regset, data->regcache, -1, buf, size);
/* PRSTATUS still needs to be treated specially. */
siginfo_type = gdbarch_get_siginfo_type (gdbarch);
- buf = xmalloc (TYPE_LENGTH (siginfo_type));
+ buf = (gdb_byte *) xmalloc (TYPE_LENGTH (siginfo_type));
cleanups = make_cleanup (xfree, buf);
bytes_read = target_read (¤t_target, TARGET_OBJECT_SIGNAL_INFO, NULL,
struct linux_corefile_thread_data
{
struct gdbarch *gdbarch;
- int pid;
bfd *obfd;
char *note_data;
int *note_size;
enum gdb_signal stop_signal;
};
-/* Called by gdbthread.c once per thread. Records the thread's
- register state for the corefile note section. */
+/* Records the thread's register state for the corefile note
+ section. */
-static int
-linux_corefile_thread_callback (struct thread_info *info, void *data)
+static void
+linux_corefile_thread (struct thread_info *info,
+ struct linux_corefile_thread_data *args)
{
- struct linux_corefile_thread_data *args = data;
-
- /* It can be current thread
- which cannot be removed by update_thread_list. */
- if (info->state == THREAD_EXITED)
- return 0;
-
- if (ptid_get_pid (info->ptid) == args->pid)
- {
- struct cleanup *old_chain;
- struct regcache *regcache;
- gdb_byte *siginfo_data;
- LONGEST siginfo_size = 0;
-
- regcache = get_thread_arch_regcache (info->ptid, args->gdbarch);
-
- old_chain = save_inferior_ptid ();
- inferior_ptid = info->ptid;
- target_fetch_registers (regcache, -1);
- siginfo_data = linux_get_siginfo_data (args->gdbarch, &siginfo_size);
- do_cleanups (old_chain);
-
- old_chain = make_cleanup (xfree, siginfo_data);
-
- args->note_data = linux_collect_thread_registers
- (regcache, info->ptid, args->obfd, args->note_data,
- args->note_size, args->stop_signal);
-
- /* Don't return anything if we got no register information above,
- such a core file is useless. */
- if (args->note_data != NULL)
- if (siginfo_data != NULL)
- args->note_data = elfcore_write_note (args->obfd,
- args->note_data,
- args->note_size,
- "CORE", NT_SIGINFO,
- siginfo_data, siginfo_size);
-
- do_cleanups (old_chain);
- }
-
- return !args->note_data;
+ struct cleanup *old_chain;
+ struct regcache *regcache;
+ gdb_byte *siginfo_data;
+ LONGEST siginfo_size = 0;
+
+ regcache = get_thread_arch_regcache (info->ptid, args->gdbarch);
+
+ old_chain = save_inferior_ptid ();
+ inferior_ptid = info->ptid;
+ target_fetch_registers (regcache, -1);
+ siginfo_data = linux_get_siginfo_data (args->gdbarch, &siginfo_size);
+ do_cleanups (old_chain);
+
+ old_chain = make_cleanup (xfree, siginfo_data);
+
+ args->note_data = linux_collect_thread_registers
+ (regcache, info->ptid, args->obfd, args->note_data,
+ args->note_size, args->stop_signal);
+
+ /* Don't return anything if we got no register information above,
+ such a core file is useless. */
+ if (args->note_data != NULL)
+ if (siginfo_data != NULL)
+ args->note_data = elfcore_write_note (args->obfd,
+ args->note_data,
+ args->note_size,
+ "CORE", NT_SIGINFO,
+ siginfo_data, siginfo_size);
+
+ do_cleanups (old_chain);
}
/* Fill the PRPSINFO structure with information about the process being
int n_fields = 0;
/* Cleanups. */
struct cleanup *c;
- int i;
gdb_assert (p != NULL);
psargs = xstrdup (fname);
if (infargs != NULL)
- psargs = reconcat (psargs, psargs, " ", infargs, NULL);
+ psargs = reconcat (psargs, psargs, " ", infargs, (char *) NULL);
make_cleanup (xfree, psargs);
char *note_data = NULL;
gdb_byte *auxv;
int auxv_len;
+ struct thread_info *curr_thr, *signalled_thr, *thr;
if (! gdbarch_iterate_over_regset_sections_p (gdbarch))
return NULL;
}
END_CATCH
+ /* Like the kernel, prefer dumping the signalled thread first.
+ "First thread" is what tools use to infer the signalled thread.
+ In case there's more than one signalled thread, prefer the
+ current thread, if it is signalled. */
+ curr_thr = inferior_thread ();
+ if (curr_thr->suspend.stop_signal != GDB_SIGNAL_0)
+ signalled_thr = curr_thr;
+ else
+ {
+ signalled_thr = iterate_over_threads (find_signalled_thread, NULL);
+ if (signalled_thr == NULL)
+ signalled_thr = curr_thr;
+ }
+
thread_args.gdbarch = gdbarch;
- thread_args.pid = ptid_get_pid (inferior_ptid);
thread_args.obfd = obfd;
thread_args.note_data = note_data;
thread_args.note_size = note_size;
- thread_args.stop_signal = find_stop_signal ();
- iterate_over_threads (linux_corefile_thread_callback, &thread_args);
+ thread_args.stop_signal = signalled_thr->suspend.stop_signal;
+
+ linux_corefile_thread (signalled_thr, &thread_args);
+ ALL_NON_EXITED_THREADS (thr)
+ {
+ if (thr == signalled_thr)
+ continue;
+ if (ptid_get_pid (thr->ptid) != ptid_get_pid (inferior_ptid))
+ continue;
+
+ linux_corefile_thread (thr, &thread_args);
+ }
+
note_data = thread_args.note_data;
if (!note_data)
return NULL;
int read, int write, int exec, int modified,
void *data)
{
- struct mem_range *range = data;
+ struct mem_range *range = (struct mem_range *) data;
if (vaddr == range->start)
{
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. */
set_gdbarch_vsyscall_range (gdbarch, linux_vsyscall_range);
set_gdbarch_infcall_mmap (gdbarch, linux_infcall_mmap);
set_gdbarch_infcall_munmap (gdbarch, linux_infcall_munmap);
+ set_gdbarch_get_siginfo_type (gdbarch, linux_get_siginfo_type);
}
/* Provide a prototype to silence -Wmissing-prototypes. */