github.com/neilgarb/delve@v1.9.2-nobreaks/service/api/command.go (about) 1 package api 2 3 import ( 4 "fmt" 5 "strconv" 6 "strings" 7 ) 8 9 type PrintGoroutinesFlags uint8 10 11 const ( 12 PrintGoroutinesStack PrintGoroutinesFlags = 1 << iota 13 PrintGoroutinesLabels 14 ) 15 16 type FormatGoroutineLoc int 17 18 const ( 19 FglRuntimeCurrent = FormatGoroutineLoc(iota) 20 FglUserCurrent 21 FglGo 22 FglStart 23 ) 24 25 const ( 26 maxGroupMembers = 5 27 maxGoroutineGroups = 50 28 ) 29 30 // The number of goroutines we're going to request on each RPC call 31 const goroutineBatchSize = 10000 32 33 func ParseGoroutineArgs(argstr string) ([]ListGoroutinesFilter, GoroutineGroupingOptions, FormatGoroutineLoc, PrintGoroutinesFlags, int, int, error) { 34 args := strings.Split(argstr, " ") 35 var filters []ListGoroutinesFilter 36 var group GoroutineGroupingOptions 37 var fgl = FglUserCurrent 38 var flags PrintGoroutinesFlags 39 var depth = 10 40 var batchSize = goroutineBatchSize 41 42 group.MaxGroupMembers = maxGroupMembers 43 group.MaxGroups = maxGoroutineGroups 44 45 for i := 0; i < len(args); i++ { 46 arg := args[i] 47 switch arg { 48 case "-u": 49 fgl = FglUserCurrent 50 case "-r": 51 fgl = FglRuntimeCurrent 52 case "-g": 53 fgl = FglGo 54 case "-s": 55 fgl = FglStart 56 case "-l": 57 flags |= PrintGoroutinesLabels 58 case "-t": 59 flags |= PrintGoroutinesStack 60 // optional depth argument 61 if i+1 < len(args) && len(args[i+1]) > 0 { 62 n, err := strconv.Atoi(args[i+1]) 63 if err == nil { 64 depth = n 65 i++ 66 } 67 } 68 69 case "-w", "-with": 70 filter, err := readGoroutinesFilter(args, &i) 71 if err != nil { 72 return nil, GoroutineGroupingOptions{}, 0, 0, 0, 0, fmt.Errorf("wrong argument: '%s'", arg) 73 } 74 filters = append(filters, *filter) 75 76 case "-wo", "-without": 77 filter, err := readGoroutinesFilter(args, &i) 78 if err != nil { 79 return nil, GoroutineGroupingOptions{}, 0, 0, 0, 0, fmt.Errorf("wrong argument: '%s'", arg) 80 } 81 filter.Negated = true 82 filters = append(filters, *filter) 83 84 case "-group": 85 var err error 86 group.GroupBy, err = readGoroutinesFilterKind(args, i+1) 87 if err != nil { 88 return nil, GoroutineGroupingOptions{}, 0, 0, 0, 0, fmt.Errorf("wrong argument: '%s'", arg) 89 } 90 i++ 91 if group.GroupBy == GoroutineLabel { 92 if i+1 >= len(args) { 93 return nil, GoroutineGroupingOptions{}, 0, 0, 0, 0, fmt.Errorf("wrong argument: '%s'", arg) 94 } 95 group.GroupByKey = args[i+1] 96 i++ 97 } 98 batchSize = 0 // grouping only works well if run on all goroutines 99 100 case "": 101 // nothing to do 102 default: 103 return nil, GoroutineGroupingOptions{}, 0, 0, 0, 0, fmt.Errorf("wrong argument: '%s'", arg) 104 } 105 } 106 return filters, group, fgl, flags, depth, batchSize, nil 107 } 108 109 func readGoroutinesFilterKind(args []string, i int) (GoroutineField, error) { 110 if i >= len(args) { 111 return GoroutineFieldNone, fmt.Errorf("%s must be followed by an argument", args[i-1]) 112 } 113 114 switch args[i] { 115 case "curloc": 116 return GoroutineCurrentLoc, nil 117 case "userloc": 118 return GoroutineUserLoc, nil 119 case "goloc": 120 return GoroutineGoLoc, nil 121 case "startloc": 122 return GoroutineStartLoc, nil 123 case "label": 124 return GoroutineLabel, nil 125 case "running": 126 return GoroutineRunning, nil 127 case "user": 128 return GoroutineUser, nil 129 default: 130 return GoroutineFieldNone, fmt.Errorf("unrecognized argument to %s %s", args[i-1], args[i]) 131 } 132 } 133 134 func readGoroutinesFilter(args []string, pi *int) (*ListGoroutinesFilter, error) { 135 r := new(ListGoroutinesFilter) 136 var err error 137 r.Kind, err = readGoroutinesFilterKind(args, *pi+1) 138 if err != nil { 139 return nil, err 140 } 141 *pi++ 142 switch r.Kind { 143 case GoroutineRunning, GoroutineUser: 144 return r, nil 145 } 146 if *pi+1 >= len(args) { 147 return nil, fmt.Errorf("%s %s needs to be followed by an expression", args[*pi-1], args[*pi]) 148 } 149 r.Arg = args[*pi+1] 150 *pi++ 151 152 return r, nil 153 }