summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTristan Gingold2015-11-18 21:45:45 +0100
committerTristan Gingold2015-11-19 05:47:59 +0100
commit92b0b82ea32982b94eb8bf19a0b498d92053fffe (patch)
tree70b04f103d145dc01d31870e50b5e6a654dc20e0
parentff4bc5fb13a997a1d00596578b6d7deb5c0b0da6 (diff)
downloadghdl-92b0b82ea32982b94eb8bf19a0b498d92053fffe.tar.gz
ghdl-92b0b82ea32982b94eb8bf19a0b498d92053fffe.tar.bz2
ghdl-92b0b82ea32982b94eb8bf19a0b498d92053fffe.zip
Add symbolizer (for mcode).
Display a backtrace in case of failed check or assert failure.
-rw-r--r--src/ghdldrv/ghdlrun.adb2
-rw-r--r--src/grt/config/grt_itf.h40
-rw-r--r--src/grt/config/jumps.c104
-rw-r--r--src/grt/config/win32.c17
-rw-r--r--src/grt/grt-backtraces.adb232
-rw-r--r--src/grt/grt-backtraces.ads34
-rw-r--r--src/grt/grt-errors.adb35
-rw-r--r--src/grt/grt-errors.ads43
-rw-r--r--src/grt/grt-lib.adb9
-rw-r--r--src/grt/grt-modules.adb2
-rw-r--r--src/ortho/mcode/binary_file-format.ads20
-rw-r--r--src/ortho/mcode/binary_file-memory.adb26
-rw-r--r--src/ortho/mcode/binary_file-memory.ads11
-rw-r--r--src/ortho/mcode/dwarf.ads3
-rw-r--r--src/ortho/mcode/ortho_code-dwarf.adb174
-rw-r--r--src/ortho/mcode/ortho_code-dwarf.ads8
-rw-r--r--src/ortho/mcode/ortho_code-flags.ads4
-rw-r--r--src/ortho/mcode/ortho_code-x86-abi.adb9
-rw-r--r--src/ortho/mcode/ortho_code-x86-emits.adb8
-rw-r--r--src/ortho/mcode/ortho_code_main.adb5
-rw-r--r--src/ortho/mcode/ortho_jit.adb52
-rw-r--r--src/ortho/mcode/symbolizer.adb655
-rw-r--r--src/ortho/mcode/symbolizer.ads48
-rw-r--r--src/ortho/ortho_jit.ads6
24 files changed, 1400 insertions, 147 deletions
diff --git a/src/ghdldrv/ghdlrun.adb b/src/ghdldrv/ghdlrun.adb
index 51cc6b0..eac0702 100644
--- a/src/ghdldrv/ghdlrun.adb
+++ b/src/ghdldrv/ghdlrun.adb
@@ -591,6 +591,8 @@ package body Ghdlrun is
Grtlink.Flag_String := Flags.Flag_String;
+ Grt.Errors.Symbolizer := Ortho_Jit.Symbolize'Access;
+
Elaborate_Proc :=
Conv (Ortho_Jit.Get_Address (Trans_Decls.Ghdl_Elaborate));
diff --git a/src/grt/config/grt_itf.h b/src/grt/config/grt_itf.h
new file mode 100644
index 0000000..1b17c3a
--- /dev/null
+++ b/src/grt/config/grt_itf.h
@@ -0,0 +1,40 @@
+/* Declarations to interface with Ada code.
+ Copyright (C) 2015 Tristan Gingold.
+
+ GHDL 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 2, or (at your option) any later
+ version.
+
+ GHDL 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 GCC; see the file COPYING. If not, write to the Free
+ Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+ 02111-1307, USA.
+
+ As a special exception, if other files instantiate generics from this
+ unit, or you link this unit with other files to produce an executable,
+ this unit does not by itself cause the resulting executable to be
+ covered by the GNU General Public License. This exception does not
+ however invalidate any other reasons why the executable file might be
+ covered by the GNU Public License.
+*/
+
+struct backtrace_addrs
+{
+ int size;
+ int skip;
+ void *addrs[32];
+};
+
+void grt_save_backtrace (struct backtrace_addrs *bt, int skip);
+
+extern void grt_overflow_error (struct backtrace_addrs *bt);
+extern void grt_null_access_error (struct backtrace_addrs *bt);
+
+void __ghdl_maybe_return_via_longjump (int val);
+int __ghdl_run_through_longjump (int (*func)(void));
diff --git a/src/grt/config/jumps.c b/src/grt/config/jumps.c
index a544f83..00e17d3 100644
--- a/src/grt/config/jumps.c
+++ b/src/grt/config/jumps.c
@@ -29,11 +29,17 @@
#include <signal.h>
#include <fcntl.h>
-#if defined (__linux__) && defined (__i386__)
-/* On i386/Linux, the context must be inspected. */
+#if defined (__linux__) || defined (__APPLE__)
+#define HAVE_BACKTRACE 1
#include <sys/ucontext.h>
#endif
+#ifdef HAVE_BACKTRACE
+#include <execinfo.h>
+#endif
+
+#include "grt_itf.h"
+
/* There is a simple setjmp/longjmp mechanism used to report failures.
We have the choice between 3 mechanisms:
* USE_BUITLIN_SJLJ: gcc builtin setjmp/longjmp, very fast but gcc specific.
@@ -70,49 +76,89 @@ typedef jmp_buf JMP_BUF;
static int run_env_en;
static JMP_BUF run_env;
-extern void grt_overflow_error (void);
-extern void grt_null_access_error (void);
-
#ifdef __APPLE__
#define NEED_SIGFPE_HANDLER
+#define NEED_SIGBUS_HANDLER
#endif
static struct sigaction prev_sigfpe_act;
+#ifdef NEED_SIGFPE_HANDLER
+static struct sigaction prev_sigsegv_act;
+#endif
+#ifdef NEED_SIGBUS_HANDLER
+static struct sigaction prev_sigbus_act;
+#endif
+
+static void
+get_bt_from_ucontext (void *uctxt, struct backtrace_addrs *bt)
+{
+ void *pc = NULL;
+ int i;
+
+#ifdef HAVE_BACKTRACE
+ bt->size = backtrace (bt->addrs, sizeof (bt->addrs) / sizeof (void *));
+ bt->skip = 0;
+#else
+ bt->size = 0;
+ return;
+#endif
+
+#if defined (__linux__) && defined (__x86_64__)
+ ucontext *u = (ucontext *)uctxt;
+ pc = (void *)u->uc_mcontext.gregs[REG_RIP];
+#endif
+#if defined (__APPLE__) && defined (__i386__)
+ ucontext_t *u = (ucontext_t *)uctxt;
+ pc = (void *)u->uc_mcontext->__ss.__eip;
+ bt->skip = 3; /* This frame + sighandler + trampoline + marker - pc. */
+ bt->addrs[3] = pc;
+#endif
+}
+
/* Handler for SIGFPE signal.
It is also raised in case of overflow (i386 linux). */
-static void grt_overflow_handler (int signo, siginfo_t *info, void *ptr)
+static void
+grt_overflow_handler (int signo, siginfo_t *info, void *ptr)
{
- grt_overflow_error ();
-}
+ struct backtrace_addrs bt;
-static struct sigaction prev_sigsegv_act;
+ get_bt_from_ucontext (ptr, &bt);
+ grt_overflow_error (&bt);
+}
/* Posix handler for overflow. This is used only by mcode. */
-static void grt_sigsegv_handler (int signo, siginfo_t *info, void *ptr)
+static void
+grt_sigsegv_handler (int signo, siginfo_t *info, void *ptr)
{
-#if defined (__linux__) && defined (__i386__)
- ucontext_t *uctxt = (ucontext_t *)ptr;
+ struct backtrace_addrs bt;
- /* Linux generates a SIGSEGV (!) for an overflow exception. */
- if (uctxt->uc_mcontext.gregs[REG_TRAPNO] == 4)
+ get_bt_from_ucontext (ptr, &bt);
+
+#if defined (__linux__) && defined (__i386__)
+ if (signo == SIGSEGV)
{
- grt_overflow_error ();
+ ucontext_t *uctxt = (ucontext_t *)ptr;
+
+ /* Linux generates a SIGSEGV (!) for an overflow exception. */
+ if (uctxt->uc_mcontext.gregs[REG_TRAPNO] == 4)
+ grt_overflow_error (&bt);
}
#endif
/* We loose. */
- grt_null_access_error ();
+ grt_null_access_error (&bt);
}
-static void grt_signal_setup (void)
+static void
+grt_signal_setup (void)
{
{
struct sigaction sigsegv_act;
sigsegv_act.sa_sigaction = &grt_sigsegv_handler;
sigemptyset (&sigsegv_act.sa_mask);
- sigsegv_act.sa_flags = SA_ONSTACK | SA_SIGINFO;
+ sigsegv_act.sa_flags = SA_SIGINFO;
#ifdef SA_ONESHOT
sigsegv_act.sa_flags |= SA_ONESHOT;
#elif defined (SA_RESETHAND)
@@ -122,6 +168,10 @@ static void grt_signal_setup (void)
/* We don't care about the return status.
If the handler is not installed, then some feature are lost. */
sigaction (SIGSEGV, &sigsegv_act, &prev_sigsegv_act);
+
+#ifdef NEED_SIGBUS_HANDLER
+ sigaction (SIGBUS, &sigsegv_act, &prev_sigbus_act);
+#endif
}
#ifdef NEED_SIGFPE_HANDLER
@@ -137,10 +187,15 @@ static void grt_signal_setup (void)
#endif
}
-static void grt_signal_restore (void)
+static void
+grt_signal_restore (void)
{
sigaction (SIGSEGV, &prev_sigsegv_act, NULL);
+#ifdef NEED_SIGBUS_HANDLER
+ sigaction (SIGBUS, &prev_sigbus_act, NULL);
+#endif
+
#ifdef NEED_SIGFPE_HANDLER
sigaction (SIGFPE, &prev_sigfpe_act, NULL);
#endif
@@ -167,3 +222,14 @@ __ghdl_run_through_longjump (int (*func)(void))
run_env_en = 0;
return res;
}
+
+void
+grt_save_backtrace (struct backtrace_addrs *bt, int skip)
+{
+#ifdef HAVE_BACKTRACE
+ bt->size = backtrace (bt->addrs, sizeof (bt->addrs) / sizeof (void *));
+ bt->skip = skip + 1;
+#else
+ bt->size = 0;
+#endif
+}
diff --git a/src/grt/config/win32.c b/src/grt/config/win32.c
index 869c7ca..63d11a2 100644
--- a/src/grt/config/win32.c
+++ b/src/grt/config/win32.c
@@ -30,13 +30,11 @@
#include <assert.h>
#include <excpt.h>
+#include "grt_itf.h"
+
static int run_env_en;
static jmp_buf run_env;
-extern void grt_overflow_error (void);
-extern void grt_null_access_error (void);
-void __ghdl_maybe_return_via_longjump (int val);
-
static EXCEPTION_DISPOSITION
ghdl_SEH_handler (struct _EXCEPTION_RECORD* ExceptionRecord,
void *EstablisherFrame,
@@ -60,7 +58,8 @@ ghdl_SEH_handler (struct _EXCEPTION_RECORD* ExceptionRecord,
switch (ExceptionRecord->ExceptionCode)
{
case EXCEPTION_ACCESS_VIOLATION:
- grt_null_access_error ();
+ /* Pc is ExceptionRecord->ExceptionAddress. */
+ grt_null_access_error (NULL);
break;
case EXCEPTION_FLT_DENORMAL_OPERAND:
@@ -77,7 +76,7 @@ ghdl_SEH_handler (struct _EXCEPTION_RECORD* ExceptionRecord,
break;
case EXCEPTION_INT_OVERFLOW:
- grt_overflow_error ();
+ grt_overflow_error (NULL);
break;
case EXCEPTION_STACK_OVERFLOW:
@@ -132,6 +131,12 @@ __ghdl_run_through_longjump (int (*func)(void))
return res;
}
+void
+grt_save_backtrace (struct backtrace_addrs *bt, int skip)
+{
+ bt->size = 0;
+}
+
#include <math.h>
double acosh (double x)
diff --git a/src/grt/grt-backtraces.adb b/src/grt/grt-backtraces.adb
new file mode 100644
index 0000000..8b779a7
--- /dev/null
+++ b/src/grt/grt-backtraces.adb
@@ -0,0 +1,232 @@
+-- GHDL Run Time (GRT) - Backtraces and symbolization.
+-- Copyright (C) 2015 Tristan Gingold
+--
+-- GHDL 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 2, or (at your option) any later
+-- version.
+--
+-- GHDL 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 GCC; see the file COPYING. If not, write to the Free
+-- Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+-- 02111-1307, USA.
+--
+-- As a special exception, if other files instantiate generics from this
+-- unit, or you link this unit with other files to produce an executable,
+-- this unit does not by itself cause the resulting executable to be
+-- covered by the GNU General Public License. This exception does not
+-- however invalidate any other reasons why the executable file might be
+-- covered by the GNU Public License.
+
+with System;
+with Grt.Types; use Grt.Types;
+with Grt.Hooks; use Grt.Hooks;
+
+package body Grt.Backtraces is
+ -- If true, disp address in backtraces.
+ Flag_Address : Boolean := False;
+
+ subtype Address_Image_String is String (1 .. Integer_Address'Size / 4);
+
+ Hex : constant array (Natural range 0 .. 15) of Character :=
+ "0123456789abcdef";
+
+ function Address_Image (Addr : Integer_Address)
+ return Address_Image_String
+ is
+ V : Integer_Address;
+ Res : Address_Image_String;
+ begin
+ V := Addr;
+ for I in reverse Res'Range loop
+ Res (I) := Hex (Natural (V mod 16));
+ V := V / 16;
+ end loop;
+ return Res;
+ end Address_Image;
+
+ function File_Basename (Name : Ghdl_C_String) return Ghdl_C_String
+ is
+ Sep : Natural;
+ begin
+ Sep := 0;
+ for I in Name'Range loop
+ case Name (I) is
+ when '\' | '/' =>
+ Sep := I + 1;
+ when NUL =>
+ exit;
+ when others =>
+ null;
+ end case;
+ end loop;
+ if Sep /= 0 and then Name (Sep) /= NUL then
+ return To_Ghdl_C_String (Name (Sep)'Address);
+ else
+ return Name;
+ end if;
+ end File_Basename;
+
+ function Is_Eq (Str : Ghdl_C_String; Ref : String) return Boolean is
+ begin
+ for I in Ref'Range loop
+ if Str (Str'First + I - Ref'First) /= Ref (I) then
+ return False;
+ end if;
+ end loop;
+ return Str (Str'First + Ref'Length) = NUL;
+ end Is_Eq;
+
+ procedure Demangle_Err (Name : Ghdl_C_String)
+ is
+ Last_Part : Natural;
+ Suffix : Ghdl_C_String;
+ Off : Natural;
+ C : Character;
+ Is_Arch : Boolean;
+ begin
+ if Name (1) = '_' then
+ if Is_Eq (Name, "__ghdl_ELABORATE") then
+ Put_Err ("Elaboration of design");
+ return;
+ end if;
+ end if;
+
+ -- Find last suffix (as it indicates processes and elaborator).
+ Last_Part := 0;
+ for I in Name'Range loop
+ exit when Name (I) = NUL;
+ if Name (I) = '_' and then Name (I + 1) = '_' then
+ Last_Part := I;
+ end if;
+ end loop;
+
+ if Last_Part /= 0 then
+ Suffix := To_Ghdl_C_String (Name (Last_Part)'Address);
+ if Is_Eq (Suffix, "__ELAB") then
+ Put_Err ("elaboration of ");
+ elsif Is_Eq (Suffix, "__PROC") then
+ Put_Err ("process ");
+ else
+ Last_Part := 0;
+ end if;
+ end if;
+ Off := 1;
+ Is_Arch := False;
+ loop
+ exit when Off = Last_Part;
+ C := Name (Off);
+ Off := Off + 1;
+ exit when C = NUL;
+ if C = '_' and then Name (Off) = '_' then
+ if Name (Off + 1) = 'A'
+ and then Name (Off + 2) = 'R'
+ and then Name (Off + 3) = 'C'
+ and then Name (Off + 4) = 'H'
+ and then Name (Off + 5) = '_'
+ and then Name (Off + 6) = '_'
+ then
+ Off := Off + 7;
+ Put_Err ('(');
+ Is_Arch := True;
+ else
+ if Is_Arch then
+ Put_Err (')');
+ Is_Arch := False;
+ end if;
+ Put_Err ('.');
+ Off := Off + 1;
+ end if;
+ else
+ Put_Err (C);
+ end if;
+ end loop;
+ if Is_Arch then
+ Put_Err (')');
+ end if;
+ end Demangle_Err;
+
+ procedure Put_Err_Backtrace (Bt : Backtrace_Addrs)
+ is
+ use System;
+
+ Filename : Address;
+ Lineno : Natural;
+ Subprg : Address;
+ Unknown : Boolean;
+ begin
+ if Bt.Size = 0
+ or else Bt.Skip >= Bt.Size
+ or else Symbolizer = null
+ then
+ -- No backtrace or no symbolizer.
+ return;
+ end if;
+
+ Unknown := False;
+ for I in Bt.Skip .. Bt.Size loop
+ Symbolizer.all (To_Address (Bt.Addrs (I)),
+ Filename, Lineno, Subprg);
+ if Subprg = Null_Address
+ and (Filename = Null_Address or Lineno = 0)
+ then
+ Unknown := True;
+ else
+ if Unknown then
+ Put_Err (" from: [unknown caller]");
+ Unknown := False;
+ end if;
+ Put_Err (" from:");
+ if Flag_Address then
+ Put_Err (" 0x");
+ Put_Err (Address_Image (Bt.Addrs (I)));
+ end if;
+ if Subprg /= Null_Address then
+ Put_Err (' ');
+ Demangle_Err (To_Ghdl_C_String (Subprg));
+ end if;
+ if Filename /= Null_Address and Lineno /= 0 then
+ Put_Err (" at ");
+ Put_Err (File_Basename (To_Ghdl_C_String (Filename)));
+ Put_Err (":");
+ Put_Err (Lineno);
+ end if;
+ Newline_Err;
+ end if;
+ end loop;
+ end Put_Err_Backtrace;
+
+ -- Return TRUE if OPT is an option for backtrace.
+ function Backtrace_Option (Opt : String) return Boolean
+ is
+ F : constant Natural := Opt'First;
+ begin
+ if Opt'Length < 10 or else Opt (F .. F + 10) /= "--backtrace" then
+ return False;
+ end if;
+ if Opt'Length = 16 and then Opt (F + 11 .. F + 15) = "-addr" then
+ Flag_Address := True;
+ return True;
+ end if;
+ return False;
+ end Backtrace_Option;
+
+ Backtrace_Hooks : aliased constant Hooks_Type :=
+ (Desc => new String'("backtrace: print backtrace on errors"),
+ Option => Backtrace_Option'Access,
+ Help => null,
+ Init => null,
+ Start => null,
+ Finish => null);
+
+ procedure Register is
+ begin
+ Register_Hooks (Backtrace_Hooks'Access);
+ end Register;
+
+end Grt.Backtraces;
diff --git a/src/grt/grt-backtraces.ads b/src/grt/grt-backtraces.ads
new file mode 100644
index 0000000..697b9dd
--- /dev/null
+++ b/src/grt/grt-backtraces.ads
@@ -0,0 +1,34 @@
+-- GHDL Run Time (GRT) - Backtraces and symbolization.
+-- Copyright (C) 2015 Tristan Gingold
+--
+-- GHDL 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 2, or (at your option) any later
+-- version.
+--
+-- GHDL 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 GCC; see the file COPYING. If not, write to the Free
+-- Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+-- 02111-1307, USA.
+--
+-- As a special exception, if other files instantiate generics from this
+-- unit, or you link this unit with other files to produce an executable,
+-- this unit does not by itself cause the resulting executable to be
+-- covered by the GNU General Public License. This exception does not
+-- however invalidate any other reasons why the executable file might be
+-- covered by the GNU Public License.
+
+with Grt.Errors; use Grt.Errors;
+
+package Grt.Backtraces is
+ pragma Preelaborate (Grt.Backtraces);
+
+ procedure Put_Err_Backtrace (Bt : Backtrace_Addrs);
+
+ procedure Register;
+end Grt.Backtraces;
diff --git a/src/grt/grt-errors.adb b/src/grt/grt-errors.adb
index 62ee86e..56d1e6f 100644
--- a/src/grt/grt-errors.adb
+++ b/src/grt/grt-errors.adb
@@ -26,6 +26,7 @@ with Grt.Stdio; use Grt.Stdio;
with Grt.Astdio; use Grt.Astdio;
with Grt.Options; use Grt.Options;
with Grt.Hooks; use Grt.Hooks;
+with Grt.Backtraces;
package body Grt.Errors is
-- Called in case of premature exit.
@@ -76,6 +77,11 @@ package body Grt.Errors is
Put (stderr, Str);
end Put_Err;
+ procedure Put_Err (C : Character) is
+ begin
+ Put (stderr, C);
+ end Put_Err;
+
procedure Put_Err (Str : Ghdl_C_String) is
begin
Put (stderr, Str);
@@ -254,13 +260,34 @@ package body Grt.Errors is
Fatal_Error;
end Internal_Error;
- procedure Grt_Overflow_Error is
+ procedure Error_E_Call_Stack (Bt : Backtrace_Addrs) is
+ begin
+ Newline_Err;
+
+ Grt.Backtraces.Put_Err_Backtrace (Bt);
+
+ Cont := False;
+ Fatal_Error;
+ end Error_E_Call_Stack;
+
+ procedure Error_E_Call_Stack (Bt : Backtrace_Addrs_Acc) is
+ begin
+ if Bt /= null then
+ Error_E_Call_Stack (Bt.all);
+ else
+ Error_E;
+ end if;
+ end Error_E_Call_Stack;
+
+ procedure Grt_Overflow_Error (Bt : Backtrace_Addrs_Acc) is
begin
- Error ("overflow detected");
+ Error_C ("overflow detected");
+ Error_E_Call_Stack (Bt);
end Grt_Overflow_Error;
- procedure Grt_Null_Access_Error is
+ procedure Grt_Null_Access_Error (Bt : Backtrace_Addrs_Acc) is
begin
- Error ("NULL access dereferenced");
+ Error_C ("NULL access dereferenced");
+ Error_E_Call_Stack (Bt);
end Grt_Null_Access_Error;
end Grt.Errors;
diff --git a/src/grt/grt-errors.ads b/src/grt/grt-errors.ads
index bb7aab9..cd7c3dc 100644
--- a/src/grt/grt-errors.ads
+++ b/src/grt/grt-errors.ads
@@ -22,6 +22,7 @@
-- covered by the GNU General Public License. This exception does not
-- however invalidate any other reasons why the executable file might be
-- covered by the GNU Public License.
+with System;
with Grt.Types; use Grt.Types;
with Grt.Hooks;
@@ -62,12 +63,44 @@ package Grt.Errors is
-- Display a message which is not an error.
procedure Info (Str : String);
+ -- Backtrace used to report call stack in case of error.
+ -- Note: for simplicity we assume that a PC is enough to display the
+ -- corresponding file name, line number and routine name. Might not be
+ -- true on some platforms.
+ -- There is a C version of this record in grt_itf.h
+ type Integer_Address_Array is array (Natural range <>) of Integer_Address;
+ type Backtrace_Addrs is record
+ Size : Natural;
+ Skip : Natural;
+ Addrs : Integer_Address_Array (0 .. 31);
+ end record;
+ pragma Convention (C, Backtrace_Addrs);
+
+ type Backtrace_Addrs_Acc is access Backtrace_Addrs;
+
+ type Symbolizer_Acc is access procedure (Pc : System.Address;
+ Filename : out System.Address;
+ Lineno : out Natural;
+ Subprg : out System.Address);
+
+ Symbolizer : Symbolizer_Acc := null;
+
+ procedure Save_Backtrace (Bt : out Backtrace_Addrs; Skip : Natural);
+ pragma Import (C, Save_Backtrace, "grt_save_backtrace");
+
+ -- Finish error message with a call stack.
+ procedure Error_E_Call_Stack (Bt : Backtrace_Addrs);
+ pragma No_Return (Error_E_Call_Stack);
+
+ procedure Error_E_Call_Stack (Bt : Backtrace_Addrs_Acc);
+ pragma No_Return (Error_E_Call_Stack);
+
-- Display an error message for an overflow.
- procedure Grt_Overflow_Error;
+ procedure Grt_Overflow_Error (Bt : Backtrace_Addrs_Acc);
pragma No_Return (Grt_Overflow_Error);
-- Display an error message for a NULL access dereference.
- procedure Grt_Null_Access_Error;
+ procedure Grt_Null_Access_Error (Bt : Backtrace_Addrs_Acc);
pragma No_Return (Grt_Null_Access_Error);
-- Called at end of error message. Central point for failures.
@@ -97,6 +130,12 @@ package Grt.Errors is
-- If true, an error is expected and the exit status is inverted.
Expect_Failure : Boolean := False;
+ -- Internal subprograms, to be called only by the symbolizer.
+ procedure Put_Err (C : Character);
+ procedure Put_Err (Str : String);
+ procedure Put_Err (Str : Ghdl_C_String);
+ procedure Put_Err (N : Integer);
+ procedure Newline_Err;
private
pragma Export (C, Grt_Overflow_Error, "grt_overflow_error");
pragma Export (C, Grt_Null_Access_Error, "grt_null_access_error");
diff --git a/src/grt/grt-lib.adb b/src/grt/grt-lib.adb
index d2b095c..95a4a09 100644
--- a/src/grt/grt-lib.adb
+++ b/src/grt/grt-lib.adb
@@ -46,6 +46,7 @@ package body Grt.Lib is
Loc : Ghdl_Location_Ptr)
is
Level : constant Integer := Severity mod 256;
+ Bt : Backtrace_Addrs;
begin
Report_H;
Report_C (Loc.Filename);
@@ -77,8 +78,10 @@ package body Grt.Lib is
Report_E (Default_Str);
end if;
if Level >= Grt.Options.Severity_Level then
+ Save_Backtrace (Bt, 2);
Error_C (Msg);
- Error_E (" failed");
+ Error_C (" failed");
+ Error_E_Call_Stack (Bt);
end if;
end Do_Report;
@@ -161,12 +164,14 @@ package body Grt.Lib is
procedure Ghdl_Bound_Check_Failed_L1 (Filename : Ghdl_C_String;
Line: Ghdl_I32)
is
+ Bt : Backtrace_Addrs;
begin
+ Save_Backtrace (Bt, 1);
Error_C ("bound check failure at ");
Error_C (Filename);
Error_C (":");
Error_C (Integer (Line));
- Error_E ("");
+ Error_E_Call_Stack (Bt);
end Ghdl_Bound_Check_Failed_L1;
function Ghdl_Integer_Exp (V : Ghdl_I32; E : Ghdl_I32)
diff --git a/src/grt/grt-modules.adb b/src/grt/grt-modules.adb
index 3fc6c4e..0feb46c 100644
--- a/src/grt/grt-modules.adb
+++ b/src/grt/grt-modules.adb
@@ -32,6 +32,7 @@ with Grt.Waves;
with Grt.Vital_Annotate;
with Grt.Disp_Tree;
with Grt.Disp_Rti;
+with Grt.Backtraces;
package body Grt.Modules is
procedure Register_Modules is
@@ -45,5 +46,6 @@ package body Grt.Modules is
Grt.Vpi.Register;
Grt.Vital_Annotate.Register;
Grt.Disp_Rti.Register;
+ Grt.Backtraces.Register;
end Register_Modules;
end Grt.Modules;
diff --git a/src/ortho/mcode/binary_file-format.ads b/src/ortho/mcode/binary_file-format.ads
new file mode 100644
index 0000000..57a65b7
--- /dev/null
+++ b/src/ortho/mcode/binary_file-format.ads
@@ -0,0 +1,20 @@
+-- Binary file writer.
+-- Copyright (C) 2015 Tristan Gingold
+--
+-- GHDL 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 2, or (at your option) any later
+-- version.
+--
+-- GHDL 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 GCC; see the file COPYING. If not, write to the Free
+-- Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+-- 02111-1307, USA.
+with Binary_File.Elf;
+
+package Binary_File.Format renames Binary_File.Elf;
diff --git a/src/ortho/mcode/binary_file-memory.adb b/src/ortho/mcode/binary_file-memory.adb
index a37af9c..9797cd6 100644
--- a/src/ortho/mcode/binary_file-memory.adb
+++ b/src/ortho/mcode/binary_file-memory.adb
@@ -16,17 +16,12 @@
-- Software Foundation, 59 Temple Place - Suite 330, Boston, MA
-- 02111-1307, USA.
with Ada.Text_IO; use Ada.Text_IO;
-with Ada.Unchecked_Conversion;
package body Binary_File.Memory is
-- Absolute section.
Sect_Abs : Section_Acc;
- function To_Pc_Type is new Ada.Unchecked_Conversion
- (Source => System.Address, Target => Pc_Type);
-
- procedure Set_Symbol_Address (Sym : Symbol; Addr : System.Address)
- is
+ procedure Set_Symbol_Address (Sym : Symbol; Addr : System.Address) is
begin
Set_Symbol_Value (Sym, To_Pc_Type (Addr));
Set_Scope (Sym, Sym_Global);
@@ -48,20 +43,21 @@ package body Binary_File.Memory is
-- Relocate section in memory.
Sect := Section_Chain;
while Sect /= null loop
+ -- Allocate memory if needed (eg: .bss)
if Sect.Data = null then
if Sect.Pc > 0 then
Resize (Sect, Sect.Pc);
Sect.Data (0 .. Sect.Pc - 1) := (others => 0);
- else
- null;
- --Sect.Data := new Byte_Array (1 .. 0);
end if;
end if;
- if Sect.Data_Max > 0
+
+ -- Set virtual address.
+ if Sect.Pc > 0
and (Sect /= Sect_Abs and Sect.Flags /= Section_Debug)
then
Sect.Vaddr := To_Pc_Type (Sect.Data (0)'Address);
end if;
+
Sect := Sect.Next;
end loop;
@@ -98,4 +94,14 @@ package body Binary_File.Memory is
Sect := Sect.Next;
end loop;
end Write_Memory_Relocate;
+
+ function Get_Section_Base (Sect : Section_Acc) return System.Address is
+ begin
+ return Sect.Data (0)'Address;
+ end Get_Section_Base;
+
+ function Get_Section_Size (Sect : Section_Acc) return Pc_Type is
+ begin
+ return Sect.Pc;
+ end Get_Section_Size;
end Binary_File.Memory;
diff --git a/src/ortho/mcode/binary_file-memory.ads b/src/ortho/mcode/binary_file-memory.ads
index a205da5..cc2b7e3 100644
--- a/src/ortho/mcode/binary_file-memory.ads
+++ b/src/ortho/mcode/binary_file-memory.ads
@@ -15,6 +15,8 @@
-- along with GCC; see the file COPYING. If not, write to the Free
-- Software Foundation, 59 Temple Place - Suite 330, Boston, MA
-- 02111-1307, USA.
+with Ada.Unchecked_Conversion;
+
package Binary_File.Memory is
-- Must be called before set_symbol_address.
@@ -22,4 +24,13 @@ package Binary_File.Memory is
procedure Set_Symbol_Address (Sym : Symbol; Addr : System.Address);
procedure Write_Memory_Relocate (Error : out Boolean);
+
+ function Get_Section_Base (Sect : Section_Acc) return System.Address;
+ function Get_Section_Size (Sect : Section_Acc) return Pc_Type;
+
+ function To_Pc_Type is new Ada.Unchecked_Conversion
+ (Source => System.Address, Target => Pc_Type);
+ function To_Address is new Ada.Unchecked_Conversion
+ (Source => Pc_Type, Target => System.Address);
+
end Binary_File.Memory;
diff --git a/src/ortho/mcode/dwarf.ads b/src/ortho/mcode/dwarf.ads
index 40ee94f..8a3058c 100644
--- a/src/ortho/mcode/dwarf.ads
+++ b/src/ortho/mcode/dwarf.ads
@@ -396,6 +396,7 @@ package Dwarf is
DW_LNS_Set_Isa : constant Unsigned_8 := 12;
-- Line number extended opcode.
+ -- Encoding is 0:Len:LNE_OP:data
DW_LNE_End_Sequence : constant Unsigned_8 := 1;
DW_LNE_Set_Address : constant Unsigned_8 := 2;
DW_LNE_Define_File : constant Unsigned_8 := 3;
@@ -442,5 +443,3 @@ package Dwarf is
DW_EH_PE_Datarel : constant Unsigned_8 := 16#30#;
DW_EH_PE_Format_Mask : constant Unsigned_8 := 16#0f#;
end Dwarf;
-
-
diff --git a/src/ortho/mcode/ortho_code-dwarf.adb b/src/ortho/mcode/ortho_code-dwarf.adb
index 309c82d..521ab85 100644
--- a/src/ortho/mcode/ortho_code-dwarf.adb
+++ b/src/ortho/mcode/ortho_code-dwarf.adb
@@ -18,13 +18,12 @@
with GNAT.Directory_Operations;
with Tables;
with Interfaces; use Interfaces;
-with Binary_File; use Binary_File;
with Dwarf; use Dwarf;
with Ada.Text_IO;
+with Ortho_Code.Flags; use Ortho_Code.Flags;
with Ortho_Code.Decls;
with Ortho_Code.Types;
with Ortho_Code.Consts;
-with Ortho_Code.Flags;
with Ortho_Ident;
with Ortho_Code.Binary;
@@ -52,21 +51,8 @@ package body Ortho_Code.Dwarf is
Info_Sym : Symbol;
Line_Sym : Symbol;
- Line_Sect : Section_Acc;
- Abbrev_Sect : Section_Acc;
- Info_Sect : Section_Acc;
- Aranges_Sect : Section_Acc;
-
Abbrev_Last : Unsigned_32;
--- procedure Gen_String (Str : String)
--- is
--- begin
--- for I in Str'Range loop
--- Gen_B8 (Character'Pos (Str (I)));
--- end loop;
--- end Gen_String;
-
procedure Gen_String_Nul (Str : String)
is
begin
@@ -118,12 +104,6 @@ package body Ortho_Code.Dwarf is
end loop;
end Gen_Uleb128;
--- procedure New_Debug_Line_Decl (Line : Int32)
--- is
--- begin
--- Line_Last := Line;
--- end New_Debug_Line_Decl;
-
procedure Set_Line_Stmt (Line : Int32)
is
Pc : Pc_Type;
@@ -154,6 +134,7 @@ package body Ortho_Code.Dwarf is
Gen_Uleb128 (Unsigned_32 (Cur_File));
Last_File := Cur_File;
elsif Cur_File = 0 then
+ -- No file yet.
return;
end if;
@@ -173,7 +154,6 @@ package body Ortho_Code.Dwarf is
+ Byte (D_Pc) * Line_Range
+ Byte (D_Ln - Line_Base));
- --Set_Current_Section (Text_Sect);
Line_Pc := Pc;
Line_Last := Line;
end Set_Line_Stmt;
@@ -269,13 +249,11 @@ package body Ortho_Code.Dwarf is
Gen_Uleb128 (Form);
end Gen_Abbrev_Tuple;
- procedure Init
- is
+ procedure Init is
begin
-- Generate type names.
Flags.Flag_Type_Name := True;
-
Orig_Sym := Create_Local_Symbol;
Set_Symbol_Pc (Orig_Sym, False);
End_Sym := Create_Local_Symbol;
@@ -533,10 +511,9 @@ package body Ortho_Code.Dwarf is
is
Off : Pc_Type;
begin
+ pragma Assert (Flag_Debug >= Debug_Dwarf);
Off := TOnodes.Table (Atype);
- if Off = Null_Pc then
- raise Program_Error;
- end if;
+ pragma Assert (Off /= Null_Pc);
Gen_32 (Unsigned_32 (Off));
end Emit_Type_Ref;
@@ -979,6 +956,10 @@ package body Ortho_Code.Dwarf is
Kind : OT_Kind;
Decl : O_Dnode;
begin
+ if Flag_Debug < Debug_Dwarf then
+ return;
+ end if;
+
-- If already emitted, then return.
if Atype <= TOnodes.Last
and then TOnodes.Table (Atype) /= Null_Pc
@@ -1160,21 +1141,23 @@ package body Ortho_Code.Dwarf is
Sdecl : O_Dnode;
Sibling_Pc : Pc_Type;
begin
- if Abbrev_Block = 0 then
- Generate_Abbrev (Abbrev_Block);
+ if Flag_Debug >= Debug_Dwarf then
+ if Abbrev_Block = 0 then
+ Generate_Abbrev (Abbrev_Block);
- Gen_Abbrev_Header (DW_TAG_Lexical_Block, DW_CHILDREN_Yes);
- Gen_Abbrev_Tuple (DW_AT_Sibling, DW_FORM_Ref4);
- Gen_Abbrev_Tuple (DW_AT_Low_Pc, DW_FORM_Addr);
- Gen_Abbrev_Tuple (DW_AT_High_Pc, DW_FORM_Addr);
- Gen_Abbrev_Tuple (0, 0);
- end if;
+ Gen_Abbrev_Header (DW_TAG_Lexical_Block, DW_CHILDREN_Yes);
+ Gen_Abbrev_Tuple (DW_AT_Sibling, DW_FORM_Ref4);
+ Gen_Abbrev_Tuple (DW_AT_Low_Pc, DW_FORM_Addr);
+ Gen_Abbrev_Tuple (DW_AT_High_Pc, DW_FORM_Addr);
+ Gen_Abbrev_Tuple (0, 0);
+ end if;
- Gen_Info_Header (Abbrev_Block);
- Sibling_Pc := Gen_Info_Sibling;
+ Gen_Info_Header (Abbrev_Block);
+ Sibling_Pc := Gen_Info_Sibling;
- Gen_Ua_32 (Subprg_Sym, Integer_32 (Get_Block_Info1 (Decl)));
- Gen_Ua_32 (Subprg_Sym, Integer_32 (Get_Block_Info2 (Decl)));
+ Gen_Ua_32 (Subprg_Sym, Integer_32 (Get_Block_Info1 (Decl)));
+ Gen_Ua_32 (Subprg_Sym, Integer_32 (Get_Block_Info2 (Decl)));
+ end if;
-- Emit decls for children.
Last := Get_Block_Last (Decl);
@@ -1184,11 +1167,13 @@ package body Ortho_Code.Dwarf is
Sdecl := Get_Decl_Chain (Sdecl);
end loop;
- -- End of children.
- Set_Current_Section (Info_Sect);
- Gen_Uleb128 (0);
+ if Flag_Debug >= Debug_Dwarf then
+ -- End of children.
+ Set_Current_Section (Info_Sect);
+ Gen_Uleb128 (0);
- Patch_Info_Sibling (Sibling_Pc);
+ Patch_Info_Sibling (Sibling_Pc);
+ end if;
end Emit_Block_Decl;
Abbrev_Function : Unsigned_32 := 0;
@@ -1198,15 +1183,12 @@ package body Ortho_Code.Dwarf is
procedure Emit_Subprg_Body (Bod : O_Dnode)
is
use Ortho_Code.Decls;
- Kind : OD_Kind;
- Decl : O_Dnode;
+ Decl : constant O_Dnode := Get_Body_Decl (Bod);
+ Kind : constant OD_Kind := Get_Decl_Kind (Decl);
Idecl : O_Dnode;
Prev_Subprg_Sym : Symbol;
Sibling_Pc : Pc_Type;
begin
- Decl := Get_Body_Decl (Bod);
- Kind := Get_Decl_Kind (Decl);
-
-- Emit interfaces type.
Idecl := Get_Subprg_Interfaces (Decl);
while Idecl /= O_Dnode_Null loop
@@ -1220,13 +1202,15 @@ package body Ortho_Code.Dwarf is
Generate_Abbrev (Abbrev_Function);
Gen_Abbrev_Header (DW_TAG_Subprogram, DW_CHILDREN_Yes);
- Gen_Abbrev_Tuple (DW_AT_Sibling, DW_FORM_Ref4);
-
- Gen_Abbrev_Tuple (DW_AT_Type, DW_FORM_Ref4);
Gen_Abbrev_Tuple (DW_AT_Name, DW_FORM_String);
Gen_Abbrev_Tuple (DW_AT_Low_Pc, DW_FORM_Addr);
Gen_Abbrev_Tuple (DW_AT_High_Pc, DW_FORM_Addr);
- Gen_Abbrev_Tuple (DW_AT_Frame_Base, DW_FORM_Block1);
+
+ if Flag_Debug >= Debug_Dwarf then
+ Gen_Abbrev_Tuple (DW_AT_Type, DW_FORM_Ref4);
+ Gen_Abbrev_Tuple (DW_AT_Sibling, DW_FORM_Ref4);
+ Gen_Abbrev_Tuple (DW_AT_Frame_Base, DW_FORM_Block1);
+ end if;
--Gen_Abbrev_Tuple (DW_AT_Return_Addr, DW_FORM_Block1);
Gen_Abbrev_Tuple (0, 0);
end if;
@@ -1236,37 +1220,48 @@ package body Ortho_Code.Dwarf is
Generate_Abbrev (Abbrev_Procedure);
Gen_Abbrev_Header (DW_TAG_Subprogram, DW_CHILDREN_Yes);
- Gen_Abbrev_Tuple (DW_AT_Sibling, DW_FORM_Ref4);
Gen_Abbrev_Tuple (DW_AT_Name, DW_FORM_String);
Gen_Abbrev_Tuple (DW_AT_Low_Pc, DW_FORM_Addr);
Gen_Abbrev_Tuple (DW_AT_High_Pc, DW_FORM_Addr);
- Gen_Abbrev_Tuple (DW_AT_Frame_Base, DW_FORM_Block1);
+ if Flag_Debug >= Debug_Dwarf then
+ Gen_Abbrev_Tuple (DW_AT_Sibling, DW_FORM_Ref4);
+ Gen_Abbrev_Tuple (DW_AT_Frame_Base, DW_FORM_Block1);
+ end if;
--Gen_Abbrev_Tuple (DW_AT_Return_Addr, DW_FORM_Block1);
Gen_Abbrev_Tuple (0, 0);
end if;
Gen_Info_Header (Abbrev_Procedure);
end if;
- Sibling_Pc := Gen_Info_Sibling;
-
- if Kind = OD_Function then
- Emit_Decl_Type (Decl);
- end if;
-
+ -- Name.
Emit_Decl_Ident (Decl);
+
+ -- Low, High.
Prev_Subprg_Sym := Subprg_Sym;
Subprg_Sym := Binary.Get_Decl_Symbol (Decl);
Gen_Ua_32 (Subprg_Sym, 0);
Gen_Ua_32 (Subprg_Sym, Integer_32 (Get_Body_Info (Bod)));
- -- Frame base.
- Gen_B8 (1);
- Gen_B8 (DW_OP_Reg5);
+ if Flag_Debug >= Debug_Dwarf then
+ -- Type.
+ if Kind = OD_Function then
+ Emit_Decl_Type (Decl);
+ end if;
+
+ -- Sibling.
+ Sibling_Pc := Gen_Info_Sibling;
+
+ -- Frame base.
+ Gen_B8 (1);
+ Gen_B8 (DW_OP_Reg5);
+ end if;
-- Interfaces.
Idecl := Get_Subprg_Interfaces (Decl);
- if Idecl /= O_Dnode_Null then
+ if Idecl /= O_Dnode_Null
+ and then Flag_Debug >= Debug_Dwarf
+ then
if Abbrev_Interface = 0 then
Generate_Abbrev (Abbrev_Interface);
@@ -1295,7 +1290,9 @@ package body Ortho_Code.Dwarf is
-- End of children.
Gen_Uleb128 (0);
- Patch_Info_Sibling (Sibling_Pc);
+ if Flag_Debug >= Debug_Dwarf then
+ Patch_Info_Sibling (Sibling_Pc);
+ end if;
Subprg_Sym := Prev_Subprg_Sym;
end Emit_Subprg_Body;
@@ -1305,26 +1302,32 @@ package body Ortho_Code.Dwarf is
use Ada.Text_IO;
use Ortho_Code.Decls;
begin
- case Get_Decl_Kind (Decl) is
- when OD_Type =>
- Emit_Type_Decl (Decl);
- when OD_Local
- | OD_Var =>
- Emit_Variable (Decl);
- when OD_Const =>
- Emit_Const (Decl);
- when OD_Function
- | OD_Procedure
- | OD_Interface =>
- null;
- when OD_Body =>
+ if Flag_Debug = Debug_Dwarf then
+ case Get_Decl_Kind (Decl) is
+ when OD_Type =>
+ Emit_Type_Decl (Decl);
+ when OD_Local
+ | OD_Var =>
+ Emit_Variable (Decl);
+ when OD_Const =>
+ Emit_Const (Decl);
+ when OD_Function
+ | OD_Procedure
+ | OD_Interface =>
+ null;
+ when OD_Body =>
+ Emit_Subprg_Body (Decl);
+ when OD_Block =>
+ Emit_Block_Decl (Decl);
+ when others =>
+ Put_Line ("dwarf.emit_decl: emit "
+ & OD_Kind'Image (Get_Decl_Kind (Decl)));
+ end case;
+ elsif Flag_Debug = Debug_Line then
+ if Get_Decl_Kind (Decl) = OD_Body then
Emit_Subprg_Body (Decl);
- when OD_Block =>
- Emit_Block_Decl (Decl);
- when others =>
- Put_Line ("dwarf.emit_decl: emit "
- & OD_Kind'Image (Get_Decl_Kind (Decl)));
- end case;
+ end if;
+ end if;
end Emit_Decl;
procedure Emit_Subprg (Bod : O_Dnode) is
@@ -1347,4 +1350,3 @@ package body Ortho_Code.Dwarf is
end Release;
end Ortho_Code.Dwarf;
-
diff --git a/src/ortho/mcode/ortho_code-dwarf.ads b/src/ortho/mcode/ortho_code-dwarf.ads
index c120bcf..095a80d 100644
--- a/src/ortho/mcode/ortho_code-dwarf.ads
+++ b/src/ortho/mcode/ortho_code-dwarf.ads
@@ -15,6 +15,8 @@
-- along with GCC; see the file COPYING. If not, write to the Free
-- Software Foundation, 59 Temple Place - Suite 330, Boston, MA
-- 02111-1307, USA.
+with Binary_File; use Binary_File;
+
package Ortho_Code.Dwarf is
procedure Init;
procedure Finish;
@@ -33,6 +35,12 @@ package Ortho_Code.Dwarf is
procedure Mark (M : out Mark_Type);
procedure Release (M : Mark_Type);
+ -- Sections created by dwarf.
+ Line_Sect : Section_Acc;
+ Abbrev_Sect : Section_Acc;
+ Info_Sect : Section_Acc;
+ Aranges_Sect : Section_Acc;
+
private
type Mark_Type is record
Last_Decl : O_Dnode;
diff --git a/src/ortho/mcode/ortho_code-flags.ads b/src/ortho/mcode/ortho_code-flags.ads
index 214cc74..30bded9 100644
--- a/src/ortho/mcode/ortho_code-flags.ads
+++ b/src/ortho/mcode/ortho_code-flags.ads
@@ -16,10 +16,10 @@
-- Software Foundation, 59 Temple Place - Suite 330, Boston, MA
-- 02111-1307, USA.
package Ortho_Code.Flags is
- type Debug_Type is (Debug_None, Debug_Dwarf);
+ type Debug_Type is (Debug_None, Debug_Line, Debug_Dwarf);
-- Debugging information generated.
- Flag_Debug : Debug_Type := Debug_None;
+ Flag_Debug : Debug_Type := Debug_Line;
-- If set, generate a map from type to type declaration.
-- Set with --be-debug=t
diff --git a/src/ortho/mcode/ortho_code-x86-abi.adb b/src/ortho/mcode/ortho_code-x86-abi.adb
index 2be10fe..0a44339 100644
--- a/src/ortho/mcode/ortho_code-x86-abi.adb
+++ b/src/ortho/mcode/ortho_code-x86-abi.adb
@@ -115,7 +115,7 @@ package body Ortho_Code.X86.Abi is
Emits.Emit_Subprg (Subprg);
if Get_Decl_Depth (Subprg.D_Decl) = O_Toplevel
- and then Flag_Debug = Debug_Dwarf
+ and then Flag_Debug /= Debug_None
then
Dwarf.Emit_Decls_Until (Subprg.D_Body);
if not Debug.Flag_Debug_Keep then
@@ -133,7 +133,8 @@ package body Ortho_Code.X86.Abi is
Cur_Subprg := Subprg;
if Get_Decl_Depth (Subprg.D_Decl) = O_Toplevel then
- if Flag_Debug = Debug_Dwarf then
+ -- Only for top-level subprograms.
+ if Flag_Debug /= Debug_None then
Dwarf.Emit_Subprg (Subprg.D_Body);
end if;
@@ -142,7 +143,7 @@ package body Ortho_Code.X86.Abi is
Release (Decls_Mark);
Consts.Release (Consts_Mark);
Release (Types_Mark);
- if Flag_Debug = Debug_Dwarf then
+ if Flag_Debug /= Debug_None then
Dwarf.Release (Dwarf_Mark);
end if;
end if;
@@ -607,7 +608,7 @@ package body Ortho_Code.X86.Abi is
is
use Ortho_Code.Flags;
begin
- if Flag_Debug = Debug_Dwarf then
+ if Flag_Debug /= Debug_None then
Dwarf.Set_Filename ("", Filename);
end if;
end New_Debug_Filename_Decl;
diff --git a/src/ortho/mcode/ortho_code-x86-emits.adb b/src/ortho/mcode/ortho_code-x86-emits.adb
index 4120801..c4cfee9 100644
--- a/src/ortho/mcode/ortho_code-x86-emits.adb
+++ b/src/ortho/mcode/ortho_code-x86-emits.adb
@@ -2356,7 +2356,7 @@ package body Ortho_Code.X86.Emits is
null;
when OE_Line =>
- if Flag_Debug = Debug_Dwarf then
+ if Flag_Debug /= Debug_None then
Dwarf.Set_Line_Stmt (Get_Expr_Line_Number (Stmt));
Set_Current_Section (Sect_Text);
end if;
@@ -2516,7 +2516,7 @@ package body Ortho_Code.X86.Emits is
Gen_1 (Opc_Leave);
Gen_1 (Opc_Ret);
- if Flag_Debug = Debug_Dwarf then
+ if Flag_Debug /= Debug_None then
Set_Body_Info (Subprg.D_Body, Int32 (Get_Current_Pc - Subprg_Pc));
end if;
end Emit_Epilogue;
@@ -2704,7 +2704,7 @@ package body Ortho_Code.X86.Emits is
Debug_Hex := True;
end if;
- if Flag_Debug = Debug_Dwarf then
+ if Flag_Debug /= Debug_None then
Dwarf.Init;
Set_Current_Section (Sect_Text);
end if;
@@ -2714,7 +2714,7 @@ package body Ortho_Code.X86.Emits is
is
use Ortho_Code.Flags;
begin
- if Flag_Debug = Debug_Dwarf then
+ if Flag_Debug /= Debug_None then
Set_Current_Section (Sect_Text);
Dwarf.Finish;
end if;
diff --git a/src/ortho/mcode/ortho_code_main.adb b/src/ortho/mcode/ortho_code_main.adb
index c515f58..b3a2e19 100644
--- a/src/ortho/mcode/ortho_code_main.adb
+++ b/src/ortho/mcode/ortho_code_main.adb
@@ -83,6 +83,9 @@ begin
elsif Arg = "-g" then
Flag_Debug := Debug_Dwarf;
I := I + 1;
+ elsif Arg = "-g0" then
+ Flag_Debug := Debug_None;
+ I := I + 1;
elsif Arg = "-p" or Arg = "-pg" then
Flag_Profile := True;
I := I + 1;
@@ -194,5 +197,3 @@ exception
Set_Exit_Status (2);
raise;
end Ortho_Code_Main;
-
-
diff --git a/src/ortho/mcode/ortho_jit.adb b/src/ortho/mcode/ortho_jit.adb
index 907aea0..f01c8fa 100644
--- a/src/ortho/mcode/ortho_jit.adb
+++ b/src/ortho/mcode/ortho_jit.adb
@@ -1,5 +1,5 @@
-- Ortho JIT implementation for mcode.
--- Copyright (C) 2009 Tristan Gingold
+-- Copyright (C) 2009 - 2015 Tristan Gingold
--
-- GHDL 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
@@ -16,6 +16,8 @@
-- Software Foundation, 59 Temple Place - Suite 330, Boston, MA
-- 02111-1307, USA.
+with System.Storage_Elements; use System.Storage_Elements;
+
with GNAT.OS_Lib; use GNAT.OS_Lib;
with Ada.Text_IO;
@@ -26,7 +28,9 @@ with Ortho_Mcode.Jit;
with Ortho_Code.Flags; use Ortho_Code.Flags;
with Ortho_Code.Debug;
with Ortho_Code.Abi;
-with Binary_File.Elf;
+with Ortho_Code.Dwarf;
+with Binary_File.Format;
+with Symbolizer;
package body Ortho_Jit is
Snap_Filename : GNAT.OS_Lib.String_Access := null;
@@ -76,7 +80,7 @@ package body Ortho_Jit is
Status := False;
return;
else
- Binary_File.Elf.Write (Fd);
+ Binary_File.Format.Write (Fd);
Close (Fd);
end if;
end;
@@ -98,6 +102,9 @@ package body Ortho_Jit is
if Opt = "-g" then
Flag_Debug := Debug_Dwarf;
return True;
+ elsif Opt = "-g0" then
+ Flag_Debug := Debug_None;
+ return True;
elsif Opt'Length > 5 and then Opt (1 .. 5) = "--be-" then
Ortho_Code.Debug.Set_Be_Flag (Opt);
return True;
@@ -122,4 +129,43 @@ package body Ortho_Jit is
return "mcode";
end Get_Jit_Name;
+ procedure Symbolize (Pc : Address;
+ Filename : out Address;
+ Lineno : out Natural;
+ Subprg : out Address)
+ is
+ use Binary_File.Memory;
+ use Symbolizer;
+
+ function Get_Section_Content (Sect : Section_Acc) return Section_Content
+ is
+ Addr : Address;
+ Size : Pc_Type;
+ begin
+ if Sect = null then
+ return (Null_Address, 0);
+ else
+ Addr := Get_Section_Base (Sect);
+ Size := Get_Section_Size (Sect);
+ return (Addr, Storage_Offset (Size));
+ end if;
+ end Get_Section_Content;
+
+ Sections : Dwarf_Sections;
+ Res : Symbolize_Result;
+ begin
+ Sections.Debug_Line :=
+ Get_Section_Content (Ortho_Code.Dwarf.Line_Sect);
+ Sections.Debug_Info :=
+ Get_Section_Content (Ortho_Code.Dwarf.Info_Sect);
+ Sections.Debug_Abbrev :=
+ Get_Section_Content (Ortho_Code.Dwarf.Abbrev_Sect);
+
+ Symbolize_Address (Pc, Sections, Res);
+
+ Filename := Res.Filename;
+ Lineno := Res.Line;
+ Subprg := Res.Subprg_Name;
+ end Symbolize;
+
end Ortho_Jit;
diff --git a/src/ortho/mcode/symbolizer.adb b/src/ortho/mcode/symbolizer.adb
new file mode 100644
index 0000000..79e7de2
--- /dev/null
+++ b/src/ortho/mcode/symbolizer.adb
@@ -0,0 +1,655 @@
+-- Dwarf symbolizer.
+-- Copyright (C) 2015 Tristan Gingold
+--
+-- GHDL 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 2, or (at your option) any later
+-- version.
+--
+-- GHDL 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 GCC; see the file COPYING. If not, write to the Free
+-- Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+-- 02111-1307, USA.
+
+with Ada.Unchecked_Conversion;
+with Interfaces; use Interfaces;
+with Dwarf; use Dwarf;
+
+package body Symbolizer is
+ type Abbrev_Array is array (Unsigned_32 range <>) of Address;
+ type Abbrev_Array_Acc is access Abbrev_Array;
+
+ -- Data for decoding abbrevs.
+ -- Abbrevs are referenced by its number, but it is not possible to directly
+ -- reference an abbrev from its number. A map is required.
+ -- The main purpose of these data is to build the map.
+ type Abbrev_Data is record
+ -- Static map. Mcode doesn't generate a lot of abbrev.
+ Sarray : Abbrev_Array (1 .. 64);
+ -- First non-decoded abbrev.
+ Next_Num : Unsigned_32;
+ -- Address (in .debug_abbrev section) of the next abbrev to be decoded.
+ Next_Addr : Address;
+ -- Address of the first byte after the abbrev section. Used to not read
+ -- past the section.
+ Last_Addr : Address;
+ -- If there are too many abbrevs, use a resizable array instead of the
+ -- static one.
+ Map : Abbrev_Array_Acc;
+ end record;
+
+ function Read_Byte (Addr : Address) return Unsigned_8
+ is
+ type Unsigned_8_Acc is access all Unsigned_8;
+ function To_Unsigned_8_Acc is new Ada.Unchecked_Conversion
+ (Address, Unsigned_8_Acc);
+ begin
+ return To_Unsigned_8_Acc (Addr).all;
+ end Read_Byte;
+
+ procedure Read_Word4 (Addr : in out Address;
+ Res : out Unsigned_32)
+ is
+ B0, B1, B2, B3 : Unsigned_8;
+ begin
+ B0 := Read_Byte (Addr + 0);
+ B1 := Read_Byte (Addr + 1);
+ B2 := Read_Byte (Addr + 2);
+ B3 := Read_Byte (Addr + 3);
+ -- FIXME: we assume little-endian
+ Res := Shift_Left (Unsigned_32 (B3), 24)
+ or Shift_Left (Unsigned_32 (B2), 16)
+ or Shift_Left (Unsigned_32 (B1), 8)
+ or Shift_Left (Unsigned_32 (B0), 0);
+ Addr := Addr + 4;
+ end Read_Word4;
+
+ procedure Read_Word2 (Addr : in out Address;
+ Res : out Unsigned_16)
+ is
+ B0, B1 : Unsigned_8;
+ begin
+ B0 := Read_Byte (Addr + 0);
+ B1 := Read_Byte (Addr + 1);
+ -- FIXME: we assume little-endian
+ Res := Shift_Left (Unsigned_16 (B1), 8)
+ or Shift_Left (Unsigned_16 (B0), 0);
+ Addr := Addr + 2;
+ end Read_Word2;
+
+ procedure Read_Byte (Addr : in out Address;
+ Res : out Unsigned_8)
+ is
+ begin
+ Res := Read_Byte (Addr);
+ Addr := Addr + 1;
+ end Read_Byte;
+
+ procedure Read_ULEB128 (Addr : in out Address;
+ Res : out Unsigned_32)
+ is
+ B : Unsigned_8;
+ Shift : Integer;
+ begin
+ Res := 0;
+ Shift := 0;
+ loop
+ B := Read_Byte (Addr);
+ Addr := Addr + 1;
+ Res := Res or Shift_Left (Unsigned_32 (B and 16#7f#), Shift);
+ exit when (B and 16#80#) = 0;
+ Shift := Shift + 7;
+ end loop;
+ end Read_ULEB128;
+
+ procedure Read_SLEB128 (Addr : in out Address;
+ Res : out Unsigned_32)
+ is
+ B : Unsigned_8;
+ Shift : Integer;
+ begin
+ Res := 0;
+ Shift := 0;
+ loop
+ B := Read_Byte (Addr);
+ Addr := Addr + 1;
+ Res := Res or Shift_Left (Unsigned_32 (B and 16#7f#), Shift);
+ Shift := Shift + 7;
+ exit when (B and 16#80#) = 0;
+ end loop;
+ if Shift < 32 and (Res and Shift_Left (1, Shift - 1)) /= 0 then
+ Res := Res or Shift_Left (-1, Shift);
+ end if;
+ end Read_SLEB128;
+
+ procedure Init_Abbrev (Abbrevs : in out Abbrev_Data;
+ Sections : Dwarf_Sections;
+ Off : Storage_Offset)
+ is
+ Old_Map : Abbrev_Array_Acc;
+ begin
+ Old_Map := Abbrevs.Map;
+ if Old_Map /= null then
+ Old_Map.all := (others => Null_Address);
+ end if;
+
+ Abbrevs := (Sarray => (others => Null_Address),
+ Next_Num => 0,
+ Next_Addr => Sections.Debug_Abbrev.Vaddr + Off,
+ Last_Addr => (Sections.Debug_Abbrev.Vaddr
+ + Sections.Debug_Abbrev.Size),
+ Map => Old_Map);
+ end Init_Abbrev;
+
+ procedure Find_Abbrev (Abbrevs : in out Abbrev_Data;
+ Num : Unsigned_32;
+ Res : out Address)
+ is
+ Code : Unsigned_32;
+ Addr : Address;
+ Tag, Name, Form : Unsigned_32;
+ begin
+ if Num > Abbrevs.Next_Num then
+ -- Not yet decoded.
+ Addr := Abbrevs.Next_Addr;
+
+ while Addr < Abbrevs.Last_Addr loop
+ -- Read abbreviation code.
+ Read_ULEB128 (Addr, Code);
+
+ if Code /= 0 then
+ -- Not a pad.
+
+ -- Insert address in map.
+ if Abbrevs.Map = null then
+ if Code <= Abbrevs.Sarray'Last then
+ Abbrevs.Sarray (Code) := Addr;
+ else
+ raise Program_Error;
+ end if;
+ else
+ if Code <= Abbrevs.Map'Last then
+ Abbrevs.Map (Code) := Addr;
+ else
+ -- Need to expand map.
+ raise Program_Error;
+ end if;
+ end if;
+
+ -- Read tag.
+ Read_ULEB128 (Addr, Tag);
+
+ -- Skip child flag.
+ Addr := Addr + 1;
+
+ -- Skip attribute specifications.
+ loop
+ Read_ULEB128 (Addr, Name);
+ Read_ULEB128 (Addr, Form);
+ exit when Name = 0 and Form = 0;
+ end loop;
+
+ -- Found.
+ exit when Code = Num;
+ end if;
+ end loop;
+
+ -- Next entry to read.
+ Abbrevs.Next_Addr := Addr;
+ end if;
+
+ -- Set result.
+ if Abbrevs.Map = null then
+ Res := Abbrevs.Sarray (Num);
+ else
+ Res := Abbrevs.Map (Num);
+ end if;
+ end Find_Abbrev;
+
+ procedure Read_Uns32 (Addr : in out Address;
+ Form : Unsigned_32;
+ Res : out Unsigned_32) is
+ begin
+ case Form is
+ when DW_FORM_Data4 =>
+ Read_Word4 (Addr, Res);
+ when others =>
+ raise Program_Error;
+ end case;
+ end Read_Uns32;
+
+ procedure Skip_String (Addr : in out Address) is
+ begin
+ while Read_Byte (Addr) /= 0 loop
+ Addr := Addr + 1;
+ end loop;
+ Addr := Addr + 1;
+ end Skip_String;
+
+ procedure Read_Addr (Addr : in out Address;
+ Res : out Address)
+ is
+ function To_Address is new Ada.Unchecked_Conversion
+ (Unsigned_32, Address);
+ V : Unsigned_32;
+ begin
+ Read_Word4 (Addr, V);
+ Res := To_Address (V);
+ end Read_Addr;
+
+ procedure Read_Addr (Addr : in out Address;
+ Form : Unsigned_32;
+ Res : out Address)
+ is
+ begin
+ case Form is
+ when DW_FORM_Addr =>
+ Read_Addr (Addr, Res);
+ when DW_FORM_String =>
+ Res := Addr;
+ Skip_String (Addr);
+ when others =>
+ raise Program_Error;
+ end case;
+ end Read_Addr;
+
+ procedure Read_Ref (Addr : in out Address;
+ Form : Unsigned_32;
+ Base : Address;
+ Res : out Address)
+ is
+ V : Unsigned_32;
+ begin
+ case Form is
+ when DW_FORM_Ref4 =>
+ Read_Word4 (Addr, V);
+ Res := Base + Storage_Offset (V);
+ when others =>
+ raise Program_Error;
+ end case;
+ end Read_Ref;
+
+ procedure Skip_Form (Addr : in out Address;
+ Form : Unsigned_32)
+ is
+ begin
+ case Form is
+ when DW_FORM_Addr =>
+ Addr := Addr + 4;
+ when DW_FORM_Flag =>
+ Addr := Addr + 1;
+ when DW_FORM_Block1 =>
+ Addr := Addr + Storage_Offset (Read_Byte (Addr)) + 1;
+ when DW_FORM_Data1 =>
+ Addr := Addr + 1;
+ when DW_FORM_Data2 =>
+ Addr := Addr + 2;
+ when DW_FORM_Data4 =>
+ Addr := Addr + 4;
+ when DW_FORM_Sdata
+ | DW_FORM_Udata =>
+ while (Read_Byte (Addr) and 16#80#) /= 0 loop
+ Addr := Addr + 1;
+ end loop;
+ Addr := Addr + 1;
+ when DW_FORM_Ref4 =>
+ Addr := Addr + 4;
+ when DW_FORM_Strp =>
+ Addr := Addr + 4;
+ when DW_FORM_String =>
+ Skip_String (Addr);
+ when others =>
+ raise Program_Error;
+ end case;
+ end Skip_Form;
+
+ procedure Find_Subprogram (Pc : Address;
+ Sections : Dwarf_Sections;
+ Res : out Symbolize_Result;
+ Abbrevs : in out Abbrev_Data;
+ Unit_Stmt_List : out Unsigned_32)
+ is
+ Base : Address;
+ Addr : Address;
+ Sect_Last_Addr : Address;
+ Next_Unit_Addr : Address;
+
+ Abbrev : Address;
+
+ Unit_Len : Unsigned_32;
+ Ver : Unsigned_16;
+ Abbrev_Off : Unsigned_32;
+ Ptr_Sz : Unsigned_8;
+ Num : Unsigned_32;
+
+ Tag : Unsigned_32;
+ Abbrev_Name : Unsigned_32;
+ Abbrev_Form : Unsigned_32;
+
+ Level : Unsigned_8;
+
+ Stmt_List : Unsigned_32;
+ Low_Pc : Address;
+ High_Pc : Address;
+ Name : Address;
+ Sibling : Address;
+ begin
+ -- Initialize result.
+ Res := (Filename => Null_Address,
+ Line => 0,
+ Subprg_Name => Null_Address);
+
+ Addr := Sections.Debug_Info.Vaddr;
+ Sect_Last_Addr := Addr + Sections.Debug_Info.Size;
+
+ while Addr < Sect_Last_Addr loop
+ -- Read unit length.
+ Base := Addr;
+ Read_Word4 (Addr, Unit_Len);
+ Next_Unit_Addr := Addr + Storage_Offset (Unit_Len);
+ Read_Word2 (Addr, Ver);
+ Read_Word4 (Addr, Abbrev_Off);
+ Read_Byte (Addr, Ptr_Sz);
+ Level := 0;
+
+ Init_Abbrev (Abbrevs, Sections, Storage_Offset (Abbrev_Off));
+ Unit_Stmt_List := Unsigned_32'Last;
+
+ loop
+ << Again >> null;
+ exit when Addr >= Next_Unit_Addr;
+ -- Read abbrev number.
+ Read_ULEB128 (Addr, Num);
+
+ -- End of children.
+ if Num = 0 then
+ Level := Level - 1;
+ goto Again;
+ end if;
+
+ Find_Abbrev (Abbrevs, Num, Abbrev);
+ if Abbrev = Null_Address then
+ -- Not found...
+ return;
+ end if;
+
+ Read_ULEB128 (Abbrev, Tag);
+ if Read_Byte (Abbrev) /= 0 then
+ Level := Level + 1;
+ end if;
+
+ -- skip child.
+ Abbrev := Abbrev + 1;
+
+ -- We are only interested in a few attributes.
+ Stmt_List := Unsigned_32'Last;
+ Low_Pc := Null_Address;
+ High_Pc := Null_Address;
+ Name := Null_Address;
+ Sibling := Null_Address;
+
+ loop
+ Read_ULEB128 (Abbrev, Abbrev_Name);
+ Read_ULEB128 (Abbrev, Abbrev_Form);
+ exit when Abbrev_Name = 0 and Abbrev_Form = 0;
+ case Abbrev_Name is
+ when DW_AT_Stmt_List =>
+ Read_Uns32 (Addr, Abbrev_Form, Stmt_List);
+ when DW_AT_Low_Pc =>
+ Read_Addr (Addr, Abbrev_Form, Low_Pc);
+ when DW_AT_High_Pc =>
+ Read_Addr (Addr, Abbrev_Form, High_Pc);
+ when DW_AT_Name =>
+ Read_Addr (Addr, Abbrev_Form, Name);
+ when DW_AT_Sibling =>
+ Read_Ref (Addr, Abbrev_Form, Base, Sibling);
+ when others =>
+ Skip_Form (Addr, Abbrev_Form);
+ end case;
+ end loop;
+
+ case Tag is
+ when DW_TAG_Compile_Unit =>
+ if Low_Pc /= Null_Address
+ and then High_Pc /= Null_Address
+ and then (Pc < Low_Pc or Pc > High_Pc)
+ then
+ -- Out of this compile unit.
+ Addr := Next_Unit_Addr;
+ exit;
+ end if;
+ Unit_Stmt_List := Stmt_List;
+ when DW_TAG_Subprogram =>
+ if Low_Pc /= Null_Address
+ and then High_Pc /= Null_Address
+ and then (Pc >= Low_Pc and Pc <= High_Pc)
+ then
+ -- Found!
+ Res.Subprg_Name := Name;
+ return;
+ end if;
+ when DW_TAG_Structure_Type
+ | DW_TAG_Enumeration_Type =>
+ if Sibling /= Null_Address then
+ Addr := Sibling;
+ Level := Level - 1;
+ end if;
+ when others =>
+ null;
+ end case;
+ end loop;
+ end loop;
+ end Find_Subprogram;
+
+ procedure Skip_Filename (Addr : in out Address)
+ is
+ File_Dir : Unsigned_32;
+ File_Time : Unsigned_32;
+ File_Len : Unsigned_32;
+ begin
+ Skip_String (Addr);
+ Read_ULEB128 (Addr, File_Dir);
+ Read_ULEB128 (Addr, File_Time);
+ Read_ULEB128 (Addr, File_Len);
+ end Skip_Filename;
+
+ procedure Find_Lineno (Pc_Addr : Address;
+ Sections : Dwarf_Sections;
+ Res : in out Symbolize_Result;
+ Stmt_List : Storage_Offset)
+ is
+ Addr : Address;
+ Last_Addr : Address;
+ Next_Addr : Address;
+
+ -- Opcode length. Use a fixed bound.
+ Opc_Length : array (Unsigned_8 range 1 .. 32) of Unsigned_8;
+
+ Total_Len : Unsigned_32;
+ Version : Unsigned_16;
+ Prolog_Len : Unsigned_32;
+ Min_Insn_Len : Unsigned_8;
+ Dflt_Is_Stmt : Unsigned_8;
+ Line_Base : Unsigned_8;
+ Line_Range : Unsigned_8;
+ Opc_Base : Unsigned_8;
+
+ B : Unsigned_8;
+ Arg : Unsigned_32;
+
+ File_Names : Address;
+
+ Ext_Len : Unsigned_32;
+ Ext_Opc : Unsigned_8;
+
+ Last : Address;
+
+ Pc : Address;
+ Line : Unsigned_32;
+ Line_Base2 : Unsigned_32;
+ New_Row : Boolean;
+
+ File_Id : Unsigned_32;
+ Prev_File_Id : Unsigned_32;
+ Prev_Pc : Address;
+ Prev_Line : Unsigned_32;
+ begin
+ if Stmt_List >= Sections.Debug_Line.Size then
+ -- Invalid stmt list.
+ return;
+ end if;
+ Addr := Sections.Debug_Line.Vaddr + Stmt_List;
+ Last_Addr := Addr + Sections.Debug_Line.Size - Stmt_List;
+
+ while Addr < Last_Addr loop
+ -- Read header.
+ Read_Word4 (Addr, Total_Len);
+ Last := Addr + Storage_Offset (Total_Len);
+ Read_Word2 (Addr, Version);
+ Read_Word4 (Addr, Prolog_Len);
+ Read_Byte (Addr, Min_Insn_Len);
+ Read_Byte (Addr, Dflt_Is_Stmt);
+ Read_Byte (Addr, Line_Base);
+ Read_Byte (Addr, Line_Range);
+ Read_Byte (Addr, Opc_Base);
+
+ Prev_Pc := Null_Address;
+ Prev_Line := 0;
+ Prev_File_Id := 0;
+ File_Id := 0;
+ New_Row := False;
+ Pc := Null_Address;
+ Line := 1;
+
+ -- Sign extend line base.
+ Line_Base2 := Unsigned_32 (Line_Base);
+ if (Line_Base and 16#80#) /= 0 then
+ Line_Base2 := Line_Base2 or 16#Ff_Ff_Ff_00#;
+ end if;
+
+ -- Read opcodes length.
+ if Opc_Base > Opc_Length'Last then
+ raise Program_Error;
+ end if;
+ for I in 1 .. Opc_Base - 1 loop
+ Read_Byte (Addr, B);
+ Opc_Length (I) := B;
+ end loop;
+
+ -- Include directories.
+ loop
+ B := Read_Byte (Addr);
+ exit when B = 0;
+ Skip_String (Addr);
+ end loop;
+ Addr := Addr + 1;
+
+ -- Filenames.
+ File_Names := Addr;
+ loop
+ B := Read_Byte (Addr);
+ exit when B = 0;
+ Skip_Filename (Addr);
+ end loop;
+ Addr := Addr + 1;
+
+ -- The debug_line 'program'.
+ while Addr < Last loop
+ -- Read opcode.
+ Read_Byte (Addr, B);
+
+ if B = 0 then
+ -- Extended opcode.
+ Read_ULEB128 (Addr, Ext_Len);
+ Next_Addr := Addr;
+ Read_Byte (Addr, Ext_Opc);
+ Next_Addr := Next_Addr + Storage_Offset (Ext_Len);
+ case Ext_Opc is
+ when DW_LNE_End_Sequence =>
+ New_Row := True;
+ when DW_LNE_Set_Address =>
+ Read_Addr (Addr, Pc);
+ when others =>
+ raise Program_Error;
+ end case;
+ pragma Assert (Addr = Next_Addr);
+ elsif B < Opc_Base then
+ -- Standard opcode.
+ case B is
+ when DW_LNS_Copy =>
+ New_Row := True;
+ when DW_LNS_Advance_Pc =>
+ Read_ULEB128 (Addr, Arg);
+ Pc := Pc
+ + Storage_Offset (Arg * Unsigned_32 (Min_Insn_Len));
+ when DW_LNS_Advance_Line =>
+ Read_SLEB128 (Addr, Arg);
+ Line := Line + Arg;
+ when DW_LNS_Const_Add_Pc =>
+ Pc := Pc + Storage_Offset
+ (Unsigned_32 ((255 - Opc_Base) / Line_Range)
+ * Unsigned_32 (Min_Insn_Len));
+ when DW_LNS_Set_File =>
+ Read_ULEB128 (Addr, File_Id);
+ when others =>
+ for J in 1 .. Opc_Length (B) loop
+ Read_ULEB128 (Addr, Arg);
+ end loop;
+ raise Program_Error;
+ end case;
+ else
+ -- Special opcode.
+ B := B - Opc_Base;
+ Pc := Pc + Storage_Offset
+ (Unsigned_32 (B / Line_Range) * Unsigned_32 (Min_Insn_Len));
+ Line := Line + Line_Base2 + Unsigned_32 (B mod Line_Range);
+ New_Row := True;
+ end if;
+
+ if New_Row then
+ New_Row := False;
+ if Pc_Addr >= Prev_Pc and then Pc_Addr < Pc then
+ Res.Line := Natural (Prev_Line);
+
+ -- Search for filename.
+ if Prev_File_Id = 0 then
+ Addr := Null_Address;
+ else
+ Addr := File_Names;
+ while Prev_File_Id > 1 loop
+ exit when Read_Byte (Addr) = 0;
+ Skip_Filename (Addr);
+ Prev_File_Id := Prev_File_Id - 1;
+ end loop;
+ end if;
+ Res.Filename := Addr;
+
+ return;
+ end if;
+ Prev_Pc := Pc;
+ Prev_Line := Line;
+ Prev_File_Id := File_Id;
+ end if;
+ end loop;
+ end loop;
+ end Find_Lineno;
+
+ procedure Symbolize_Address (Pc : Address;
+ Sections : Dwarf_Sections;
+ Res : out Symbolize_Result)
+ is
+ Abbrevs : Abbrev_Data;
+ Unit_Stmt_List : Unsigned_32;
+ begin
+ Find_Subprogram (Pc, Sections, Res, Abbrevs, Unit_Stmt_List);
+
+ if Unit_Stmt_List /= Unsigned_32'Last then
+ Find_Lineno (Pc, Sections, Res, Storage_Offset (Unit_Stmt_List));
+ end if;
+ end Symbolize_Address;
+end Symbolizer;
diff --git a/src/ortho/mcode/symbolizer.ads b/src/ortho/mcode/symbolizer.ads
new file mode 100644
index 0000000..c31b948
--- /dev/null
+++ b/src/ortho/mcode/symbolizer.ads
@@ -0,0 +1,48 @@
+-- Dwarf symbolizer.
+-- Copyright (C) 2015 Tristan Gingold
+--
+-- GHDL 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 2, or (at your option) any later
+-- version.
+--
+-- GHDL 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 GCC; see the file COPYING. If not, write to the Free
+-- Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+-- 02111-1307, USA.
+
+with System.Storage_Elements;
+use System; use System.Storage_Elements;
+
+package Symbolizer is
+ -- Address (in memory) and size of a debug section.
+ type Section_Content is record
+ Vaddr : Address;
+ Size : Storage_Offset;
+ end record;
+
+ -- Input sections.
+ type Dwarf_Sections is record
+ Debug_Line : Section_Content;
+ Debug_Info : Section_Content;
+ Debug_Abbrev : Section_Content;
+ end record;
+
+ -- The result, using C strings.
+ type Symbolize_Result is record
+ Filename : Address;
+ Line : Natural;
+ Subprg_Name : Address;
+ end record;
+
+ -- Translate PC to filename, line number and subprogram name using dwarf
+ -- debug infos.
+ procedure Symbolize_Address (Pc : Address;
+ Sections : Dwarf_Sections;
+ Res : out Symbolize_Result);
+end Symbolizer;
diff --git a/src/ortho/ortho_jit.ads b/src/ortho/ortho_jit.ads
index 89c3663..76a3f29 100644
--- a/src/ortho/ortho_jit.ads
+++ b/src/ortho/ortho_jit.ads
@@ -39,5 +39,9 @@ package Ortho_Jit is
-- Return the name of the code generator, to be displayed by --version.
function Get_Jit_Name return String;
-end Ortho_Jit;
+ procedure Symbolize (Pc : Address;
+ Filename : out Address;
+ Lineno : out Natural;
+ Subprg : out Address);
+end Ortho_Jit;