From 0e56e5906568a70ee8c2f8596437e9194dc88b81 Mon Sep 17 00:00:00 2001
From: Ian Lance Taylor <iant@google.com>
Date: Fri, 28 Sep 2012 14:48:30 +0000
Subject: [PATCH] libgo: Use libbacktrace rather than debug/elf registration.

From-SVN: r191831
---
 ChangeLog                        |   6 ++
 Makefile.def                     |   1 +
 Makefile.in                      |   1 +
 libgo/Makefile.am                |   9 +-
 libgo/Makefile.in                |  12 ++-
 libgo/go/debug/elf/elf_test.go   |   3 +-
 libgo/go/debug/elf/file_test.go  |   3 +-
 libgo/go/debug/elf/runtime.go    | 161 -------------------------------
 libgo/go/net/http/pprof/pprof.go |   1 -
 libgo/go/net/ip_test.go          |   1 -
 libgo/go/runtime/debug/stack.go  |   1 -
 libgo/go/runtime/pprof/pprof.go  |   1 -
 libgo/go/testing/testing.go      |   1 -
 libgo/runtime/go-caller.c        | 150 +++++++++++++++++++++-------
 libgo/runtime/go-callers.c       |  74 +++++++-------
 libgo/runtime/runtime.h          |   4 +-
 16 files changed, 173 insertions(+), 256 deletions(-)
 delete mode 100644 libgo/go/debug/elf/runtime.go

diff --git a/ChangeLog b/ChangeLog
index 6da506e39aca..38217c4b8970 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,9 @@
+2012-09-28  Ian Lance Taylor  <iant@google.com>
+
+	* Makefile.def: Make all-target-libgo depend on
+	all-target-libbacktrace.
+	* Makefile.in: Rebuild.
+
 2012-09-26  Ian Lance Taylor  <iant@google.com>
 
 	* Makefile.def: Make all-gcc depend on all-libbacktrace.
diff --git a/Makefile.def b/Makefile.def
index b3430a4e82ec..c22388a0702e 100644
--- a/Makefile.def
+++ b/Makefile.def
@@ -491,6 +491,7 @@ dependencies = { module=configure-target-fastjar; on=configure-target-zlib; };
 dependencies = { module=all-target-fastjar; on=all-target-zlib; };
 dependencies = { module=configure-target-libgo; on=configure-target-libffi; };
 dependencies = { module=configure-target-libgo; on=all-target-libstdc++-v3; };
+dependencies = { module=all-target-libgo; on=all-target-libbacktrace; };
 dependencies = { module=all-target-libgo; on=all-target-libffi; };
 dependencies = { module=configure-target-libjava; on=configure-target-zlib; };
 dependencies = { module=configure-target-libjava; on=configure-target-boehm-gc; };
diff --git a/Makefile.in b/Makefile.in
index 2cdd08cf491e..9536afffbca2 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -45348,6 +45348,7 @@ configure-target-fastjar: maybe-configure-target-zlib
 all-target-fastjar: maybe-all-target-zlib
 configure-target-libgo: maybe-configure-target-libffi
 configure-target-libgo: maybe-all-target-libstdc++-v3
+all-target-libgo: maybe-all-target-libbacktrace
 all-target-libgo: maybe-all-target-libffi
 configure-target-libjava: maybe-configure-target-zlib
 configure-target-libjava: maybe-configure-target-boehm-gc
diff --git a/libgo/Makefile.am b/libgo/Makefile.am
index 3d2c8b94008f..084399d41724 100644
--- a/libgo/Makefile.am
+++ b/libgo/Makefile.am
@@ -39,7 +39,8 @@ ACLOCAL_AMFLAGS = -I ./config -I ../config
 
 AM_CFLAGS = -fexceptions -fplan9-extensions $(SPLIT_STACK) $(WARN_CFLAGS) \
 	$(STRINGOPS_FLAG) $(OSCFLAGS) \
-	-I $(srcdir)/../libgcc -I $(MULTIBUILDTOP)../../gcc/include
+	-I $(srcdir)/../libgcc -I $(srcdir)/../libbacktrace \
+	-I $(MULTIBUILDTOP)../../gcc/include
 
 if USING_SPLIT_STACK
 AM_LDFLAGS = -XCClinker $(SPLIT_STACK)
