Merge GDB 7.6.50

Pulled in from:
ftp://sourceware.org/pub/gdb/snapshots/current/gdb-7.6.50.20131211.tar.bz2

Fixes included:
- reorder lines to move declarations to top of functions in gdb/amd-tdep.c
- new header includes in nacl-manifest.c
- target_gdbarch uses changed to target_gdbarch() as it's now a function
pointer

BUG=None
TEST=gdb_tests + debug_stub_tests
R=halyavin@google.com, eaeltsin@google.com, mcgrathr@chromium.org
diff --git a/gdb/amd64-linux-tdep.c b/gdb/amd64-linux-tdep.c
index 7fe92d1..dd78f3a 100644
--- a/gdb/amd64-linux-tdep.c
+++ b/gdb/amd64-linux-tdep.c
@@ -1535,6 +1535,14 @@
   tdep->i386_syscall_record = amd64_linux_syscall_record;
 }
 
+void
+amd64_linux_init_gregset (struct gdbarch_tdep *tdep)
+{
+  tdep->gregset_reg_offset = amd64_linux_gregset_reg_offset;
+  tdep->gregset_num_regs = ARRAY_SIZE (amd64_linux_gregset_reg_offset);
+  tdep->sizeof_gregset = 27 * 8;
+}
+
 static void
 amd64_linux_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
 {
@@ -1546,10 +1554,7 @@
 
   gdb_assert (tdesc_data);
 
-  tdep->gregset_reg_offset = amd64_linux_gregset_reg_offset;
-  tdep->gregset_num_regs = ARRAY_SIZE (amd64_linux_gregset_reg_offset);
-  tdep->sizeof_gregset = 27 * 8;
-
+  amd64_linux_init_gregset (tdep);
   amd64_init_abi (info, gdbarch);
 
   /* Reserve a number for orig_rax.  */
diff --git a/gdb/amd64-linux-tdep.h b/gdb/amd64-linux-tdep.h
index 6e85a5b..ed54dfb 100644
--- a/gdb/amd64-linux-tdep.h
+++ b/gdb/amd64-linux-tdep.h
@@ -311,4 +311,6 @@
   amd64_sys_move_pages = 279,
 };
 
+extern void amd64_linux_init_gregset (struct gdbarch_tdep *tdep);
+
 #endif /* amd64-linux-tdep.h */
diff --git a/gdb/amd64-tdep.c b/gdb/amd64-tdep.c
index 19968fc..6a2af29 100644
--- a/gdb/amd64-tdep.c
+++ b/gdb/amd64-tdep.c
@@ -2062,6 +2062,75 @@
   return min (pc + offset + 2, current_pc);
 }
 
