Commit 0effc3f9 by Ian Lance Taylor

libgo: Implement and use runtime.Caller, runtime.Func.FileLine.

From-SVN: r185025
parent 1f3d0afc
...@@ -1024,12 +1024,14 @@ go_debug_dwarf_files = \ ...@@ -1024,12 +1024,14 @@ go_debug_dwarf_files = \
go/debug/dwarf/buf.go \ go/debug/dwarf/buf.go \
go/debug/dwarf/const.go \ go/debug/dwarf/const.go \
go/debug/dwarf/entry.go \ go/debug/dwarf/entry.go \
go/debug/dwarf/line.go \
go/debug/dwarf/open.go \ go/debug/dwarf/open.go \
go/debug/dwarf/type.go \ go/debug/dwarf/type.go \
go/debug/dwarf/unit.go go/debug/dwarf/unit.go
go_debug_elf_files = \ go_debug_elf_files = \
go/debug/elf/elf.go \ go/debug/elf/elf.go \
go/debug/elf/file.go go/debug/elf/file.go \
go/debug/elf/runtime.go
go_debug_gosym_files = \ go_debug_gosym_files = \
go/debug/gosym/pclntab.go \ go/debug/gosym/pclntab.go \
go/debug/gosym/symtab.go go/debug/gosym/symtab.go
......
...@@ -1340,13 +1340,15 @@ go_debug_dwarf_files = \ ...@@ -1340,13 +1340,15 @@ go_debug_dwarf_files = \
go/debug/dwarf/buf.go \ go/debug/dwarf/buf.go \
go/debug/dwarf/const.go \ go/debug/dwarf/const.go \
go/debug/dwarf/entry.go \ go/debug/dwarf/entry.go \
go/debug/dwarf/line.go \
go/debug/dwarf/open.go \ go/debug/dwarf/open.go \
go/debug/dwarf/type.go \ go/debug/dwarf/type.go \
go/debug/dwarf/unit.go go/debug/dwarf/unit.go
go_debug_elf_files = \ go_debug_elf_files = \
go/debug/elf/elf.go \ go/debug/elf/elf.go \
go/debug/elf/file.go go/debug/elf/file.go \
go/debug/elf/runtime.go
go_debug_gosym_files = \ go_debug_gosym_files = \
go/debug/gosym/pclntab.go \ go/debug/gosym/pclntab.go \
......
...@@ -431,3 +431,30 @@ const ( ...@@ -431,3 +431,30 @@ const (
encUnsignedChar = 0x08 encUnsignedChar = 0x08
encImaginaryFloat = 0x09 encImaginaryFloat = 0x09
) )
// Line number opcodes.
const (
LineExtendedOp = 0
LineCopy = 1
LineAdvancePC = 2
LineAdvanceLine = 3
LineSetFile = 4
LineSetColumn = 5
LineNegateStmt = 6
LineSetBasicBlock = 7
LineConstAddPC = 8
LineFixedAdvancePC = 9
// next 3 are DWARF 3
LineSetPrologueEnd = 10
LineSetEpilogueBegin = 11
LineSetISA = 12
)
// Line number extended opcodes.
const (
LineExtEndSequence = 1
LineExtSetAddress = 2
LineExtDefineFile = 3
// next 1 is DWARF 4
LineExtSetDiscriminator = 4
)
...@@ -246,6 +246,15 @@ func (d *Data) Reader() *Reader { ...@@ -246,6 +246,15 @@ func (d *Data) Reader() *Reader {
return r return r
} }
// unitReader returns a new reader starting at a specific unit.
func (d *Data) unitReader(i int) *Reader {
r := &Reader{d: d}
r.unit = i
u := &d.unit[i]
r.b = makeBuf(d, "info", u.off, u.data, u.addrsize)
return r
}
// Seek positions the Reader at offset off in the encoded entry stream. // Seek positions the Reader at offset off in the encoded entry stream.
// Offset 0 can be used to denote the first entry. // Offset 0 can be used to denote the first entry.
func (r *Reader) Seek(off Offset) { func (r *Reader) Seek(off Offset) {
......
// 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.
package dwarf_test
import (
. "debug/dwarf"
"path/filepath"
"testing"
)
type lineTest struct {
pc uint64
file string
line int
}
var elfLineTests = [...]lineTest{
{0x4004c4, "typedef.c", 83},
{0x4004c8, "typedef.c", 84},
{0x4004ca, "typedef.c", 84},
{0x4003e0, "", 0},
}
var machoLineTests = [...]lineTest{
{0x0, "typedef.c", 83},
}
func TestLineElf(t *testing.T) {
testLine(t, elfData(t, "testdata/typedef.elf"), elfLineTests[:], "elf")
}
func TestLineMachO(t *testing.T) {
testLine(t, machoData(t, "testdata/typedef.macho"), machoLineTests[:], "macho")
}
func testLine(t *testing.T, d *Data, tests []lineTest, kind string) {
for _, v := range tests {
file, line, err := d.FileLine(v.pc)
if err != nil {
t.Errorf("%s: %v", kind, err)
continue
}
if file != "" {
file = filepath.Base(file)
}
if file != v.file || line != v.line {
t.Errorf("%s: for %d have %q:%d want %q:%d",
kind, v.pc, file, line, v.file, v.line)
}
}
}
...@@ -12,9 +12,19 @@ import "strconv" ...@@ -12,9 +12,19 @@ import "strconv"
type unit struct { type unit struct {
base Offset // byte offset of header within the aggregate info base Offset // byte offset of header within the aggregate info
off Offset // byte offset of data within the aggregate info off Offset // byte offset of data within the aggregate info
lineoff Offset // byte offset of data within the line info
data []byte data []byte
atable abbrevTable atable abbrevTable
addrsize int addrsize int
dir string
pc []addrRange // PC ranges in this compilation unit
lines []mapLineInfo // PC -> line mapping
}
// A range is an address range.
type addrRange struct {
low uint64
high uint64
} }
func (d *Data) parseUnits() ([]unit, error) { func (d *Data) parseUnits() ([]unit, error) {
......
...@@ -2,9 +2,10 @@ ...@@ -2,9 +2,10 @@
// Use of this source code is governed by a BSD-style // Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
package elf package elf_test
import ( import (
. "debug/elf"
"fmt" "fmt"
"testing" "testing"
) )
......
...@@ -563,7 +563,7 @@ func (f *File) DWARF() (*dwarf.Data, error) { ...@@ -563,7 +563,7 @@ func (f *File) DWARF() (*dwarf.Data, error) {
// There are many other DWARF sections, but these // There are many other DWARF sections, but these
// are the required ones, and the debug/dwarf package // are the required ones, and the debug/dwarf package
// does not use the others, so don't bother loading them. // does not use the others, so don't bother loading them.
var names = [...]string{"abbrev", "info", "str"} var names = [...]string{"abbrev", "info", "line", "str"}
var dat [len(names)][]byte var dat [len(names)][]byte
for i, name := range names { for i, name := range names {
name = ".debug_" + name name = ".debug_" + name
...@@ -592,8 +592,8 @@ func (f *File) DWARF() (*dwarf.Data, error) { ...@@ -592,8 +592,8 @@ func (f *File) DWARF() (*dwarf.Data, error) {
} }
} }
abbrev, info, str := dat[0], dat[1], dat[2] abbrev, info, line, str := dat[0], dat[1], dat[2], dat[3]
return dwarf.New(abbrev, nil, nil, info, nil, nil, nil, str) return dwarf.New(abbrev, nil, nil, info, line, nil, nil, str)
} }
// Symbols returns the symbol table for f. // Symbols returns the symbol table for f.
......
...@@ -2,10 +2,11 @@ ...@@ -2,10 +2,11 @@
// Use of this source code is governed by a BSD-style // Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
package elf package elf_test
import ( import (
"debug/dwarf" "debug/dwarf"
. "debug/elf"
"encoding/binary" "encoding/binary"
"net" "net"
"os" "os"
......
// 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.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
}
...@@ -467,7 +467,7 @@ func (f *File) DWARF() (*dwarf.Data, error) { ...@@ -467,7 +467,7 @@ func (f *File) DWARF() (*dwarf.Data, error) {
// There are many other DWARF sections, but these // There are many other DWARF sections, but these
// are the required ones, and the debug/dwarf package // are the required ones, and the debug/dwarf package
// does not use the others, so don't bother loading them. // does not use the others, so don't bother loading them.
var names = [...]string{"abbrev", "info", "str"} var names = [...]string{"abbrev", "info", "line", "str"}
var dat [len(names)][]byte var dat [len(names)][]byte
for i, name := range names { for i, name := range names {
name = "__debug_" + name name = "__debug_" + name
...@@ -482,8 +482,8 @@ func (f *File) DWARF() (*dwarf.Data, error) { ...@@ -482,8 +482,8 @@ func (f *File) DWARF() (*dwarf.Data, error) {
dat[i] = b dat[i] = b
} }
abbrev, info, str := dat[0], dat[1], dat[2] abbrev, info, line, str := dat[0], dat[1], dat[2], dat[3]
return dwarf.New(abbrev, nil, nil, info, nil, nil, nil, str) return dwarf.New(abbrev, nil, nil, info, line, nil, nil, str)
} }
// ImportedSymbols returns the names of all symbols // ImportedSymbols returns the names of all symbols
......
...@@ -2,9 +2,10 @@ ...@@ -2,9 +2,10 @@
// Use of this source code is governed by a BSD-style // Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
package macho package macho_test
import ( import (
. "debug/macho"
"reflect" "reflect"
"testing" "testing"
) )
......
...@@ -2,10 +2,11 @@ ...@@ -2,10 +2,11 @@
// Use of this source code is governed by a BSD-style // Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
package binary package binary_test
import ( import (
"bytes" "bytes"
. "encoding/binary"
"io" "io"
"math" "math"
"reflect" "reflect"
...@@ -187,7 +188,7 @@ func BenchmarkReadStruct(b *testing.B) { ...@@ -187,7 +188,7 @@ func BenchmarkReadStruct(b *testing.B) {
bsr := &byteSliceReader{} bsr := &byteSliceReader{}
var buf bytes.Buffer var buf bytes.Buffer
Write(&buf, BigEndian, &s) Write(&buf, BigEndian, &s)
n := dataSize(reflect.ValueOf(s)) n := DataSize(reflect.ValueOf(s))
b.SetBytes(int64(n)) b.SetBytes(int64(n))
t := s t := s
b.ResetTimer() b.ResetTimer()
......
// 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.
package binary
import "reflect"
// Export for testing.
func DataSize(v reflect.Value) int {
return dataSize(v)
}
var Overflow = overflow
...@@ -2,10 +2,11 @@ ...@@ -2,10 +2,11 @@
// Use of this source code is governed by a BSD-style // Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
package binary package binary_test
import ( import (
"bytes" "bytes"
. "encoding/binary"
"io" "io"
"testing" "testing"
) )
...@@ -134,8 +135,8 @@ func testOverflow(t *testing.T, buf []byte, n0 int, err0 error) { ...@@ -134,8 +135,8 @@ func testOverflow(t *testing.T, buf []byte, n0 int, err0 error) {
} }
func TestOverflow(t *testing.T) { func TestOverflow(t *testing.T) {
testOverflow(t, []byte{0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x2}, -10, overflow) testOverflow(t, []byte{0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x2}, -10, Overflow)
testOverflow(t, []byte{0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x1, 0, 0}, -13, overflow) testOverflow(t, []byte{0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x1, 0, 0}, -13, Overflow)
} }
func TestNonCanonicalZero(t *testing.T) { func TestNonCanonicalZero(t *testing.T) {
......
...@@ -14,6 +14,7 @@ package log ...@@ -14,6 +14,7 @@ package log
import ( import (
"bytes" "bytes"
_ "debug/elf"
"fmt" "fmt"
"io" "io"
"os" "os"
......
...@@ -17,9 +17,9 @@ const ( ...@@ -17,9 +17,9 @@ const (
Rdate = `[0-9][0-9][0-9][0-9]/[0-9][0-9]/[0-9][0-9]` Rdate = `[0-9][0-9][0-9][0-9]/[0-9][0-9]/[0-9][0-9]`
Rtime = `[0-9][0-9]:[0-9][0-9]:[0-9][0-9]` Rtime = `[0-9][0-9]:[0-9][0-9]:[0-9][0-9]`
Rmicroseconds = `\.[0-9][0-9][0-9][0-9][0-9][0-9]` Rmicroseconds = `\.[0-9][0-9][0-9][0-9][0-9][0-9]`
Rline = `[0-9]+:` // must update if the calls to l.Printf / l.Print below move Rline = `(54|56):` // must update if the calls to l.Printf / l.Print below move
Rlongfile = `.*/[A-Za-z0-9_\-]+\.go:|\?\?\?:` + Rline Rlongfile = `.*/[A-Za-z0-9_\-]+\.go:` + Rline
Rshortfile = `[A-Za-z0-9_\-]+\.go:|\?\?\?:` + Rline Rshortfile = `[A-Za-z0-9_\-]+\.go:` + Rline
) )
type tester struct { type tester struct {
......
...@@ -35,6 +35,7 @@ package pprof ...@@ -35,6 +35,7 @@ package pprof
import ( import (
"bufio" "bufio"
"bytes" "bytes"
_ "debug/elf"
"fmt" "fmt"
"html/template" "html/template"
"io" "io"
......
...@@ -6,6 +6,7 @@ package net ...@@ -6,6 +6,7 @@ package net
import ( import (
"bytes" "bytes"
_ "debug/elf"
"reflect" "reflect"
"runtime" "runtime"
"testing" "testing"
......
...@@ -8,6 +8,7 @@ package debug ...@@ -8,6 +8,7 @@ package debug
import ( import (
"bytes" "bytes"
_ "debug/elf"
"fmt" "fmt"
"io/ioutil" "io/ioutil"
"os" "os"
......
...@@ -32,16 +32,8 @@ func Caller(skip int) (pc uintptr, file string, line int, ok bool) ...@@ -32,16 +32,8 @@ func Caller(skip int) (pc uintptr, file string, line int, ok bool)
func Callers(skip int, pc []uintptr) int func Callers(skip int, pc []uintptr) int
type Func struct { // Keep in sync with runtime.h:struct Func type Func struct { // Keep in sync with runtime.h:struct Func
name string name string
typ string // go type string entry uintptr // entry pc
src string // src file name
pcln []byte // pc/ln tab for this func
entry uintptr // entry pc
pc0 uintptr // starting pc, ln for table
ln0 int32
frame int32 // stack frame size
args int32 // number of 32-bit in/out args
locals int32 // number of 32-bit locals
} }
// FuncForPC returns a *Func describing the function that contains the // FuncForPC returns a *Func describing the function that contains the
...@@ -65,6 +57,10 @@ func (f *Func) FileLine(pc uintptr) (file string, line int) { ...@@ -65,6 +57,10 @@ func (f *Func) FileLine(pc uintptr) (file string, line int) {
// implemented in symtab.c // implemented in symtab.c
func funcline_go(*Func, uintptr) (string, int) func funcline_go(*Func, uintptr) (string, int)
// A gccgo specific hook to use debug info to get file/line info.
func RegisterDebugLookup(func(pc uintptr, function *string, file *string, line *int) bool,
func(sym string, val *uintptr) bool)
// mid returns the current os thread (m) id. // mid returns the current os thread (m) id.
func mid() uint32 func mid() uint32
......
...@@ -11,6 +11,7 @@ package pprof ...@@ -11,6 +11,7 @@ package pprof
import ( import (
"bufio" "bufio"
"bytes" "bytes"
_ "debug/elf"
"fmt" "fmt"
"io" "io"
"runtime" "runtime"
......
...@@ -79,6 +79,7 @@ ...@@ -79,6 +79,7 @@
package testing package testing
import ( import (
_ "debug/elf"
"flag" "flag"
"fmt" "fmt"
"os" "os"
......
...@@ -8,8 +8,64 @@ ...@@ -8,8 +8,64 @@
#include <stdint.h> #include <stdint.h>
#include "runtime.h"
#include "go-string.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. */
/* The function that returns function/file/line information. */
typedef _Bool (*infofn_type) (uintptr_t, struct __go_string *,
struct __go_string *, int *);
static infofn_type infofn;
/* The function that returns the value of a symbol, used to get the
entry address of a function. */
typedef _Bool (*symvalfn_type) (struct __go_string, uintptr_t *);
static symvalfn_type symvalfn;
/* This is called by debug/elf to register the function that returns
function/file/line information. */
void RegisterDebugLookup (infofn_type, symvalfn_type)
__asm__ ("libgo_runtime.runtime.RegisterDebugLookup");
void
RegisterDebugLookup (infofn_type pi, symvalfn_type ps)
{
infofn = pi;
symvalfn = ps;
}
/* Return function/file/line information for PC. */
_Bool
__go_file_line (uintptr_t pc, struct __go_string *fn, struct __go_string *file,
int *line)
{
if (infofn == NULL)
return 0;
return infofn (pc, fn, file, line);
}
/* Return the value of a symbol. */
_Bool
__go_symbol_value (struct __go_string sym, uintptr_t *val)
{
if (symvalfn == NULL)
return 0;
return symvalfn (sym, val);
}
/* The values returned by runtime.Caller. */ /* The values returned by runtime.Caller. */
struct caller_ret struct caller_ret
...@@ -20,32 +76,71 @@ struct caller_ret ...@@ -20,32 +76,71 @@ struct caller_ret
_Bool ok; _Bool ok;
}; };
/* Implement runtime.Caller. */
struct caller_ret Caller (int n) asm ("libgo_runtime.runtime.Caller"); struct caller_ret Caller (int n) asm ("libgo_runtime.runtime.Caller");
Func *FuncForPC (uintptr_t) asm ("libgo_runtime.runtime.FuncForPC");
/* Implement runtime.Caller. */
struct caller_ret struct caller_ret
Caller (int n __attribute__ ((unused))) Caller (int skip)
{ {
struct caller_ret ret; struct caller_ret ret;
uintptr pc;
int32 n;
struct __go_string fn;
/* A proper implementation needs to dig through the debugging runtime_memclr (&ret, sizeof ret);
information. */ n = runtime_callers (skip + 1, &pc, 1);
ret.pc = (uint64_t) (uintptr_t) __builtin_return_address (0); if (n < 1)
ret.file.__data = NULL; return ret;
ret.file.__length = 0; ret.pc = pc;
ret.line = 0; ret.ok = __go_file_line (pc, &fn, &ret.file, &ret.line);
ret.ok = 0;
return ret; return ret;
} }
/* Implement runtime.FuncForPC. */ /* Implement runtime.FuncForPC. */
void *FuncForPC (uintptr_t) asm ("libgo_runtime.runtime.FuncForPC"); Func *
FuncForPC (uintptr_t pc)
{
Func *ret;
struct __go_string fn;
struct __go_string file;
int line;
uintptr_t val;
void * if (!__go_file_line (pc, &fn, &file, &line))
FuncForPC(uintptr_t pc __attribute__ ((unused))) return NULL;
if (!__go_symbol_value (fn, &val))
return NULL;
ret = (Func *) runtime_malloc (sizeof (*ret));
ret->name = fn;
ret->entry = val;
return ret;
}
/* Look up the file and line information for a PC within a
function. */
struct funcline_go_return
{ {
return NULL; struct __go_string retfile;
int retline;
};
struct funcline_go_return
runtime_funcline_go (Func *f, uintptr targetpc)
__asm__ ("libgo_runtime.runtime.funcline_go");
struct funcline_go_return
runtime_funcline_go (Func *f __attribute__((unused)), uintptr targetpc)
{
struct funcline_go_return ret;
struct __go_string fn;
if (!__go_file_line (targetpc, &fn, &ret.retfile, &ret.retline))
runtime_memclr (&ret, sizeof ret);
return ret;
} }
...@@ -25,8 +25,13 @@ backtrace (struct _Unwind_Context *context, void *varg) ...@@ -25,8 +25,13 @@ backtrace (struct _Unwind_Context *context, void *varg)
{ {
struct callers_data *arg = (struct callers_data *) varg; struct callers_data *arg = (struct callers_data *) varg;
uintptr pc; uintptr pc;
int ip_before_insn = 0;
#ifdef HAVE_GETIPINFO
pc = _Unwind_GetIPInfo (context, &ip_before_insn);
#else
pc = _Unwind_GetIP (context); pc = _Unwind_GetIP (context);
#endif
/* FIXME: If PC is in the __morestack routine, we should ignore /* FIXME: If PC is in the __morestack routine, we should ignore
it. */ it. */
...@@ -37,6 +42,11 @@ backtrace (struct _Unwind_Context *context, void *varg) ...@@ -37,6 +42,11 @@ backtrace (struct _Unwind_Context *context, void *varg)
return _URC_END_OF_STACK; return _URC_END_OF_STACK;
else 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->pcbuf[arg->index] = pc;
++arg->index; ++arg->index;
} }
...@@ -48,7 +58,7 @@ runtime_callers (int32 skip, uintptr *pcbuf, int32 m) ...@@ -48,7 +58,7 @@ runtime_callers (int32 skip, uintptr *pcbuf, int32 m)
{ {
struct callers_data arg; struct callers_data arg;
arg.skip = skip; arg.skip = skip + 1;
arg.pcbuf = pcbuf; arg.pcbuf = pcbuf;
arg.index = 0; arg.index = 0;
arg.max = m; arg.max = m;
......
...@@ -225,11 +225,7 @@ runtime_MProf_Malloc(void *p, uintptr size) ...@@ -225,11 +225,7 @@ runtime_MProf_Malloc(void *p, uintptr size)
return; return;
m->nomemprof++; m->nomemprof++;
#if 0
nstk = runtime_callers(1, stk, 32); nstk = runtime_callers(1, stk, 32);
#else
nstk = 0;
#endif
runtime_lock(&proflock); runtime_lock(&proflock);
b = stkbucket(stk, nstk, true); b = stkbucket(stk, nstk, true);
b->recent_allocs++; b->recent_allocs++;
......
...@@ -211,22 +211,3 @@ runtime_cputicks(void) ...@@ -211,22 +211,3 @@ runtime_cputicks(void)
return 0; return 0;
#endif #endif
} }
struct funcline_go_return
{
String retfile;
int32 retline;
};
struct funcline_go_return
runtime_funcline_go(void *f, uintptr targetpc)
__asm__("libgo_runtime.runtime.funcline_go");
struct funcline_go_return
runtime_funcline_go(void *f __attribute__((unused)),
uintptr targetpc __attribute__((unused)))
{
struct funcline_go_return ret;
runtime_memclr(&ret, sizeof ret);
return ret;
}
...@@ -48,6 +48,7 @@ typedef unsigned int uintptr __attribute__ ((mode (pointer))); ...@@ -48,6 +48,7 @@ typedef unsigned int uintptr __attribute__ ((mode (pointer)));
typedef uint8 bool; typedef uint8 bool;
typedef uint8 byte; typedef uint8 byte;
typedef struct Func Func;
typedef struct G G; typedef struct G G;
typedef union Lock Lock; typedef union Lock Lock;
typedef struct M M; typedef struct M M;
...@@ -201,6 +202,14 @@ enum ...@@ -201,6 +202,14 @@ enum
#define NSIG 32 #define NSIG 32
#endif #endif
// NOTE(rsc): keep in sync with extern.go:/type.Func.
// Eventually, the loaded symbol table should be closer to this form.
struct Func
{
String name;
uintptr entry; // entry pc
};
/* Macros. */ /* Macros. */
#ifdef GOOS_windows #ifdef GOOS_windows
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment