gitlab.com/Raven-IO/raven-delve@v1.22.4/service/dap/types.go (about)

     1  package dap
     2  
     3  import (
     4  	"encoding/json"
     5  	"errors"
     6  	"fmt"
     7  )
     8  
     9  // Launch debug sessions support the following modes:
    10  //
    11  //	-- [DEFAULT] "debug" - builds and launches debugger for specified program (similar to 'dlv debug')
    12  //
    13  //	   Required args: program
    14  //	   Optional args with default: output, cwd, noDebug
    15  //	   Optional args: buildFlags, args
    16  //
    17  //	-- "test" - builds and launches debugger for specified test (similar to 'dlv test')
    18  //
    19  //	   same args as above
    20  //
    21  //	-- "exec" - launches debugger for precompiled binary (similar to 'dlv exec')
    22  //
    23  //	   Required args: program
    24  //	   Optional args with default: cwd, noDebug
    25  //	   Optional args: args
    26  //
    27  //	-- "replay" - replays a trace generated by mozilla rr. Mozilla rr must be installed.
    28  //
    29  //	   Required args: traceDirPath
    30  //	   Optional args: args
    31  //
    32  //	-- "core" - examines a core dump (only supports linux and windows core dumps).
    33  //
    34  //	   Required args: program, coreFilePath
    35  //	   Optional args: args
    36  //
    37  // TODO(hyangah): change this to 'validateLaunchMode' that checks
    38  // all the required/optional fields mentioned above.
    39  func isValidLaunchMode(mode string) bool {
    40  	switch mode {
    41  	case "exec", "debug", "test", "replay", "core":
    42  		return true
    43  	}
    44  	return false
    45  }
    46  
    47  // Default values for Launch/Attach configs.
    48  // Used to initialize configuration variables before decoding
    49  // arguments in launch/attach requests.
    50  var (
    51  	defaultLaunchAttachCommonConfig = LaunchAttachCommonConfig{
    52  		Backend:         "default",
    53  		StackTraceDepth: 50,
    54  	}
    55  	defaultLaunchConfig = LaunchConfig{
    56  		Mode:                     "debug",
    57  		LaunchAttachCommonConfig: defaultLaunchAttachCommonConfig,
    58  	}
    59  	defaultAttachConfig = AttachConfig{
    60  		Mode:                     "local",
    61  		LaunchAttachCommonConfig: defaultLaunchAttachCommonConfig,
    62  	}
    63  )
    64  
    65  // LaunchConfig is the collection of launch request attributes recognized by DAP implementation.
    66  type LaunchConfig struct {
    67  	// Acceptable values are:
    68  	//   "debug": compiles your program with optimizations disabled, starts and attaches to it.
    69  	//   "test": compiles your unit test program with optimizations disabled, starts and attaches to it.
    70  	//   "exec": executes a precompiled binary and begins a debug session.
    71  	//   "replay": replays an rr trace.
    72  	//   "core": examines a core dump.
    73  	//
    74  	// Default is "debug".
    75  	Mode string `json:"mode,omitempty"`
    76  
    77  	// Path to the program folder (or any go file within that folder)
    78  	// when in `debug` or `test` mode, and to the pre-built binary file
    79  	// to debug in `exec` mode.
    80  	// If it is not an absolute path, it will be interpreted as a path
    81  	// relative to Delve's working directory.
    82  	// Required when mode is `debug`, `test`, `exec`, and `core`.
    83  	Program string `json:"program,omitempty"`
    84  
    85  	// Command line arguments passed to the debugged program.
    86  	// Relative paths used in Args will be interpreted as paths relative
    87  	// to `cwd`.
    88  	Args []string `json:"args,omitempty"`
    89  
    90  	// Working directory of the program being debugged.
    91  	// If a relative path is provided, it will be interpreted as
    92  	// a relative path to Delve's working directory. This is
    93  	// similar to `dlv --wd` flag.
    94  	//
    95  	// If not specified or empty, Delve's working directory is
    96  	// used by default. But for `test` mode, Delve tries to find
    97  	// the test's package source directory and run tests from there.
    98  	// This matches the behavior of `dlv test` and `go test`.
    99  	Cwd string `json:"cwd,omitempty"`
   100  
   101  	// Build flags, to be passed to the Go compiler.
   102  	// Relative paths used in BuildFlags will be interpreted as paths
   103  	// relative to Delve's current working directory.
   104  	//
   105  	// It should be a string like `dlv --build-flags`, or
   106  	// an array of strings that is augmented when invoking the go build or
   107  	// test command through os/exec.Command API.
   108  	// For example, both forms are acceptable.
   109  	//    "buildFlags": "-tags=integration -ldflags='-X main.Hello=World'"
   110  	// or
   111  	//    "buildFlags": ["-tags=integration", "-ldflags=-X main.Hello=World"]
   112  	// Using other types is an error.
   113  	BuildFlags BuildFlags `json:"buildFlags,omitempty"`
   114  
   115  	// Output path for the binary of the debuggee.
   116  	// Relative path is interpreted as the path relative to
   117  	// the Delve's current working directory.
   118  	// This is deleted after the debug session ends.
   119  	Output string `json:"output,omitempty"`
   120  
   121  	// NoDebug is used to run the program without debugging.
   122  	NoDebug bool `json:"noDebug,omitempty"`
   123  
   124  	// TraceDirPath is the trace directory path for replay mode.
   125  	// Relative path is interpreted as a path relative to Delve's
   126  	// current working directory.
   127  	// This is required for "replay" mode but unused in other modes.
   128  	TraceDirPath string `json:"traceDirPath,omitempty"`
   129  
   130  	// CoreFilePath is the core file path for core mode.
   131  	//
   132  	// This is required for "core" mode but unused in other modes.
   133  	CoreFilePath string `json:"coreFilePath,omitempty"`
   134  
   135  	// DlvCwd is the new working directory for Delve server.
   136  	// If specified, the server will change its working
   137  	// directory to the specified directory using os.Chdir.
   138  	// Any other launch attributes with relative paths interpreted
   139  	// using Delve's working directory will use this new directory.
   140  	// When Delve needs to build the program (in debug/test modes),
   141  	// it will run the go command from this directory as well.
   142  	//
   143  	// If a relative path is provided as DlvCwd, it will be
   144  	// interpreted as a path relative to Delve's current working
   145  	// directory.
   146  	DlvCwd string `json:"dlvCwd,omitempty"`
   147  
   148  	// Env specifies optional environment variables for Delve server
   149  	// in addition to the environment variables Delve initially
   150  	// started with.
   151  	// Variables with 'nil' values can be used to unset the named
   152  	// environment variables.
   153  	// Values are interpreted verbatim. Variable substitution or
   154  	// reference to other environment variables is not supported.
   155  	Env map[string]*string `json:"env,omitempty"`
   156  
   157  	// The output mode specifies how to handle the program's output.
   158  	OutputMode string `json:"outputMode,omitempty"`
   159  
   160  	LaunchAttachCommonConfig
   161  }
   162  
   163  // LaunchAttachCommonConfig is the attributes common in both launch/attach requests.
   164  type LaunchAttachCommonConfig struct {
   165  	// Automatically stop program after launch or attach.
   166  	StopOnEntry bool `json:"stopOnEntry,omitempty"`
   167  
   168  	// Backend used for debugging. See `dlv backend` for allowed values.
   169  	// Default is "default".
   170  	Backend string `json:"backend,omitempty"`
   171  
   172  	// Maximum depth of stack trace to return.
   173  	// Default is 50.
   174  	StackTraceDepth int `json:"stackTraceDepth,omitempty"`
   175  
   176  	// Boolean value to indicate whether global package variables
   177  	// should be shown in the variables pane or not.
   178  	ShowGlobalVariables bool `json:"showGlobalVariables,omitempty"`
   179  
   180  	// Boolean value to indicate whether registers should be shown
   181  	// in the variables pane or not.
   182  	ShowRegisters bool `json:"showRegisters,omitempty"`
   183  
   184  	// Boolean value to indicate whether system goroutines
   185  	// should be hidden from the call stack view.
   186  	HideSystemGoroutines bool `json:"hideSystemGoroutines,omitempty"`
   187  
   188  	// String value to indicate which system goroutines should be
   189  	// shown in the call stack view. See filtering documentation:
   190  	// https://gitlab.com/Raven-IO/raven-delve/blob/master/Documentation/cli/README.md#goroutines
   191  	GoroutineFilters string `json:"goroutineFilters,omitempty"`
   192  
   193  	// Array of string values indicating the keys of pprof labels to show as a
   194  	// goroutine name in the threads view. If the array has one element, only
   195  	// that label's value will be shown; otherwise, each of the labels will be
   196  	// shown as "key:value". To show all labels, specify the single element "*".
   197  	ShowPprofLabels []string `json:"showPprofLabels,omitempty"`
   198  
   199  	// An array of mappings from a local path (client) to the remote path (debugger).
   200  	// This setting is useful when working in a file system with symbolic links,
   201  	// running remote debugging, or debugging an executable compiled externally.
   202  	// The debug adapter will replace the local path with the remote path in all of the calls.
   203  	// See also Documentation/cli/substitutepath.md.
   204  	SubstitutePath []SubstitutePath `json:"substitutePath,omitempty"`
   205  }
   206  
   207  // SubstitutePath defines a mapping from a local path to the remote path.
   208  // Both 'from' and 'to' must be specified and non-null.
   209  // Empty values can be used to add or remove absolute path prefixes when mapping.
   210  // For example, mapping with empty 'to' can be used to work with binaries with trimmed paths.
   211  type SubstitutePath struct {
   212  	// The local path to be replaced when passing paths to the debugger.
   213  	From string `json:"from,omitempty"`
   214  	// The remote path to be replaced when passing paths back to the client.
   215  	To string `json:"to,omitempty"`
   216  }
   217  
   218  func (m *SubstitutePath) UnmarshalJSON(data []byte) error {
   219  	// use custom unmarshal to check if both from/to are set.
   220  	type tmpType struct {
   221  		From *string
   222  		To   *string
   223  	}
   224  	var tmp tmpType
   225  
   226  	if err := json.Unmarshal(data, &tmp); err != nil {
   227  		if _, ok := err.(*json.UnmarshalTypeError); ok {
   228  			return fmt.Errorf(`cannot use %s as 'substitutePath' of type {"from":string, "to":string}`, data)
   229  		}
   230  		return err
   231  	}
   232  	if tmp.From == nil || tmp.To == nil {
   233  		return errors.New("'substitutePath' requires both 'from' and 'to' entries")
   234  	}
   235  	*m = SubstitutePath{*tmp.From, *tmp.To}
   236  	return nil
   237  }
   238  
   239  // AttachConfig is the collection of attach request attributes recognized by DAP implementation.
   240  // 'processId' and 'waitFor' are mutually exclusive, and can't be specified at the same time.
   241  type AttachConfig struct {
   242  	// Acceptable values are:
   243  	//   "local": attaches to the local process with the given ProcessID.
   244  	//   "remote": expects the debugger to already be running to "attach" to an in-progress debug session.
   245  	//
   246  	// Default is "local".
   247  	Mode string `json:"mode"`
   248  
   249  	// The numeric ID of the process to be debugged.
   250  	ProcessID int `json:"processId,omitempty"`
   251  
   252  	// Wait for a process with a name beginning with this prefix.
   253  	AttachWaitFor string `json:"waitFor,omitempty"`
   254  
   255  	LaunchAttachCommonConfig
   256  }
   257  
   258  // unmarshalLaunchAttachArgs wraps unmarshaling of launch/attach request's
   259  // arguments attribute. Upon unmarshal failure, it returns an error massaged
   260  // to be suitable for end-users.
   261  func unmarshalLaunchAttachArgs(input json.RawMessage, config interface{}) error {
   262  	if err := json.Unmarshal(input, config); err != nil {
   263  		if uerr, ok := err.(*json.UnmarshalTypeError); ok {
   264  			// Format json.UnmarshalTypeError error string in our own way. E.g.,
   265  			//   "json: cannot unmarshal number into Go struct field LaunchArgs.substitutePath of type dap.SubstitutePath"
   266  			//   => "cannot unmarshal number into 'substitutePath' of type {from:string, to:string}"
   267  			//   "json: cannot unmarshal number into Go struct field LaunchArgs.program of type string" (go1.16)
   268  			//   => "cannot unmarshal number into 'program' of type string"
   269  			typ := uerr.Type.String()
   270  			if uerr.Field == "substitutePath" {
   271  				typ = `{"from":string, "to":string}`
   272  			}
   273  			return fmt.Errorf("cannot unmarshal %v into %q of type %v", uerr.Value, uerr.Field, typ)
   274  		}
   275  		return err
   276  	}
   277  	return nil
   278  }
   279  
   280  func prettyPrint(config interface{}) string {
   281  	pretty, err := json.MarshalIndent(config, "", "\t")
   282  	if err != nil {
   283  		return fmt.Sprintf("%#v", config)
   284  	}
   285  	return string(pretty)
   286  }
   287  
   288  // BuildFlags is either string or []string.
   289  type BuildFlags struct {
   290  	value interface{}
   291  }
   292  
   293  func (s *BuildFlags) UnmarshalJSON(b []byte) error {
   294  	if v := string(b); v == "" || v == "null" {
   295  		s.value = nil
   296  		return nil
   297  	}
   298  	var strs []string
   299  	if err := json.Unmarshal(b, &strs); err == nil {
   300  		s.value = strs
   301  		return nil
   302  	}
   303  	var str string
   304  	if err := json.Unmarshal(b, &str); err != nil {
   305  		s.value = nil
   306  		if uerr, ok := err.(*json.UnmarshalTypeError); ok {
   307  			return fmt.Errorf(`cannot unmarshal %v into "buildFlags" of type []string or string`, uerr.Value)
   308  		}
   309  		return err
   310  	}
   311  	s.value = str
   312  	return nil
   313  }