mirror of
				https://github.com/go-delve/delve.git
				synced 2025-10-31 10:47:27 +08:00 
			
		
		
		
	service,terminal: support logical breakpoints (#1742)
Changes CreateBreakpoint to create a logical breakpoint when multiple addresses are specified, FindLocation and the api.Location type to return logical locations and the cli to support logical breakpoints.
This commit is contained in:
		 Alessandro Arzilli
					Alessandro Arzilli
				
			
				
					committed by
					
						 Derek Parker
						Derek Parker
					
				
			
			
				
	
			
			
			 Derek Parker
						Derek Parker
					
				
			
						parent
						
							222deeec36
						
					
				
				
					commit
					e8d4ed7ece
				
			| @ -4,6 +4,7 @@ package terminal | |||||||
|  |  | ||||||
| import ( | import ( | ||||||
| 	"bufio" | 	"bufio" | ||||||
|  | 	"bytes" | ||||||
| 	"errors" | 	"errors" | ||||||
| 	"fmt" | 	"fmt" | ||||||
| 	"go/parser" | 	"go/parser" | ||||||
| @ -1188,6 +1189,9 @@ func clearAll(t *Term, ctx callContext, args string) error { | |||||||
| 		} | 		} | ||||||
| 		locPCs = make(map[uint64]struct{}) | 		locPCs = make(map[uint64]struct{}) | ||||||
| 		for _, loc := range locs { | 		for _, loc := range locs { | ||||||
|  | 			for _, pc := range loc.PCs { | ||||||
|  | 				locPCs[pc] = struct{}{} | ||||||
|  | 			} | ||||||
| 			locPCs[loc.PC] = struct{}{} | 			locPCs[loc.PC] = struct{}{} | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| @ -1297,6 +1301,7 @@ func setBreakpoint(t *Term, ctx callContext, tracepoint bool, argstr string) err | |||||||
| 	} | 	} | ||||||
| 	for _, loc := range locs { | 	for _, loc := range locs { | ||||||
| 		requestedBp.Addr = loc.PC | 		requestedBp.Addr = loc.PC | ||||||
|  | 		requestedBp.Addrs = loc.PCs | ||||||
|  |  | ||||||
| 		bp, err := t.client.CreateBreakpoint(requestedBp) | 		bp, err := t.client.CreateBreakpoint(requestedBp) | ||||||
| 		if err != nil { | 		if err != nil { | ||||||
| @ -2222,9 +2227,24 @@ func formatBreakpointName(bp *api.Breakpoint, upcase bool) string { | |||||||
| } | } | ||||||
|  |  | ||||||
| func formatBreakpointLocation(bp *api.Breakpoint) string { | func formatBreakpointLocation(bp *api.Breakpoint) string { | ||||||
|  | 	var out bytes.Buffer | ||||||
|  | 	if len(bp.Addrs) > 0 { | ||||||
|  | 		for i, addr := range bp.Addrs { | ||||||
|  | 			if i == 0 { | ||||||
|  | 				fmt.Fprintf(&out, "%#x", addr) | ||||||
|  | 			} else { | ||||||
|  | 				fmt.Fprintf(&out, ",%#x", addr) | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 	} else { | ||||||
|  | 		// In case we are connecting to an older version of delve that does not return the Addrs field. | ||||||
|  | 		fmt.Fprintf(&out, "%#x", bp.Addr) | ||||||
|  | 	} | ||||||
|  | 	fmt.Fprintf(&out, " for ") | ||||||
| 	p := ShortenFilePath(bp.File) | 	p := ShortenFilePath(bp.File) | ||||||
| 	if bp.FunctionName != "" { | 	if bp.FunctionName != "" { | ||||||
| 		return fmt.Sprintf("%#v for %s() %s:%d", bp.Addr, bp.FunctionName, p, bp.Line) | 		fmt.Fprintf(&out, "%s() ", bp.FunctionName) | ||||||
| 	} | 	} | ||||||
| 	return fmt.Sprintf("%#v for %s:%d", bp.Addr, p, bp.Line) | 	fmt.Fprintf(&out, "%s:%d", p, bp.Line) | ||||||
|  | 	return out.String() | ||||||
| } | } | ||||||
|  | |||||||
| @ -126,11 +126,16 @@ type Thread struct { | |||||||
| } | } | ||||||
|  |  | ||||||
| // Location holds program location information. | // Location holds program location information. | ||||||
|  | // In most cases a Location object will represent a physical location, with | ||||||
|  | // a single PC address held in the PC field. | ||||||
|  | // FindLocations however returns logical locations that can either have | ||||||
|  | // multiple PC addresses each (due to inlining) or no PC address at all. | ||||||
| type Location struct { | type Location struct { | ||||||
| 	PC       uint64    `json:"pc"` | 	PC       uint64    `json:"pc"` | ||||||
| 	File     string    `json:"file"` | 	File     string    `json:"file"` | ||||||
| 	Line     int       `json:"line"` | 	Line     int       `json:"line"` | ||||||
| 	Function *Function `json:"function,omitempty"` | 	Function *Function `json:"function,omitempty"` | ||||||
|  | 	PCs      []uint64  `json:"pcs,omitempty"` | ||||||
| } | } | ||||||
|  |  | ||||||
| // Stackframe describes one frame in a stack trace. | // Stackframe describes one frame in a stack trace. | ||||||
|  | |||||||
| @ -446,6 +446,8 @@ func (d *Debugger) CreateBreakpoint(requestedBp *api.Breakpoint) (*api.Breakpoin | |||||||
| 		addrs, err = proc.FindFileLocation(d.target, fileName, requestedBp.Line) | 		addrs, err = proc.FindFileLocation(d.target, fileName, requestedBp.Line) | ||||||
| 	case len(requestedBp.FunctionName) > 0: | 	case len(requestedBp.FunctionName) > 0: | ||||||
| 		addrs, err = proc.FindFunctionLocation(d.target, requestedBp.FunctionName, requestedBp.Line) | 		addrs, err = proc.FindFunctionLocation(d.target, requestedBp.FunctionName, requestedBp.Line) | ||||||
|  | 	case len(requestedBp.Addrs) > 0: | ||||||
|  | 		addrs = requestedBp.Addrs | ||||||
| 	default: | 	default: | ||||||
| 		addrs = []uint64{requestedBp.Addr} | 		addrs = []uint64{requestedBp.Addr} | ||||||
| 	} | 	} | ||||||
|  | |||||||
| @ -251,8 +251,8 @@ func (loc *RegexLocationSpec) Find(d *Debugger, scope *proc.EvalScope, locStr st | |||||||
| 	r := make([]api.Location, 0, len(matches)) | 	r := make([]api.Location, 0, len(matches)) | ||||||
| 	for i := range matches { | 	for i := range matches { | ||||||
| 		addrs, _ := proc.FindFunctionLocation(d.target, matches[i], 0) | 		addrs, _ := proc.FindFunctionLocation(d.target, matches[i], 0) | ||||||
| 		for _, addr := range addrs { | 		if len(addrs) > 0 { | ||||||
| 			r = append(r, api.Location{PC: addr}) | 			r = append(r, addressesToLocation(addrs)) | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| 	return r, nil | 	return r, nil | ||||||
| @ -283,7 +283,7 @@ func (loc *AddrLocationSpec) Find(d *Debugger, scope *proc.EvalScope, locStr str | |||||||
| 			if err != nil { | 			if err != nil { | ||||||
| 				return nil, err | 				return nil, err | ||||||
| 			} | 			} | ||||||
| 			return []api.Location{{PC: uint64(pc)}}, nil | 			return []api.Location{{PC: pc}}, nil | ||||||
| 		default: | 		default: | ||||||
| 			return nil, fmt.Errorf("wrong expression kind: %v", v.Kind) | 			return nil, fmt.Errorf("wrong expression kind: %v", v.Kind) | ||||||
| 		} | 		} | ||||||
| @ -389,25 +389,21 @@ func (loc *NormalLocationSpec) Find(d *Debugger, scope *proc.EvalScope, locStr s | |||||||
| 				return []api.Location{{File: candidateFiles[0], Line: loc.LineOffset}}, nil | 				return []api.Location{{File: candidateFiles[0], Line: loc.LineOffset}}, nil | ||||||
| 			} | 			} | ||||||
| 		} | 		} | ||||||
| 	} else { // len(candidateFUncs) == 1 | 	} else { // len(candidateFuncs) == 1 | ||||||
| 		addrs, err = proc.FindFunctionLocation(d.target, candidateFuncs[0], loc.LineOffset) | 		addrs, err = proc.FindFunctionLocation(d.target, candidateFuncs[0], loc.LineOffset) | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		return nil, err | 		return nil, err | ||||||
| 	} | 	} | ||||||
| 	return addressesToLocations(addrs), nil | 	return []api.Location{addressesToLocation(addrs)}, nil | ||||||
| } | } | ||||||
|  |  | ||||||
| func addressesToLocations(addrs []uint64) []api.Location { | func addressesToLocation(addrs []uint64) api.Location { | ||||||
| 	if addrs == nil { | 	if len(addrs) <= 0 { | ||||||
| 		return nil | 		return api.Location{} | ||||||
| 	} | 	} | ||||||
| 	r := make([]api.Location, len(addrs)) | 	return api.Location{PC: addrs[0], PCs: addrs} | ||||||
| 	for i := range addrs { |  | ||||||
| 		r[i] = api.Location{PC: addrs[i]} |  | ||||||
| 	} |  | ||||||
| 	return r |  | ||||||
| } | } | ||||||
|  |  | ||||||
| func (loc *OffsetLocationSpec) Find(d *Debugger, scope *proc.EvalScope, locStr string, includeNonExecutableLines bool) ([]api.Location, error) { | func (loc *OffsetLocationSpec) Find(d *Debugger, scope *proc.EvalScope, locStr string, includeNonExecutableLines bool) ([]api.Location, error) { | ||||||
| @ -427,7 +423,7 @@ func (loc *OffsetLocationSpec) Find(d *Debugger, scope *proc.EvalScope, locStr s | |||||||
| 			return []api.Location{{File: file, Line: line + loc.Offset}}, nil | 			return []api.Location{{File: file, Line: line + loc.Offset}}, nil | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| 	return addressesToLocations(addrs), err | 	return []api.Location{addressesToLocation(addrs)}, err | ||||||
| } | } | ||||||
|  |  | ||||||
| func (loc *LineLocationSpec) Find(d *Debugger, scope *proc.EvalScope, locStr string, includeNonExecutableLines bool) ([]api.Location, error) { | func (loc *LineLocationSpec) Find(d *Debugger, scope *proc.EvalScope, locStr string, includeNonExecutableLines bool) ([]api.Location, error) { | ||||||
| @ -444,5 +440,5 @@ func (loc *LineLocationSpec) Find(d *Debugger, scope *proc.EvalScope, locStr str | |||||||
| 			return []api.Location{{File: file, Line: loc.Line}}, nil | 			return []api.Location{{File: file, Line: loc.Line}}, nil | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| 	return addressesToLocations(addrs), err | 	return []api.Location{addressesToLocation(addrs)}, err | ||||||
| } | } | ||||||
|  | |||||||
| @ -231,6 +231,9 @@ type CreateBreakpointOut struct { | |||||||
| // the breakpoint will be created on the specified function:line | // the breakpoint will be created on the specified function:line | ||||||
| // location. | // location. | ||||||
| // | // | ||||||
|  | // - If arg.Breakpoint.Addrs is filled it will create a logical breakpoint | ||||||
|  | // corresponding to all specified addresses. | ||||||
|  | // | ||||||
| // - Otherwise the value specified by arg.Breakpoint.Addr will be used. | // - Otherwise the value specified by arg.Breakpoint.Addr will be used. | ||||||
| func (s *RPCServer) CreateBreakpoint(arg CreateBreakpointIn, out *CreateBreakpointOut) error { | func (s *RPCServer) CreateBreakpoint(arg CreateBreakpointIn, out *CreateBreakpointOut) error { | ||||||
| 	createdbp, err := s.debugger.CreateBreakpoint(&arg.Breakpoint) | 	createdbp, err := s.debugger.CreateBreakpoint(&arg.Breakpoint) | ||||||
| @ -577,7 +580,7 @@ type FindLocationOut struct { | |||||||
| 	Locations []api.Location | 	Locations []api.Location | ||||||
| } | } | ||||||
|  |  | ||||||
| // FindLocation returns concrete location information described by a location expression | // FindLocation returns concrete location information described by a location expression. | ||||||
| // | // | ||||||
| //  loc ::= <filename>:<line> | <function>[:<line>] | /<regex>/ | (+|-)<offset> | <line> | *<address> | //  loc ::= <filename>:<line> | <function>[:<line>] | /<regex>/ | (+|-)<offset> | <line> | *<address> | ||||||
| //  * <filename> can be the full path of a file or just a suffix | //  * <filename> can be the full path of a file or just a suffix | ||||||
|  | |||||||
		Reference in New Issue
	
	Block a user