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

     1  //go:build go1.15 && !go1.22
     2  // +build go1.15,!go1.22
     3  
     4  package module
     5  
     6  import (
     7  	_ "unsafe"
     8  
     9  	"github.com/Rookout/GoSDK/pkg/rookoutErrors"
    10  
    11  	"github.com/go-errors/errors"
    12  )
    13  
    14  type PCDataEntry struct {
    15  	Offset uintptr
    16  	Value  int32
    17  }
    18  
    19  
    20  func decodePCDataEntries(p []byte) (pcDataEntries []PCDataEntry) {
    21  	if p == nil {
    22  		return pcDataEntries
    23  	}
    24  	var pc uintptr
    25  	val := int32(-1)
    26  	p, ok := step(p, &pc, &val, true)
    27  	for {
    28  		if !ok {
    29  			return pcDataEntries
    30  		}
    31  		pcDataEntries = append(pcDataEntries, PCDataEntry{Offset: pc, Value: val})
    32  		if len(p) <= 0 {
    33  			return pcDataEntries
    34  		}
    35  		p, ok = step(p, &pc, &val, false)
    36  	}
    37  }
    38  
    39  
    40  
    41  func findNewAddressByOriginalAddress(originalAddress uintptr, addressMappings []AddressMapping) (uintptr, bool) {
    42  	for _, mapping := range addressMappings {
    43  		if originalAddress == mapping.OriginalAddress {
    44  			return mapping.NewAddress, true
    45  		}
    46  	}
    47  	return 0, false
    48  }
    49  
    50  
    51  
    52  func updatePCDataEntries(pcDataEntries []PCDataEntry, offsetMappings []AddressMapping) {
    53  	for i := 0; i < len(pcDataEntries); i++ {
    54  		newOffset, found := findNewAddressByOriginalAddress(pcDataEntries[i].Offset, offsetMappings)
    55  		if found {
    56  			pcDataEntries[i].Offset = newOffset
    57  		}
    58  	}
    59  }
    60  
    61  
    62  
    63  func getEntryForOffset(offset uintptr, pcDataEntries []PCDataEntry) (int, *PCDataEntry) {
    64  	prevPCOffset := uintptr(0)
    65  	for index, pcDataEntry := range pcDataEntries {
    66  		if prevPCOffset <= offset && pcDataEntry.Offset > offset {
    67  			return index, &pcDataEntry
    68  		}
    69  		prevPCOffset = pcDataEntry.Offset
    70  	}
    71  
    72  	return -1, nil
    73  }
    74  
    75  
    76  func UvarintToBytes(x uint64) (buf []byte) {
    77  	for x >= 0x80 {
    78  		buf = append(buf, byte(x)|0x80)
    79  		x >>= 7
    80  	}
    81  	buf = append(buf, byte(x))
    82  	return buf
    83  }
    84  
    85  
    86  func writeUvarintToBytes(bytes []byte, x uint64) ([]byte, error) {
    87  	encodedVariant := UvarintToBytes(x)
    88  	bytes = append(bytes, encodedVariant...)
    89  	return bytes, nil
    90  }
    91  
    92  func encode(v int32) uint32 {
    93  	return uint32(v<<1) ^ uint32(v>>31)
    94  }
    95  
    96  
    97  func writePCDataEntry(p []byte, value int32, offset int32) ([]byte, error) {
    98  	p, err := writeUvarintToBytes(p, uint64(encode(value)))
    99  	if err != nil {
   100  		return nil, err
   101  	}
   102  	p, err = writeUvarintToBytes(p, uint64(offset/pcQuantum))
   103  	if err != nil {
   104  		return nil, err
   105  	}
   106  
   107  	return p, nil
   108  }
   109  
   110  func removeDuplicateValues(pcDataEntries []PCDataEntry) (noDups []PCDataEntry) {
   111  	if len(pcDataEntries) == 0 {
   112  		return nil
   113  	}
   114  	for i := range pcDataEntries {
   115  		if i == len(pcDataEntries)-1 {
   116  			noDups = append(noDups, pcDataEntries[i])
   117  			break
   118  		}
   119  
   120  		if pcDataEntries[i].Value == pcDataEntries[i+1].Value {
   121  			continue
   122  		}
   123  		noDups = append(noDups, pcDataEntries[i])
   124  	}
   125  
   126  	return noDups
   127  }
   128  
   129  
   130  func encodePCDataEntries(pcDataEntries []PCDataEntry) (encoded []byte, err error) {
   131  	if len(pcDataEntries) == 0 {
   132  		return nil, nil
   133  	}
   134  	encoded = make([]byte, 0, len(pcDataEntries)*20)
   135  	prevOffset := int32(0)
   136  	prevValue := int32(-1)
   137  
   138  	for _, newPair := range pcDataEntries {
   139  		valueDelta := newPair.Value - prevValue
   140  		offsetDelta := int32(newPair.Offset) - prevOffset
   141  		encoded, err = writePCDataEntry(encoded, valueDelta, offsetDelta)
   142  		if err != nil {
   143  			return nil, err
   144  		}
   145  		prevOffset = int32(newPair.Offset)
   146  		prevValue = newPair.Value
   147  	}
   148  	
   149  	encoded = append(encoded, 0)
   150  	return encoded, nil
   151  }
   152  
   153  
   154  
   155  
   156  
   157  
   158  
   159  
   160  
   161  func addCallbackEntry(pcDataEntries []PCDataEntry, callbackOffsetStart, callbackOffsetEnd uintptr, pcDataGenerator func(uintptr, uintptr, int32) ([]PCDataEntry, error)) ([]PCDataEntry, error) {
   162  	callbackEntryIndex, entryForCallback := getEntryForOffset(callbackOffsetStart, pcDataEntries)
   163  	if callbackEntryIndex == -1 {
   164  		return nil, errors.New("No PCData entry in table after breakpoint")
   165  	}
   166  
   167  	newPCDataEntries := pcDataEntries
   168  	callbackPCDataEntries, err := pcDataGenerator(callbackOffsetStart, callbackOffsetEnd, entryForCallback.Value)
   169  	if err != nil {
   170  		return nil, err
   171  	}
   172  	fromCallbackUntilEnd := append(callbackPCDataEntries, newPCDataEntries[callbackEntryIndex:]...)
   173  	newPCDataEntries = append(newPCDataEntries[:callbackEntryIndex], fromCallbackUntilEnd...)
   174  	return newPCDataEntries, nil
   175  }
   176  
   177  func addOffsetAndValueToEntries(offset uintptr, value int32, entries []PCDataEntry) []PCDataEntry {
   178  	var callbackPCDataEntries []PCDataEntry
   179  
   180  	for _, callbackPCInfo := range entries {
   181  		callbackPCDataEntries = append(callbackPCDataEntries, PCDataEntry{offset + callbackPCInfo.Offset, value + callbackPCInfo.Value})
   182  	}
   183  
   184  	return callbackPCDataEntries
   185  }
   186  
   187  
   188  func addCallbacksEntries(pcDataEntries []PCDataEntry, offsetMappings []AddressMapping, pcDataGenerator func(uintptr, uintptr, int32) ([]PCDataEntry, error)) ([]PCDataEntry, error) {
   189  	for mapIndex, mapping := range offsetMappings {
   190  		if _, ok := CallbacksMarkers[mapping.OriginalAddress]; ok {
   191  			callbackOffsetStart := mapping.NewAddress
   192  			callbackOffsetEnd := offsetMappings[mapIndex+1].NewAddress
   193  			newPCDataEntries, err := addCallbackEntry(pcDataEntries, callbackOffsetStart, callbackOffsetEnd, pcDataGenerator)
   194  			if err != nil {
   195  				return nil, err
   196  			}
   197  			pcDataEntries = newPCDataEntries
   198  		}
   199  	}
   200  
   201  	return pcDataEntries, nil
   202  }
   203  
   204  type PCDataPatcher struct {
   205  	newFuncEntry   uintptr
   206  	offsetMappings []AddressMapping
   207  	isPatched      bool
   208  	instSizeReader func(pc uintptr) (uintptr, rookoutErrors.RookoutError)
   209  }
   210  
   211  
   212  
   213  
   214  
   215  
   216  
   217  
   218  func verifyOffsetMappings(offsetMappings []AddressMapping) rookoutErrors.RookoutError {
   219  	numLastMappingsToCheck := 2
   220  	if len(offsetMappings) < numLastMappingsToCheck {
   221  		return rookoutErrors.NewIllegalAddressMappings()
   222  	}
   223  	lastMappings := offsetMappings[len(offsetMappings)-numLastMappingsToCheck:]
   224  	for _, m := range lastMappings {
   225  		if _, ok := CallbacksMarkers[m.OriginalAddress]; ok {
   226  			return rookoutErrors.NewIllegalAddressMappings()
   227  		}
   228  	}
   229  
   230  	return nil
   231  }
   232  
   233  func NewPCDataPatcher(newFuncEntry uintptr, offsetMappings []AddressMapping, isPatched bool, instSizeReader func(uintptr) (uintptr, rookoutErrors.RookoutError)) (*PCDataPatcher, error) {
   234  	if err := verifyOffsetMappings(offsetMappings); err != nil {
   235  		return nil, err
   236  	}
   237  	return &PCDataPatcher{
   238  		newFuncEntry:   newFuncEntry,
   239  		offsetMappings: offsetMappings,
   240  		isPatched:      isPatched,
   241  		instSizeReader: instSizeReader,
   242  	}, nil
   243  }
   244  
   245  func (p *PCDataPatcher) updateOffsets(table []PCDataEntry) error {
   246  	updatePCDataEntries(table, p.offsetMappings)
   247  
   248  	
   249  	
   250  	
   251  	
   252  	
   253  	
   254  	
   255  	
   256  	
   257  	
   258  	var newMappings []AddressMapping
   259  	for i := 0; i < len(p.offsetMappings); i++ {
   260  		currentMapping := p.offsetMappings[i]
   261  		if _, ok := CallbacksMarkers[currentMapping.OriginalAddress]; ok {
   262  			i++ 
   263  			
   264  			for ; i < len(p.offsetMappings); i++ {
   265  				if _, ok := CallbacksMarkers[p.offsetMappings[i].OriginalAddress]; !ok {
   266  					break
   267  				}
   268  			}
   269  			if i < len(p.offsetMappings) {
   270  				newMappings = append(newMappings, AddressMapping{OriginalAddress: p.offsetMappings[i].NewAddress, NewAddress: currentMapping.NewAddress})
   271  			} else {
   272  				
   273  				return rookoutErrors.NewIllegalAddressMappings()
   274  			}
   275  		}
   276  	}
   277  	updatePCDataEntries(table, newMappings)
   278  
   279  	return nil
   280  }
   281  
   282  func (p *PCDataPatcher) createSanitized(oldTable []PCDataEntry, builder func([]PCDataEntry) ([]PCDataEntry, error)) ([]PCDataEntry, error) {
   283  	var oldTableCopy []PCDataEntry = nil
   284  	if len(oldTable) > 0 {
   285  		oldTableCopy = make([]PCDataEntry, len(oldTable))
   286  		copy(oldTableCopy, oldTable)
   287  	}
   288  
   289  	newTable, err := builder(oldTableCopy)
   290  	if err != nil {
   291  		return nil, err
   292  	}
   293  	return removeDuplicateValues(newTable), nil
   294  }
   295  
   296  
   297  
   298  
   299  func (p *PCDataPatcher) CreatePCData(tableIndex int, oldTable []PCDataEntry) ([]PCDataEntry, error) {
   300  	return p.createSanitized(oldTable,
   301  		func(table []PCDataEntry) ([]PCDataEntry, error) {
   302  			err := p.updateOffsets(table)
   303  			if err != nil {
   304  				return nil, err
   305  			}
   306  
   307  			if p.isPatched && tableIndex == _PCDATA_UnsafePoint {
   308  				table, err = p.fixAsyncUnsafePointPCData(table)
   309  			}
   310  
   311  			return table, err
   312  		})
   313  }
   314  
   315  
   316  func (p *PCDataPatcher) CreatePCLine(oldTable []PCDataEntry) ([]PCDataEntry, error) {
   317  	return p.createSanitized(oldTable,
   318  		func(table []PCDataEntry) ([]PCDataEntry, error) {
   319  			err := p.updateOffsets(table)
   320  			return table, err
   321  		})
   322  }
   323  
   324  
   325  
   326  func (p *PCDataPatcher) CreatePCSP(oldTable []PCDataEntry) ([]PCDataEntry, error) {
   327  	return p.createSanitized(oldTable,
   328  		func(table []PCDataEntry) ([]PCDataEntry, error) {
   329  			err := p.updateOffsets(table)
   330  			if err != nil {
   331  				return nil, err
   332  			}
   333  			if p.isPatched {
   334  				pcspGenerator := func(callbackOffsetStart, callbackOffsetEnd uintptr, callbackOffsetValue int32) ([]PCDataEntry, error) {
   335  					
   336  					patchedPCSP, err := generatePCSP(callbackOffsetStart+p.newFuncEntry, callbackOffsetEnd+p.newFuncEntry)
   337  					if err != nil {
   338  						return nil, err
   339  					}
   340  					
   341  					return addOffsetAndValueToEntries(callbackOffsetStart, callbackOffsetValue, patchedPCSP), nil
   342  				}
   343  				table, err = addCallbacksEntries(table, p.offsetMappings, pcspGenerator)
   344  				if err != nil {
   345  					return nil, err
   346  				}
   347  			}
   348  			return table, nil
   349  		})
   350  }
   351  
   352  
   353  
   354  
   355  
   356  
   357  
   358  
   359  func (p *PCDataPatcher) fixAsyncUnsafePointPCData(entries []PCDataEntry) ([]PCDataEntry, error) {
   360  	if len(entries) == 0 {
   361  		entries = []PCDataEntry{{Offset: p.offsetMappings[len(p.offsetMappings)-1].NewAddress, Value: _PCDATA_UnsafePointSafe}}
   362  	}
   363  	
   364  	pcdataAsyncUnsafeGenerator := func(callbackOffsetStart, callbackOffsetEnd uintptr, callbackOffsetValue int32) ([]PCDataEntry, error) {
   365  		firstCallbackInstructionPC := callbackOffsetStart + p.newFuncEntry
   366  		firstCallbackInstructionSize, err := p.instSizeReader(firstCallbackInstructionPC)
   367  		if err != nil {
   368  			return nil, err
   369  		}
   370  		callbackEntries := []PCDataEntry{
   371  			{
   372  				
   373  				Offset: callbackOffsetStart + firstCallbackInstructionSize,
   374  				Value:  callbackOffsetValue,
   375  			},
   376  			{
   377  				
   378  				Offset: callbackOffsetEnd,
   379  				Value:  _PCDATA_UnsafePointUnsafe,
   380  			},
   381  		}
   382  		return callbackEntries, nil
   383  	}
   384  	return addCallbacksEntries(entries, p.offsetMappings, pcdataAsyncUnsafeGenerator)
   385  }