github.com/Rookout/GoSDK@v0.1.48/pkg/services/instrumentation/dwarf/op/op.go (about)

     1  // The MIT License (MIT)
     2  
     3  // Copyright (c) 2014 Derek Parker
     4  
     5  // Permission is hereby granted, free of charge, to any person obtaining a copy of
     6  // this software and associated documentation files (the "Software"), to deal in
     7  // the Software without restriction, including without limitation the rights to
     8  // use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
     9  // the Software, and to permit persons to whom the Software is furnished to do so,
    10  // subject to the following conditions:
    11  
    12  // The above copyright notice and this permission notice shall be included in all
    13  // copies or substantial portions of the Software.
    14  
    15  // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
    16  // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
    17  // FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
    18  // COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
    19  // IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
    20  // CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
    21  
    22  package op
    23  
    24  import (
    25  	"bytes"
    26  	"errors"
    27  	"fmt"
    28  )
    29  
    30  
    31  
    32  type Opcode byte
    33  
    34  
    35  type Piece struct {
    36  	Size  int
    37  	Kind  PieceKind
    38  	Val   uint64
    39  	Bytes []byte
    40  }
    41  
    42  
    43  type PieceKind uint8
    44  
    45  const (
    46  	AddrPiece PieceKind = iota 
    47  	RegPiece                   
    48  	ImmPiece                   
    49  )
    50  
    51  
    52  
    53  
    54  func ExecuteStackProgram(regs Registers, instructions []byte, ptrSize int) (int64, []Piece, error) {
    55  	dwarfLocator, err := NewDwarfLocator(instructions, ptrSize)
    56  	if err != nil {
    57  		return 0, nil, err
    58  	}
    59  
    60  	return dwarfLocator.Locate(regs)
    61  }
    62  
    63  type DwarfLocator struct {
    64  	executors []OpcodeExecutor
    65  	ptrSize   int
    66  }
    67  
    68  func NewDwarfLocator(instructions []byte, ptrSize int) (*DwarfLocator, error) {
    69  	var executors []OpcodeExecutor
    70  	ctx := &OpcodeExecutorCreatorContext{
    71  		prog:        make([]byte, len(instructions)),
    72  		pointerSize: ptrSize,
    73  	}
    74  	copy(ctx.prog, instructions)
    75  	buf := bytes.NewBuffer(instructions)
    76  	ctx.buf = buf
    77  
    78  	for {
    79  		opcodeByte, err := buf.ReadByte()
    80  		if err != nil {
    81  			break
    82  		}
    83  		opcode := Opcode(opcodeByte)
    84  		if opcode == DW_OP_nop {
    85  			continue
    86  		}
    87  		executorCreator, ok := OpcodeToExecutorCreator(opcode)
    88  		if !ok {
    89  			return nil, fmt.Errorf("invalid instruction %#v", opcode)
    90  		}
    91  
    92  		executor, err := executorCreator(opcode, ctx)
    93  		if err != nil {
    94  			return nil, err
    95  		}
    96  		executors = append(executors, executor)
    97  	}
    98  
    99  	return &DwarfLocator{executors: executors, ptrSize: ptrSize}, nil
   100  }
   101  
   102  func (d *DwarfLocator) newDwarfLocatorContext(regs Registers) *OpcodeExecutorContext {
   103  	return &OpcodeExecutorContext{
   104  		Stack:     make([]int64, 0, 3),
   105  		PtrSize:   d.ptrSize,
   106  		Registers: regs,
   107  	}
   108  }
   109  
   110  func (d *DwarfLocator) Locate(regs Registers) (int64, []Piece, error) {
   111  	ctx := d.newDwarfLocatorContext(regs)
   112  
   113  	for _, executor := range d.executors {
   114  		if err := executor.Execute(ctx); err != nil {
   115  			return 0, nil, err
   116  		}
   117  	}
   118  
   119  	if ctx.Pieces != nil {
   120  		if len(ctx.Pieces) == 1 && ctx.Pieces[0].Kind == RegPiece {
   121  			return int64(regs.Uint64Val(ctx.Pieces[0].Val)), ctx.Pieces, nil
   122  		}
   123  		return 0, ctx.Pieces, nil
   124  	}
   125  
   126  	if len(ctx.Stack) == 0 {
   127  		return 0, nil, errors.New("empty OP stack")
   128  	}
   129  
   130  	return ctx.Stack[len(ctx.Stack)-1], nil, nil
   131  }