+/* Check whether it is mov %ebp,%reg instruction.  The function returns the
+   size of instruction or zero if it is not recognized.  Fills reg with the
+   destination register number.  */
+static int
+amd64_is_mov_rbp_reg(gdb_byte* op, int* reg)
+{
+  int cur = 0;
+  *reg = 0;
+  /* [0x40] 0x89 0xe8  mov %ebp, %eax  */
+  if (op[cur] == 0x40 || op[cur] == 0x41)
+    {
+      cur++;
+      *reg += (op[cur] & 1) * 8;
+    }
+  if (op[cur] == 0x89 && (op[cur + 1] & 0xf8) == 0xe8)
+    {
+      *reg += op[cur + 1] & 7;
+      return cur + 2;
+    }
+  cur = 0;
+  *reg = 0;
+  /* [0x40] 0x8b 0xc5  mov %ebp, %eax  */
+  if (op[cur] == 0x40 || op[cur] == 0x44)
+    {
+      *reg += (op[cur] & 4) * 2;
+      cur++;
+    }
+  if (op[cur] == 0x8b && (op[cur + 1] & 0xc7) == 0xc5)
+    {
+      reg += (op[cur + 1] >> 3) & 7;
+      return cur + 2;
+    }
+  *reg = 0;
+  return 0;
+}
+
+/* Check whether it is push %rbp instruction or equivalent sequence
+   mov %ebp, %reg // push %reg.  Returns size of the instruction or zero
+   if it is not recognized.  */
+static int
+amd64_is_push_rbp(CORE_ADDR pc)
+{
+  int cur = 0;
+  int reg = 0;
+  int reg_push = 0;
+  gdb_byte op[5];
+  if (target_read_code(pc, op, 5) != 0)
+    return 0;
+  /* 55  push %rbp  */
+  if (op[0] == 0x55)
+    return 1;
+  cur = amd64_is_mov_rbp_reg(op, &reg);
+  if (cur == 0)
+    return 0;
+  /* Recognize push %reg instruction. */
+  if (op[cur] == 0x40 || op[cur] == 0x41)
+    {
+      reg_push += (op[cur] & 1) * 8;
+      cur++;
+    }
+  if ((op[cur] & 0xf8) == 0x50)
+    {
+      reg_push += op[cur] & 7;
+      if (reg == reg_push)
+	return cur + 1;
+    }
+  return 0;
+}
+
 /* Do a limited analysis of the prologue at PC and update CACHE
    accordingly.  Bail out early if CURRENT_PC is reached.  Return the
    address where the analysis stopped.
@@ -2094,7 +2163,7 @@
   static const gdb_byte mov_esp_ebp_2[2] = { 0x8b, 0xec };
 
   gdb_byte buf[3];
-  gdb_byte op;
+  int push_rbp_size;
 
   if (current_pc <= pc)
     return current_pc;
@@ -2104,20 +2173,22 @@
   else
     pc = amd64_analyze_stack_align (pc, current_pc, cache);
 
-  op = read_code_unsigned_integer (pc, 1, byte_order);
+  push_rbp_size = amd64_is_push_rbp(pc);
 
-  if (op == 0x55)		/* pushq %rbp */
+  if (push_rbp_size)		/* pushq %rbp */
     {
       /* Take into account that we've executed the `pushq %rbp' that
          starts this instruction sequence.  */
       cache->saved_regs[AMD64_RBP_REGNUM] = 0;
       cache->sp_offset += 8;
 
+      pc += push_rbp_size;
+
       /* If that's all, return now.  */
-      if (current_pc <= pc + 1)
+      if (current_pc <= pc)
         return current_pc;
 
-      read_code (pc + 1, buf, 3);
+      read_code (pc, buf, 3);
 
       /* Check for `movq %rsp, %rbp'.  */
       if (memcmp (buf, mov_rsp_rbp_1, 3) == 0
@@ -2125,7 +2196,7 @@
 	{
 	  /* OK, we actually have a frame.  */
 	  cache->frameless_p = 0;
-	  return pc + 4;
+	  return pc + 3;
 	}
 
       /* For X32, also check for `movq %esp, %ebp'.  */
@@ -2136,11 +2207,11 @@
 	    {
 	      /* OK, we actually have a frame.  */
 	      cache->frameless_p = 0;
-	      return pc + 3;
+	      return pc + 2;
 	    }
 	}
 
-      return pc + 1;
+      return pc;
     }
 
   return pc;
diff --git a/gdb/configure.tgt b/gdb/configure.tgt
index 47e98d9..f9a5ed1 100644
--- a/gdb/configure.tgt
+++ b/gdb/configure.tgt
@@ -228,6 +228,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 1469299..5ff11ba 100644
--- a/gdb/defs.h
+++ b/gdb/defs.h
@@ -591,6 +591,7 @@
   GDB_OSABI_DICOS,
   GDB_OSABI_DARWIN,
   GDB_OSABI_SYMBIAN,
+  GDB_OSABI_NACL,
   GDB_OSABI_OPENVMS,
   GDB_OSABI_LYNXOS178,
   GDB_OSABI_NEWLIB,
