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  }