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, ®);
+ 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)
{