Merge GDB 7.5.1
Merge bug fixes:
* Remove normal elf formats from nacl target in bfd/configure.bfd
* Force usage of AT_ENTRY_POINT mode for calling user functions.
* Update gdb/configure.tgt to exclude solib.o that is linked twice otherwise.
Review URL: https://codereview.chromium.org/11969036
diff --git a/codereview.settings b/codereview.settings
new file mode 100644
index 0000000..45318e0
--- /dev/null
+++ b/codereview.settings
@@ -0,0 +1,7 @@
+# This file is used by git-cl to get repository specific information.
+CODE_REVIEW_SERVER: codereview.chromium.org
+CC_LIST: native-client-reviews@googlegroups.com
+STATUS: http://nativeclient-status.appspot.com/status
+VIEW_VC: http://git.chromium.org/gitweb?p=native_client/nacl-gdb.git;a=commit;h=
+PUSH_URL_CONFIG: url.ssh://gerrit.chromium.org.pushinsteadof
+ORIGIN_URL_CONFIG: http://git.chromium.org
diff --git a/gdb/configure.tgt b/gdb/configure.tgt
index 36d4304..7bdb3c6 100644
--- a/gdb/configure.tgt
+++ b/gdb/configure.tgt
@@ -215,6 +215,13 @@
fi
build_gdbserver=yes
;;
+x86_64-*-nacl*)
+ # Target: NaCl, remote debugging only.
+ gdb_target_obs="i386-tdep.o glibc-tdep.o i387-tdep.o \
+ solib-svr4.o symfile-mem.o amd64-tdep.o \
+ nacl-manifest.o nacl-tdep.o i386-linux-tdep.o \
+ amd64-linux-tdep.o linux-tdep.o linux-record.o"
+ ;;
i[34567]86-*-gnu*)
# Target: Intel 386 running the GNU Hurd
gdb_target_obs="i386-tdep.o i387-tdep.o i386gnu-tdep.o solib-svr4.o"
diff --git a/gdb/defs.h b/gdb/defs.h
index 04ced04..c7ef759 100644
--- a/gdb/defs.h
+++ b/gdb/defs.h
@@ -897,6 +897,7 @@
GDB_OSABI_DICOS,
GDB_OSABI_DARWIN,
GDB_OSABI_SYMBIAN,
+ GDB_OSABI_NACL,
GDB_OSABI_OPENVMS,
GDB_OSABI_INVALID /* keep this last */
diff --git a/gdb/features/i386/amd64-linux.c b/gdb/features/i386/amd64-linux.c
index 71efcbe..2eb9f96 100644
--- a/gdb/features/i386/amd64-linux.c
+++ b/gdb/features/i386/amd64-linux.c
@@ -42,8 +42,8 @@
tdesc_create_reg (feature, "rdx", 3, 1, NULL, 64, "int64");
tdesc_create_reg (feature, "rsi", 4, 1, NULL, 64, "int64");
tdesc_create_reg (feature, "rdi", 5, 1, NULL, 64, "int64");
- tdesc_create_reg (feature, "rbp", 6, 1, NULL, 64, "data_ptr");
- tdesc_create_reg (feature, "rsp", 7, 1, NULL, 64, "data_ptr");
+ tdesc_create_reg (feature, "rbp", 6, 1, NULL, 64, "int64");
+ tdesc_create_reg (feature, "rsp", 7, 1, NULL, 64, "int64");
tdesc_create_reg (feature, "r8", 8, 1, NULL, 64, "int64");
tdesc_create_reg (feature, "r9", 9, 1, NULL, 64, "int64");
tdesc_create_reg (feature, "r10", 10, 1, NULL, 64, "int64");
@@ -52,7 +52,7 @@
tdesc_create_reg (feature, "r13", 13, 1, NULL, 64, "int64");
tdesc_create_reg (feature, "r14", 14, 1, NULL, 64, "int64");
tdesc_create_reg (feature, "r15", 15, 1, NULL, 64, "int64");
- tdesc_create_reg (feature, "rip", 16, 1, NULL, 64, "code_ptr");
+ tdesc_create_reg (feature, "rip", 16, 1, NULL, 64, "int64");
tdesc_create_reg (feature, "eflags", 17, 1, NULL, 32, "i386_eflags");
tdesc_create_reg (feature, "cs", 18, 1, NULL, 32, "int32");
tdesc_create_reg (feature, "ss", 19, 1, NULL, 32, "int32");
diff --git a/gdb/nacl-manifest.c b/gdb/nacl-manifest.c
new file mode 100644
index 0000000..5627d26
--- /dev/null
+++ b/gdb/nacl-manifest.c
@@ -0,0 +1,432 @@
+/* Handle Native Client manifest files.
+
+ Copyright (C) 2011 Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+#include "defs.h"
+
+#include "command.h"
+#include "completer.h"
+#include "exec.h"
+#include "observer.h"
+#include "readline/readline.h"
+#include "solib.h"
+#include "symfile.h"
+#include "objfiles.h"
+
+#include <ctype.h>
+#include <stdio.h>
+#include <string.h>
+
+#define MANIFEST_MAX_NESTING 4
+
+#define MANIFEST_MAX_STRING_SIZE 256
+
+struct file_list
+ {
+ struct file_list *next;
+
+ char original_name[MANIFEST_MAX_STRING_SIZE];
+
+ char name[MANIFEST_MAX_STRING_SIZE];
+ };
+
+/* Mapping of 32-bit *.so libraries. */
+static struct file_list *nacl_file_list_32 = NULL;
+
+/* Mapping of 64-bit *.so libraries. */
+static struct file_list *nacl_file_list_64 = NULL;
+
+/* runnable-ld.so or statically linked 32-bit program name. */
+static char *nacl_program_filename_32 = NULL;
+
+/* runnable-ld.so or statically linked 64-bit program name. */
+static char *nacl_program_filename_64 = NULL;
+
+const char *
+nacl_manifest_find (char *original_name)
+{
+ struct file_list *curr;
+ int addr_bit;
+
+ /* HACK: NaCl uses "/lib/" library path to inform service runtime that the
+ file should be opened as solib vs. ordinary file. Split that prefix
+ here so that GDB can find these files via manifest or as is. */
+ if (strncmp (original_name, "/lib/", 5) == 0)
+ original_name += 5;
+
+ addr_bit = gdbarch_addr_bit(target_gdbarch);
+
+ if (addr_bit == 32)
+ curr = nacl_file_list_32;
+ else if (addr_bit == 64)
+ curr = nacl_file_list_64;
+ else
+ error(_("Can't map files with manifest due to unknown architecture"));
+
+ for (; curr; curr = curr->next)
+ {
+ if (strcmp (original_name, curr->original_name) == 0)
+ return curr->name;
+ }
+
+ if (strcmp(original_name, "NaClMain") == 0)
+ {
+ if (addr_bit == 32 && nacl_program_filename_32)
+ return nacl_program_filename_32;
+ if (addr_bit == 64 && nacl_program_filename_64)
+ return nacl_program_filename_64;
+ error(_("runnable-ld.so not found in manifest"));
+ }
+ if (strlen(original_name) == 0)
+ {
+ return nacl_manifest_find("main.nexe");
+ }
+ /* TODO: Should we complain if we have a manifest but failed to find
+ /lib/filename there? */
+
+ return original_name;
+}
+
+static void
+nacl_manifest_free_list (struct file_list *nacl_file_list)
+{
+ while (nacl_file_list)
+ {
+ struct file_list *next = nacl_file_list->next;
+
+ xfree (nacl_file_list);
+ nacl_file_list = next;
+ }
+}
+
+static void
+nacl_manifest_free (void)
+{
+ nacl_manifest_free_list(nacl_file_list_32);
+ nacl_manifest_free_list(nacl_file_list_64);
+ xfree (nacl_program_filename_32);
+ xfree (nacl_program_filename_64);
+ nacl_program_filename_32 = NULL;
+ nacl_program_filename_64 = NULL;
+}
+
+/* Very dumb parser for JSON subset used in Native Client manifest files.
+ This is a SAX-style parser that runs callbacks on JSON events. */
+
+struct json_manifest_reader
+ {
+ /* Manifest file. */
+ FILE *file;
+
+ /* Stack of members being parsed. */
+ const char *members[MANIFEST_MAX_NESTING];
+
+ /* Members stack size. */
+ int nesting;
+
+ /* Manifest file directory without slash at the end. */
+ char *dirname;
+ };
+
+static void
+json_on_member (struct json_manifest_reader *r, const char *member)
+{
+ if (r->nesting == MANIFEST_MAX_NESTING)
+ error (_("Invalid manifest file."));
+
+ r->members[r->nesting] = member;
+ ++r->nesting;
+}
+
+static void
+json_on_end_member (struct json_manifest_reader *r, const char *member)
+{
+ --r->nesting;
+}
+
+static void
+append_dir_name (struct json_manifest_reader *r,
+ char *full_path,
+ int max_path_size,
+ char *name)
+{
+ full_path[0] = '\0';
+ if (r->dirname)
+ {
+ if (strlen (r->dirname) + strlen (SLASH_STRING) >= max_path_size)
+ error (_("Mapped file name in manifest is too long."));
+ strcpy (full_path, r->dirname);
+ strcat (full_path, SLASH_STRING);
+ }
+ if (strlen (full_path) + strlen (name) >= max_path_size)
+ error (_("Mapped file name in manifest is too long."));
+ strcat (full_path, name);
+}
+
+static struct file_list *
+json_append_file_list (struct json_manifest_reader *r,
+ struct file_list **nacl_file_list,
+ const char *original_name,
+ const char *name)
+{
+ struct file_list *curr = XZALLOC (struct file_list);
+
+ if (strlen(original_name) >= MANIFEST_MAX_STRING_SIZE)
+ error (_("Original file name in manifest is too long."));
+ strcpy (curr->original_name, original_name);
+ append_dir_name (r, curr->name, MANIFEST_MAX_STRING_SIZE, name);
+
+ curr->next = *nacl_file_list;
+ *nacl_file_list = curr;
+ return curr;
+}
+
+static void
+json_on_string_value (struct json_manifest_reader *r, const char *value)
+{
+ if (r->nesting == 3 &&
+ strcmp(r->members[0], "program") == 0 &&
+ strcmp(r->members[2], "url") == 0)
+ {
+ /* We'll xfree nacl_program_filename_* in nacl_manifest_free. */
+ if (strcmp (r->members[1], "x86-32") == 0)
+ {
+ nacl_program_filename_32 = malloc (MANIFEST_MAX_STRING_SIZE);
+ append_dir_name (r, nacl_program_filename_32,
+ MANIFEST_MAX_STRING_SIZE, value);
+ }
+ else if (strcmp (r->members[1], "x86-64") == 0)
+ {
+ nacl_program_filename_64 = malloc (MANIFEST_MAX_STRING_SIZE);
+ append_dir_name (r, nacl_program_filename_64,
+ MANIFEST_MAX_STRING_SIZE, value);
+ }
+ }
+ else if (r->nesting == 4 &&
+ strcmp (r->members[0], "files") == 0 &&
+ strcmp (r->members[3], "url") == 0)
+ {
+ if (strcmp(r->members[2], "x86-32") == 0)
+ json_append_file_list(r, &nacl_file_list_32, r->members[1], value);
+ else if (strcmp(r->members[2], "x86-64") == 0)
+ json_append_file_list(r, &nacl_file_list_64, r->members[1], value);
+ }
+}
+
+/* Basic parsing utilities. */
+
+static int
+json_getc (struct json_manifest_reader *r)
+{
+ return fgetc (r->file);
+}
+
+static int
+json_getc_nonspace (struct json_manifest_reader *r)
+{
+ int c;
+
+ while (isspace (c = json_getc (r)));
+ return c;
+}
+
+/* Parsing routines.
+
+ json_parse_something assumes we are just going to read first character of
+ something, probably skipping preceding whitespaces.
+
+ json_finish_parse_something assumes we already read first character of
+ something, and checked it was correct. */
+
+
+static void json_parse_value (struct json_manifest_reader *r);
+
+static void
+json_finish_parse_string (struct json_manifest_reader *r, char *buf, int len)
+{
+ int c;
+
+ for (; len; --len)
+ {
+ c = json_getc (r);
+ if (c == '"')
+ {
+ *buf = '\0';
+ return;
+ }
+
+ if (c == '\n' || c == EOF)
+ break;
+
+ *buf++ = (char)c;
+ }
+
+ error (_("Invalid manifest file."));
+}
+
+/* We only accept non-empty objects. */
+
+static void
+json_finish_parse_object (struct json_manifest_reader *r)
+{
+ int c;
+ char buf[MANIFEST_MAX_STRING_SIZE];
+
+ do
+ {
+ c = json_getc_nonspace(r);
+ if (c == '}')
+ break;
+ if (c != '\"')
+ error (_("Invalid manifest file."));
+
+ json_finish_parse_string (r, buf, MANIFEST_MAX_STRING_SIZE);
+ json_on_member (r, buf);
+
+ if (json_getc_nonspace (r) != ':')
+ error (_("Invalid manifest file."));
+
+ json_parse_value (r);
+ json_on_end_member (r, buf);
+ }
+ while ((c = json_getc_nonspace (r)) == ',');
+
+ if (c != '}')
+ error (_("Invalid manifest file."));
+}
+
+/* We only accept objects or strings. */
+
+static void
+json_parse_value (struct json_manifest_reader *r)
+{
+ int c = json_getc_nonspace (r);
+
+ if (c == '{')
+ {
+ json_finish_parse_object (r);
+ }
+ else if (c == '\"')
+ {
+ char buf[MANIFEST_MAX_STRING_SIZE];
+
+ json_finish_parse_string (r, buf, MANIFEST_MAX_STRING_SIZE);
+ json_on_string_value (r, buf);
+ }
+ else
+ {
+ error (_("Invalid manifest file."));
+ }
+}
+
+/* GDB commands for specifying Native Client files. */
+
+static void
+nacl_irt_command (char *args, int from_tty)
+{
+ if (args)
+ {
+ char **argv;
+ struct cleanup *old_chain;
+ char *nacl_irt_filename;
+
+ argv = gdb_buildargv(args);
+ old_chain = make_cleanup_freeargv(argv);
+ if (*argv == NULL)
+ error (_("No IRT file name was specified"));
+
+ nacl_irt_filename = tilde_expand (*argv);
+ make_cleanup(xfree, nacl_irt_filename);
+
+ symbol_file_add (nacl_irt_filename, from_tty ? SYMFILE_VERBOSE : 0,
+ NULL, OBJF_USERLOADED);
+ /* Recalculate frames. */
+ reinit_frame_cache ();
+ do_cleanups(old_chain);
+ }
+}
+
+static struct observer *about_to_proceed_observer = NULL;
+
+static void
+about_to_proceed_hook ()
+{
+ if (exec_bfd == NULL)
+ {
+ const char *filename = nacl_manifest_find ("NaClMain");
+ exec_file_attach (filename, 0);
+ symbol_file_add (filename, SYMFILE_MAINLINE, NULL, 0);
+ }
+}
+
+static void
+nacl_manifest_command (char *args, int from_tty)
+{
+ if (args)
+ {
+ char **argv;
+ struct cleanup *old_chain;
+ char *manifest_filename;
+ struct json_manifest_reader r = { 0 };
+
+ argv = gdb_buildargv (args);
+ old_chain = make_cleanup_freeargv (argv);
+ if (*argv == NULL)
+ error (_("No manifest file name was specified"));
+
+ manifest_filename = tilde_expand (*argv);
+ make_cleanup (xfree, manifest_filename);
+
+ r.file = fopen (manifest_filename, "r");
+ if (!r.file)
+ perror_with_name (manifest_filename);
+ make_cleanup_fclose (r.file);
+
+ r.dirname = ldirname (manifest_filename);
+ make_cleanup (xfree, r.dirname);
+
+ /* TODO: Kill existing manifest only if new one parsed OK! */
+ nacl_manifest_free ();
+ json_parse_value (&r);
+
+ solib_add (NULL, from_tty, NULL, 1);
+
+ if (about_to_proceed_observer == NULL)
+ {
+ about_to_proceed_observer
+ = observer_attach_about_to_proceed (about_to_proceed_hook);
+ }
+
+ do_cleanups(old_chain);
+ }
+}
+
+void
+_initialize_nacl_manifest (void)
+{
+ struct cmd_list_element *c;
+
+ c = add_com ("nacl-irt", class_files, nacl_irt_command,
+ _("Use FILE as Native Client IRT to be debugged."));
+ set_cmd_completer (c, filename_completer);
+
+ c = add_com ("nacl-manifest", class_files, nacl_manifest_command,
+ _("Use FILE as Native Client manifest for the program"
+ " to be debugged."));
+ set_cmd_completer (c, filename_completer);
+}
diff --git a/gdb/nacl-manifest.h b/gdb/nacl-manifest.h
new file mode 100644
index 0000000..1035314
--- /dev/null
+++ b/gdb/nacl-manifest.h
@@ -0,0 +1,29 @@
+/* Handle Native Client manifest files.
+
+ Copyright (C) 2011 Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+#ifndef NACL_MANIFEST_H
+#define NACL_MANIFEST_H
+
+/* Real filename for Native Client program. */
+const char *nacl_manifest_program (void);
+
+/* Real filename for Native Client original_name. */
+const char *nacl_manifest_find (char *original_name);
+
+#endif
diff --git a/gdb/nacl-tdep.c b/gdb/nacl-tdep.c
new file mode 100644
index 0000000..fe485b1
--- /dev/null
+++ b/gdb/nacl-tdep.c
@@ -0,0 +1,233 @@
+/* Target-dependent code for NaCl.
+
+ Copyright (C) 2001, 2003-2012 Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+#include "defs.h"
+#include "amd64-linux-tdep.h"
+#include "i386-linux-tdep.h"
+#include "linux-tdep.h"
+#include "amd64-tdep.h"
+#include "nacl-manifest.h"
+#include "symtab.h"
+#include "solib-svr4.h"
+#include "frame.h"
+#include "osabi.h"
+#include "disasm.h"
+#include "breakpoint.h"
+#include "target.h"
+#include "elf-bfd.h"
+#include "inferior.h"
+
+static enum gdb_osabi
+nacl_osabi_sniffer (bfd *abfd)
+{
+ /* WARNING! This way of checking for NaCl OS ABI is deprecated.
+ See http://code.google.com/p/nativeclient/issues/detail?id=2971 */
+ if (bfd_get_flavour (abfd) == bfd_target_elf_flavour &&
+ elf_elfheader (abfd)->e_ident[EI_OSABI] == 123)
+ return GDB_OSABI_NACL;
+
+ return GDB_OSABI_UNKNOWN;
+}
+
+static void
+nacl_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
+{
+ /* NaCl uses SVR4-style shared libraries. */
+ set_gdbarch_skip_trampoline_code (gdbarch, find_solib_trampoline_target);
+ set_solib_svr4_map_so_name (gdbarch, nacl_manifest_find);
+ set_gdbarch_process_record (gdbarch, i386_process_record);
+ set_gdbarch_call_dummy_location(gdbarch, AT_ENTRY_POINT);
+}
+
+static void
+i386_nacl_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
+{
+ struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+ linux_init_abi (info, gdbarch);
+ i386_elf_init_abi (info, gdbarch);
+ tdep->tdesc = tdesc_i386_linux;
+ set_solib_svr4_fetch_link_map_offsets (gdbarch,
+ svr4_ilp32_fetch_link_map_offsets);
+ nacl_init_abi (info, gdbarch);
+}
+
+static CORE_ADDR
+amd64_nacl_addr_bits_remove (struct gdbarch *gdbarch, CORE_ADDR val)
+{
+ return val & 0xffffffffUL;
+}
+
+static CORE_ADDR
+amd64_nacl_unwind_pc (struct gdbarch *gdbarch, struct frame_info *this_frame)
+{
+ CORE_ADDR pc;
+ pc = frame_unwind_register_unsigned (this_frame, gdbarch_pc_regnum (gdbarch));
+ return amd64_nacl_addr_bits_remove (gdbarch, pc);
+}
+
+static CORE_ADDR
+amd64_nacl_unwind_sp (struct gdbarch *gdbarch, struct frame_info *this_frame)
+{
+ CORE_ADDR sp;
+ sp = frame_unwind_register_unsigned (this_frame, gdbarch_sp_regnum (gdbarch));
+ return amd64_nacl_addr_bits_remove (gdbarch, sp);
+}
+
+struct link_map_offsets *
+amd64_nacl_fetch_link_map_offsets (void)
+{
+ static struct link_map_offsets lmo;
+ static struct link_map_offsets *lmp = NULL;
+
+ if (lmp == NULL)
+ {
+ lmp = &lmo;
+
+ lmo.r_version_offset = 0;
+ lmo.r_version_size = 4;
+ lmo.r_map_offset = 4;
+ lmo.r_brk_offset = 8;
+ /* Dynamic linker is in the normal list of shared objects. */
+ lmo.r_ldsomap_offset = -1;
+
+ lmo.link_map_size = 24;
+ lmo.l_addr_offset = 0;
+ lmo.l_name_offset = 8;
+ lmo.l_ld_offset = 12;
+ lmo.l_next_offset = 16;
+ lmo.l_prev_offset = 20;
+ }
+
+ return lmp;
+}
+
+static CORE_ADDR
+amd64_nacl_skip_rsp_sandboxing (CORE_ADDR addr)
+{
+ gdb_byte buf[3];
+ if (target_read_memory (addr, buf, sizeof(buf)) == 0)
+ {
+ /* 4c 01 fc add %r15,%rsp */
+ if (buf[0] == 0x4c && buf[1] == 0x01 && buf[2] == 0xfc)
+ {
+ return addr + 3;
+ }
+ }
+ return addr;
+}
+
+static CORE_ADDR
+amd64_nacl_adjust_breakpoint_address (struct gdbarch *gdbarch, CORE_ADDR addr)
+{
+ return amd64_nacl_skip_rsp_sandboxing (addr);
+}
+
+static int
+amd64_nacl_software_single_step (struct frame_info *frame)
+{
+ struct gdbarch *gdbarch;
+ CORE_ADDR pc;
+ CORE_ADDR bp_pc;
+
+ gdbarch = get_frame_arch (frame);
+ pc = get_frame_register_unsigned (frame, gdbarch_pc_regnum (gdbarch));
+ pc = amd64_nacl_addr_bits_remove (gdbarch, pc);
+
+ /* Check if next instruction is rsp sandboxing. If yes, assume current
+ instruction is rsp modification. */
+ pc += gdb_insn_length (gdbarch, pc);
+ bp_pc = amd64_nacl_skip_rsp_sandboxing (pc);
+ if (bp_pc != pc)
+ {
+ insert_single_step_breakpoint (gdbarch,
+ get_frame_address_space (frame),
+ bp_pc);
+ return 1;
+ }
+
+ return 0;
+}
+
+static struct frame_id
+amd64_nacl_dummy_id (struct gdbarch *gdbarch, struct frame_info *this_frame)
+{
+ CORE_ADDR fp;
+
+ fp = get_frame_register_unsigned (this_frame, AMD64_RBP_REGNUM) + 16;
+ fp = amd64_nacl_addr_bits_remove(gdbarch, fp);
+
+ return frame_id_build (fp, get_frame_pc (this_frame));
+}
+
+static void
+amd64_nacl_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
+{
+ struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+
+ linux_init_abi (info, gdbarch);
+ amd64_init_abi (info, gdbarch);
+ tdep->tdesc = tdesc_amd64_linux;
+ set_solib_svr4_fetch_link_map_offsets (gdbarch,
+ amd64_nacl_fetch_link_map_offsets);
+ nacl_init_abi (info, gdbarch);
+
+ /* NaCl data model.
+
+ WARNING! This might confuse a lot of code, as it uses
+ if (set_gdbarch_ptr_bit (gdbarch) == <bits>)
+ to distinguish between i386 and x86_64 (lame!). Luckily, most of that
+ code is about native debugging and syscalls, so it is not used for NaCl.
+
+ TODO(eaeltsin): find better way to distinguish between i386 and x86_64! */
+ set_gdbarch_long_bit (gdbarch, 32);
+ set_gdbarch_ptr_bit (gdbarch, 32);
+
+ /* TODO(eaeltsin): we might use address size instead of pointer size to
+ distinguish between i386 and x86_64... At least address size is not
+ a property of the data model. */
+ set_gdbarch_addr_bit (gdbarch, 64);
+
+ /* How to extract addresses from registers. */
+ set_gdbarch_addr_bits_remove (gdbarch, amd64_nacl_addr_bits_remove);
+ set_gdbarch_unwind_pc (gdbarch, amd64_nacl_unwind_pc);
+ set_gdbarch_unwind_sp (gdbarch, amd64_nacl_unwind_sp);
+
+ /* Where to set breakpoints. */
+ set_gdbarch_adjust_breakpoint_address (gdbarch,
+ amd64_nacl_adjust_breakpoint_address);
+ set_gdbarch_software_single_step (gdbarch, amd64_nacl_software_single_step);
+ /* Recognizing dummy frames. */
+ set_gdbarch_dummy_id(gdbarch, amd64_nacl_dummy_id);
+}
+
+/* Provide a prototype to silence -Wmissing-prototypes. */
+extern void _initialize_nacl_tdep (void);
+
+void
+_initialize_nacl_tdep (void)
+{
+ gdbarch_register_osabi_sniffer (bfd_arch_i386, bfd_target_elf_flavour,
+ nacl_osabi_sniffer);
+
+ gdbarch_register_osabi (bfd_arch_i386, bfd_mach_x86_64,
+ GDB_OSABI_NACL, amd64_nacl_init_abi);
+
+ gdbarch_register_osabi (bfd_arch_i386, 0,
+ GDB_OSABI_NACL, i386_nacl_init_abi);
+}
diff --git a/gdb/osabi.c b/gdb/osabi.c
index faffe30..909138e 100644
--- a/gdb/osabi.c
+++ b/gdb/osabi.c
@@ -72,6 +72,7 @@
"DICOS",
"Darwin",
"Symbian",
+ "NaCl",
"OpenVMS",
"<invalid>"
diff --git a/gdb/solib-svr4.c b/gdb/solib-svr4.c
index 307e483..e129197 100644
--- a/gdb/solib-svr4.c
+++ b/gdb/solib-svr4.c
@@ -50,6 +50,8 @@
static struct link_map_offsets *svr4_fetch_link_map_offsets (void);
static int svr4_have_link_map_offsets (void);
static void svr4_relocate_main_executable (void);
+static const char *svr4_map_so_name(char *name);
+static int svr4_have_map_so_name (void);
/* Link map info to include in an allocated so_list entry. */
@@ -1227,7 +1229,15 @@
continue;
}
- strncpy (new->so_name, buffer, SO_NAME_MAX_PATH_SIZE - 1);
+ if (svr4_have_map_so_name ())
+ {
+ strncpy (new->so_name, svr4_map_so_name (buffer),
+ SO_NAME_MAX_PATH_SIZE - 1);
+ }
+ else
+ {
+ strncpy (new->so_name, buffer, SO_NAME_MAX_PATH_SIZE - 1);
+ }
new->so_name[SO_NAME_MAX_PATH_SIZE - 1] = '\0';
strcpy (new->so_original_name, new->so_name);
xfree (buffer);
@@ -1292,7 +1302,7 @@
/* Assume that everything is a library if the dynamic loader was loaded
late by a static executable. */
- if (exec_bfd && bfd_get_section_by_name (exec_bfd, ".dynamic") == NULL)
+ if (exec_bfd && find_program_interpreter() == NULL)
ignore_first = 0;
else
ignore_first = 1;
@@ -2326,6 +2336,8 @@
{
/* Return a description of the layout of `struct link_map'. */
struct link_map_offsets *(*fetch_link_map_offsets)(void);
+ /* Return real path for the solib name given by ld.so. */
+ const char *(*map_so_name)(char*);
};
/* Return a default for the architecture-specific operations. */
@@ -2337,6 +2349,7 @@
ops = OBSTACK_ZALLOC (obstack, struct solib_svr4_ops);
ops->fetch_link_map_offsets = NULL;
+ ops->map_so_name = NULL;
return ops;
}
@@ -2354,6 +2367,17 @@
set_solib_ops (gdbarch, &svr4_so_ops);
}
+/* Set function to map ld.so solib names to real paths. */
+
+void
+set_solib_svr4_map_so_name(struct gdbarch *gdbarch,
+ const char* (*map_so_name) (char*))
+{
+ struct solib_svr4_ops *ops = gdbarch_data (gdbarch, solib_svr4_data);
+
+ ops->map_so_name = map_so_name;
+}
+
/* Fetch a link_map_offsets structure using the architecture-specific
`struct link_map_offsets' fetcher. */
@@ -2375,6 +2399,25 @@
return (ops->fetch_link_map_offsets != NULL);
}
+
+/* Return real path for the solib name given by ld.so. */
+
+static const char *
+svr4_map_so_name(char *name)
+{
+ struct solib_svr4_ops *ops = gdbarch_data (target_gdbarch, solib_svr4_data);
+ gdb_assert (ops->map_so_name);
+ return ops->map_so_name (name);
+}
+
+/* Return 1 if a solib name map function has been defined, 0 otherwise. */
+
+static int
+svr4_have_map_so_name(void)
+{
+ struct solib_svr4_ops *ops = gdbarch_data (target_gdbarch, solib_svr4_data);
+ return (ops->map_so_name != NULL);
+}
/* Most OS'es that have SVR4-style ELF dynamic libraries define a
diff --git a/gdb/solib-svr4.h b/gdb/solib-svr4.h
index f9a02c9..e90a24d 100644
--- a/gdb/solib-svr4.h
+++ b/gdb/solib-svr4.h
@@ -71,6 +71,9 @@
extern void set_solib_svr4_fetch_link_map_offsets
(struct gdbarch *gdbarch, struct link_map_offsets *(*func) (void));
+extern void set_solib_svr4_map_so_name
+ (struct gdbarch *gdbarch, const char *(*map_so_name) (char*));
+
/* This function is called by thread_db.c. Return the address of the
link map for the given objfile. */
extern CORE_ADDR svr4_fetch_objfile_link_map (struct objfile *objfile);