return siginfo_type;
}
-int
-linux_has_shared_address_space (void)
+static int
+linux_has_shared_address_space (struct gdbarch *gdbarch)
{
/* Determine whether we are running on uClinux or normal Linux
kernel. */
{
struct cleanup *cleanup = make_cleanup (xfree, data);
const char *p = data;
- const char *ep;
- ULONGEST val;
printf_filtered (_("Process: %s\n"),
pulongest (strtoulst (p, &p, 10)));
while (*p && isspace (*p))
p++;
- if (*p == '(' && (ep = strchr (p, ')')) != NULL)
+ if (*p == '(')
{
- printf_filtered ("Exec file: %.*s\n", (int) (ep - p - 1), p + 1);
- p = ep + 1;
+ const char *ep = strchr (p, ')');
+ if (ep != NULL)
+ {
+ printf_filtered ("Exec file: %.*s\n",
+ (int) (ep - p - 1), p + 1);
+ p = ep + 1;
+ }
}
while (*p && isspace (*p))
}
}
+/* List memory regions in the inferior for a corefile. */
+
+static int
+linux_find_memory_regions (struct gdbarch *gdbarch,
+ find_memory_region_ftype func, void *obfd)
+{
+ char filename[100];
+ gdb_byte *data;
+
+ /* We need to know the real target PID to access /proc. */
+ if (current_inferior ()->fake_pid_p)
+ return 1;
+
+ xsnprintf (filename, sizeof filename,
+ "/proc/%d/smaps", current_inferior ()->pid);
+ data = target_fileio_read_stralloc (filename);
+ if (data == NULL)
+ {
+ /* Older Linux kernels did not support /proc/PID/smaps. */
+ xsnprintf (filename, sizeof filename,
+ "/proc/%d/maps", current_inferior ()->pid);
+ data = target_fileio_read_stralloc (filename);
+ }
+ if (data)
+ {
+ struct cleanup *cleanup = make_cleanup (xfree, data);
+ char *line;
+
+ line = strtok (data, "\n");
+ while (line)
+ {
+ ULONGEST addr, endaddr, offset, inode;
+ const char *permissions, *device, *filename;
+ size_t permissions_len, device_len;
+ int read, write, exec;
+ int modified = 0, has_anonymous = 0;
+
+ read_mapping (line, &addr, &endaddr, &permissions, &permissions_len,
+ &offset, &device, &device_len, &inode, &filename);
+
+ /* Decode permissions. */
+ read = (memchr (permissions, 'r', permissions_len) != 0);
+ write = (memchr (permissions, 'w', permissions_len) != 0);
+ exec = (memchr (permissions, 'x', permissions_len) != 0);
+
+ /* Try to detect if region was modified by parsing smaps counters. */
+ for (line = strtok (NULL, "\n");
+ line && line[0] >= 'A' && line[0] <= 'Z';
+ line = strtok (NULL, "\n"))
+ {
+ char keyword[64 + 1];
+ unsigned long number;
+
+ if (sscanf (line, "%64s%lu kB\n", keyword, &number) != 2)
+ {
+ warning (_("Error parsing {s,}maps file '%s'"), filename);
+ break;
+ }
+ if (strcmp (keyword, "Anonymous:") == 0)
+ has_anonymous = 1;
+ if (number != 0 && (strcmp (keyword, "Shared_Dirty:") == 0
+ || strcmp (keyword, "Private_Dirty:") == 0
+ || strcmp (keyword, "Swap:") == 0
+ || strcmp (keyword, "Anonymous:") == 0))
+ modified = 1;
+ }
+
+ /* Older Linux kernels did not support the "Anonymous:" counter.
+ If it is missing, we can't be sure - dump all the pages. */
+ if (!has_anonymous)
+ modified = 1;
+
+ /* Invoke the callback function to create the corefile segment. */
+ func (addr, endaddr - addr, read, write, exec, modified, obfd);
+ }
+
+ do_cleanups (cleanup);
+ return 0;
+ }
+
+ return 1;
+}
+
/* Determine which signal stopped execution. */
static int
find_signalled_thread (struct thread_info *info, void *data)
{
- if (info->suspend.stop_signal != TARGET_SIGNAL_0
+ if (info->suspend.stop_signal != GDB_SIGNAL_0
&& ptid_get_pid (info->ptid) == ptid_get_pid (inferior_ptid))
return 1;
return 0;
}
-static enum target_signal
+static enum gdb_signal
find_stop_signal (void)
{
struct thread_info *info =
if (info)
return info->suspend.stop_signal;
else
- return TARGET_SIGNAL_0;
+ return GDB_SIGNAL_0;
}
/* Generate corefile notes for SPU contexts. */
linux_collect_thread_registers (const struct regcache *regcache,
ptid_t ptid, bfd *obfd,
char *note_data, int *note_size,
- enum target_signal stop_signal)
+ enum gdb_signal stop_signal)
{
struct gdbarch *gdbarch = get_regcache_arch (regcache);
struct core_regset_section *sect_list;
if (strcmp (sect_list->sect_name, ".reg") == 0)
note_data = (char *) elfcore_write_prstatus
(obfd, note_data, note_size, lwp,
- target_signal_to_host (stop_signal), buf);
+ gdb_signal_to_host (stop_signal), buf);
else
note_data = (char *) elfcore_write_register_note
(obfd, note_data, note_size,
return note_data;
}
+/* Fetch the siginfo data for the current thread, if it exists. If
+ there is no data, or we could not read it, return NULL. Otherwise,
+ return a newly malloc'd buffer holding the data and fill in *SIZE
+ with the size of the data. The caller is responsible for freeing
+ the data. */
+
+static gdb_byte *
+linux_get_siginfo_data (struct gdbarch *gdbarch, LONGEST *size)
+{
+ struct type *siginfo_type;
+ gdb_byte *buf;
+ LONGEST bytes_read;
+ struct cleanup *cleanups;
+
+ if (!gdbarch_get_siginfo_type_p (gdbarch))
+ return NULL;
+
+ siginfo_type = gdbarch_get_siginfo_type (gdbarch);
+
+ buf = xmalloc (TYPE_LENGTH (siginfo_type));
+ cleanups = make_cleanup (xfree, buf);
+
+ bytes_read = target_read (¤t_target, TARGET_OBJECT_SIGNAL_INFO, NULL,
+ buf, 0, TYPE_LENGTH (siginfo_type));
+ if (bytes_read == TYPE_LENGTH (siginfo_type))
+ {
+ discard_cleanups (cleanups);
+ *size = bytes_read;
+ }
+ else
+ {
+ do_cleanups (cleanups);
+ buf = NULL;
+ }
+
+ return buf;
+}
+
struct linux_corefile_thread_data
{
struct gdbarch *gdbarch;
char *note_data;
int *note_size;
int num_notes;
- enum target_signal stop_signal;
+ enum gdb_signal stop_signal;
linux_collect_thread_registers_ftype collect;
};
{
struct cleanup *old_chain;
struct regcache *regcache;
+ gdb_byte *siginfo_data;
+ LONGEST siginfo_size;
+
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 = args->collect (regcache, info->ptid, args->obfd,
args->note_data, args->note_size,
args->stop_signal);
args->num_notes++;
+
+ 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);
+ args->num_notes++;
+ }
+
+ do_cleanups (old_chain);
}
return !args->note_data;
{
set_gdbarch_core_pid_to_str (gdbarch, linux_core_pid_to_str);
set_gdbarch_info_proc (gdbarch, linux_info_proc);
+ set_gdbarch_find_memory_regions (gdbarch, linux_find_memory_regions);
set_gdbarch_make_corefile_notes (gdbarch, linux_make_corefile_notes_1);
+ set_gdbarch_has_shared_address_space (gdbarch,
+ linux_has_shared_address_space);
}
+/* Provide a prototype to silence -Wmissing-prototypes. */
+extern initialize_file_ftype _initialize_linux_tdep;
+
void
_initialize_linux_tdep (void)
{