diff --git a/gdb/features/i386/amd64-linux.c b/gdb/features/i386/amd64-linux.c
index 8cbf4bf..1c8875b 100644
--- a/gdb/features/i386/amd64-linux.c
+++ b/gdb/features/i386/amd64-linux.c
@@ -44,8 +44,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");
@@ -54,7 +54,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/frame.c b/gdb/frame.c
index 6a8b5ae..79dea26 100644
--- a/gdb/frame.c
+++ b/gdb/frame.c
@@ -558,6 +558,7 @@
 frame_id_eq (struct frame_id l, struct frame_id r)
 {
   int eq;
+  const uint32_t max_addr = (uint32_t) -1;
 
   if (!l.stack_addr_p && l.special_addr_p
       && !r.stack_addr_p && r.special_addr_p)
@@ -571,7 +572,12 @@
     /* Like a NaN, if either ID is invalid, the result is false.
        Note that a frame ID is invalid iff it is the null frame ID.  */
     eq = 0;
-  else if (l.stack_addr != r.stack_addr)
+    /* Hack for PNaCl support.  Due to base address hiding
+       stack_addr may differ by base address.  This creates false
+       positives for normal 64-bit mode, so we need to find a better way.  */
+  else if ((l.stack_addr != r.stack_addr && l.stack_addr > max_addr
+	   && r.stack_addr > max_addr)
+	   || (uint32_t)l.stack_addr != (uint32_t)r.stack_addr)
     /* If .stack addresses are different, the frames are different.  */
     eq = 0;
   else if (l.code_addr_p && r.code_addr_p && l.code_addr != r.code_addr)
diff --git a/gdb/i386-linux-tdep.c b/gdb/i386-linux-tdep.c
index b46a51e..ef006e8 100644
--- a/gdb/i386-linux-tdep.c
+++ b/gdb/i386-linux-tdep.c
@@ -709,6 +709,14 @@
   return closure;
 }
 
+void
+i386_linux_init_gregset (struct gdbarch_tdep *tdep)
+{
+  tdep->gregset_reg_offset = i386_linux_gregset_reg_offset;
+  tdep->gregset_num_regs = ARRAY_SIZE (i386_linux_gregset_reg_offset);
+  tdep->sizeof_gregset = 17 * 4;
+}
+
 static void
 i386_linux_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
 {
@@ -747,9 +755,7 @@
 
   tdep->register_reggroup_p = i386_linux_register_reggroup_p;
 
-  tdep->gregset_reg_offset = i386_linux_gregset_reg_offset;
-  tdep->gregset_num_regs = ARRAY_SIZE (i386_linux_gregset_reg_offset);
-  tdep->sizeof_gregset = 17 * 4;
+  i386_linux_init_gregset (tdep);
 
   tdep->jb_pc_offset = 20;	/* From <bits/setjmp.h>.  */
 
diff --git a/gdb/i386-linux-tdep.h b/gdb/i386-linux-tdep.h
index 54b5058..cd3d2c1 100644
--- a/gdb/i386-linux-tdep.h
+++ b/gdb/i386-linux-tdep.h
@@ -67,4 +67,6 @@
 
 extern int i386_linux_gregset_reg_offset[];
 
+extern void i386_linux_init_gregset (struct gdbarch_tdep *tdep);
+
 #endif /* i386-linux-tdep.h */
diff --git a/gdb/nacl-manifest.c b/gdb/nacl-manifest.c
new file mode 100644
index 0000000..a6c4788
--- /dev/null
+++ b/gdb/nacl-manifest.c
@@ -0,0 +1,440 @@
+/* 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 "nacl-manifest.h"
+
+#include "defs.h"
+#include "command.h"
+#include "completer.h"
+#include "exec.h"
+#include "frame.h"
+#include "gdbcore.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_file_list_32 = NULL;
+  nacl_manifest_free_list(nacl_file_list_64);
+  nacl_file_list_64 = NULL;
+  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,
+		 const 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 (void)
+{
+  if (exec_bfd == NULL)
+    {
+      const char *filename = nacl_manifest_find ("NaClMain");
+      exec_file_attach ((char *) 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);
+    }
+}
+
+/* Provide a prototype to silence -Wmissing-prototypes.  */
+extern void _initialize_nacl_manifest (void);
+
+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..068033c
--- /dev/null
+++ b/gdb/nacl-tdep.c
@@ -0,0 +1,250 @@
+/* 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)
+{
+  /* We removed Linux remote debugging support from NaCl debugger, so we must
+     handle all ELF files ourselves now.
+
+     If we want to support both Linux and NaCl remote debugging simultaneously,
+     we would have to find some way to distinguish NaCl and Linux binaries here.
+     Currently there is no way to distinguish PNaCl-produced binaries from
+     Linux binaries.
+
+     See issues https://code.google.com/p/nativeclient/issues/detail?id=2971 and
+     https://code.google.com/p/nativeclient/issues/detail?id=3313
+     for details.  */
+  if (bfd_get_flavour (abfd) == bfd_target_elf_flavour)
+    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);
+  i386_linux_init_gregset (tdep);
+  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);
+}
+
+static 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 int
+amd64_nacl_inner_than (CORE_ADDR lhs, CORE_ADDR rhs)
+{
+  return (uint32_t)lhs < (uint32_t)rhs;
+}
+
+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);
+  amd64_linux_init_gregset (tdep);
+  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);
+  set_gdbarch_inner_than (gdbarch, amd64_nacl_inner_than);
+
+  /* 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 a170974..93f434a 100644
--- a/gdb/osabi.c
+++ b/gdb/osabi.c
@@ -71,6 +71,7 @@
   "DICOS",
   "Darwin",
   "Symbian",
+  "NaCl",
   "OpenVMS",
   "LynxOS178",
   "Newlib",
diff --git a/gdb/solib-svr4.c b/gdb/solib-svr4.c
index 9538af6..0a7c1ca 100644
--- a/gdb/solib-svr4.c
+++ b/gdb/solib-svr4.c
@@ -51,6 +51,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);
 static void svr4_free_library_list (void *p_list);
 
 /* Link map info to include in an allocated so_list entry.  */
