github.com/ks888/tgo@v0.0.0-20190130135156-80bf89407292/tracee/moduledata.go (about)

     1  package tracee
     2  
     3  import (
     4  	"debug/dwarf"
     5  	"encoding/binary"
     6  	"fmt"
     7  
     8  	"github.com/ks888/tgo/log"
     9  )
    10  
    11  // moduleData represents the value of the moduledata type.
    12  // It offers a set of methods to get the field value of the type rather than simply returns the parsed result.
    13  // It is because the moduledata can be large and the parsing cost is too high.
    14  // TODO: try to use the parser by optimizing the load array operation.
    15  type moduleData struct {
    16  	moduleDataAddr uint64
    17  	moduleDataType dwarf.Type
    18  	fields         map[string]*dwarf.StructField
    19  }
    20  
    21  func newModuleData(moduleDataAddr uint64, moduleDataType dwarf.Type) *moduleData {
    22  	fields := make(map[string]*dwarf.StructField)
    23  	for _, field := range moduleDataType.(*dwarf.StructType).Field {
    24  		fields[field.Name] = field
    25  	}
    26  
    27  	return &moduleData{moduleDataAddr: moduleDataAddr, moduleDataType: moduleDataType, fields: fields}
    28  }
    29  
    30  // pclntable retrieves the pclntable data specified by `index` because retrieving all the ftab data can be heavy.
    31  func (md *moduleData) pclntable(reader memoryReader, index int) uint64 {
    32  	ptrToArrayType, ptrToArray := md.retrieveArrayInSlice(reader, "pclntable")
    33  	elementType := ptrToArrayType.(*dwarf.PtrType).Type
    34  
    35  	return ptrToArray + uint64(index)*uint64(elementType.Size())
    36  }
    37  
    38  // functab retrieves the functab data specified by `index` because retrieving all the ftab data can be heavy.
    39  func (md *moduleData) functab(reader memoryReader, index int) (entry, funcoff uint64) {
    40  	ptrToFtabType, ptrToArray := md.retrieveArrayInSlice(reader, "ftab")
    41  	ftabType := ptrToFtabType.(*dwarf.PtrType).Type
    42  	functabSize := uint64(ftabType.Size())
    43  
    44  	buff := make([]byte, functabSize)
    45  	if err := reader.ReadMemory(ptrToArray+uint64(index)*functabSize, buff); err != nil {
    46  		log.Debugf("failed to read memory: %v", err)
    47  		return
    48  	}
    49  
    50  	if innerFtabType, ok := ftabType.(*dwarf.TypedefType); ok {
    51  		// some go version wraps the ftab.
    52  		ftabType = innerFtabType.Type
    53  	}
    54  
    55  	for _, field := range ftabType.(*dwarf.StructType).Field {
    56  		val := binary.LittleEndian.Uint64(buff[field.ByteOffset : field.ByteOffset+field.Type.Size()])
    57  		switch field.Name {
    58  		case "entry":
    59  			entry = val
    60  		case "funcoff":
    61  			funcoff = val
    62  		}
    63  	}
    64  	return
    65  }
    66  
    67  func (md *moduleData) ftabLen(reader memoryReader) int {
    68  	return md.retrieveSliceLen(reader, "ftab")
    69  }
    70  
    71  func (md *moduleData) findfunctab(reader memoryReader) uint64 {
    72  	return md.retrieveUint64(reader, "findfunctab")
    73  }
    74  
    75  func (md *moduleData) minpc(reader memoryReader) uint64 {
    76  	return md.retrieveUint64(reader, "minpc")
    77  }
    78  
    79  func (md *moduleData) maxpc(reader memoryReader) uint64 {
    80  	return md.retrieveUint64(reader, "maxpc")
    81  }
    82  
    83  func (md *moduleData) types(reader memoryReader) uint64 {
    84  	return md.retrieveUint64(reader, "types")
    85  }
    86  
    87  func (md *moduleData) etypes(reader memoryReader) uint64 {
    88  	return md.retrieveUint64(reader, "etypes")
    89  }
    90  
    91  func (md *moduleData) next(reader memoryReader) uint64 {
    92  	return md.retrieveUint64(reader, "next")
    93  }
    94  
    95  func (md *moduleData) retrieveArrayInSlice(reader memoryReader, fieldName string) (dwarf.Type, uint64) {
    96  	typ, buff := md.retrieveFieldOfStruct(reader, md.fields[fieldName], "array")
    97  	if buff == nil {
    98  		return nil, 0
    99  	}
   100  
   101  	return typ, binary.LittleEndian.Uint64(buff)
   102  }
   103  
   104  func (md *moduleData) retrieveSliceLen(reader memoryReader, fieldName string) int {
   105  	_, buff := md.retrieveFieldOfStruct(reader, md.fields[fieldName], "len")
   106  	if buff == nil {
   107  		return 0
   108  	}
   109  
   110  	return int(binary.LittleEndian.Uint64(buff))
   111  }
   112  
   113  func (md *moduleData) retrieveFieldOfStruct(reader memoryReader, strct *dwarf.StructField, fieldName string) (dwarf.Type, []byte) {
   114  	strctType, ok := strct.Type.(*dwarf.StructType)
   115  	if !ok {
   116  		log.Printf("unexpected type: %#v", md.fields[fieldName].Type)
   117  		return nil, nil
   118  	}
   119  
   120  	var field *dwarf.StructField
   121  	for _, candidate := range strctType.Field {
   122  		if candidate.Name == fieldName {
   123  			field = candidate
   124  			break
   125  		}
   126  	}
   127  	if field == nil {
   128  		panic(fmt.Sprintf("%s field not found", fieldName))
   129  	}
   130  
   131  	buff := make([]byte, field.Type.Size())
   132  	addr := md.moduleDataAddr + uint64(strct.ByteOffset) + uint64(field.ByteOffset)
   133  	if err := reader.ReadMemory(addr, buff); err != nil {
   134  		log.Debugf("failed to read memory: %v", err)
   135  		return nil, nil
   136  	}
   137  	return field.Type, buff
   138  }
   139  
   140  func (md *moduleData) retrieveUint64(reader memoryReader, fieldName string) uint64 {
   141  	field := md.fields[fieldName]
   142  	if field.Type.Size() != 8 {
   143  		log.Printf("the type size is not expected value: %d", field.Type.Size())
   144  	}
   145  
   146  	buff := make([]byte, 8)
   147  	if err := reader.ReadMemory(md.moduleDataAddr+uint64(field.ByteOffset), buff); err != nil {
   148  		log.Debugf("failed to read memory: %v", err)
   149  		return 0
   150  	}
   151  	return binary.LittleEndian.Uint64(buff)
   152  }