diff options
Diffstat (limited to 'control/controlclient/debug.go')
| -rw-r--r-- | control/controlclient/debug.go | 87 |
1 files changed, 3 insertions, 84 deletions
diff --git a/control/controlclient/debug.go b/control/controlclient/debug.go index b14643f7a..bc58b4fd5 100644 --- a/control/controlclient/debug.go +++ b/control/controlclient/debug.go @@ -8,12 +8,11 @@ import ( "bytes" "compress/gzip" "context" - "fmt" "log" "net/http" - "runtime" - "strconv" "time" + + "tailscale.com/util/goroutines" ) func dumpGoroutinesToURL(c *http.Client, targetURL string) { @@ -22,7 +21,7 @@ func dumpGoroutinesToURL(c *http.Client, targetURL string) { zbuf := new(bytes.Buffer) zw := gzip.NewWriter(zbuf) - zw.Write(scrubbedGoroutineDump()) + zw.Write(goroutines.ScrubbedGoroutineDump()) zw.Close() req, err := http.NewRequestWithContext(ctx, "PUT", targetURL, zbuf) @@ -40,83 +39,3 @@ func dumpGoroutinesToURL(c *http.Client, targetURL string) { log.Printf("dumpGoroutinesToURL complete to %v (after %v)", targetURL, d) } } - -// scrubbedGoroutineDump returns the list of all current goroutines, but with the actual -// values of arguments scrubbed out, lest it contain some private key material. -func scrubbedGoroutineDump() []byte { - var buf []byte - // Grab stacks multiple times into increasingly larger buffer sizes - // to minimize the risk that we blow past our iOS memory limit. - for size := 1 << 10; size <= 1<<20; size += 1 << 10 { - buf = make([]byte, size) - buf = buf[:runtime.Stack(buf, true)] - if len(buf) < size { - // It fit. - break - } - } - return scrubHex(buf) -} - -func scrubHex(buf []byte) []byte { - saw := map[string][]byte{} // "0x123" => "v1%3" (unique value 1 and its value mod 8) - - foreachHexAddress(buf, func(in []byte) { - if string(in) == "0x0" { - return - } - if v, ok := saw[string(in)]; ok { - for i := range in { - in[i] = '_' - } - copy(in, v) - return - } - inStr := string(in) - u64, err := strconv.ParseUint(string(in[2:]), 16, 64) - for i := range in { - in[i] = '_' - } - if err != nil { - in[0] = '?' - return - } - v := []byte(fmt.Sprintf("v%d%%%d", len(saw)+1, u64%8)) - saw[inStr] = v - copy(in, v) - }) - return buf -} - -var ohx = []byte("0x") - -// foreachHexAddress calls f with each subslice of b that matches -// regexp `0x[0-9a-f]*`. -func foreachHexAddress(b []byte, f func([]byte)) { - for len(b) > 0 { - i := bytes.Index(b, ohx) - if i == -1 { - return - } - b = b[i:] - hx := hexPrefix(b) - f(hx) - b = b[len(hx):] - } -} - -func hexPrefix(b []byte) []byte { - for i, c := range b { - if i < 2 { - continue - } - if !isHexByte(c) { - return b[:i] - } - } - return b -} - -func isHexByte(b byte) bool { - return '0' <= b && b <= '9' || 'a' <= b && b <= 'f' || 'A' <= b && b <= 'F' -} |