@@ -1369,7 +1371,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);
@@ -1435,7 +1445,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;
@@ -2985,6 +2995,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.  */
@@ -2996,6 +3008,7 @@
 
   ops = OBSTACK_ZALLOC (obstack, struct solib_svr4_ops);
   ops->fetch_link_map_offsets = NULL;
+  ops->map_so_name = NULL;
   return ops;
 }
 
@@ -3013,6 +3026,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.  */
 
@@ -3034,6 +3058,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 66a06e1..ff04d2f 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);
diff --git a/gdb/utils.c b/gdb/utils.c
index 975c432..4172f23 100644
--- a/gdb/utils.c
+++ b/gdb/utils.c
@@ -72,6 +72,10 @@
 #include "interps.h"
 #include "gdb_regex.h"
 
+#if defined(_WIN32) && !defined(__CYGWIN__)
+#include <windows.h>
+#endif
+
 #if !HAVE_DECL_MALLOC
 extern PTR malloc ();		/* ARI: PTR */
 #endif
@@ -193,6 +197,20 @@
 }
 
 
+#if defined(_WIN32) && !defined(__CYGWIN__)
+
+static void
+do_freeargv (void *arg)
+{
+  int i = 0;
+  char** args = (char**) arg;
+  for (i = 0; args[i] != NULL; i++)
+    free(args[i]);
+  free(args);
+}
+
+#else
+
 /* Cleanup utilities.
 
    These are not defined in cleanups.c (nor declared in cleanups.h)
@@ -205,6 +223,8 @@
   freeargv ((char **) arg);
 }
 
+#endif
+
 struct cleanup *
 make_cleanup_freeargv (char **arg)
 {
@@ -3484,6 +3504,45 @@
   return dirname;
 }
 
+#if defined(_WIN32) && !defined(__CYGWIN__)
+
+char **
+gdb_buildargv (const char *s)
+{
+  LPWSTR wide_string;
+  int wide_len;
+  int arg_len;
+  int num_args;
+  LPWSTR* args;
+  char** result;
+  int i;
+  if (s == NULL)
+    return NULL;
+  wide_len = MultiByteToWideChar(CP_UTF8, 0, s, -1, NULL, 0);
+  wide_string = malloc(2 * wide_len);
+  if (wide_string == NULL)
+    malloc_failure (0);
+  MultiByteToWideChar(CP_UTF8, 0, s, -1, wide_string, wide_len);
+  args = CommandLineToArgvW(wide_string, &num_args);
+  free(wide_string);
+  result = malloc((num_args + 1) * sizeof(char*));
+  for (i = 0; i < num_args; i++)
+    {
+      arg_len = WideCharToMultiByte(CP_UTF8, 0, args[i], -1, NULL, 0,
+                                    NULL, NULL);
+      result[i] = malloc(arg_len);
+      if (result[i] == NULL)
+        malloc_failure(0);
+      WideCharToMultiByte(CP_UTF8, 0, args[i], -1, result[i], arg_len,
+                          NULL, NULL);
+    }
+  result[num_args] = NULL;
+  LocalFree(args);
+  return result;
+}
+
+#else
+
 /* Call libiberty's buildargv, and return the result.
    If buildargv fails due to out-of-memory, call nomem.
    Therefore, the returned value is guaranteed to be non-NULL,
@@ -3499,6 +3558,8 @@
   return argv;
 }
 
+#endif
+
 int
 compare_positive_ints (const void *ap, const void *bp)
 {