mirror of
				https://github.com/go-delve/delve.git
				synced 2025-10-31 10:47:27 +08:00 
			
		
		
		
	proc: bugfix: Truncate stacktrace when FDE of a frame can not be found
Instead of returning an error when FDE of a frame can not be found, just truncate the stack trace. Fixes #462
This commit is contained in:
		| @ -65,6 +65,14 @@ func NewFrameIndex() FrameDescriptionEntries { | |||||||
| 	return make(FrameDescriptionEntries, 0, 1000) | 	return make(FrameDescriptionEntries, 0, 1000) | ||||||
| } | } | ||||||
|  |  | ||||||
|  | type NoFDEForPCError struct { | ||||||
|  | 	PC uint64 | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (err *NoFDEForPCError) Error() string { | ||||||
|  | 	return fmt.Sprintf("could not find FDE for PC %#v", err.PC) | ||||||
|  | } | ||||||
|  |  | ||||||
| // Returns the Frame Description Entry for the given PC. | // Returns the Frame Description Entry for the given PC. | ||||||
| func (fdes FrameDescriptionEntries) FDEForPC(pc uint64) (*FrameDescriptionEntry, error) { | func (fdes FrameDescriptionEntries) FDEForPC(pc uint64) (*FrameDescriptionEntry, error) { | ||||||
| 	idx := sort.Search(len(fdes), func(i int) bool { | 	idx := sort.Search(len(fdes), func(i int) bool { | ||||||
| @ -77,7 +85,7 @@ func (fdes FrameDescriptionEntries) FDEForPC(pc uint64) (*FrameDescriptionEntry, | |||||||
| 		return true | 		return true | ||||||
| 	}) | 	}) | ||||||
| 	if idx == len(fdes) { | 	if idx == len(fdes) { | ||||||
| 		return nil, fmt.Errorf("could not find FDE for PC %#v", pc) | 		return nil, &NoFDEForPCError{pc} | ||||||
| 	} | 	} | ||||||
| 	return fdes[idx], nil | 	return fdes[idx], nil | ||||||
| } | } | ||||||
|  | |||||||
| @ -1655,3 +1655,33 @@ func TestPanicBreakpoint(t *testing.T) { | |||||||
| 		} | 		} | ||||||
| 	}) | 	}) | ||||||
| } | } | ||||||
|  |  | ||||||
|  | func TestIssue462(t *testing.T) { | ||||||
|  | 	// Stacktrace of Goroutine 0 fails with an error | ||||||
|  | 	if runtime.GOOS == "windows" { | ||||||
|  | 		return | ||||||
|  | 	} | ||||||
|  | 	withTestProcess("testnextnethttp", t, func(p *Process, fixture protest.Fixture) { | ||||||
|  | 		go func() { | ||||||
|  | 			for !p.Running() { | ||||||
|  | 				time.Sleep(50 * time.Millisecond) | ||||||
|  | 			} | ||||||
|  |  | ||||||
|  | 			// Wait for program to start listening. | ||||||
|  | 			for { | ||||||
|  | 				conn, err := net.Dial("tcp", "localhost:9191") | ||||||
|  | 				if err == nil { | ||||||
|  | 					conn.Close() | ||||||
|  | 					break | ||||||
|  | 				} | ||||||
|  | 				time.Sleep(50 * time.Millisecond) | ||||||
|  | 			} | ||||||
|  |  | ||||||
|  | 			p.RequestManualStop() | ||||||
|  | 		}() | ||||||
|  |  | ||||||
|  | 		assertNoError(p.Continue(), t, "Continue()") | ||||||
|  | 		_, err := p.CurrentThread.Stacktrace(40) | ||||||
|  | 		assertNoError(err, t, "Stacktrace()") | ||||||
|  | 	}) | ||||||
|  | } | ||||||
|  | |||||||
| @ -4,6 +4,7 @@ import ( | |||||||
| 	"encoding/binary" | 	"encoding/binary" | ||||||
| 	"errors" | 	"errors" | ||||||
| 	"fmt" | 	"fmt" | ||||||
|  | 	"github.com/derekparker/delve/dwarf/frame" | ||||||
| ) | ) | ||||||
|  |  | ||||||
| // NoReturnAddr is returned when return address | // NoReturnAddr is returned when return address | ||||||
| @ -101,6 +102,12 @@ func (it *StackIterator) Next() bool { | |||||||
| 	} | 	} | ||||||
| 	it.frame, it.err = it.dbp.frameInfo(it.pc, it.sp, it.top) | 	it.frame, it.err = it.dbp.frameInfo(it.pc, it.sp, it.top) | ||||||
| 	if it.err != nil { | 	if it.err != nil { | ||||||
|  | 		if _, nofde := it.err.(*frame.NoFDEForPCError); nofde && !it.top { | ||||||
|  | 			it.frame = Stackframe{ Current: Location{ PC: it.pc, File: "?", Line: -1  }, Call: Location{ PC: it.pc, File: "?", Line: -1 }, CFA: 0, Ret: 0 } | ||||||
|  | 			it.atend = true | ||||||
|  | 			it.err = nil | ||||||
|  | 			return true | ||||||
|  | 		} | ||||||
| 		return false | 		return false | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
|  | |||||||
| @ -3,6 +3,7 @@ package proc | |||||||
| import ( | import ( | ||||||
| 	"debug/gosym" | 	"debug/gosym" | ||||||
| 	"encoding/binary" | 	"encoding/binary" | ||||||
|  | 	"errors" | ||||||
| 	"fmt" | 	"fmt" | ||||||
| 	"path/filepath" | 	"path/filepath" | ||||||
| 	"reflect" | 	"reflect" | ||||||
| @ -353,6 +354,9 @@ func (thread *Thread) Scope() (*EvalScope, error) { | |||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		return nil, err | 		return nil, err | ||||||
| 	} | 	} | ||||||
|  | 	if len(locations) < 1 { | ||||||
|  | 		return nil, errors.New("could not decode first frame") | ||||||
|  | 	} | ||||||
| 	return locations[0].Scope(thread), nil | 	return locations[0].Scope(thread), nil | ||||||
| } | } | ||||||
|  |  | ||||||
|  | |||||||
| @ -422,11 +422,13 @@ func (g *G) UserCurrent() Location { | |||||||
| 	it := newStackIterator(g.dbp, pc, sp) | 	it := newStackIterator(g.dbp, pc, sp) | ||||||
| 	for it.Next() { | 	for it.Next() { | ||||||
| 		frame := it.Frame() | 		frame := it.Frame() | ||||||
|  | 		if frame.Call.Fn != nil { | ||||||
| 			name := frame.Call.Fn.Name | 			name := frame.Call.Fn.Name | ||||||
| 			if (strings.Index(name, ".") >= 0) && (!strings.HasPrefix(name, "runtime.") || isExportedRuntime(name)) { | 			if (strings.Index(name, ".") >= 0) && (!strings.HasPrefix(name, "runtime.") || isExportedRuntime(name)) { | ||||||
| 				return frame.Call | 				return frame.Call | ||||||
| 			} | 			} | ||||||
| 		} | 		} | ||||||
|  | 	} | ||||||
| 	return g.CurrentLoc | 	return g.CurrentLoc | ||||||
| } | } | ||||||
|  |  | ||||||
|  | |||||||
		Reference in New Issue
	
	Block a user
	 aarzilli
					aarzilli