github.com/MerlinKodo/gvisor@v0.0.0-20231110090155-957f62ecf90e/runsc/cmd/symbolize.go (about)

     1  // Copyright 2020 The gVisor Authors.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package cmd
    16  
    17  import (
    18  	"bufio"
    19  	"context"
    20  	"os"
    21  	"strconv"
    22  	"strings"
    23  
    24  	"github.com/MerlinKodo/gvisor/pkg/coverage"
    25  	"github.com/MerlinKodo/gvisor/runsc/cmd/util"
    26  	"github.com/MerlinKodo/gvisor/runsc/flag"
    27  	"github.com/google/subcommands"
    28  )
    29  
    30  // Symbolize implements subcommands.Command for the "symbolize" command.
    31  type Symbolize struct {
    32  	dumpAll bool
    33  }
    34  
    35  // Name implements subcommands.Command.Name.
    36  func (*Symbolize) Name() string {
    37  	return "symbolize"
    38  }
    39  
    40  // Synopsis implements subcommands.Command.Synopsis.
    41  func (*Symbolize) Synopsis() string {
    42  	return "Convert synthetic instruction pointers from kcov into positions in the runsc source code. Only used when Go coverage is enabled."
    43  }
    44  
    45  // Usage implements subcommands.Command.Usage.
    46  func (*Symbolize) Usage() string {
    47  	return `symbolize - converts synthetic instruction pointers into positions in the runsc source code.
    48  
    49  This command takes instruction pointers from stdin and converts them into their
    50  corresponding file names and line/column numbers in the runsc source code. The
    51  inputs are not interpreted as actual addresses, but as synthetic values that are
    52  exposed through /sys/kernel/debug/kcov. One can extract coverage information
    53  from kcov and translate those values into locations in the source code by
    54  running symbolize on the same runsc binary.
    55  `
    56  }
    57  
    58  // SetFlags implements subcommands.Command.SetFlags.
    59  func (c *Symbolize) SetFlags(f *flag.FlagSet) {
    60  	f.BoolVar(&c.dumpAll, "all", false, "dump information on all coverage blocks along with their synthetic PCs")
    61  }
    62  
    63  // Execute implements subcommands.Command.Execute.
    64  func (c *Symbolize) Execute(_ context.Context, f *flag.FlagSet, args ...any) subcommands.ExitStatus {
    65  	if f.NArg() != 0 {
    66  		f.Usage()
    67  		return subcommands.ExitUsageError
    68  	}
    69  	if !coverage.Available() {
    70  		return util.Errorf("symbolize can only be used when coverage is available.")
    71  	}
    72  	coverage.InitCoverageData()
    73  
    74  	if c.dumpAll {
    75  		if err := coverage.WriteAllBlocks(os.Stdout); err != nil {
    76  			return util.Errorf("Failed to write out blocks: %v", err)
    77  		}
    78  		return subcommands.ExitSuccess
    79  	}
    80  
    81  	scanner := bufio.NewScanner(os.Stdin)
    82  	for scanner.Scan() {
    83  		// Input is always base 16, but may or may not have a leading "0x".
    84  		str := strings.TrimPrefix(scanner.Text(), "0x")
    85  		pc, err := strconv.ParseUint(str, 16 /* base */, 64 /* bitSize */)
    86  		if err != nil {
    87  			return util.Errorf("Failed to symbolize \"%s\": %v", scanner.Text(), err)
    88  		}
    89  		if err := coverage.Symbolize(os.Stdout, pc); err != nil {
    90  			return util.Errorf("Failed to symbolize \"%s\": %v", scanner.Text(), err)
    91  		}
    92  	}
    93  	return subcommands.ExitSuccess
    94  }