mirror of
				https://github.com/tailscale/tailscale.git
				synced 2025-10-31 08:11:32 +01:00 
			
		
		
		
	Updates #14520 Updates #14517 (in that I pulled this out of there) Change-Id: Ibc28162816e083fcadf550586c06805c76e378fc Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
		
			
				
	
	
		
			94 lines
		
	
	
		
			1.9 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			94 lines
		
	
	
		
			1.9 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
| // Copyright (c) Tailscale Inc & AUTHORS
 | |
| // SPDX-License-Identifier: BSD-3-Clause
 | |
| 
 | |
| // The goroutines package contains utilities for tracking and getting active goroutines.
 | |
| package goroutines
 | |
| 
 | |
| import (
 | |
| 	"bytes"
 | |
| 	"fmt"
 | |
| 	"runtime"
 | |
| 	"strconv"
 | |
| )
 | |
| 
 | |
| // ScrubbedGoroutineDump returns either the current goroutine's stack or all
 | |
| // goroutines' stacks, but with the actual values of arguments scrubbed out,
 | |
| // lest it contain some private key material.
 | |
| func ScrubbedGoroutineDump(all bool) []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, all)]
 | |
| 		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'
 | |
| }
 |