6b2dd0f
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
78e1a10
From: Peter Jones <pjones@redhat.com>
e153146
Date: Tue, 9 Jul 2019 17:05:03 +0200
31cddd6
Subject: [PATCH] make better backtraces
78e1a10
78e1a10
Signed-off-by: Peter Jones <pjones@redhat.com>
78e1a10
---
15a2072
 Makefile.util.def                       |   6 ++
e153146
 grub-core/Makefile.core.def             |  16 ++--
78e1a10
 grub-core/{lib => commands}/backtrace.c |   2 +-
78e1a10
 grub-core/gdb/cstub.c                   |   1 -
15a2072
 grub-core/kern/arm64/backtrace.c        |  94 ++++++++++++++++++++++++
15a2072
 grub-core/kern/backtrace.c              |  97 +++++++++++++++++++++++++
78e1a10
 grub-core/kern/dl.c                     |  45 ++++++++++++
15a2072
 grub-core/kern/i386/backtrace.c         | 125 ++++++++++++++++++++++++++++++++
78e1a10
 grub-core/kern/i386/pc/init.c           |   4 +-
78e1a10
 grub-core/kern/ieee1275/init.c          |   1 -
78e1a10
 grub-core/kern/misc.c                   |  13 ++--
78e1a10
 grub-core/kern/mm.c                     |   6 +-
78e1a10
 grub-core/lib/arm64/backtrace.c         |  62 ----------------
78e1a10
 grub-core/lib/i386/backtrace.c          |  78 --------------------
78e1a10
 include/grub/backtrace.h                |  10 ++-
78e1a10
 include/grub/dl.h                       |   2 +
78e1a10
 include/grub/kernel.h                   |   3 +
78e1a10
 grub-core/kern/arm/efi/startup.S        |   2 +
78e1a10
 grub-core/kern/arm/startup.S            |   2 +
78e1a10
 grub-core/kern/arm64/efi/startup.S      |   2 +
78e1a10
 grub-core/kern/i386/qemu/startup.S      |   3 +-
78e1a10
 grub-core/kern/ia64/efi/startup.S       |   3 +-
78e1a10
 grub-core/kern/sparc64/ieee1275/crt0.S  |   3 +-
78e1a10
 grub-core/Makefile.am                   |   1 +
e153146
 24 files changed, 414 insertions(+), 167 deletions(-)
78e1a10
 rename grub-core/{lib => commands}/backtrace.c (98%)
78e1a10
 create mode 100644 grub-core/kern/arm64/backtrace.c
78e1a10
 create mode 100644 grub-core/kern/backtrace.c
78e1a10
 create mode 100644 grub-core/kern/i386/backtrace.c
78e1a10
 delete mode 100644 grub-core/lib/arm64/backtrace.c
78e1a10
 delete mode 100644 grub-core/lib/i386/backtrace.c
78e1a10
15a2072
diff --git a/Makefile.util.def b/Makefile.util.def
46968b6
index afc4d7b0c3e..41906486a71 100644
15a2072
--- a/Makefile.util.def
15a2072
+++ b/Makefile.util.def
46968b6
@@ -51,6 +51,12 @@ library = {
15a2072
   common = grub-core/partmap/msdos.c;
15a2072
   common = grub-core/fs/proc.c;
15a2072
   common = grub-core/fs/archelp.c;
15a2072
+  common = grub-core/kern/backtrace.c;
15a2072
+
15a2072
+  x86 = grub-core/kern/i386/backtrace.c;
15a2072
+  i386_xen = grub-core/kern/i386/backtrace.c;
15a2072
+  x86_64_xen = grub-core/kern/i386/backtrace.c;
15a2072
+  arm64 = grub-core/kern/arm64/backtrace.c;
15a2072
 };
15a2072
 
