service: fix a bunch of linter warnings from GoLand (#3551)

This commit is contained in:
Derek Parker 2023-11-05 10:36:37 -06:00 committed by GitHub
parent 4d1c1f3a36
commit c727ec52c5
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 106 additions and 97 deletions

@ -85,7 +85,7 @@ import (
// a time. This goroutine issues commands to the underlying debugger // a time. This goroutine issues commands to the underlying debugger
// and sends back events and responses. It takes a setup-done channel // and sends back events and responses. It takes a setup-done channel
// as an argument and temporarily blocks the request loop until setup // as an argument and temporarily blocks the request loop until setup
// for asynchronous execution is complete and targe is running. // for asynchronous execution is complete and target is running.
// Once done, it unblocks processing of parallel requests unblocks // Once done, it unblocks processing of parallel requests unblocks
// (e.g. disconnecting while the program is running). // (e.g. disconnecting while the program is running).
// //
@ -99,7 +99,7 @@ type Server struct {
// listener is used to accept the client connection. // listener is used to accept the client connection.
// When working with a predetermined client, this is nil. // When working with a predetermined client, this is nil.
listener net.Listener listener net.Listener
// session is the debug session that comes with an client connection. // session is the debug session that comes with a client connection.
session *Session session *Session
sessionMu sync.Mutex sessionMu sync.Mutex
} }
@ -158,7 +158,7 @@ type Session struct {
// changing the state of the running process at the same time. // changing the state of the running process at the same time.
changeStateMu sync.Mutex changeStateMu sync.Mutex
// stdoutReader the programs's stdout. // stdoutReader the program's stdout.
stdoutReader io.ReadCloser stdoutReader io.ReadCloser
// stderrReader the program's stderr. // stderrReader the program's stderr.
@ -258,7 +258,7 @@ type dapClientCapabilities struct {
// DefaultLoadConfig controls how variables are loaded from the target's memory. // DefaultLoadConfig controls how variables are loaded from the target's memory.
// These limits are conservative to minimize performance overhead for bulk loading. // These limits are conservative to minimize performance overhead for bulk loading.
// With dlv-dap, users do not have a way to adjust these. // With dlv-dap, users do not have a way to adjust these.
// Instead we are focusing in interactive loading with nested reloads, array/map // Instead, we are focusing in interactive loading with nested reloads, array/map
// paging and context-specific string limits. // paging and context-specific string limits.
var DefaultLoadConfig = proc.LoadConfig{ var DefaultLoadConfig = proc.LoadConfig{
FollowPointers: true, FollowPointers: true,
@ -379,7 +379,7 @@ func (s *Server) Stop() {
if s.listener != nil { if s.listener != nil {
// If run goroutine is blocked on accept, this will unblock it. // If run goroutine is blocked on accept, this will unblock it.
_ = s.listener.Close() s.listener.Close()
} }
s.sessionMu.Lock() s.sessionMu.Lock()
@ -419,7 +419,7 @@ func (s *Session) Close() {
// If this was a client loop exit (on error or disconnect), serveDAPCodec() // If this was a client loop exit (on error or disconnect), serveDAPCodec()
// will be first. // will be first.
// Duplicate close calls return an error, but are not fatal. // Duplicate close calls return an error, but are not fatal.
_ = s.conn.Close() s.conn.Close()
} }
// triggerServerStop closes DisconnectChan if not nil, which // triggerServerStop closes DisconnectChan if not nil, which
@ -438,7 +438,7 @@ func (c *Config) triggerServerStop() {
c.DisconnectChan = nil c.DisconnectChan = nil
} }
// There should be no logic here after the stop-server // There should be no logic here after the stop-server
// signal that might cause everything to shutdown before this // signal that might cause everything to shut down before this
// logic gets executed. // logic gets executed.
} }
@ -516,7 +516,13 @@ func (s *Session) address() string {
func (s *Session) ServeDAPCodec() { func (s *Session) ServeDAPCodec() {
// Close conn, but not the debugger in case we are in AcceptMulti mode. // Close conn, but not the debugger in case we are in AcceptMulti mode.
// If not, debugger will be shut down in Stop(). // If not, debugger will be shut down in Stop().
var triggerServerStop bool
defer s.conn.Close() defer s.conn.Close()
defer func() {
if triggerServerStop {
s.config.triggerServerStop()
}
}()
reader := bufio.NewReader(s.conn) reader := bufio.NewReader(s.conn)
for { for {
request, err := dap.ReadProtocolMessage(reader) request, err := dap.ReadProtocolMessage(reader)
@ -526,18 +532,17 @@ func (s *Session) ServeDAPCodec() {
// potentially got some new DAP request that we do not yet have // potentially got some new DAP request that we do not yet have
// decoding support for, so we can respond with an ErrorResponse. // decoding support for, so we can respond with an ErrorResponse.
// //
// Other errors, such as unmarshaling errors, will log the error and cause the server to trigger // Other errors, such as unmarshalling errors, will log the error and cause the server to trigger
// a stop. // a stop.
if err != nil { if err != nil {
s.config.log.Debug("DAP error: ", err) s.config.log.Debug("DAP error: ", err)
select { select {
case <-s.config.StopTriggered: case <-s.config.StopTriggered:
default: default:
if !s.config.AcceptMulti { triggerServerStop = !s.config.AcceptMulti
defer s.config.triggerServerStop()
}
if err != io.EOF { // EOF means client closed connection if err != io.EOF { // EOF means client closed connection
if decodeErr, ok := err.(*dap.DecodeProtocolMessageFieldError); ok { var decodeErr *dap.DecodeProtocolMessageFieldError
if errors.As(err, &decodeErr) {
// Send an error response to the users if we were unable to process the message. // Send an error response to the users if we were unable to process the message.
s.sendInternalErrorResponse(decodeErr.Seq, err.Error()) s.sendInternalErrorResponse(decodeErr.Seq, err.Error())
continue continue
@ -558,7 +563,7 @@ func (s *Session) ServeDAPCodec() {
// In case a handler panics, we catch the panic to avoid crashing both // In case a handler panics, we catch the panic to avoid crashing both
// the server and the target. We send an error response back, but // the server and the target. We send an error response back, but
// in case its a dup and ignored by the client, we also log the error. // in case it's a dup and ignored by the client, we also log the error.
func (s *Session) recoverPanic(request dap.Message) { func (s *Session) recoverPanic(request dap.Message) {
if ierr := recover(); ierr != nil { if ierr := recover(); ierr != nil {
s.config.log.Errorf("recovered panic: %s\n%s\n", ierr, debug.Stack()) s.config.log.Errorf("recovered panic: %s\n%s\n", ierr, debug.Stack())
@ -606,10 +611,10 @@ func (s *Session) handleRequest(request dap.Message) {
case *dap.PauseRequest: // Required case *dap.PauseRequest: // Required
s.onPauseRequest(request) s.onPauseRequest(request)
return return
case *dap.TerminateRequest: // Optional (capability supportsTerminateRequest) case *dap.TerminateRequest: // Optional (capability 'supportsTerminateRequest')
/*TODO*/ s.onTerminateRequest(request) // not yet implemented /*TODO*/ s.onTerminateRequest(request) // not yet implemented
return return
case *dap.RestartRequest: // Optional (capability supportsRestartRequest) case *dap.RestartRequest: // Optional (capability 'supportsRestartRequest')
/*TODO*/ s.onRestartRequest(request) // not yet implemented /*TODO*/ s.onRestartRequest(request) // not yet implemented
return return
} }
@ -636,7 +641,7 @@ func (s *Session) handleRequest(request dap.Message) {
case *dap.ThreadsRequest: // Required case *dap.ThreadsRequest: // Required
// On start-up, the client requests the baseline of currently existing threads // On start-up, the client requests the baseline of currently existing threads
// right away as there are a number of DAP requests that require a thread id // right away as there are a number of DAP requests that require a thread id
// (pause, continue, stacktrace, etc). This can happen after the program // (pause, continue, stacktrace, etc.). This can happen after the program
// continues on entry, preventing the client from handling any pause requests // continues on entry, preventing the client from handling any pause requests
// from the user. We remedy this by sending back a placeholder thread id // from the user. We remedy this by sending back a placeholder thread id
// for the current goroutine. // for the current goroutine.
@ -655,7 +660,7 @@ func (s *Session) handleRequest(request dap.Message) {
return return
} }
s.onSetBreakpointsRequest(request) s.onSetBreakpointsRequest(request)
case *dap.SetFunctionBreakpointsRequest: // Optional (capability supportsFunctionBreakpoints) case *dap.SetFunctionBreakpointsRequest: // Optional (capability 'supportsFunctionBreakpoints')
s.changeStateMu.Lock() s.changeStateMu.Lock()
defer s.changeStateMu.Unlock() defer s.changeStateMu.Unlock()
s.config.log.Debug("halting execution to set breakpoints") s.config.log.Debug("halting execution to set breakpoints")
@ -685,7 +690,7 @@ func (s *Session) handleRequest(request dap.Message) {
switch request := request.(type) { switch request := request.(type) {
//--- Asynchronous requests --- //--- Asynchronous requests ---
case *dap.ConfigurationDoneRequest: // Optional (capability supportsConfigurationDoneRequest) case *dap.ConfigurationDoneRequest: // Optional (capability 'supportsConfigurationDoneRequest')
go func() { go func() {
defer s.recoverPanic(request) defer s.recoverPanic(request)
s.onConfigurationDoneRequest(request, resumeRequestLoop) s.onConfigurationDoneRequest(request, resumeRequestLoop)
@ -715,13 +720,13 @@ func (s *Session) handleRequest(request dap.Message) {
s.onStepOutRequest(request, resumeRequestLoop) s.onStepOutRequest(request, resumeRequestLoop)
}() }()
<-resumeRequestLoop <-resumeRequestLoop
case *dap.StepBackRequest: // Optional (capability supportsStepBack) case *dap.StepBackRequest: // Optional (capability 'supportsStepBack')
go func() { go func() {
defer s.recoverPanic(request) defer s.recoverPanic(request)
s.onStepBackRequest(request, resumeRequestLoop) s.onStepBackRequest(request, resumeRequestLoop)
}() }()
<-resumeRequestLoop <-resumeRequestLoop
case *dap.ReverseContinueRequest: // Optional (capability supportsStepBack) case *dap.ReverseContinueRequest: // Optional (capability 'supportsStepBack')
go func() { go func() {
defer s.recoverPanic(request) defer s.recoverPanic(request)
s.onReverseContinueRequest(request, resumeRequestLoop) s.onReverseContinueRequest(request, resumeRequestLoop)
@ -730,11 +735,11 @@ func (s *Session) handleRequest(request dap.Message) {
//--- Synchronous requests --- //--- Synchronous requests ---
case *dap.SetBreakpointsRequest: // Required case *dap.SetBreakpointsRequest: // Required
s.onSetBreakpointsRequest(request) s.onSetBreakpointsRequest(request)
case *dap.SetFunctionBreakpointsRequest: // Optional (capability supportsFunctionBreakpoints) case *dap.SetFunctionBreakpointsRequest: // Optional (capability 'supportsFunctionBreakpoints')
s.onSetFunctionBreakpointsRequest(request) s.onSetFunctionBreakpointsRequest(request)
case *dap.SetInstructionBreakpointsRequest: // Optional (capability 'supportsInstructionBreakpoints') case *dap.SetInstructionBreakpointsRequest: // Optional (capability 'supportsInstructionBreakpoints')
s.onSetInstructionBreakpointsRequest(request) s.onSetInstructionBreakpointsRequest(request)
case *dap.SetExceptionBreakpointsRequest: // Optional (capability exceptionBreakpointFilters) case *dap.SetExceptionBreakpointsRequest: // Optional (capability 'exceptionBreakpointFilters')
s.onSetExceptionBreakpointsRequest(request) s.onSetExceptionBreakpointsRequest(request)
case *dap.ThreadsRequest: // Required case *dap.ThreadsRequest: // Required
s.onThreadsRequest(request) s.onThreadsRequest(request)
@ -746,43 +751,43 @@ func (s *Session) handleRequest(request dap.Message) {
s.onVariablesRequest(request) s.onVariablesRequest(request)
case *dap.EvaluateRequest: // Required case *dap.EvaluateRequest: // Required
s.onEvaluateRequest(request) s.onEvaluateRequest(request)
case *dap.SetVariableRequest: // Optional (capability supportsSetVariable) case *dap.SetVariableRequest: // Optional (capability 'supportsSetVariable')
s.onSetVariableRequest(request) s.onSetVariableRequest(request)
case *dap.ExceptionInfoRequest: // Optional (capability supportsExceptionInfoRequest) case *dap.ExceptionInfoRequest: // Optional (capability 'supportsExceptionInfoRequest')
s.onExceptionInfoRequest(request) s.onExceptionInfoRequest(request)
case *dap.DisassembleRequest: // Optional (capability supportsDisassembleRequest) case *dap.DisassembleRequest: // Optional (capability 'supportsDisassembleRequest')
s.onDisassembleRequest(request) s.onDisassembleRequest(request)
//--- Requests that we may want to support --- //--- Requests that we may want to support ---
case *dap.SourceRequest: // Required case *dap.SourceRequest: // Required
/*TODO*/ s.sendUnsupportedErrorResponse(request.Request) // https://github.com/go-delve/delve/issues/2851 /*TODO*/ s.sendUnsupportedErrorResponse(request.Request) // https://github.com/go-delve/delve/issues/2851
case *dap.SetExpressionRequest: // Optional (capability supportsSetExpression) case *dap.SetExpressionRequest: // Optional (capability 'supportsSetExpression')
/*TODO*/ s.onSetExpressionRequest(request) // Not yet implemented /*TODO*/ s.onSetExpressionRequest(request) // Not yet implemented
case *dap.LoadedSourcesRequest: // Optional (capability supportsLoadedSourcesRequest) case *dap.LoadedSourcesRequest: // Optional (capability 'supportsLoadedSourcesRequest')
/*TODO*/ s.onLoadedSourcesRequest(request) // Not yet implemented /*TODO*/ s.onLoadedSourcesRequest(request) // Not yet implemented
case *dap.ReadMemoryRequest: // Optional (capability supportsReadMemoryRequest) case *dap.ReadMemoryRequest: // Optional (capability 'supportsReadMemoryRequest')
/*TODO*/ s.onReadMemoryRequest(request) // Not yet implemented /*TODO*/ s.onReadMemoryRequest(request) // Not yet implemented
case *dap.CancelRequest: // Optional (capability supportsCancelRequest) case *dap.CancelRequest: // Optional (capability 'supportsCancelRequest')
/*TODO*/ s.onCancelRequest(request) // Not yet implemented (does this make sense?) /*TODO*/ s.onCancelRequest(request) // Not yet implemented (does this make sense?)
case *dap.ModulesRequest: // Optional (capability supportsModulesRequest) case *dap.ModulesRequest: // Optional (capability 'supportsModulesRequest')
/*TODO*/ s.sendUnsupportedErrorResponse(request.Request) // Not yet implemented (does this make sense?) /*TODO*/ s.sendUnsupportedErrorResponse(request.Request) // Not yet implemented (does this make sense?)
//--- Requests that we do not plan to support --- //--- Requests that we do not plan to support ---
case *dap.RestartFrameRequest: // Optional (capability supportsRestartFrame) case *dap.RestartFrameRequest: // Optional (capability 'supportsRestartFrame')
s.sendUnsupportedErrorResponse(request.Request) s.sendUnsupportedErrorResponse(request.Request)
case *dap.GotoRequest: // Optional (capability supportsGotoTargetsRequest) case *dap.GotoRequest: // Optional (capability 'supportsGotoTargetsRequest')
s.sendUnsupportedErrorResponse(request.Request) s.sendUnsupportedErrorResponse(request.Request)
case *dap.TerminateThreadsRequest: // Optional (capability supportsTerminateThreadsRequest) case *dap.TerminateThreadsRequest: // Optional (capability 'supportsTerminateThreadsRequest')
s.sendUnsupportedErrorResponse(request.Request) s.sendUnsupportedErrorResponse(request.Request)
case *dap.StepInTargetsRequest: // Optional (capability supportsStepInTargetsRequest) case *dap.StepInTargetsRequest: // Optional (capability 'supportsStepInTargetsRequest')
s.sendUnsupportedErrorResponse(request.Request) s.sendUnsupportedErrorResponse(request.Request)
case *dap.GotoTargetsRequest: // Optional (capability supportsGotoTargetsRequest) case *dap.GotoTargetsRequest: // Optional (capability 'supportsGotoTargetsRequest')
s.sendUnsupportedErrorResponse(request.Request) s.sendUnsupportedErrorResponse(request.Request)
case *dap.CompletionsRequest: // Optional (capability supportsCompletionsRequest) case *dap.CompletionsRequest: // Optional (capability 'supportsCompletionsRequest')
s.sendUnsupportedErrorResponse(request.Request) s.sendUnsupportedErrorResponse(request.Request)
case *dap.DataBreakpointInfoRequest: // Optional (capability supportsDataBreakpoints) case *dap.DataBreakpointInfoRequest: // Optional (capability 'supportsDataBreakpoints')
s.sendUnsupportedErrorResponse(request.Request) s.sendUnsupportedErrorResponse(request.Request)
case *dap.SetDataBreakpointsRequest: // Optional (capability supportsDataBreakpoints) case *dap.SetDataBreakpointsRequest: // Optional (capability 'supportsDataBreakpoints')
s.sendUnsupportedErrorResponse(request.Request) s.sendUnsupportedErrorResponse(request.Request)
case *dap.BreakpointLocationsRequest: // Optional (capability supportsBreakpointLocationsRequest) case *dap.BreakpointLocationsRequest: // Optional (capability 'supportsBreakpointLocationsRequest')
s.sendUnsupportedErrorResponse(request.Request) s.sendUnsupportedErrorResponse(request.Request)
default: default:
// This is a DAP message that go-dap has a struct for, so // This is a DAP message that go-dap has a struct for, so
@ -953,7 +958,7 @@ func (s *Session) onLaunchRequest(request *dap.LaunchRequest) {
return return
} }
// Assign the non-empty core file path to debugger configuration. This will // Assign the non-empty core file path to debugger configuration. This will
// trigger a native core file replay instead of an rr trace replay // trigger a native core file replay instead of a rr trace replay
s.config.Debugger.CoreFile = args.CoreFilePath s.config.Debugger.CoreFile = args.CoreFilePath
args.Backend = "core" args.Backend = "core"
} }
@ -1103,7 +1108,7 @@ func (s *Session) onLaunchRequest(request *dap.LaunchRequest) {
return return
} }
var clear func() var closeAll func()
if redirected { if redirected {
var ( var (
readers [2]io.ReadCloser readers [2]io.ReadCloser
@ -1123,7 +1128,7 @@ func (s *Session) onLaunchRequest(request *dap.LaunchRequest) {
s.config.Debugger.Stderr = outputRedirects[1] s.config.Debugger.Stderr = outputRedirects[1]
redirectedFunc(readers[0], readers[1]) redirectedFunc(readers[0], readers[1])
clear = func() { closeAll = func() {
for index := range readers { for index := range readers {
if closeErr := readers[index].Close(); closeErr != nil { if closeErr := readers[index].Close(); closeErr != nil {
s.config.log.Warnf("failed to clear redirects - %v", closeErr) s.config.log.Warnf("failed to clear redirects - %v", closeErr)
@ -1142,8 +1147,8 @@ func (s *Session) onLaunchRequest(request *dap.LaunchRequest) {
gobuild.Remove(s.binaryToRemove) gobuild.Remove(s.binaryToRemove)
} }
s.sendShowUserErrorResponse(request.Request, FailedToLaunch, "Failed to launch", err.Error()) s.sendShowUserErrorResponse(request.Request, FailedToLaunch, "Failed to launch", err.Error())
if redirected { if closeAll != nil {
clear() closeAll()
} }
return return
} }
@ -1305,14 +1310,15 @@ func (s *Session) stopDebugSession(killProcess bool) error {
// goroutine can wrap-up and exit. // goroutine can wrap-up and exit.
s.setHaltRequested(true) s.setHaltRequested(true)
state, err := s.halt() state, err := s.halt()
if err == proc.ErrProcessDetached { if errors.Is(err, proc.ErrProcessDetached) {
s.config.log.Debug("halt returned error: ", err) s.config.log.Debug("halt returned error: ", err)
return nil return nil
} }
if err != nil { if err != nil {
switch err.(type) { var errProcessExited proc.ErrProcessExited
case proc.ErrProcessExited: switch {
exited = err case errors.As(err, &errProcessExited):
exited = errProcessExited
default: default:
s.config.log.Error("halt returned error: ", err) s.config.log.Error("halt returned error: ", err)
if err.Error() == "no such process" { if err.Error() == "no such process" {
@ -1335,10 +1341,13 @@ func (s *Session) stopDebugSession(killProcess bool) error {
} }
err = s.debugger.Detach(killProcess) err = s.debugger.Detach(killProcess)
if err != nil { if err != nil {
switch err.(type) { var errProcessExited proc.ErrProcessExited
case proc.ErrProcessExited: switch {
s.config.log.Debug(err) case errors.As(err, &errProcessExited):
s.logToConsole(exited.Error()) s.config.log.Debug(errProcessExited)
if exited != nil {
s.logToConsole(exited.Error())
}
err = nil err = nil
default: default:
s.config.log.Error("detach returned error: ", err) s.config.log.Error("detach returned error: ", err)
@ -1511,7 +1520,7 @@ func setLogMessage(bp *api.Breakpoint, msg string) error {
} }
func (s *Session) updateBreakpointsResponse(breakpoints []dap.Breakpoint, i int, err error, got *api.Breakpoint) { func (s *Session) updateBreakpointsResponse(breakpoints []dap.Breakpoint, i int, err error, got *api.Breakpoint) {
breakpoints[i].Verified = (err == nil) breakpoints[i].Verified = err == nil
if err != nil { if err != nil {
breakpoints[i].Message = err.Error() breakpoints[i].Message = err.Error()
} else { } else {
@ -1651,7 +1660,7 @@ func closeIfOpen(ch chan struct{}) {
} }
// onConfigurationDoneRequest handles 'configurationDone' request. // onConfigurationDoneRequest handles 'configurationDone' request.
// This is an optional request enabled by capability supportsConfigurationDoneRequest. // This is an optional request enabled by capability 'supportsConfigurationDoneRequest'.
// It gets triggered after all the debug requests that follow initialized event, // It gets triggered after all the debug requests that follow initialized event,
// so the s.debugger is guaranteed to be set. Expects the target to be halted. // so the s.debugger is guaranteed to be set. Expects the target to be halted.
func (s *Session) onConfigurationDoneRequest(request *dap.ConfigurationDoneRequest, allowNextStateChange chan struct{}) { func (s *Session) onConfigurationDoneRequest(request *dap.ConfigurationDoneRequest, allowNextStateChange chan struct{}) {
@ -1741,11 +1750,12 @@ func (s *Session) onThreadsRequest(request *dap.ThreadsRequest) {
var threads []dap.Thread var threads []dap.Thread
if err != nil { if err != nil {
switch err.(type) { var errProcessExited proc.ErrProcessExited
case proc.ErrProcessExited: switch {
case errors.As(err, &errProcessExited):
// If the program exits very quickly, the initial threads request will complete after it has exited. // If the program exits very quickly, the initial threads request will complete after it has exited.
// A TerminatedEvent has already been sent. Ignore the err returned in this case. // A TerminatedEvent has already been sent. Ignore the error returned in this case.
s.config.log.Debug(err) s.config.log.Debug(errProcessExited)
default: default:
s.send(&dap.OutputEvent{ s.send(&dap.OutputEvent{
Event: *newEvent("output"), Event: *newEvent("output"),
@ -1826,7 +1836,7 @@ func (s *Session) onThreadsRequest(request *dap.ThreadsRequest) {
// - "remote" -- attaches client to a debugger already attached to a process. // - "remote" -- attaches client to a debugger already attached to a process.
// Required args: none (host/port are used externally to connect) // Required args: none (host/port are used externally to connect)
func (s *Session) onAttachRequest(request *dap.AttachRequest) { func (s *Session) onAttachRequest(request *dap.AttachRequest) {
var args AttachConfig = defaultAttachConfig // narrow copy for initializing non-zero default values var args = defaultAttachConfig // narrow copy for initializing non-zero default values
if err := unmarshalLaunchAttachArgs(request.Arguments, &args); err != nil { if err := unmarshalLaunchAttachArgs(request.Arguments, &args); err != nil {
s.sendShowUserErrorResponse(request.Request, FailedToAttach, "Failed to attach", fmt.Sprintf("invalid debug configuration - %v", err)) s.sendShowUserErrorResponse(request.Request, FailedToAttach, "Failed to attach", fmt.Sprintf("invalid debug configuration - %v", err))
return return
@ -1932,7 +1942,7 @@ func (s *Session) onStepOutRequest(request *dap.StepOutRequest, allowNextStateCh
} }
func (s *Session) sendStepResponse(threadId int, message dap.Message) { func (s *Session) sendStepResponse(threadId int, message dap.Message) {
// All of the threads will be continued by this request, so we need to send // All the threads will be continued by this request, so we need to send
// a continued event so the UI can properly reflect the current state. // a continued event so the UI can properly reflect the current state.
s.send(&dap.ContinuedEvent{ s.send(&dap.ContinuedEvent{
Event: *newEvent("continued"), Event: *newEvent("continued"),
@ -2042,7 +2052,7 @@ type stackFrame struct {
frameIndex int frameIndex int
} }
// onStackTraceRequest handles stackTrace requests. // onStackTraceRequest handles 'stackTrace' requests.
// This is a mandatory request to support. // This is a mandatory request to support.
// As per DAP spec, this request only gets triggered as a follow-up // As per DAP spec, this request only gets triggered as a follow-up
// to a successful threads request as part of the "request waterfall". // to a successful threads request as part of the "request waterfall".
@ -2126,7 +2136,7 @@ func (s *Session) onScopesRequest(request *dap.ScopesRequest) {
frame := sf.(stackFrame).frameIndex frame := sf.(stackFrame).frameIndex
// Check if the function is optimized. // Check if the function is optimized.
fn, err := s.debugger.Function(int64(goid), frame, 0, DefaultLoadConfig) fn, err := s.debugger.Function(int64(goid), frame, 0)
if fn == nil || err != nil { if fn == nil || err != nil {
var details string var details string
if err != nil { if err != nil {
@ -2193,7 +2203,7 @@ func (s *Session) onScopesRequest(request *dap.ScopesRequest) {
if s.args.ShowRegisters { if s.args.ShowRegisters {
// Retrieve registers // Retrieve registers
regs, err := s.debugger.ScopeRegisters(int64(goid), frame, 0, false) regs, err := s.debugger.ScopeRegisters(int64(goid), frame, 0)
if err != nil { if err != nil {
s.sendErrorResponse(request.Request, UnableToListRegisters, "Unable to list registers", err.Error()) s.sendErrorResponse(request.Request, UnableToListRegisters, "Unable to list registers", err.Error())
return return
@ -2431,7 +2441,7 @@ func (s *Session) childrenToDAPVariables(v *fullyQualifiedVariable) []dap.Variab
} }
if v.isScope && v.Name == "Registers" { if v.isScope && v.Name == "Registers" {
// Align all of the register names. // Align all the register names.
name = fmt.Sprintf("%6s", strings.ToLower(c.Name)) name = fmt.Sprintf("%6s", strings.ToLower(c.Name))
// Set the correct evaluate name for the register. // Set the correct evaluate name for the register.
cfqname = fmt.Sprintf("_%s", strings.ToUpper(c.Name)) cfqname = fmt.Sprintf("_%s", strings.ToUpper(c.Name))
@ -2769,7 +2779,7 @@ func (s *Session) onEvaluateRequest(request *dap.EvaluateRequest) {
s.sendErrorResponseWithOpts(request.Request, UnableToEvaluateExpression, "Unable to evaluate expression", err.Error(), showErrorToUser) s.sendErrorResponseWithOpts(request.Request, UnableToEvaluateExpression, "Unable to evaluate expression", err.Error(), showErrorToUser)
return return
} }
// The call completed and we can reply with its return values (if any) // The call completed, and we can reply with its return values (if any)
if len(retVars) > 0 { if len(retVars) > 0 {
// Package one or more return values in a single scope-like nameless variable // Package one or more return values in a single scope-like nameless variable
// that preserves their names. // that preserves their names.
@ -2937,7 +2947,7 @@ func (s *Session) onRestartRequest(request *dap.RestartRequest) {
} }
// onStepBackRequest handles 'stepBack' request. // onStepBackRequest handles 'stepBack' request.
// This is an optional request enabled by capability supportsStepBackRequest. // This is an optional request enabled by capability 'supportsStepBackRequest'.
func (s *Session) onStepBackRequest(request *dap.StepBackRequest, allowNextStateChange chan struct{}) { func (s *Session) onStepBackRequest(request *dap.StepBackRequest, allowNextStateChange chan struct{}) {
s.sendStepResponse(request.Arguments.ThreadId, &dap.StepBackResponse{Response: *newResponse(request.Request)}) s.sendStepResponse(request.Arguments.ThreadId, &dap.StepBackResponse{Response: *newResponse(request.Request)})
s.stepUntilStopAndNotify(api.ReverseNext, request.Arguments.ThreadId, request.Arguments.Granularity, allowNextStateChange) s.stepUntilStopAndNotify(api.ReverseNext, request.Arguments.ThreadId, request.Arguments.Granularity, allowNextStateChange)
@ -2945,7 +2955,7 @@ func (s *Session) onStepBackRequest(request *dap.StepBackRequest, allowNextState
// onReverseContinueRequest performs a rewind command call up to the previous // onReverseContinueRequest performs a rewind command call up to the previous
// breakpoint or the start of the process // breakpoint or the start of the process
// This is an optional request enabled by capability supportsStepBackRequest. // This is an optional request enabled by capability 'supportsStepBackRequest'.
func (s *Session) onReverseContinueRequest(request *dap.ReverseContinueRequest, allowNextStateChange chan struct{}) { func (s *Session) onReverseContinueRequest(request *dap.ReverseContinueRequest, allowNextStateChange chan struct{}) {
s.send(&dap.ReverseContinueResponse{ s.send(&dap.ReverseContinueResponse{
Response: *newResponse(request.Request), Response: *newResponse(request.Request),
@ -3051,7 +3061,7 @@ func (s *Session) onSetVariableRequest(request *dap.SetVariableRequest) {
// injection - after the injected call is completed, the debuggee can // injection - after the injected call is completed, the debuggee can
// be in a completely different state (see the note in doCall) due to // be in a completely different state (see the note in doCall) due to
// how the call injection is implemented. Ideally, we need to also refresh // how the call injection is implemented. Ideally, we need to also refresh
// the stack frames but that is complicated. For now we don't try to actively // the stack frames but that is complicated. For now, we don't try to actively
// invalidate this state hoping that the editors will refetch the state // invalidate this state hoping that the editors will refetch the state
// as soon as the user resumes debugging. // as soon as the user resumes debugging.
@ -3115,7 +3125,7 @@ func (s *Session) onDisassembleRequest(request *dap.DisassembleRequest) {
return return
} }
start := uint64(addr) start := addr
maxInstructionLength := s.debugger.Target().BinInfo().Arch.MaxInstructionLength() maxInstructionLength := s.debugger.Target().BinInfo().Arch.MaxInstructionLength()
byteOffset := request.Arguments.InstructionOffset * maxInstructionLength byteOffset := request.Arguments.InstructionOffset * maxInstructionLength
// Adjust the offset to include instructions before the requested address. // Adjust the offset to include instructions before the requested address.
@ -3193,7 +3203,7 @@ func findInstructions(procInstructions []proc.AsmInstruction, addr uint64, instr
ref := sort.Search(len(procInstructions), func(i int) bool { ref := sort.Search(len(procInstructions), func(i int) bool {
return procInstructions[i].Loc.PC >= addr return procInstructions[i].Loc.PC >= addr
}) })
if ref == len(procInstructions) || procInstructions[ref].Loc.PC != uint64(addr) { if ref == len(procInstructions) || procInstructions[ref].Loc.PC != addr {
return nil, -1, fmt.Errorf("could not find memory reference") return nil, -1, fmt.Errorf("could not find memory reference")
} }
// offset is the number of instructions that should appear before the first instruction // offset is the number of instructions that should appear before the first instruction
@ -3530,7 +3540,8 @@ func (s *Session) resetHandlesForStoppedEvent() {
} }
func processExited(state *api.DebuggerState, err error) bool { func processExited(state *api.DebuggerState, err error) bool {
_, isexited := err.(proc.ErrProcessExited) var errProcessExited proc.ErrProcessExited
isexited := errors.As(err, &errProcessExited)
return isexited || err == nil && state.Exited return isexited || err == nil && state.Exited
} }
@ -3585,7 +3596,7 @@ func (s *Session) resumeOnce(command string, allowNextStateChange chan struct{})
} }
// runUntilStopAndNotify runs a debugger command until it stops on // runUntilStopAndNotify runs a debugger command until it stops on
// termination, error, breakpoint, etc, when an appropriate // termination, error, breakpoint, etc., when an appropriate
// event needs to be sent to the client. allowNextStateChange is // event needs to be sent to the client. allowNextStateChange is
// a channel that will be closed to signal that an // a channel that will be closed to signal that an
// asynchronous command has completed setup or was interrupted // asynchronous command has completed setup or was interrupted
@ -3718,7 +3729,7 @@ func (s *Session) runUntilStop(command string, allowNextStateChange chan struct{
return state, err return state, err
} }
// Make this a var so it can be stubbed in testing. // Make this a var, so it can be stubbed in testing.
var resumeOnceAndCheckStop = func(s *Session, command string, allowNextStateChange chan struct{}) (*api.DebuggerState, error) { var resumeOnceAndCheckStop = func(s *Session, command string, allowNextStateChange chan struct{}) (*api.DebuggerState, error) {
return s.resumeOnceAndCheckStop(command, allowNextStateChange) return s.resumeOnceAndCheckStop(command, allowNextStateChange)
} }

@ -218,7 +218,7 @@ func New(config *Config, processArgs []string) (*Debugger, error) {
var err error var err error
d.target, err = d.Launch(d.processArgs, d.config.WorkingDir) d.target, err = d.Launch(d.processArgs, d.config.WorkingDir)
if err != nil { if err != nil {
if _, ok := err.(*proc.ErrUnsupportedArch); !ok { if !errors.Is(err, &proc.ErrUnsupportedArch{}) {
err = go11DecodeErrorCheck(err) err = go11DecodeErrorCheck(err)
err = noDebugErrorWarning(err) err = noDebugErrorWarning(err)
err = fmt.Errorf("could not launch process: %s", err) err = fmt.Errorf("could not launch process: %s", err)
@ -308,8 +308,8 @@ func (d *Debugger) Launch(processArgs []string, wd string) (*proc.TargetGroup, e
grp, err := d.recordingRun(run) grp, err := d.recordingRun(run)
if err != nil { if err != nil {
d.log.Errorf("could not record target: %v", err) d.log.Errorf("could not record target: %v", err)
// this is ugly but we can't respond to any client requests at this // this is ugly, but we can't respond to any client requests at this
// point so it's better if we die. // point, so it's better if we die.
os.Exit(1) os.Exit(1)
} }
d.recordingDone() d.recordingDone()
@ -384,7 +384,7 @@ func betterGdbserialLaunchError(p *proc.TargetGroup, err error) (*proc.TargetGro
if runtime.GOOS != "darwin" { if runtime.GOOS != "darwin" {
return p, err return p, err
} }
if _, isUnavailable := err.(*gdbserial.ErrBackendUnavailable); !isUnavailable { if !errors.Is(err, &gdbserial.ErrBackendUnavailable{}) {
return p, err return p, err
} }
@ -593,7 +593,8 @@ func (d *Debugger) state(retLoadCfg *proc.LoadConfig, withBreakpointInfo bool) (
exited := false exited := false
if _, err := tgt.Valid(); err != nil { if _, err := tgt.Valid(); err != nil {
_, exited = err.(proc.ErrProcessExited) var errProcessExited proc.ErrProcessExited
exited = errors.As(err, &errProcessExited)
} }
state = &api.DebuggerState{ state = &api.DebuggerState{
@ -744,10 +745,6 @@ func (d *Debugger) CreateBreakpoint(requestedBp *api.Breakpoint, locExpr string,
} }
} }
if err != nil {
return nil, err
}
if locExpr != "" { if locExpr != "" {
loc, err := locspec.Parse(locExpr) loc, err := locspec.Parse(locExpr)
if err != nil { if err != nil {
@ -951,7 +948,7 @@ func parseHitCondition(hitCond string) (token.Token, int, error) {
// A hit condition can be in the following formats: // A hit condition can be in the following formats:
// - "number" // - "number"
// - "OP number" // - "OP number"
hitConditionRegex := regexp.MustCompile(`((=|>|<|%|!)+|)( |)((\d|_)+)`) hitConditionRegex := regexp.MustCompile(`(([=><%!])+|)( |)((\d|_)+)`)
match := hitConditionRegex.FindStringSubmatch(strings.TrimSpace(hitCond)) match := hitConditionRegex.FindStringSubmatch(strings.TrimSpace(hitCond))
if match == nil || len(match) != 6 { if match == nil || len(match) != 6 {
@ -1305,12 +1302,13 @@ func (d *Debugger) Command(command *api.DebuggerCommand, resumeNotify chan struc
} }
if err != nil { if err != nil {
if pe, ok := err.(proc.ErrProcessExited); ok && command.Name != api.SwitchGoroutine && command.Name != api.SwitchThread { var errProcessExited proc.ErrProcessExited
if errors.As(err, &errProcessExited) && command.Name != api.SwitchGoroutine && command.Name != api.SwitchThread {
state := &api.DebuggerState{} state := &api.DebuggerState{}
state.Pid = d.target.Selected.Pid() state.Pid = d.target.Selected.Pid()
state.Exited = true state.Exited = true
state.ExitStatus = pe.Status state.ExitStatus = errProcessExited.Status
state.Err = pe state.Err = errProcessExited
return state, nil return state, nil
} }
return nil, err return nil, err
@ -1530,7 +1528,7 @@ func (d *Debugger) PackageVariables(filter string, cfg proc.LoadConfig) ([]*proc
} }
// ThreadRegisters returns registers of the specified thread. // ThreadRegisters returns registers of the specified thread.
func (d *Debugger) ThreadRegisters(threadID int, floatingPoint bool) (*op.DwarfRegisters, error) { func (d *Debugger) ThreadRegisters(threadID int) (*op.DwarfRegisters, error) {
d.targetMutex.Lock() d.targetMutex.Lock()
defer d.targetMutex.Unlock() defer d.targetMutex.Unlock()
@ -1546,7 +1544,7 @@ func (d *Debugger) ThreadRegisters(threadID int, floatingPoint bool) (*op.DwarfR
} }
// ScopeRegisters returns registers for the specified scope. // ScopeRegisters returns registers for the specified scope.
func (d *Debugger) ScopeRegisters(goid int64, frame, deferredCall int, floatingPoint bool) (*op.DwarfRegisters, error) { func (d *Debugger) ScopeRegisters(goid int64, frame, deferredCall int) (*op.DwarfRegisters, error) {
d.targetMutex.Lock() d.targetMutex.Lock()
defer d.targetMutex.Unlock() defer d.targetMutex.Unlock()
@ -1587,7 +1585,7 @@ func (d *Debugger) FunctionArguments(goid int64, frame, deferredCall int, cfg pr
} }
// Function returns the current function. // Function returns the current function.
func (d *Debugger) Function(goid int64, frame, deferredCall int, cfg proc.LoadConfig) (*proc.Function, error) { func (d *Debugger) Function(goid int64, frame, deferredCall int) (*proc.Function, error) {
d.targetMutex.Lock() d.targetMutex.Lock()
defer d.targetMutex.Unlock() defer d.targetMutex.Unlock()
@ -1775,7 +1773,7 @@ func (d *Debugger) GroupGoroutines(gs []*proc.G, group *api.GoroutineGroupingOpt
// Stacktrace returns a list of Stackframes for the given goroutine. The // Stacktrace returns a list of Stackframes for the given goroutine. The
// length of the returned list will be min(stack_len, depth). // length of the returned list will be min(stack_len, depth).
// If 'full' is true, then local vars, function args, etc will be returned as well. // If 'full' is true, then local vars, function args, etc. will be returned as well.
func (d *Debugger) Stacktrace(goroutineID int64, depth int, opts api.StacktraceOptions) ([]proc.Stackframe, error) { func (d *Debugger) Stacktrace(goroutineID int64, depth int, opts api.StacktraceOptions) ([]proc.Stackframe, error) {
d.targetMutex.Lock() d.targetMutex.Lock()
defer d.targetMutex.Unlock() defer d.targetMutex.Unlock()
@ -1893,7 +1891,7 @@ func (d *Debugger) convertDefers(defers []*proc.Defer) []api.Defer {
if defers[i].Unreadable != nil { if defers[i].Unreadable != nil {
r[i].Unreadable = defers[i].Unreadable.Error() r[i].Unreadable = defers[i].Unreadable.Error()
} else { } else {
var entry uint64 = defers[i].DeferPC var entry = defers[i].DeferPC
if ddfn != nil { if ddfn != nil {
entry = ddfn.Entry entry = ddfn.Entry
} }
@ -2164,7 +2162,7 @@ func (d *Debugger) StopRecording() error {
return d.stopRecording() return d.stopRecording()
} }
// StopReason returns the reason the reason why the target process is stopped. // StopReason returns the reason why the target process is stopped.
// A process could be stopped for multiple simultaneous reasons, in which // A process could be stopped for multiple simultaneous reasons, in which
// case only one will be reported. // case only one will be reported.
func (d *Debugger) StopReason() proc.StopReason { func (d *Debugger) StopReason() proc.StopReason {
@ -2353,7 +2351,7 @@ func (d *Debugger) ChanGoroutines(goid int64, frame, deferredCall int, expr stri
} }
func go11DecodeErrorCheck(err error) error { func go11DecodeErrorCheck(err error) error {
if _, isdecodeerr := err.(dwarf.DecodeError); !isdecodeerr { if !errors.Is(err, dwarf.DecodeError{}) {
return err return err
} }
@ -2368,7 +2366,7 @@ func go11DecodeErrorCheck(err error) error {
const NoDebugWarning string = "debuggee must not be built with 'go run' or -ldflags='-s -w', which strip debug info" const NoDebugWarning string = "debuggee must not be built with 'go run' or -ldflags='-s -w', which strip debug info"
func noDebugErrorWarning(err error) error { func noDebugErrorWarning(err error) error {
if _, isdecodeerr := err.(dwarf.DecodeError); isdecodeerr || strings.Contains(err.Error(), "could not open debug info") { if errors.Is(err, dwarf.DecodeError{}) || strings.Contains(err.Error(), "could not open debug info") {
return fmt.Errorf("%s - %s", err.Error(), NoDebugWarning) return fmt.Errorf("%s - %s", err.Error(), NoDebugWarning)
} }
return err return err

@ -202,7 +202,7 @@ func (s *RPCServer) ListRegisters(arg interface{}, registers *string) error {
return err return err
} }
dregs, err := s.debugger.ThreadRegisters(state.CurrentThread.ID, false) dregs, err := s.debugger.ThreadRegisters(state.CurrentThread.ID)
if err != nil { if err != nil {
return err return err
} }

@ -465,9 +465,9 @@ func (s *RPCServer) ListRegisters(arg ListRegistersIn, out *ListRegistersOut) er
var err error var err error
if arg.Scope != nil { if arg.Scope != nil {
regs, err = s.debugger.ScopeRegisters(arg.Scope.GoroutineID, arg.Scope.Frame, arg.Scope.DeferredCall, arg.IncludeFp) regs, err = s.debugger.ScopeRegisters(arg.Scope.GoroutineID, arg.Scope.Frame, arg.Scope.DeferredCall)
} else { } else {
regs, err = s.debugger.ThreadRegisters(arg.ThreadID, arg.IncludeFp) regs, err = s.debugger.ThreadRegisters(arg.ThreadID)
} }
if err != nil { if err != nil {
return err return err