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);