github.com/Rookout/GoSDK@v0.1.48/pkg/services/instrumentation/dwarf/frame/parser.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 frame contains data structures and 23 // related functions for parsing and searching 24 // through Dwarf .debug_frame data. 25 package frame 26 27 import ( 28 "bytes" 29 "encoding/binary" 30 "fmt" 31 "io" 32 33 "github.com/Rookout/GoSDK/pkg/services/instrumentation/dwarf/util" 34 ) 35 36 type parsefunc func(*parseContext) parsefunc 37 38 type parseContext struct { 39 staticBase uint64 40 41 buf *bytes.Buffer 42 totalLen int 43 entries FrameDescriptionEntries 44 ciemap map[int]*CommonInformationEntry 45 common *CommonInformationEntry 46 frame *FrameDescriptionEntry 47 length uint32 48 ptrSize int 49 ehFrameAddr uint64 50 err error 51 } 52 53 54 55 56 57 58 func Parse(data []byte, order binary.ByteOrder, staticBase uint64, ptrSize int, ehFrameAddr uint64) (FrameDescriptionEntries, error) { 59 var ( 60 buf = bytes.NewBuffer(data) 61 pctx = &parseContext{buf: buf, totalLen: len(data), entries: newFrameIndex(), staticBase: staticBase, ptrSize: ptrSize, ehFrameAddr: ehFrameAddr, ciemap: map[int]*CommonInformationEntry{}} 62 ) 63 64 for fn := parselength; buf.Len() != 0; { 65 fn = fn(pctx) 66 if pctx.err != nil { 67 return nil, pctx.err 68 } 69 } 70 71 for i := range pctx.entries { 72 pctx.entries[i].order = order 73 } 74 75 return pctx.entries, nil 76 } 77 78 func (ctx *parseContext) parsingEHFrame() bool { 79 return ctx.ehFrameAddr > 0 80 } 81 82 func (ctx *parseContext) cieEntry(cieid uint32) bool { 83 if ctx.parsingEHFrame() { 84 return cieid == 0x00 85 } 86 return cieid == 0xffffffff 87 } 88 89 func (ctx *parseContext) offset() int { 90 return ctx.totalLen - ctx.buf.Len() 91 } 92 93 func parselength(ctx *parseContext) parsefunc { 94 start := ctx.offset() 95 binary.Read(ctx.buf, binary.LittleEndian, &ctx.length) 96 97 if ctx.length == 0 { 98 99 return parselength 100 } 101 102 var cieid uint32 103 binary.Read(ctx.buf, binary.LittleEndian, &cieid) 104 105 ctx.length -= 4 106 107 if ctx.cieEntry(cieid) { 108 ctx.common = &CommonInformationEntry{Length: ctx.length, staticBase: ctx.staticBase, CIE_id: cieid} 109 ctx.ciemap[start] = ctx.common 110 return parseCIE 111 } 112 113 if ctx.ehFrameAddr > 0 { 114 cieid = uint32(start - int(cieid) + 4) 115 } 116 117 common := ctx.ciemap[int(cieid)] 118 119 if common == nil { 120 ctx.err = fmt.Errorf("unknown CIE_id %#x at %#x", cieid, start) 121 } 122 123 ctx.frame = &FrameDescriptionEntry{Length: ctx.length, CIE: common} 124 return parseFDE 125 } 126 127 func parseFDE(ctx *parseContext) parsefunc { 128 startOff := ctx.offset() 129 r := ctx.buf.Next(int(ctx.length)) 130 131 reader := bytes.NewReader(r) 132 num := ctx.readEncodedPtr(addrSum(ctx.ehFrameAddr+uint64(startOff), reader), reader, ctx.frame.CIE.ptrEncAddr) 133 ctx.frame.begin = num + ctx.staticBase 134 135 136 137 138 139 sizePtrEnc := ctx.frame.CIE.ptrEncAddr & 0x0f 140 ctx.frame.size = ctx.readEncodedPtr(0, reader, sizePtrEnc) 141 142 143 144 ctx.entries = append(ctx.entries, ctx.frame) 145 146 if ctx.parsingEHFrame() && len(ctx.frame.CIE.Augmentation) > 0 { 147 148 149 150 n, _ := util.DecodeULEB128(reader) 151 reader.Seek(int64(n), io.SeekCurrent) 152 } 153 154 155 156 157 158 off, _ := reader.Seek(0, io.SeekCurrent) 159 ctx.frame.Instructions = r[off:] 160 ctx.length = 0 161 162 return parselength 163 } 164 165 func addrSum(base uint64, buf *bytes.Reader) uint64 { 166 n, _ := buf.Seek(0, io.SeekCurrent) 167 return base + uint64(n) 168 } 169 170 func parseCIE(ctx *parseContext) parsefunc { 171 data := ctx.buf.Next(int(ctx.length)) 172 buf := bytes.NewBuffer(data) 173 174 ctx.common.Version, _ = buf.ReadByte() 175 176 177 ctx.common.Augmentation, _ = util.ParseString(buf) 178 179 if ctx.parsingEHFrame() { 180 if ctx.common.Augmentation == "eh" { 181 ctx.err = fmt.Errorf("unsupported 'eh' augmentation at %#x", ctx.offset()) 182 } 183 if len(ctx.common.Augmentation) > 0 && ctx.common.Augmentation[0] != 'z' { 184 ctx.err = fmt.Errorf("unsupported augmentation at %#x (does not start with 'z')", ctx.offset()) 185 } 186 } 187 188 189 ctx.common.CodeAlignmentFactor, _ = util.DecodeULEB128(buf) 190 191 192 ctx.common.DataAlignmentFactor, _ = util.DecodeSLEB128(buf) 193 194 195 if ctx.parsingEHFrame() && ctx.common.Version == 1 { 196 b, _ := buf.ReadByte() 197 ctx.common.ReturnAddressRegister = uint64(b) 198 } else { 199 ctx.common.ReturnAddressRegister, _ = util.DecodeULEB128(buf) 200 } 201 202 ctx.common.ptrEncAddr = ptrEncAbs 203 204 if ctx.parsingEHFrame() && len(ctx.common.Augmentation) > 0 { 205 _, _ = util.DecodeULEB128(buf) 206 for i := 1; i < len(ctx.common.Augmentation); i++ { 207 switch ctx.common.Augmentation[i] { 208 case 'L': 209 _, _ = buf.ReadByte() 210 case 'R': 211 212 b, _ := buf.ReadByte() 213 ctx.common.ptrEncAddr = ptrEnc(b) 214 if !ctx.common.ptrEncAddr.Supported() { 215 ctx.err = fmt.Errorf("pointer encoding not supported %#x at %#x", ctx.common.ptrEncAddr, ctx.offset()) 216 return nil 217 } 218 case 'S': 219 220 case 'P': 221 222 223 224 225 e, _ := buf.ReadByte() 226 if !ptrEnc(e).Supported() { 227 ctx.err = fmt.Errorf("pointer encoding not supported %#x at %#x", e, ctx.offset()) 228 return nil 229 } 230 ctx.readEncodedPtr(0, buf, ptrEnc(e)) 231 default: 232 ctx.err = fmt.Errorf("unsupported augmentation character %c at %#x", ctx.common.Augmentation[i], ctx.offset()) 233 return nil 234 } 235 } 236 } 237 238 239 240 241 242 ctx.common.InitialInstructions = buf.Bytes() 243 ctx.length = 0 244 245 return parselength 246 } 247 248 249 250 251 252 253 254 func (ctx *parseContext) readEncodedPtr(addr uint64, buf util.ByteReaderWithLen, ptrEnc ptrEnc) uint64 { 255 if ptrEnc == ptrEncOmit { 256 return 0 257 } 258 259 var ptr uint64 260 261 switch ptrEnc & 0xf { 262 case ptrEncAbs, ptrEncSigned: 263 ptr, _ = util.ReadUintRaw(buf, binary.LittleEndian, ctx.ptrSize) 264 case ptrEncUleb: 265 ptr, _ = util.DecodeULEB128(buf) 266 case ptrEncUdata2: 267 ptr, _ = util.ReadUintRaw(buf, binary.LittleEndian, 2) 268 case ptrEncSdata2: 269 ptr, _ = util.ReadUintRaw(buf, binary.LittleEndian, 2) 270 ptr = uint64(int16(ptr)) 271 case ptrEncUdata4: 272 ptr, _ = util.ReadUintRaw(buf, binary.LittleEndian, 4) 273 case ptrEncSdata4: 274 ptr, _ = util.ReadUintRaw(buf, binary.LittleEndian, 4) 275 ptr = uint64(int32(ptr)) 276 case ptrEncUdata8, ptrEncSdata8: 277 ptr, _ = util.ReadUintRaw(buf, binary.LittleEndian, 8) 278 case ptrEncSleb: 279 n, _ := util.DecodeSLEB128(buf) 280 ptr = uint64(n) 281 } 282 283 if ptrEnc&0xf0 == ptrEncPCRel { 284 ptr += addr 285 } 286 287 return ptr 288 } 289 290 291 292 func DwarfEndian(infoSec []byte) binary.ByteOrder { 293 if len(infoSec) < 6 { 294 return binary.BigEndian 295 } 296 x, y := infoSec[4], infoSec[5] 297 switch { 298 case x == 0 && y == 0: 299 return binary.BigEndian 300 case x == 0: 301 return binary.BigEndian 302 case y == 0: 303 return binary.LittleEndian 304 default: 305 return binary.BigEndian 306 } 307 }