/* 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
+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);
/* This function is suitable for architectures that don't
extend/override the standard siginfo structure. */
-struct type *
+static struct type *
linux_get_siginfo_type (struct gdbarch *gdbarch)
{
struct linux_gdbarch_data *linux_gdbarch_data;
This should work OK enough, however. */
static int
-dump_mapping_p (unsigned int 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 (cmdline_f)
{
xsnprintf (filename, sizeof filename, "/proc/%ld/cmdline", pid);
- data = target_fileio_read_stralloc (filename);
+ data = target_fileio_read_stralloc (NULL, filename);
if (data)
{
struct cleanup *cleanup = make_cleanup (xfree, data);
if (cwd_f)
{
xsnprintf (filename, sizeof filename, "/proc/%ld/cwd", pid);
- data = target_fileio_readlink (filename, &target_errno);
+ data = target_fileio_readlink (NULL, filename, &target_errno);
if (data)
{
struct cleanup *cleanup = make_cleanup (xfree, data);
if (exe_f)
{
xsnprintf (filename, sizeof filename, "/proc/%ld/exe", pid);
- data = target_fileio_readlink (filename, &target_errno);
+ data = target_fileio_readlink (NULL, filename, &target_errno);
if (data)
{
struct cleanup *cleanup = make_cleanup (xfree, data);
if (mappings_f)
{
xsnprintf (filename, sizeof filename, "/proc/%ld/maps", pid);
- data = target_fileio_read_stralloc (filename);
+ data = target_fileio_read_stralloc (NULL, filename);
if (data)
{
struct cleanup *cleanup = make_cleanup (xfree, data);
if (status_f)
{
xsnprintf (filename, sizeof filename, "/proc/%ld/status", pid);
- data = target_fileio_read_stralloc (filename);
+ data = target_fileio_read_stralloc (NULL, filename);
if (data)
{
struct cleanup *cleanup = make_cleanup (xfree, data);
if (stat_f)
{
xsnprintf (filename, sizeof filename, "/proc/%ld/stat", pid);
- data = target_fileio_read_stralloc (filename);
+ data = target_fileio_read_stralloc (NULL, filename);
if (data)
{
struct cleanup *cleanup = make_cleanup (xfree, data);
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. */
- unsigned int filterflags = (COREFILTER_ANON_PRIVATE
+ filter_flags filterflags = (COREFILTER_ANON_PRIVATE
| COREFILTER_ANON_SHARED
| COREFILTER_ELF_HEADERS
| COREFILTER_HUGETLB_PRIVATE);
{
xsnprintf (coredumpfilter_name, sizeof (coredumpfilter_name),
"/proc/%d/coredump_filter", pid);
- coredumpfilterdata = target_fileio_read_stralloc (coredumpfilter_name);
+ coredumpfilterdata = target_fileio_read_stralloc (NULL,
+ coredumpfilter_name);
if (coredumpfilterdata != NULL)
{
- sscanf (coredumpfilterdata, "%x", &filterflags);
+ unsigned int flags;
+
+ sscanf (coredumpfilterdata, "%x", &flags);
+ filterflags = (enum filter_flag) flags;
xfree (coredumpfilterdata);
}
}
xsnprintf (mapsfilename, sizeof mapsfilename, "/proc/%d/smaps", pid);
- data = target_fileio_read_stralloc (mapsfilename);
+ data = target_fileio_read_stralloc (NULL, mapsfilename);
if (data == NULL)
{
/* Older Linux kernels did not support /proc/PID/smaps. */
xsnprintf (mapsfilename, sizeof mapsfilename, "/proc/%d/maps", pid);
- data = target_fileio_read_stralloc (mapsfilename);
+ data = target_fileio_read_stralloc (NULL, mapsfilename);
}
if (data != NULL)
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
/* Obtaining PID and filename. */
pid = ptid_get_pid (inferior_ptid);
xsnprintf (filename, sizeof (filename), "/proc/%d/cmdline", (int) pid);
- fname = target_fileio_read_stralloc (filename);
+ fname = target_fileio_read_stralloc (NULL, filename);
if (fname == NULL || *fname == '\0')
{
p->pr_psargs[sizeof (p->pr_psargs) - 1] = '\0';
xsnprintf (filename, sizeof (filename), "/proc/%d/stat", (int) pid);
- proc_stat = target_fileio_read_stralloc (filename);
+ proc_stat = target_fileio_read_stralloc (NULL, filename);
make_cleanup (xfree, proc_stat);
if (proc_stat == NULL || *proc_stat == '\0')
/* Finally, obtaining the UID and GID. For that, we read and parse the
contents of the `/proc/PID/status' file. */
xsnprintf (filename, sizeof (filename), "/proc/%d/status", (int) pid);
- proc_status = target_fileio_read_stralloc (filename);
+ proc_status = target_fileio_read_stralloc (NULL, filename);
make_cleanup (xfree, proc_status);
if (proc_status == NULL || *proc_status == '\0')
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)
{
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. */