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 }