@@ -1062,8 +1063,7 @@ go_debug_dwarf_files = \
 	go/debug/dwarf/unit.go
 go_debug_elf_files = \
 	go/debug/elf/elf.go \
-	go/debug/elf/file.go \
-	go/debug/elf/runtime.go
+	go/debug/elf/file.go
 go_debug_gosym_files = \
 	go/debug/gosym/pclntab.go \
 	go/debug/gosym/symtab.go
@@ -1782,7 +1782,8 @@ libgo_la_SOURCES = $(runtime_files)
 libgo_la_LDFLAGS = $(PTHREAD_CFLAGS) $(AM_LDFLAGS)
 
 libgo_la_LIBADD = \
-	$(libgo_go_objs) $(LIBFFI) $(PTHREAD_LIBS) $(MATH_LIBS) $(NET_LIBS)
+	$(libgo_go_objs) ../libbacktrace/libbacktrace.la \
+	$(LIBFFI) $(PTHREAD_LIBS) $(MATH_LIBS) $(NET_LIBS)
 
 libgobegin_a_SOURCES = \
 	runtime/go-main.c
diff --git a/libgo/Makefile.in b/libgo/Makefile.in
index d8b6890022f1..8fd098679d20 100644
--- a/libgo/Makefile.in
+++ b/libgo/Makefile.in
@@ -169,7 +169,8 @@ am__DEPENDENCIES_2 = bufio.lo bytes.lo bytes/index.lo crypto.lo \
 	text/tabwriter.lo text/template.lo text/template/parse.lo \
 	testing/iotest.lo testing/quick.lo unicode/utf16.lo \
 	unicode/utf8.lo