15a2072
 library = {
78e1a10
diff --git a/grub-core/Makefile.core.def b/grub-core/Makefile.core.def
46968b6
index 5354f9613d3..4b7c45a7b06 100644
78e1a10
--- a/grub-core/Makefile.core.def
78e1a10
+++ b/grub-core/Makefile.core.def
46968b6
@@ -142,6 +142,12 @@ kernel = {
78e1a10
   common = kern/rescue_reader.c;
78e1a10
   common = kern/term.c;
46968b6
   common = kern/verifiers.c;
78e1a10
+  common = kern/backtrace.c;
78e1a10
+
78e1a10
+  x86 = kern/i386/backtrace.c;
78e1a10
+  i386_xen = kern/i386/backtrace.c;
78e1a10
+  x86_64_xen = kern/i386/backtrace.c;
78e1a10
+  arm64 = kern/arm64/backtrace.c;
78e1a10
 
78e1a10
   noemu = kern/compiler-rt.c;
78e1a10
   noemu = kern/mm.c;
46968b6
@@ -188,9 +194,6 @@ kernel = {
78e1a10
 
78e1a10
   softdiv = lib/division.c;
78e1a10
 
78e1a10
-  x86 = lib/i386/backtrace.c;
78e1a10
-  x86 = lib/backtrace.c;
78e1a10
-
78e1a10
   i386 = kern/i386/dl.c;
78e1a10
   i386_xen = kern/i386/dl.c;
e153146
   i386_xen_pvh = kern/i386/dl.c;
46968b6
@@ -2398,15 +2401,12 @@ module = {
78e1a10
 
78e1a10
 module = {
78e1a10
   name = backtrace;
78e1a10
-  x86 = lib/i386/backtrace.c;
e153146
-  i386_xen_pvh = lib/i386/backtrace.c;
78e1a10
-  i386_xen = lib/i386/backtrace.c;
78e1a10
-  x86_64_xen = lib/i386/backtrace.c;
78e1a10
-  common = lib/backtrace.c;
78e1a10
+  common = commands/backtrace.c;
78e1a10
   enable = x86;
e153146
   enable = i386_xen_pvh;
78e1a10
   enable = i386_xen;
78e1a10
   enable = x86_64_xen;
78e1a10
+  enable = arm64;
78e1a10
 };
78e1a10
 
78e1a10
 module = {
78e1a10
diff --git a/grub-core/lib/backtrace.c b/grub-core/commands/backtrace.c
78e1a10
similarity index 98%
78e1a10
rename from grub-core/lib/backtrace.c
78e1a10
rename to grub-core/commands/backtrace.c
78e1a10
index c0ad6ab8be1..8b5ec3913b5 100644
78e1a10
--- a/grub-core/lib/backtrace.c
78e1a10
+++ b/grub-core/commands/backtrace.c
78e1a10
@@ -54,7 +54,7 @@ grub_cmd_backtrace (grub_command_t cmd __attribute__ ((unused)),
78e1a10
 		    int argc __attribute__ ((unused)),
78e1a10
 		    char **args __attribute__ ((unused)))
78e1a10
 {
78e1a10
-  grub_backtrace ();
78e1a10
+  grub_backtrace (1);
78e1a10
   return 0;
78e1a10
 }
78e1a10
 
78e1a10
diff --git a/grub-core/gdb/cstub.c b/grub-core/gdb/cstub.c
78e1a10
index b64acd70fee..99281472d36 100644
78e1a10
--- a/grub-core/gdb/cstub.c
78e1a10
+++ b/grub-core/gdb/cstub.c
78e1a10
@@ -215,7 +215,6 @@ grub_gdb_trap (int trap_no)
78e1a10
       grub_printf ("Unhandled exception 0x%x at ", trap_no);
78e1a10
       grub_backtrace_print_address ((void *) grub_gdb_regs[PC]);
78e1a10
       grub_printf ("\n");
78e1a10
-      grub_backtrace_pointer ((void *) grub_gdb_regs[EBP]);
78e1a10
       grub_fatal ("Unhandled exception");
78e1a10
     }
78e1a10
 
78e1a10
diff --git a/grub-core/kern/arm64/backtrace.c b/grub-core/kern/arm64/backtrace.c
78e1a10
new file mode 100644
78e1a10
index 00000000000..019c6fdfef2
78e1a10
--- /dev/null
78e1a10
+++ b/grub-core/kern/arm64/backtrace.c
78e1a10
@@ -0,0 +1,94 @@
78e1a10
+/*
78e1a10
+ *  GRUB  --  GRand Unified Bootloader
78e1a10
+ *  Copyright (C) 2009  Free Software Foundation, Inc.
78e1a10
+ *
78e1a10
+ *  GRUB is free software: you can redistribute it and/or modify
78e1a10
+ *  it under the terms of the GNU General Public License as published by
78e1a10
+ *  the Free Software Foundation, either version 3 of the License, or
78e1a10
+ *  (at your option) any later version.
78e1a10
+ *
78e1a10
+ *  GRUB is distributed in the hope that it will be useful,
78e1a10
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
78e1a10
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
78e1a10
+ *  GNU General Public License for more details.
78e1a10
+ *
78e1a10
+ *  You should have received a copy of the GNU General Public License
78e1a10
+ *  along with GRUB.  If not, see <http://www.gnu.org/licenses/>.
78e1a10
+ */
78e1a10
+
78e1a10
+#include <grub/misc.h>
78e1a10
+#include <grub/command.h>
78e1a10
+#include <grub/err.h>
78e1a10
+#include <grub/dl.h>
78e1a10
+#include <grub/mm.h>
78e1a10
+#include <grub/term.h>
78e1a10
+#include <grub/backtrace.h>
78e1a10
+
78e1a10
+#define MAX_STACK_FRAME 102400
78e1a10
+
78e1a10
+struct fplr
78e1a10
+{
78e1a10
+  void *lr;
78e1a10
+  struct fplr *fp;
78e1a10
+};
78e1a10
+
78e1a10
+void
78e1a10
+grub_backtrace_pointer (void *frame, unsigned int skip)
78e1a10
+{
78e1a10
+  unsigned int x = 0;
78e1a10
+  struct fplr *fplr = (struct fplr *)frame;
78e1a10
+
78e1a10
+  while (fplr)
78e1a10
+    {
78e1a10
+      const char *name = NULL;
78e1a10
+      char *addr = NULL;
78e1a10
+
78e1a10
+      grub_dprintf("backtrace", "fp is %p next_fp is %p\n",
78e1a10
+		   fplr, fplr->fp);
78e1a10
+
78e1a10
+      if (x >= skip)
78e1a10
+	{
78e1a10
+	  name = grub_get_symbol_by_addr (fplr->lr, 1);
78e1a10
+	  if (name)
78e1a10
+	    addr = grub_resolve_symbol (name);
78e1a10
+	  grub_backtrace_print_address (fplr->lr);
78e1a10
+
78e1a10
+	  if (addr && addr != fplr->lr)
78e1a10
+	    grub_printf (" %s() %p+%p \n", name ? name : "unknown", addr,
78e1a10
+			 (void *)((grub_uint64_t)fplr->lr - (grub_uint64_t)addr));
78e1a10
+	  else
78e1a10
+	    grub_printf(" %s() %p \n", name ? name : "unknown", addr);
78e1a10
+
78e1a10
+	}
78e1a10
+
78e1a10
+      x += 1;
78e1a10
+
78e1a10
+      if (fplr->fp < fplr ||
78e1a10
+	  (grub_uint64_t)fplr->fp - (grub_uint64_t)fplr > MAX_STACK_FRAME ||
78e1a10
+	  fplr->fp == fplr)
78e1a10
+	{
78e1a10
+	  break;
78e1a10
+	}
78e1a10
+      fplr = fplr->fp;
78e1a10
+    }
78e1a10
+}
78e1a10
+
78e1a10
+asm ("\t.global \"_text\"\n"
78e1a10
+     "_text:\n"
78e1a10
+     "\t.quad .text\n"
78e1a10
+     "\t.global \"_data\"\n"
78e1a10
+     "_data:\n"
78e1a10
+     "\t.quad .data\n"
78e1a10
+     );
78e1a10
+
78e1a10
+extern grub_uint64_t _text;
78e1a10
+extern grub_uint64_t _data;
78e1a10
+
78e1a10
+void
78e1a10
+grub_backtrace_arch (unsigned int skip)
78e1a10
+{
78e1a10
+  grub_printf ("Backtrace (.text %p .data %p):\n",
78e1a10
+	       (void *)_text, (void *)_data);
78e1a10
+  skip += 1;
78e1a10
+  grub_backtrace_pointer(__builtin_frame_address(0), skip);
78e1a10
+}
78e1a10
diff --git a/grub-core/kern/backtrace.c b/grub-core/kern/backtrace.c
78e1a10
new file mode 100644
15a2072
index 00000000000..4a82e865cc6
78e1a10
--- /dev/null
78e1a10
+++ b/grub-core/kern/backtrace.c
15a2072
@@ -0,0 +1,97 @@
78e1a10
+/*
78e1a10
+ *  GRUB  --  GRand Unified Bootloader
78e1a10
+ *  Copyright (C) 2009  Free Software Foundation, Inc.
78e1a10
+ *
78e1a10
+ *  GRUB is free software: you can redistribute it and/or modify
78e1a10
+ *  it under the terms of the GNU General Public License as published by
78e1a10
+ *  the Free Software Foundation, either version 3 of the License, or
78e1a10
+ *  (at your option) any later version.
78e1a10
+ *
78e1a10
+ *  GRUB is distributed in the hope that it will be useful,
78e1a10
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
78e1a10
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
78e1a10
+ *  GNU General Public License for more details.
78e1a10
+ *
78e1a10
+ *  You should have received a copy of the GNU General Public License
78e1a10
+ *  along with GRUB.  If not, see <http://www.gnu.org/licenses/>.
78e1a10
+ */
78e1a10
+
78e1a10
+#include <grub/misc.h>
78e1a10
+#include <grub/command.h>
78e1a10
+#include <grub/err.h>
78e1a10
+#include <grub/dl.h>
78e1a10
+#include <grub/mm.h>
78e1a10
+#include <grub/term.h>
78e1a10
+#include <grub/backtrace.h>
78e1a10
+
78e1a10
+GRUB_MOD_LICENSE ("GPLv3+");
78e1a10
+
78e1a10
+static void
78e1a10
+grub_backtrace_print_address_default (void *addr)
78e1a10
+{
15a2072
+#ifndef GRUB_UTIL
78e1a10
+  grub_dl_t mod;
78e1a10
+  void *start_addr;
78e1a10
+
78e1a10
+  FOR_DL_MODULES (mod)
78e1a10
+  {
78e1a10
+    grub_dl_segment_t segment;
78e1a10
+    for (segment = mod->segment; segment; segment = segment->next)
78e1a10
+      if (segment->addr <= addr && (grub_uint8_t *) segment->addr
78e1a10
+	  + segment->size > (grub_uint8_t *) addr)
78e1a10
+	{
78e1a10
+	  grub_printf ("%s.%x+%" PRIxGRUB_SIZE, mod->name,
78e1a10
+		       segment->section,
78e1a10
+		       (grub_size_t)
78e1a10
+		       ((grub_uint8_t *)addr - (grub_uint8_t *)segment->addr));
78e1a10
+	  return;
78e1a10
+	}
78e1a10
+  }
78e1a10
+
78e1a10
+  start_addr = grub_resolve_symbol ("_start");
78e1a10
+  if (start_addr && start_addr < addr)
78e1a10
+    grub_printf ("kernel+%" PRIxGRUB_SIZE,
78e1a10
+		 (grub_size_t)
78e1a10
+		  ((grub_uint8_t *)addr - (grub_uint8_t *)start_addr));
78e1a10
+  else
15a2072
+#endif
78e1a10
+    grub_printf ("%p", addr);
78e1a10
+}
78e1a10
+
78e1a10
+static void
78e1a10
+grub_backtrace_pointer_default (void *frame __attribute__((__unused__)),
78e1a10
+				unsigned int skip __attribute__((__unused__)))
78e1a10
+{
78e1a10
+  return;
78e1a10
+}
78e1a10
+
78e1a10
+void
78e1a10
+grub_backtrace_pointer (void *frame, unsigned int skip)
78e1a10
+     __attribute__((__weak__,
78e1a10
+		    __alias__(("grub_backtrace_pointer_default"))));
78e1a10
+
78e1a10
+void
78e1a10
+grub_backtrace_print_address (void *addr)
78e1a10
+     __attribute__((__weak__,
78e1a10
+		    __alias__(("grub_backtrace_print_address_default"))));
78e1a10
+
78e1a10
+static void
78e1a10
+grub_backtrace_arch_default(unsigned int skip)
78e1a10
+{
78e1a10
+  grub_backtrace_pointer(__builtin_frame_address(0), skip + 1);
78e1a10
+}
78e1a10
+
78e1a10
+void grub_backtrace_arch (unsigned int skip)
78e1a10
+     __attribute__((__weak__, __alias__(("grub_backtrace_arch_default"))));
78e1a10
+
78e1a10
+void grub_backtrace (unsigned int skip)
78e1a10
+{
78e1a10
+  grub_backtrace_arch(skip + 1);
78e1a10
+}
78e1a10
+
78e1a10
+void grub_debug_backtrace (const char * const debug,
78e1a10
+			   unsigned int skip)
78e1a10
+{
78e1a10
+  if (grub_debug_enabled (debug))
78e1a10
+    grub_backtrace (skip + 1);
78e1a10
+}
78e1a10
diff --git a/grub-core/kern/dl.c b/grub-core/kern/dl.c
46968b6
index 7afb9e6f724..88d2077709e 100644
78e1a10
--- a/grub-core/kern/dl.c
78e1a10
+++ b/grub-core/kern/dl.c
78e1a10
@@ -124,6 +124,50 @@ grub_dl_resolve_symbol (const char *name)
78e1a10
   return 0;
78e1a10
 }
78e1a10
 
78e1a10
+void *
78e1a10
+grub_resolve_symbol (const char *name)
78e1a10
+{
78e1a10
+	grub_symbol_t sym;
78e1a10
+
78e1a10
+	sym = grub_dl_resolve_symbol (name);
78e1a10
+	if (sym)
78e1a10
+		return sym->addr;
78e1a10
+	return NULL;
78e1a10
+}
78e1a10
+
78e1a10
+const char *
78e1a10
+grub_get_symbol_by_addr(const void *addr, int isfunc)
78e1a10
+{
78e1a10
+  unsigned int i;
78e1a10
+  grub_symbol_t before = NULL, after = NULL;
78e1a10
+  for (i = 0; i < GRUB_SYMTAB_SIZE; i++)
78e1a10
+    {
78e1a10
+      grub_symbol_t sym;
78e1a10
+      for (sym = grub_symtab[i]; sym; sym = sym->next)
78e1a10
+	{
78e1a10
+	  //grub_printf ("addr 0x%08llx symbol %s\n", (unsigned long long)sym->addr, sym->name);
78e1a10
+	  if (sym->addr > addr)
78e1a10
+	    {
78e1a10
+	      if (!after || sym->addr > after->addr)
78e1a10
+		after = sym;
78e1a10
+	    }
78e1a10
+
78e1a10
+	  if (isfunc != sym->isfunc)
78e1a10
+	    continue;
78e1a10
+	  if (sym->addr > addr)
78e1a10
+	    continue;
78e1a10
+
78e1a10
+	  if ((!before && sym->addr <= addr) || (before && before->addr <= sym->addr))
78e1a10
+	    before = sym;
78e1a10
+	}
78e1a10
+    }
78e1a10
+
78e1a10
+  if (before && addr < after->addr)
78e1a10
+    return before->name;
78e1a10
+
78e1a10
+  return NULL;
78e1a10
+}
78e1a10
+
78e1a10
 /* Register a symbol with the name NAME and the address ADDR.  */
78e1a10
 grub_err_t
78e1a10
 grub_dl_register_symbol (const char *name, void *addr, int isfunc,
78e1a10
@@ -336,6 +380,7 @@ grub_dl_resolve_symbols (grub_dl_t mod, Elf_Ehdr *e)
78e1a10
   const char *str;
78e1a10
   Elf_Word size, entsize;
78e1a10
 
78e1a10
+  grub_dprintf ("modules", "Resolving symbols for \"%s\"\n", mod->name);
78e1a10
   for (i = 0, s = (Elf_Shdr *) ((char *) e + e->e_shoff);
78e1a10
        i < e->e_shnum;
78e1a10
        i++, s = (Elf_Shdr *) ((char *) s + e->e_shentsize))
78e1a10
diff --git a/grub-core/kern/i386/backtrace.c b/grub-core/kern/i386/backtrace.c
78e1a10
new file mode 100644
15a2072
index 00000000000..2413f9a57db
78e1a10
--- /dev/null
78e1a10
+++ b/grub-core/kern/i386/backtrace.c
15a2072
@@ -0,0 +1,125 @@
78e1a10
+/*
78e1a10
+ *  GRUB  --  GRand Unified Bootloader
78e1a10
+ *  Copyright (C) 2009  Free Software Foundation, Inc.
78e1a10
+ *
78e1a10
+ *  GRUB is free software: you can redistribute it and/or modify
78e1a10
+ *  it under the terms of the GNU General Public License as published by
78e1a10
+ *  the Free Software Foundation, either version 3 of the License, or
78e1a10
+ *  (at your option) any later version.
78e1a10
+ *
78e1a10
+ *  GRUB is distributed in the hope that it will be useful,
78e1a10
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
78e1a10
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
78e1a10
+ *  GNU General Public License for more details.
78e1a10
+ *
78e1a10
+ *  You should have received a copy of the GNU General Public License
78e1a10
+ *  along with GRUB.  If not, see <http://www.gnu.org/licenses/>.
78e1a10
+ */
78e1a10
+
78e1a10
+#include <grub/misc.h>
78e1a10
+#include <grub/command.h>
78e1a10
+#include <grub/err.h>
78e1a10
+#include <grub/dl.h>
78e1a10
+#include <grub/mm.h>
78e1a10
+#include <grub/term.h>
78e1a10
+#include <grub/backtrace.h>
78e1a10
+
78e1a10
+#define MAX_STACK_FRAME 102400
78e1a10
+
78e1a10
+void
78e1a10
+grub_backtrace_pointer (void *frame, unsigned int skip)
78e1a10
+{
78e1a10
+  void **ebp = (void **)frame;
78e1a10
+  unsigned long x = 0;
78e1a10
+
78e1a10
+  while (ebp)
78e1a10
+    {
78e1a10
+      void **next_ebp = (void **)ebp[0];
78e1a10
+      const char *name = NULL;
78e1a10
+      char *addr = NULL;
78e1a10
+
78e1a10
+      grub_dprintf("backtrace", "ebp is %p next_ebp is %p\n", ebp, next_ebp);
78e1a10
+
78e1a10
+      if (x >= skip)
78e1a10
+	{
78e1a10
+	  name = grub_get_symbol_by_addr (ebp[1], 1);
78e1a10
+	  if (name)
78e1a10
+	    addr = grub_resolve_symbol (name);
78e1a10
+	  grub_backtrace_print_address (ebp[1]);
78e1a10
+
78e1a10
+	  if (addr && addr != ebp[1])
78e1a10
+	    grub_printf (" %s() %p+%p \n", name ? name : "unknown", addr,
78e1a10
+			 (char *)((char *)ebp[1] - addr));
78e1a10
+	  else
78e1a10
+	    grub_printf(" %s() %p \n", name ? name : "unknown", addr);
78e1a10
+
78e1a10
+#if 0
78e1a10
+	  grub_printf ("(");
78e1a10
+	  for (i = 0, arg = ebp[2]; arg != next_ebp && i < 12; arg++, i++)
78e1a10
+	    grub_printf ("%p,", arg);
78e1a10
+	  grub_printf (")\n");
78e1a10
+#endif
78e1a10
+	}
78e1a10
+
78e1a10
+      x += 1;
78e1a10
+
78e1a10
+      if (next_ebp < ebp || next_ebp - ebp > MAX_STACK_FRAME || next_ebp == ebp)
78e1a10
+	{
78e1a10
+	  //grub_printf ("Invalid stack frame at %p (%p)\n", ebp, next_ebp);
78e1a10
+	  break;
78e1a10
+	}
78e1a10
+      ebp = next_ebp;
78e1a10
+    }
78e1a10
+}
78e1a10
+
78e1a10
+#if defined (__x86_64__)
78e1a10
+asm ("\t.global \"_text\"\n"
78e1a10
+     "_text:\n"
78e1a10
+     "\t.quad .text\n"
78e1a10
+     "\t.global \"_data\"\n"
78e1a10
+     "_data:\n"
78e1a10
+     "\t.quad .data\n"
78e1a10
+     );
78e1a10
+#elif defined(__i386__)
78e1a10
+asm ("\t.global \"_text\"\n"
78e1a10
+     "_text:\n"
78e1a10
+     "\t.long .text\n"
78e1a10
+     "\t.global \"_data\"\n"
78e1a10
+     "_data:\n"
78e1a10
+     "\t.long .data\n"
78e1a10
+     );
78e1a10
+#else
78e1a10
+#warning I dunno...
78e1a10
+#endif
78e1a10
+
78e1a10
+extern unsigned long _text;
78e1a10
+extern unsigned long _data;
78e1a10
+
15a2072
+#ifdef GRUB_UTIL
15a2072
+#define EXT_C(x) x
15a2072
+#endif
15a2072
+
78e1a10
+void
78e1a10
+grub_backtrace_arch (unsigned int skip)
78e1a10
+{
78e1a10
+  grub_printf ("Backtrace (.text %p .data %p):\n",
78e1a10
+	       (void *)_text, (void *)_data);
78e1a10
+  skip += 1;
78e1a10
+#if defined (__x86_64__)
78e1a10
+  asm volatile ("movq %%rbp, %%rdi\n"
78e1a10
+		"movq 0, %%rsi\n"
78e1a10
+		"movl %0, %%esi\n"
78e1a10
+		"call " EXT_C("grub_backtrace_pointer")
78e1a10
+		:
78e1a10
+		: "r" (skip));
78e1a10
+#elif defined(__i386__)
78e1a10
+  asm volatile ("addl $8, %%esp\n"
78e1a10
+		"pushl %0\n"
78e1a10
+		"pushl %%ebp\n"
78e1a10
+		"call " EXT_C("grub_backtrace_pointer")
78e1a10
+		:
78e1a10
+		: "r" (skip));
78e1a10
+#else
78e1a10
+  grub_backtrace_pointer(__builtin_frame_address(0), skip);
78e1a10
+#endif
78e1a10
+}
78e1a10
diff --git a/grub-core/kern/i386/pc/init.c b/grub-core/kern/i386/pc/init.c
78e1a10
index 27bc68b8a53..b51d0abfa6e 100644
78e1a10
--- a/grub-core/kern/i386/pc/init.c
78e1a10
+++ b/grub-core/kern/i386/pc/init.c
78e1a10
@@ -153,7 +153,7 @@ compact_mem_regions (void)
78e1a10
 }
78e1a10
 
78e1a10
 grub_addr_t grub_modbase;
78e1a10
-extern grub_uint8_t _start[], _edata[];
78e1a10
+extern grub_uint8_t _edata[];
78e1a10
 
78e1a10
 /* Helper for grub_machine_init.  */
78e1a10
 static int
78e1a10
@@ -217,7 +217,7 @@ grub_machine_init (void)
78e1a10
   /* This has to happen before any BIOS calls. */
78e1a10
   grub_via_workaround_init ();
78e1a10
 
78e1a10
-  grub_modbase = GRUB_MEMORY_MACHINE_DECOMPRESSION_ADDR + (_edata - _start);
78e1a10
+  grub_modbase = GRUB_MEMORY_MACHINE_DECOMPRESSION_ADDR + (_edata - (grub_uint8_t *)_start);
78e1a10
 
78e1a10
   /* Initialize the console as early as possible.  */
78e1a10
   grub_console_init ();
78e1a10
diff --git a/grub-core/kern/ieee1275/init.c b/grub-core/kern/ieee1275/init.c
e153146
index 0cd2a627231..937c1bc44cb 100644
78e1a10
--- a/grub-core/kern/ieee1275/init.c
78e1a10
+++ b/grub-core/kern/ieee1275/init.c
e153146
@@ -63,7 +63,6 @@
78e1a10
 #define HEAP_MAX_ADDR		(unsigned long) (32 * 1024 * 1024)
78e1a10
 #endif
78e1a10
 
78e1a10
-extern char _start[];
78e1a10
 extern char _end[];
78e1a10
 
78e1a10
 #ifdef __sparc__
78e1a10
diff --git a/grub-core/kern/misc.c b/grub-core/kern/misc.c
46968b6
index c60601b699d..a432a6be54a 100644
78e1a10
--- a/grub-core/kern/misc.c
78e1a10
+++ b/grub-core/kern/misc.c
46968b6
@@ -1197,15 +1197,15 @@ grub_printf_fmt_check (const char *fmt, const char *fmt_expected)
46968b6
 
78e1a10
 
78e1a10
 /* Abort GRUB. This function does not return.  */
78e1a10
-static void __attribute__ ((noreturn))
78e1a10
+static inline void __attribute__ ((noreturn))
78e1a10
 grub_abort (void)
78e1a10
 {
78e1a10
-#ifndef GRUB_UTIL
78e1a10
-#if (defined(__i386__) || defined(__x86_64__)) && !defined(GRUB_MACHINE_EMU)
78e1a10
-  grub_backtrace();
78e1a10
+#if !defined(GRUB_MACHINE_EMU) && !defined(GRUB_UTIL)
78e1a10
+  grub_backtrace (1);
78e1a10
+#else
78e1a10
+  grub_printf ("\n");
78e1a10
 #endif
78e1a10
-#endif
78e1a10
-  grub_printf ("\nAborted.");
78e1a10
+  grub_printf ("Aborted.");
78e1a10
 
78e1a10
 #ifndef GRUB_UTIL
78e1a10
   if (grub_term_inputs)
46968b6
@@ -1232,6 +1232,7 @@ grub_fatal (const char *fmt, ...)
78e1a10
 {
78e1a10
   va_list ap;
78e1a10
 
78e1a10
+  grub_printf ("\n");
78e1a10
   va_start (ap, fmt);
78e1a10
   grub_vprintf (_(fmt), ap);
78e1a10
   va_end (ap);
78e1a10
diff --git a/grub-core/kern/mm.c b/grub-core/kern/mm.c
46968b6
index c070afc621f..d8c8377578b 100644
78e1a10
--- a/grub-core/kern/mm.c
78e1a10
+++ b/grub-core/kern/mm.c
46968b6
@@ -97,13 +97,13 @@ get_header_from_pointer (void *ptr, grub_mm_header_t *p, grub_mm_region_t *r)
78e1a10
       break;
78e1a10
 
78e1a10
   if (! *r)
78e1a10
-    grub_fatal ("out of range pointer %p", ptr);
78e1a10
+    grub_fatal ("out of range pointer %p\n", ptr);
78e1a10
 
78e1a10
   *p = (grub_mm_header_t) ptr - 1;
78e1a10
   if ((*p)->magic == GRUB_MM_FREE_MAGIC)
78e1a10
-    grub_fatal ("double free at %p", *p);
78e1a10
+    grub_fatal ("double free at %p\n", *p);
78e1a10
   if ((*p)->magic != GRUB_MM_ALLOC_MAGIC)
78e1a10
-    grub_fatal ("alloc magic is broken at %p: %lx", *p,
78e1a10
+    grub_fatal ("alloc magic is broken at %p: %lx\n", *p,
78e1a10
 		(unsigned long) (*p)->magic);
78e1a10
 }
78e1a10
 
78e1a10
diff --git a/grub-core/lib/arm64/backtrace.c b/grub-core/lib/arm64/backtrace.c
78e1a10
deleted file mode 100644
78e1a10
index 1079b5380e1..00000000000
78e1a10
--- a/grub-core/lib/arm64/backtrace.c
78e1a10
+++ /dev/null
78e1a10
@@ -1,62 +0,0 @@
78e1a10
-/*
78e1a10
- *  GRUB  --  GRand Unified Bootloader
78e1a10
- *  Copyright (C) 2009  Free Software Foundation, Inc.
78e1a10
- *
78e1a10
- *  GRUB is free software: you can redistribute it and/or modify
78e1a10
- *  it under the terms of the GNU General Public License as published by
78e1a10
- *  the Free Software Foundation, either version 3 of the License, or
78e1a10
- *  (at your option) any later version.
78e1a10
- *
78e1a10
- *  GRUB is distributed in the hope that it will be useful,
78e1a10
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
78e1a10
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
78e1a10
- *  GNU General Public License for more details.
78e1a10
- *
78e1a10
- *  You should have received a copy of the GNU General Public License
78e1a10
- *  along with GRUB.  If not, see <http://www.gnu.org/licenses/>.
78e1a10
- */
78e1a10
-
78e1a10
-#include <grub/misc.h>
78e1a10
-#include <grub/command.h>
78e1a10
-#include <grub/err.h>
78e1a10
-#include <grub/dl.h>
78e1a10
-#include <grub/mm.h>
78e1a10
-#include <grub/term.h>
78e1a10
-#include <grub/backtrace.h>
78e1a10
-
78e1a10
-#define MAX_STACK_FRAME 102400
78e1a10
-
78e1a10
-void
78e1a10
-grub_backtrace_pointer (int frame)
78e1a10
-{
78e1a10
-  while (1)
78e1a10
-    {
78e1a10
-      void *lp = __builtin_return_address (frame);
78e1a10
-      if (!lp)
78e1a10
-	break;
78e1a10
-
78e1a10
-      lp = __builtin_extract_return_addr (lp);
78e1a10
-
78e1a10
-      grub_printf ("%p: ", lp);
78e1a10
-      grub_backtrace_print_address (lp);
78e1a10
-      grub_printf (" (");
78e1a10
-      for (i = 0; i < 2; i++)
78e1a10
-	grub_printf ("%p,", ((void **)ptr) [i + 2]);
78e1a10
-      grub_printf ("%p)\n", ((void **)ptr) [i + 2]);
78e1a10
-      nptr = *(void **)ptr;
78e1a10
-      if (nptr < ptr || (void **) nptr - (void **) ptr > MAX_STACK_FRAME
78e1a10
-	  || nptr == ptr)
78e1a10
-	{
78e1a10
-	  grub_printf ("Invalid stack frame at %p (%p)\n", ptr, nptr);
78e1a10
-	  break;
78e1a10
-	}
78e1a10
-      ptr = nptr;
78e1a10
-    }
78e1a10
-}
78e1a10
-
78e1a10
-void
78e1a10
-grub_backtrace (void)
78e1a10
-{
78e1a10
-  grub_backtrace_pointer (1);
78e1a10
-}
78e1a10
-
78e1a10
diff --git a/grub-core/lib/i386/backtrace.c b/grub-core/lib/i386/backtrace.c
78e1a10
deleted file mode 100644
78e1a10
index c67273db3ae..00000000000
78e1a10
--- a/grub-core/lib/i386/backtrace.c
78e1a10
+++ /dev/null
78e1a10
@@ -1,78 +0,0 @@
78e1a10
-/*
78e1a10
- *  GRUB  --  GRand Unified Bootloader
78e1a10
- *  Copyright (C) 2009  Free Software Foundation, Inc.
78e1a10
- *
78e1a10
- *  GRUB is free software: you can redistribute it and/or modify
78e1a10
- *  it under the terms of the GNU General Public License as published by
78e1a10
- *  the Free Software Foundation, either version 3 of the License, or
78e1a10
- *  (at your option) any later version.
78e1a10
- *
78e1a10
- *  GRUB is distributed in the hope that it will be useful,
78e1a10
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
78e1a10
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
78e1a10
- *  GNU General Public License for more details.
78e1a10
- *
78e1a10
- *  You should have received a copy of the GNU General Public License
78e1a10
- *  along with GRUB.  If not, see <http://www.gnu.org/licenses/>.
78e1a10
- */
78e1a10
-#include <config.h>
78e1a10
-#ifdef GRUB_UTIL
78e1a10
-#define REALLY_GRUB_UTIL GRUB_UTIL
78e1a10
-#undef GRUB_UTIL
78e1a10
-#endif
78e1a10
-
78e1a10
-#include <grub/symbol.h>
78e1a10
-#include <grub/dl.h>
78e1a10
-
78e1a10
-#ifdef REALLY_GRUB_UTIL
78e1a10
-#define GRUB_UTIL REALLY_GRUB_UTIL
78e1a10
-#undef REALLY_GRUB_UTIL
78e1a10
-#endif
78e1a10
-
78e1a10
-#include <grub/misc.h>
78e1a10
-#include <grub/command.h>
78e1a10
-#include <grub/err.h>
78e1a10
-#include <grub/mm.h>
78e1a10
-#include <grub/term.h>
78e1a10
-#include <grub/backtrace.h>
78e1a10
-
78e1a10
-#define MAX_STACK_FRAME 102400
78e1a10
-
78e1a10
-void
78e1a10
-grub_backtrace_pointer (void *ebp)
78e1a10
-{
78e1a10
-  void *ptr, *nptr;
78e1a10
-  unsigned i;
78e1a10
-
78e1a10
-  ptr = ebp;
78e1a10
-  while (1)
78e1a10
-    {
78e1a10
-      grub_printf ("%p: ", ptr);
78e1a10
-      grub_backtrace_print_address (((void **) ptr)[1]);
78e1a10
-      grub_printf (" (");
78e1a10
-      for (i = 0; i < 2; i++)
78e1a10
-	grub_printf ("%p,", ((void **)ptr) [i + 2]);
78e1a10
-      grub_printf ("%p)\n", ((void **)ptr) [i + 2]);
78e1a10
-      nptr = *(void **)ptr;
78e1a10
-      if (nptr < ptr || (void **) nptr - (void **) ptr > MAX_STACK_FRAME
78e1a10
-	  || nptr == ptr)
78e1a10
-	{
78e1a10
-	  grub_printf ("Invalid stack frame at %p (%p)\n", ptr, nptr);
78e1a10
-	  break;
78e1a10
-	}
78e1a10
-      ptr = nptr;
78e1a10
-    }
78e1a10
-}
78e1a10
-
78e1a10
-void
78e1a10
-grub_backtrace (void)
78e1a10
-{
78e1a10
-#ifdef __x86_64__
78e1a10
-  asm volatile ("movq %%rbp, %%rdi\n"
78e1a10
-		"callq *%%rax": :"a"(grub_backtrace_pointer));
78e1a10
-#else
78e1a10
-  asm volatile ("movl %%ebp, %%eax\n"
78e1a10
-		"calll *%%ecx": :"c"(grub_backtrace_pointer));
78e1a10
-#endif
78e1a10
-}
78e1a10
-
78e1a10
diff --git a/include/grub/backtrace.h b/include/grub/backtrace.h
78e1a10
index 395519762f0..275cf85e2d3 100644
78e1a10
--- a/include/grub/backtrace.h
78e1a10
+++ b/include/grub/backtrace.h
78e1a10
@@ -19,8 +19,14 @@
78e1a10
 #ifndef GRUB_BACKTRACE_HEADER
78e1a10
 #define GRUB_BACKTRACE_HEADER	1
78e1a10
 
78e1a10
-void grub_backtrace (void);
78e1a10
-void grub_backtrace_pointer (void *ptr);
78e1a10
+#include <grub/symbol.h>
78e1a10
+#include <grub/types.h>
78e1a10
+
78e1a10
+void EXPORT_FUNC(grub_debug_backtrace) (const char * const debug,
78e1a10
+					unsigned int skip);
78e1a10
+void EXPORT_FUNC(grub_backtrace) (unsigned int skip);
78e1a10
+void grub_backtrace_arch (unsigned int skip);
78e1a10
+void grub_backtrace_pointer (void *ptr, unsigned int skip);
78e1a10
 void grub_backtrace_print_address (void *addr);
78e1a10
 
78e1a10
 #endif
78e1a10
diff --git a/include/grub/dl.h b/include/grub/dl.h
46968b6
index 91933b85f2c..2f76e6b0437 100644
78e1a10
--- a/include/grub/dl.h
78e1a10
+++ b/include/grub/dl.h
46968b6
@@ -259,6 +259,8 @@ grub_dl_is_persistent (grub_dl_t mod)
78e1a10
 
78e1a10
 #endif
78e1a10
 
78e1a10
+void * EXPORT_FUNC(grub_resolve_symbol) (const char *name);
78e1a10
+const char * EXPORT_FUNC(grub_get_symbol_by_addr) (const void *addr, int isfunc);
78e1a10
 grub_err_t grub_dl_register_symbol (const char *name, void *addr,
78e1a10
 				    int isfunc, grub_dl_t mod);
78e1a10
 
78e1a10
diff --git a/include/grub/kernel.h b/include/grub/kernel.h
46968b6
index abbca5ea335..300a9766cda 100644
78e1a10
--- a/include/grub/kernel.h
78e1a10
+++ b/include/grub/kernel.h
46968b6
@@ -111,6 +111,9 @@ grub_addr_t grub_modules_get_end (void);
78e1a10
 
78e1a10
 #endif
78e1a10
 
78e1a10
+void EXPORT_FUNC(start) (void);
78e1a10
+void EXPORT_FUNC(_start) (void);
78e1a10
+
78e1a10
 /* The start point of the C code.  */
78e1a10
 void grub_main (void) __attribute__ ((noreturn));
78e1a10
 
78e1a10
diff --git a/grub-core/kern/arm/efi/startup.S b/grub-core/kern/arm/efi/startup.S
78e1a10
index 9f8265315a9..f3bc41f9d0f 100644
78e1a10
--- a/grub-core/kern/arm/efi/startup.S
78e1a10
+++ b/grub-core/kern/arm/efi/startup.S
78e1a10
@@ -23,6 +23,8 @@
78e1a10
 	.file 	"startup.S"
78e1a10
 	.text
78e1a10
 	.arm
78e1a10
+	.globl	start, _start
78e1a10
+FUNCTION(start)
78e1a10
 FUNCTION(_start)
78e1a10
 	/*
78e1a10
 	 *  EFI_SYSTEM_TABLE and EFI_HANDLE are passed in r1/r0.
78e1a10
diff --git a/grub-core/kern/arm/startup.S b/grub-core/kern/arm/startup.S
78e1a10
index 3946fe8e183..5679a1d00ad 100644
78e1a10
--- a/grub-core/kern/arm/startup.S
78e1a10
+++ b/grub-core/kern/arm/startup.S
78e1a10
@@ -48,6 +48,8 @@
78e1a10
 	
78e1a10
 	.text
78e1a10
 	.arm
78e1a10
+	.globl	start, _start
78e1a10
+FUNCTION(start)
78e1a10
 FUNCTION(_start)
78e1a10
 	b	codestart
78e1a10
 	
78e1a10
diff --git a/grub-core/kern/arm64/efi/startup.S b/grub-core/kern/arm64/efi/startup.S
78e1a10
index 666a7ee3c92..41676bdb2b8 100644
78e1a10
--- a/grub-core/kern/arm64/efi/startup.S
78e1a10
+++ b/grub-core/kern/arm64/efi/startup.S
78e1a10
@@ -19,7 +19,9 @@
78e1a10
 #include <grub/symbol.h>
78e1a10
 
78e1a10
 	.file 	"startup.S"
78e1a10
+	.globl start, _start
78e1a10
 	.text
78e1a10
+FUNCTION(start)
78e1a10
 FUNCTION(_start)
78e1a10
 	/*
78e1a10
 	 *  EFI_SYSTEM_TABLE and EFI_HANDLE are passed in x1/x0.
78e1a10
diff --git a/grub-core/kern/i386/qemu/startup.S b/grub-core/kern/i386/qemu/startup.S
78e1a10
index 0d89858d9b3..939f182fc74 100644
78e1a10
--- a/grub-core/kern/i386/qemu/startup.S
78e1a10
+++ b/grub-core/kern/i386/qemu/startup.S
78e1a10
@@ -24,7 +24,8 @@
78e1a10
 
78e1a10
 	.text
78e1a10
 	.code32
78e1a10
-	.globl _start
78e1a10
+	.globl start, _start
78e1a10
+start:
78e1a10
 _start:
78e1a10
 	jmp	codestart
78e1a10
 
78e1a10
diff --git a/grub-core/kern/ia64/efi/startup.S b/grub-core/kern/ia64/efi/startup.S
78e1a10
index d75c6d7cc74..8f2a593e529 100644
78e1a10
--- a/grub-core/kern/ia64/efi/startup.S
78e1a10
+++ b/grub-core/kern/ia64/efi/startup.S
78e1a10
@@ -24,8 +24,9 @@
78e1a10
 	.psr lsb
78e1a10
 	.lsb
78e1a10
 
78e1a10
-	.global _start
78e1a10
+	.global start, _start
78e1a10
 	.proc _start
78e1a10
+start:
78e1a10
 _start:
78e1a10
 	alloc loc0=ar.pfs,2,4,0,0
78e1a10
 	mov loc1=rp
78e1a10
diff --git a/grub-core/kern/sparc64/ieee1275/crt0.S b/grub-core/kern/sparc64/ieee1275/crt0.S
78e1a10
index 03b916f0534..701bf63abcf 100644
78e1a10
--- a/grub-core/kern/sparc64/ieee1275/crt0.S
78e1a10
+++ b/grub-core/kern/sparc64/ieee1275/crt0.S
78e1a10
@@ -22,7 +22,8 @@
78e1a10
 
78e1a10
 	.text
78e1a10
 	.align	4
78e1a10
-	.globl	_start
78e1a10
+	.globl	start, _start
78e1a10
+start:
78e1a10
 _start:
78e1a10
 	ba	codestart
78e1a10
 	 mov  %o4, %o0
78e1a10
diff --git a/grub-core/Makefile.am b/grub-core/Makefile.am
46968b6
index 80e7a83edf9..f512573c0da 100644
78e1a10
--- a/grub-core/Makefile.am
78e1a10
+++ b/grub-core/Makefile.am
78e1a10
@@ -66,6 +66,7 @@ CLEANFILES += grub_script.yy.c grub_script.yy.h
78e1a10
 
78e1a10
 include $(srcdir)/Makefile.core.am
78e1a10
 
78e1a10
+KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/backtrace.h
78e1a10
 KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/cache.h
78e1a10
 KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/command.h
78e1a10
 KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/device.h