Skip to content
This repository has been archived by the owner on Dec 1, 2021. It is now read-only.

Commit

Permalink
Merge pull request #193 from pkg/fixedbugs/188
Browse files Browse the repository at this point in the history
Return errors.Frame to a uintptr
  • Loading branch information
davecheney committed Jan 9, 2019
2 parents 72fa05e + e9933c1 commit 565c8d0
Show file tree
Hide file tree
Showing 3 changed files with 58 additions and 40 deletions.
1 change: 1 addition & 0 deletions format_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -385,6 +385,7 @@ func TestFormatWrappedNew(t *testing.T) {
}

func testFormatRegexp(t *testing.T, n int, arg interface{}, format, want string) {
t.Helper()
got := fmt.Sprintf(format, arg)
gotLines := strings.SplitN(got, "\n", -1)
wantLines := strings.SplitN(want, "\n", -1)
Expand Down
85 changes: 51 additions & 34 deletions stack.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,42 @@ import (
)

// Frame represents a program counter inside a stack frame.
type Frame runtime.Frame
type Frame uintptr

// pc returns the program counter for this frame;
// multiple frames may have the same PC value.
func (f Frame) pc() uintptr { return uintptr(f) - 1 }

// file returns the full path to the file that contains the
// function for this Frame's pc.
func (f Frame) file() string {
fn := runtime.FuncForPC(f.pc())
if fn == nil {
return "unknown"
}
file, _ := fn.FileLine(f.pc())
return file
}

// line returns the line number of source code of the
// function for this Frame's pc.
func (f Frame) line() int {
fn := runtime.FuncForPC(f.pc())
if fn == nil {
return 0
}
_, line := fn.FileLine(f.pc())
return line
}

// name returns the name of this function, if known.
func (f Frame) name() string {
fn := runtime.FuncForPC(f.pc())
if fn == nil {
return "unknown"
}
return fn.Name()
}

// Format formats the frame according to the fmt.Formatter interface.
//
Expand All @@ -35,25 +70,16 @@ func (f Frame) format(w io.Writer, s fmt.State, verb rune) {
case 's':
switch {
case s.Flag('+'):
if f.Function == "" {
io.WriteString(w, "unknown")
} else {
io.WriteString(w, f.Function)
io.WriteString(w, "\n\t")
io.WriteString(w, f.File)
}
io.WriteString(w, f.name())
io.WriteString(w, "\n\t")
io.WriteString(w, f.file())
default:
file := f.File
if file == "" {
file = "unknown"
}
io.WriteString(w, path.Base(file))
io.WriteString(w, path.Base(f.file()))
}
case 'd':
io.WriteString(w, strconv.Itoa(f.Line))
io.WriteString(w, strconv.Itoa(f.line()))
case 'n':
name := f.Function
io.WriteString(s, funcname(name))
io.WriteString(w, funcname(f.name()))
case 'v':
f.format(w, s, 's')
io.WriteString(w, ":")
Expand All @@ -79,9 +105,9 @@ func (st StackTrace) Format(s fmt.State, verb rune) {
switch {
case s.Flag('+'):
b.Grow(len(st) * stackMinLen)
for _, fr := range st {
for _, f := range st {
b.WriteByte('\n')
fr.format(&b, s, verb)
f.format(&b, s, verb)
}
case s.Flag('#'):
fmt.Fprintf(&b, "%#v", []Frame(st))
Expand Down Expand Up @@ -125,29 +151,20 @@ func (s *stack) Format(st fmt.State, verb rune) {
case 'v':
switch {
case st.Flag('+'):
frames := runtime.CallersFrames(*s)
for {
frame, more := frames.Next()
fmt.Fprintf(st, "\n%+v", Frame(frame))
if !more {
break
}
for _, pc := range *s {
f := Frame(pc)
fmt.Fprintf(st, "\n%+v", f)
}
}
}
}

func (s *stack) StackTrace() StackTrace {
var st []Frame
frames := runtime.CallersFrames(*s)
for {
frame, more := frames.Next()
st = append(st, Frame(frame))
if !more {
break
}
f := make([]Frame, len(*s))
for i := 0; i < len(f); i++ {
f[i] = Frame((*s)[i])
}
return st
return f
}

func callers() *stack {
Expand Down
12 changes: 6 additions & 6 deletions stack_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,19 +35,19 @@ func TestFrameFormat(t *testing.T) {
"github.com/pkg/errors.init\n" +
"\t.+/github.com/pkg/errors/stack_test.go",
}, {
Frame{},
0,
"%s",
"unknown",
}, {
Frame{},
0,
"%+s",
"unknown",
}, {
initpc,
"%d",
"9",
}, {
Frame{},
0,
"%d",
"0",
}, {
Expand All @@ -69,7 +69,7 @@ func TestFrameFormat(t *testing.T) {
"%n",
"X.val",
}, {
Frame{},
0,
"%n",
"",
}, {
Expand All @@ -82,7 +82,7 @@ func TestFrameFormat(t *testing.T) {
"github.com/pkg/errors.init\n" +
"\t.+/github.com/pkg/errors/stack_test.go:9",
}, {
Frame{},
0,
"%v",
"unknown:0",
}}
Expand Down Expand Up @@ -246,7 +246,7 @@ func caller() Frame {
n := runtime.Callers(2, pcs[:])
frames := runtime.CallersFrames(pcs[:n])
frame, _ := frames.Next()
return Frame(frame)
return Frame(frame.PC)
}

//go:noinline
Expand Down

0 comments on commit 565c8d0

Please sign in to comment.