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  }