delve/service/dap/command.go
Stefan Haller f8c8b33da3
Show pprof labels in thread names (#3501)
* Add pprofLabelForThreadNames config

The config is a string value that indicates the key of a pprof label whose value
should be shown as a goroutine name in the threads view.
2023-12-04 15:44:10 +01:00

170 lines
4.2 KiB
Go

package dap
import (
"bytes"
"errors"
"fmt"
"sort"
"strings"
"github.com/go-delve/delve/pkg/config"
"github.com/google/go-dap"
)
func (s *Session) delveCmd(goid, frame int, cmdstr string) (string, error) {
vals := strings.SplitN(strings.TrimSpace(cmdstr), " ", 2)
cmdname := vals[0]
var args string
if len(vals) > 1 {
args = strings.TrimSpace(vals[1])
}
for _, cmd := range debugCommands(s) {
for _, alias := range cmd.aliases {
if alias == cmdname {
return cmd.cmdFn(goid, frame, args)
}
}
}
return "", errNoCmd
}
type cmdfunc func(goid, frame int, args string) (string, error)
type command struct {
aliases []string
helpMsg string
cmdFn cmdfunc
}
const (
msgHelp = `Prints the help message.
dlv help [command]
Type "help" followed by the name of a command for more information about it.`
msgConfig = `Changes configuration parameters.
dlv config -list
Show all configuration parameters.
dlv config -list <parameter>
Show value of a configuration parameter.
dlv config <parameter> <value>
Changes the value of a configuration parameter.
dlv config substitutePath <from> <to>
dlv config substitutePath <from>
dlv config substitutePath -clear
Adds or removes a path substitution rule. If -clear is used all substitutePath rules are removed.
See also Documentation/cli/substitutepath.md.
dlv config showPprofLabels <label>
dlv config showPprofLabels -clear <label>
dlv config showPprofLabels -clear
Adds or removes a label key to show in the callstack view. If -clear is used without an argument,
all labels are removed.`
msgSources = `Print list of source files.
dlv sources [<regex>]
If regex is specified only the source files matching it will be returned.`
)
// debugCommands returns a list of commands with default commands defined.
func debugCommands(s *Session) []command {
return []command{
{aliases: []string{"help", "h"}, cmdFn: s.helpMessage, helpMsg: msgHelp},
{aliases: []string{"config"}, cmdFn: s.evaluateConfig, helpMsg: msgConfig},
{aliases: []string{"sources", "s"}, cmdFn: s.sources, helpMsg: msgSources},
}
}
var errNoCmd = errors.New("command not available")
func (s *Session) helpMessage(_, _ int, args string) (string, error) {
var buf bytes.Buffer
if args != "" {
for _, cmd := range debugCommands(s) {
for _, alias := range cmd.aliases {
if alias == args {
return cmd.helpMsg, nil
}
}
}
return "", errNoCmd
}
fmt.Fprintln(&buf, "The following commands are available:")
for _, cmd := range debugCommands(s) {
h := cmd.helpMsg
if idx := strings.Index(h, "\n"); idx >= 0 {
h = h[:idx]
}
if len(cmd.aliases) > 1 {
fmt.Fprintf(&buf, " dlv %s (alias: %s) \t %s\n", cmd.aliases[0], strings.Join(cmd.aliases[1:], " | "), h)
} else {
fmt.Fprintf(&buf, " dlv %s \t %s\n", cmd.aliases[0], h)
}
}
fmt.Fprintln(&buf)
fmt.Fprintln(&buf, "Type 'dlv help' followed by a command for full documentation.")
return buf.String(), nil
}
func (s *Session) evaluateConfig(_, _ int, expr string) (string, error) {
argv := config.Split2PartsBySpace(expr)
name := argv[0]
if name == "-list" {
if len(argv) > 1 {
return config.ConfigureListByName(&s.args, argv[1], "cfgName"), nil
}
return listConfig(&s.args), nil
}
updated, res, err := configureSet(&s.args, expr)
if err != nil {
return "", err
}
if updated {
// Send invalidated events for areas that are affected by configuration changes.
switch name {
case "showGlobalVariables", "showRegisters":
// Variable data has become invalidated.
s.send(&dap.InvalidatedEvent{
Event: *newEvent("invalidated"),
Body: dap.InvalidatedEventBody{
Areas: []dap.InvalidatedAreas{"variables"},
},
})
case "goroutineFilters", "hideSystemGoroutines", "showPprofLabels":
// Thread related data has become invalidated.
s.send(&dap.InvalidatedEvent{
Event: *newEvent("invalidated"),
Body: dap.InvalidatedEventBody{
Areas: []dap.InvalidatedAreas{"threads"},
},
})
}
res += "\nUpdated"
}
return res, nil
}
func (s *Session) sources(_, _ int, filter string) (string, error) {
sources, err := s.debugger.Sources(filter)
if err != nil {
return "", err
}
sort.Strings(sources)
return strings.Join(sources, "\n"), nil
}