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 }