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 }