-libgo_la_DEPENDENCIES = $(am__DEPENDENCIES_2) $(am__DEPENDENCIES_1) \
+libgo_la_DEPENDENCIES = $(am__DEPENDENCIES_2) \
+	../libbacktrace/libbacktrace.la $(am__DEPENDENCIES_1) \
 	$(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \
 	$(am__DEPENDENCIES_1)
 @LIBGO_IS_LINUX_FALSE@am__objects_1 = lock_sema.lo thread-sema.lo
@@ -435,7 +436,8 @@ AM_CPPFLAGS = -I $(srcdir)/runtime $(LIBFFIINCS) $(PTHREAD_CFLAGS)
 ACLOCAL_AMFLAGS = -I ./config -I ../config
 AM_CFLAGS = -fexceptions -fplan9-extensions $(SPLIT_STACK) $(WARN_CFLAGS) \
 	$(STRINGOPS_FLAG) $(OSCFLAGS) \
-	-I $(srcdir)/../libgcc -I $(MULTIBUILDTOP)../../gcc/include
+	-I $(srcdir)/../libgcc -I $(srcdir)/../libbacktrace \
+	-I $(MULTIBUILDTOP)../../gcc/include
 
 @USING_SPLIT_STACK_TRUE@AM_LDFLAGS = -XCClinker $(SPLIT_STACK)
 
@@ -1287,8 +1289,7 @@ go_debug_dwarf_files = \
 
 go_debug_elf_files = \
 	go/debug/elf/elf.go \
-	go/debug/elf/file.go \
-	go/debug/elf/runtime.go
+	go/debug/elf/file.go
 
 go_debug_gosym_files = \
 	go/debug/gosym/pclntab.go \
@@ -1932,7 +1933,8 @@ libgo_go_objs = \
 libgo_la_SOURCES = $(runtime_files)
 libgo_la_LDFLAGS = $(PTHREAD_CFLAGS) $(AM_LDFLAGS)
 libgo_la_LIBADD = \
-	$(libgo_go_objs) $(LIBFFI) $(PTHREAD_LIBS) $(MATH_LIBS) $(NET_LIBS)
+	$(libgo_go_objs) ../libbacktrace/libbacktrace.la \
+	$(LIBFFI) $(PTHREAD_LIBS) $(MATH_LIBS) $(NET_LIBS)
 
 libgobegin_a_SOURCES = \
 	runtime/go-main.c
diff --git a/libgo/go/debug/elf/elf_test.go b/libgo/go/debug/elf/elf_test.go
index b8cdbcc7e518..67b961b5c6c2 100644
--- a/libgo/go/debug/elf/elf_test.go
+++ b/libgo/go/debug/elf/elf_test.go
@@ -2,10 +2,9 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-package elf_test
+package elf
 
 import (
-	. "debug/elf"
 	"fmt"
 	"testing"
 )
diff --git a/libgo/go/debug/elf/file_test.go b/libgo/go/debug/elf/file_test.go
index 105b697a4fb7..98f2723c86e6 100644
--- a/libgo/go/debug/elf/file_test.go
+++ b/libgo/go/debug/elf/file_test.go
@@ -2,11 +2,10 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-package elf_test
+package elf
 
 import (
 	"debug/dwarf"
-	. "debug/elf"
 	"encoding/binary"
 	"net"
 	"os"
diff --git a/libgo/go/debug/elf/runtime.go b/libgo/go/debug/elf/runtime.go
deleted file mode 100644
index 17cb6fbc99ef..000000000000
--- a/libgo/go/debug/elf/runtime.go
+++ /dev/null
@@ -1,161 +0,0 @@
-// Copyright 2012 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-// This is gccgo-specific code that uses DWARF information to fetch
-// file/line information for PC values.  This package registers itself
-// with the runtime package.
-
-package elf
-
-import (
-	"debug/dwarf"
-	"debug/macho"
-	"os"
-	"runtime"
-	"sort"
-	"sync"
-)
-
-func init() {
-	// Register our lookup functions with the runtime package.
-	runtime.RegisterDebugLookup(funcFileLine, symbolValue)
-}
-
-// The file struct holds information for a specific file that is part
-// of the execution.
-type file struct {
-	elf   *File       // If ELF
-	macho *macho.File // If Mach-O
-	dwarf *dwarf.Data // DWARF information
-
-	symsByName []sym // Sorted by name
-	symsByAddr []sym // Sorted by address
-}
-
-// Sort symbols by name.
-type symsByName []sym
-
-func (s symsByName) Len() int           { return len(s) }
-func (s symsByName) Less(i, j int) bool { return s[i].name < s[j].name }
-func (s symsByName) Swap(i, j int)      { s[i], s[j] = s[j], s[i] }
-
-// Sort symbols by address.
-type symsByAddr []sym
-
-func (s symsByAddr) Len() int           { return len(s) }
-func (s symsByAddr) Less(i, j int) bool { return s[i].addr < s[j].addr }
-func (s symsByAddr) Swap(i, j int)      { s[i], s[j] = s[j], s[i] }
-
-// The sym structure holds the information we care about for a symbol,
-// namely name and address.
-type sym struct {
-	name string
-	addr uintptr
-}
-
-// Open an input file.
-func open(name string) (*file, error) {
-	efile, err := Open(name)
-	var mfile *macho.File
-	if err != nil {
-		var merr error
-		mfile, merr = macho.Open(name)
-		if merr != nil {
-			return nil, err
-		}
-	}
-
-	r := &file{elf: efile, macho: mfile}
-
-	if efile != nil {
-		r.dwarf, err = efile.DWARF()
-	} else {
-		r.dwarf, err = mfile.DWARF()
-	}
-	if err != nil {
-		return nil, err
-	}
-
-	var syms []sym
-	if efile != nil {
-		esyms, err := efile.Symbols()
-		if err != nil {
-			return nil, err
-		}
-		syms = make([]sym, 0, len(esyms))
-		for _, s := range esyms {
-			if ST_TYPE(s.Info) == STT_FUNC {
-				syms = append(syms, sym{s.Name, uintptr(s.Value)})
-			}
-		}
-	} else {
-		syms = make([]sym, 0, len(mfile.Symtab.Syms))
-		for _, s := range mfile.Symtab.Syms {
-			syms = append(syms, sym{s.Name, uintptr(s.Value)})
-		}
-	}
-
-	r.symsByName = make([]sym, len(syms))
-	copy(r.symsByName, syms)
-	sort.Sort(symsByName(r.symsByName))
-
-	r.symsByAddr = syms
-	sort.Sort(symsByAddr(r.symsByAddr))
-
-	return r, nil
-}
-
-// The main executable
-var executable *file
-
-// Only open the executable once.
-var executableOnce sync.Once
-
-func openExecutable() {
-	executableOnce.Do(func() {
-		f, err := open("/proc/self/exe")
-		if err != nil {
-			f, err = open(os.Args[0])
-			if err != nil {
-				return
-			}
-		}
-		executable = f
-	})
-}
-
-// The funcFileLine function looks up the function name, file name,
-// and line number for a PC value.
-func funcFileLine(pc uintptr, function *string, file *string, line *int) bool {
-	openExecutable()
-	if executable == nil || executable.dwarf == nil {
-		return false
-	}
-	f, ln, err := executable.dwarf.FileLine(uint64(pc))
-	if err != nil {
-		return false
-	}
-	*file = f
-	*line = ln
-
-	*function = ""
-	if len(executable.symsByAddr) > 0 && pc >= executable.symsByAddr[0].addr {
-		i := sort.Search(len(executable.symsByAddr),
-			func(i int) bool { return executable.symsByAddr[i].addr > pc })
-		*function = executable.symsByAddr[i-1].name
-	}
-
-	return true
-}
-
-// The symbolValue function fetches the value of a symbol.
-func symbolValue(name string, val *uintptr) bool {
-	i := sort.Search(len(executable.symsByName),
-		func(i int) bool { return executable.symsByName[i].name >= name })
-	if i >= len(executable.symsByName) || executable.symsByName[i].name != name {
-		return false
-	}
-	*val = executable.symsByName[i].addr
-	return true
-}
diff --git a/libgo/go/net/http/pprof/pprof.go b/libgo/go/net/http/pprof/pprof.go
index b8874f35d2f7..06fcde1447fb 100644
--- a/libgo/go/net/http/pprof/pprof.go
+++ b/libgo/go/net/http/pprof/pprof.go
@@ -35,7 +35,6 @@ package pprof
 import (
 	"bufio"
 	"bytes"
-	_ "debug/elf"
 	"fmt"
 	"html/template"
 	"io"
diff --git a/libgo/go/net/ip_test.go b/libgo/go/net/ip_test.go
index d0e987b85f7b..df647ef73c0f 100644
--- a/libgo/go/net/ip_test.go
+++ b/libgo/go/net/ip_test.go
@@ -6,7 +6,6 @@ package net
 
 import (
 	"bytes"
-	_ "debug/elf"
 	"reflect"
 	"runtime"
 	"testing"
diff --git a/libgo/go/runtime/debug/stack.go b/libgo/go/runtime/debug/stack.go
index fc74e537b754..a533a5c3bf48 100644
--- a/libgo/go/runtime/debug/stack.go
+++ b/libgo/go/runtime/debug/stack.go
@@ -8,7 +8,6 @@ package debug
 
 import (
 	"bytes"
-	_ "debug/elf"
 	"fmt"
 	"io/ioutil"
 	"os"
diff --git a/libgo/go/runtime/pprof/pprof.go b/libgo/go/runtime/pprof/pprof.go
index 87f17d2db124..f67e8a8f9aef 100644
--- a/libgo/go/runtime/pprof/pprof.go
+++ b/libgo/go/runtime/pprof/pprof.go
@@ -11,7 +11,6 @@ package pprof
 import (
 	"bufio"
 	"bytes"
-	_ "debug/elf"
 	"fmt"
 	"io"
 	"runtime"
diff --git a/libgo/go/testing/testing.go b/libgo/go/testing/testing.go
index 1cb8a078c6d1..f59ce8ed6f73 100644
--- a/libgo/go/testing/testing.go
+++ b/libgo/go/testing/testing.go
@@ -79,7 +79,6 @@
 package testing
 
 import (
-	_ "debug/elf"
 	"flag"
 	"fmt"
 	"os"
diff --git a/libgo/runtime/go-caller.c b/libgo/runtime/go-caller.c
index b99d20c225f6..7d5df852886e 100644
--- a/libgo/runtime/go-caller.c
+++ b/libgo/runtime/go-caller.c
@@ -8,41 +8,99 @@
 
 #include <stdint.h>
 
+#include "backtrace.h"
+
 #include "runtime.h"
 #include "go-string.h"
 
 /* Get the function name, file name, and line number for a PC value.
-   We use the DWARF debug information to get this.  Rather than write
-   a whole new library in C, we use the existing Go library.
-   Unfortunately, the Go library is only available if the debug/elf
-   package is imported (we use debug/elf for both ELF and Mach-O, in
-   this case).  We arrange for the debug/elf package to register
-   itself, and tweak the various packages that need this information
-   to import debug/elf where possible.  */
+   We use the backtrace library to get this.  */
+
+/* Data structure to gather file/line information.  */
+
+struct caller
+{
+  struct __go_string fn;
+  struct __go_string file;
+  int line;
+};
+
+/* Collect file/line information for a PC value.  If this is called
+   more than once, due to inlined functions, we use the last call, as
+   that is usually the most useful one.  */
+
+static int
+callback (void *data, uintptr_t pc __attribute__ ((unused)),
+	  const char *filename, int lineno, const char *function)
+{
+  struct caller *c = (struct caller *) data;
+
+  if (function == NULL)
+    {
+      c->fn.__data = NULL;
+      c->fn.__length = 0;
+    }
+  else
+    {
+      char *s;
+
+      c->fn.__length = __builtin_strlen (function);
+      s = runtime_malloc (c->fn.__length);
+      __builtin_memcpy (s, function, c->fn.__length);
+      c->fn.__data = (unsigned char *) s;
+    }
+
+  if (filename == NULL)
+    {
+      c->file.__data = NULL;
+      c->file.__length = 0;
+    }
+  else
+    {
+      char *s;
+
+      c->file.__length = __builtin_strlen (filename);
+      s = runtime_malloc (c->file.__length);
+      __builtin_memcpy (s, filename, c->file.__length);
+      c->file.__data = (unsigned char *) s;
+    }
+
+  c->line = lineno;
+
+  return 0;
+}
 
-/* The function that returns function/file/line information.  */
+/* The error callback for backtrace_pcinfo and backtrace_syminfo.  */
 
-typedef _Bool (*infofn_type) (uintptr_t, struct __go_string *,
-			      struct __go_string *, int *);
-static infofn_type infofn;
+static void
+error_callback (void *data __attribute__ ((unused)),
+		const char *msg, int errnum)
+{
+  if (errnum == -1)
+    return;
+  if (errnum > 0)
+    runtime_printf ("%s errno %d\n", msg, errnum);
+  runtime_throw (msg);
+}
+
+/* The backtrace library state.  */
 
-/* The function that returns the value of a symbol, used to get the
-   entry address of a function.  */
+static void *back_state;
 
-typedef _Bool (*symvalfn_type) (struct __go_string, uintptr_t *);
-static symvalfn_type symvalfn;
+/* A lock to control creating back_state.  */
 
-/* This is called by debug/elf to register the function that returns
-   function/file/line information.  */
+static Lock back_state_lock;
 
-void RegisterDebugLookup (infofn_type, symvalfn_type)
-  __asm__ ("runtime.RegisterDebugLookup");
+/* Fetch back_state, creating it if necessary.  */
 
-void
-RegisterDebugLookup (infofn_type pi, symvalfn_type ps)
+struct backtrace_state *
+__go_get_backtrace_state ()
 {
-  infofn = pi;
-  symvalfn = ps;
+  runtime_lock (&back_state_lock);
+  if (back_state == NULL)
+    back_state = backtrace_create_state (NULL, 1, error_callback, NULL);
+  runtime_unlock (&back_state_lock);
+  return back_state;
 }
 
 /* Return function/file/line information for PC.  */
@@ -51,19 +109,38 @@ _Bool
 __go_file_line (uintptr pc, struct __go_string *fn, struct __go_string *file,
 		int *line)
 {
-  if (infofn == NULL)
-    return 0;
-  return infofn (pc, fn, file, line);
+  struct caller c;
+
+  runtime_memclr (&c, sizeof c);
+  backtrace_pcinfo (__go_get_backtrace_state (), pc, callback,
+		    error_callback, &c);
+  *fn = c.fn;
+  *file = c.file;
+  *line = c.line;
+  return c.file.__length > 0;
 }
 
-/* Return the value of a symbol.  */
+/* Collect symbol information.  */
 
-_Bool
-__go_symbol_value (struct __go_string sym, uintptr_t *val)
+static void
+syminfo_callback (void *data, uintptr_t pc __attribute__ ((unused)),
+		  const char *symname __attribute__ ((unused)),
+		  uintptr_t address)
+{
+  uintptr_t *pval = (uintptr_t *) data;
+
+  *pval = address;
+}
+
+/* Set *VAL to the value of the symbol for PC.  */
+
+static _Bool
+__go_symbol_value (uintptr_t pc, uintptr_t *val)
 {
-  if (symvalfn == NULL)
-    return 0;
-  return symvalfn (sym, val);
+  *val = 0;
+  backtrace_syminfo (__go_get_backtrace_state (), pc, syminfo_callback,
+		     error_callback, &val);
+  return *val != 0;
 }
 
 /* The values returned by runtime.Caller.  */
@@ -112,12 +189,15 @@ FuncForPC (uintptr_t pc)
 
   if (!__go_file_line (pc, &fn, &file, &line))
     return NULL;
-  if (!__go_symbol_value (fn, &val))
-    return NULL;
 
   ret = (Func *) runtime_malloc (sizeof (*ret));
   ret->name = fn;
-  ret->entry = val;
+
+  if (__go_symbol_value (pc, &val))
+    ret->entry = val;
+  else
+    ret->entry = 0;
+
   return ret;
 }
 
diff --git a/libgo/runtime/go-callers.c b/libgo/runtime/go-callers.c
index 3eea5f2ceadf..71d69f6ad5d1 100644
--- a/libgo/runtime/go-callers.c
+++ b/libgo/runtime/go-callers.c
@@ -6,64 +6,56 @@
 
 #include "config.h"
 
-#include "unwind.h"
+#include "backtrace.h"
 
 #include "runtime.h"
 
-/* Argument passed to backtrace function.  */
+/* Argument passed to callback function.  */
 
 struct callers_data
 {
-  int skip;
   uintptr *pcbuf;
   int index;
   int max;
 };
 
-static _Unwind_Reason_Code
-backtrace (struct _Unwind_Context *context, void *varg)
+/* Callback function for backtrace_simple.  Just collect the PC
+   values.  Return zero to continue, non-zero to stop.  */
+
+static int
+callback (void *data, uintptr_t pc)
+{
+  struct callers_data *arg = (struct callers_data *) data;
+
+  arg->pcbuf[arg->index] = pc;
+  ++arg->index;
+  return arg->index >= arg->max;
+}
+
+/* Error callback.  */
+
+static void
+error_callback (void *data __attribute__ ((unused)),
+		const char *msg, int errnum)
 {
-  struct callers_data *arg = (struct callers_data *) varg;
-  uintptr pc;
-  int ip_before_insn = 0;
-
-#ifdef HAVE_GETIPINFO
-  pc = _Unwind_GetIPInfo (context, &ip_before_insn);
-#else
-  pc = _Unwind_GetIP (context);
-#endif
-
-  /* FIXME: If PC is in the __morestack routine, we should ignore
-     it.  */
-
-  if (arg->skip > 0)
-    --arg->skip;
-  else if (arg->index >= arg->max)
-    return _URC_END_OF_STACK;
-  else
-    {
-      /* Here PC will be the return address.  We actually want the
-	 address of the call instruction, so back up one byte and
-	 count on the lookup routines handling that correctly.  */
-      if (!ip_before_insn)
-	--pc;
-      arg->pcbuf[arg->index] = pc;
-      ++arg->index;
-    }
-  return _URC_NO_REASON;
+  if (errnum != 0)
+    runtime_printf ("%s errno %d\n", msg, errnum);
+  runtime_throw (msg);
 }
 
+/* Gather caller PC's.  */
+
 int32
 runtime_callers (int32 skip, uintptr *pcbuf, int32 m)
 {
-  struct callers_data arg;
-
-  arg.skip = skip + 1;
-  arg.pcbuf = pcbuf;
-  arg.index = 0;
-  arg.max = m;
-  _Unwind_Backtrace (backtrace, &arg);
-  return arg.index;
+  struct callers_data data;
+
+  data.pcbuf = pcbuf;
+  data.index = 0;
+  data.max = m;
+  backtrace_simple (__go_get_backtrace_state (), skip + 1, callback,
+		    error_callback, &data);
+  return data.index;
 }
 
 int Callers (int, struct __go_open_array)
diff --git a/libgo/runtime/runtime.h b/libgo/runtime/runtime.h
index cebc1fd98013..f96d740fb1ce 100644
--- a/libgo/runtime/runtime.h
+++ b/libgo/runtime/runtime.h
@@ -517,6 +517,8 @@ void	__go_register_gc_roots(struct root_list*);
 // the stacks are allocated by the splitstack library.
 extern uintptr runtime_stacks_sys;
 
-extern _Bool __go_file_line (uintptr, String*, String*, int *);
+struct backtrace_state;
+extern struct backtrace_state *__go_get_backtrace_state(void);
+extern _Bool __go_file_line(uintptr, String*, String*, int *);
 
 int32 getproccount(void);
-- 
GitLab