From 935d76d1c7b36df6553c27e99af203cc0f15c98c Mon Sep 17 00:00:00 2001 From: virusdefender Date: Fri, 15 Sep 2023 15:07:22 +0800 Subject: [PATCH] parse field tag --- objfile/internals.go | 1 + objfile/objfile.go | 118 +++++++++++++++++++++++++++++-------------- 2 files changed, 81 insertions(+), 38 deletions(-) diff --git a/objfile/internals.go b/objfile/internals.go index 1a6225e..ab459c4 100644 --- a/objfile/internals.go +++ b/objfile/internals.go @@ -1160,6 +1160,7 @@ func (rtype *Rtype114_115_116_117_118_32) parse(rawData []byte, littleEndian boo type Type struct { VA uint64 Str string + Tag string CStr string Kind string Reconstructed string `json:",omitempty"` // for Some types we can reconstruct the original definition back to Go code diff --git a/objfile/objfile.go b/objfile/objfile.go index 2bfd60a..b8c1aa6 100644 --- a/objfile/objfile.go +++ b/objfile/objfile.go @@ -10,6 +10,7 @@ package objfile import ( "bytes" "encoding/binary" + "errors" "fmt" "io" "os" @@ -839,7 +840,7 @@ func (e *Entry) readVarint(address uint64) (int, int, error) { } } -func (e *Entry) readRTypeName(runtimeVersion string, typeFlags tflag, namePtr uint64, is64bit bool, littleendian bool) (name string, err error) { +func (e *Entry) readRTypeName(runtimeVersion string, typeFlags tflag, namePtr uint64, is64bit bool, littleendian bool) (name string, tag string, err error) { // name str (for <= 1.16 encodes length like this, beyond it uses a varint encoding) // The first byte is a bit field containing: // @@ -872,23 +873,24 @@ func (e *Entry) readRTypeName(runtimeVersion string, typeFlags tflag, namePtr ui case "1.5": fallthrough case "1.6": + // TODO: parse field tag // pointer to GoString nameLen, err := e.ReadPointerSizeMem(namePtr+ptrSize, is64bit, littleendian) if err != nil { - return "", fmt.Errorf("Failed to read name") + return "", "", fmt.Errorf("Failed to read name") } deref, err := e.ReadPointerSizeMem(namePtr, is64bit, littleendian) if err != nil { - return "", fmt.Errorf("Failed to read name") + return "", "", fmt.Errorf("Failed to read name") } name_raw, err := e.raw.read_memory(deref, nameLen) if err != nil { - return "", fmt.Errorf("Failed to read name") + return "", "", fmt.Errorf("Failed to read name") } - return string(name_raw), nil + return string(name_raw), "", nil case "1.7": // types flags exists >= 1.7 fallthrough case "1.8": // type flag tflagExtraStart exists >= 1.8 @@ -908,22 +910,41 @@ func (e *Entry) readRTypeName(runtimeVersion string, typeFlags tflag, namePtr ui case "1.15": fallthrough case "1.16": - name_len_raw, err := e.raw.read_memory(namePtr, 3) + flag, err := e.raw.read_memory(namePtr, 1) if err != nil { - return "", fmt.Errorf("Failed to read name") + return "", "", errors.New("Failed to read flag") } - name_len := uint16(uint16(name_len_raw[1])<<8 | uint16(name_len_raw[2])) + name_len_raw, err := e.raw.read_memory(namePtr+1, 2) + if err != nil { + return "", "", fmt.Errorf("Failed to read name") + } + + name_len := uint16(uint16(name_len_raw[0])<<8 | uint16(name_len_raw[1])) name_raw, err := e.raw.read_memory(namePtr+3, uint64(name_len)) if err != nil { - return "", fmt.Errorf("Failed to read name") + return "", "", fmt.Errorf("Failed to read name") } name := string(name_raw) + + if flag[0] == 3 { + tag_len_raw, err := e.raw.read_memory(namePtr+3+uint64(name_len), 2) + if err != nil { + return "", "", errors.New("Failed to read name") + } + + tag_len := uint16(uint16(tag_len_raw[0])<<8 | uint16(tag_len_raw[1])) + tag_raw, err := e.raw.read_memory(namePtr+3+uint64(name_len)+2, uint64(tag_len)) + if err != nil { + return "", "", errors.New("Failed to read name") + } + tag = string(tag_raw) + } if typeFlags&tflagExtraStar != 0 { - return name[1:], nil + return name[1:], tag, nil } else { - return name, nil + return name, tag, nil } case "1.17": fallthrough @@ -932,24 +953,39 @@ func (e *Entry) readRTypeName(runtimeVersion string, typeFlags tflag, namePtr ui case "1.19": fallthrough case "1.20": + flag, err := e.raw.read_memory(namePtr, 1) + if err != nil { + return "", "", errors.New("Failed to read flag") + } varint_len, namelen, err := e.readVarint(namePtr + 1) if err != nil { - return "", fmt.Errorf("Failed to read name") + // TODO: replace all misuses of fmt.Errorf to errors.New + return "", "", fmt.Errorf("Failed to read name") } - name_raw, err := e.raw.read_memory(namePtr+1+uint64(varint_len), uint64(namelen)) if err != nil { - return "", fmt.Errorf("Failed to read name") + return "", "", fmt.Errorf("Failed to read name") } - name := string(name_raw) + + if flag[0] == 3 { + varint_len, taglen, err := e.readVarint(namePtr + 1 + uint64(varint_len) + uint64(namelen)) + if err != nil { + return "", "", errors.New("Failed to read tag") + } + tag_raw, err := e.raw.read_memory(namePtr+1+uint64(varint_len)+uint64(namelen)+uint64(varint_len), uint64(taglen)) + if err != nil { + return "", "", errors.New("Failed to read tag") + } + tag = string(tag_raw) + } if typeFlags&tflagExtraStar != 0 { - return name[1:], nil + return name[1:], tag, nil } else { - return name, nil + return name, tag, nil } } - return "", fmt.Errorf("Failed to read name") + return "", "", fmt.Errorf("Failed to read name") } func decodePtrSizeBytes(data []byte, is64bit bool, littleendian bool) (result uint64) { @@ -1056,12 +1092,12 @@ func (e *Entry) ParseType_impl(runtimeVersion string, moduleData *ModuleData, ty return parsedTypesIn, fmt.Errorf("Failed to parse type") } - name, err := e.readRTypeName(runtimeVersion, 0, uint64(rtype.Str), is64bit, littleendian) + name, tag, err := e.readRTypeName(runtimeVersion, 0, uint64(rtype.Str), is64bit, littleendian) if err != nil { return parsedTypesIn, fmt.Errorf("Failed to read type name") } - _type = &Type{VA: typeAddress, Str: name, CStr: typename_to_c(name), Kind: ((Kind)(rtype.Kind & 0x1f)).String(), baseSize: uint16(unsafe.Sizeof(rtype)), kindEnum: ((Kind)(rtype.Kind & 0x1f)), flags: tflagNamed} + _type = &Type{VA: typeAddress, Str: name, Tag: tag, CStr: typename_to_c(name), Kind: ((Kind)(rtype.Kind & 0x1f)).String(), baseSize: uint16(unsafe.Sizeof(rtype)), kindEnum: ((Kind)(rtype.Kind & 0x1f)), flags: tflagNamed} } else { var rtype Rtype15_32 rtype_raw, err := e.raw.read_memory(typeAddress, uint64(unsafe.Sizeof(rtype))) @@ -1074,11 +1110,11 @@ func (e *Entry) ParseType_impl(runtimeVersion string, moduleData *ModuleData, ty return parsedTypesIn, fmt.Errorf("Failed to parse type") } - name, err := e.readRTypeName(runtimeVersion, 0, uint64(rtype.Str), is64bit, littleendian) + name, tag, err := e.readRTypeName(runtimeVersion, 0, uint64(rtype.Str), is64bit, littleendian) if err != nil { return parsedTypesIn, fmt.Errorf("Failed to read type name") } - _type = &Type{VA: typeAddress, Str: name, CStr: typename_to_c(name), Kind: ((Kind)(rtype.Kind & 0x1f)).String(), baseSize: uint16(unsafe.Sizeof(rtype)), kindEnum: ((Kind)(rtype.Kind & 0x1f)), flags: tflagNamed} + _type = &Type{VA: typeAddress, Str: name, Tag: tag, CStr: typename_to_c(name), Kind: ((Kind)(rtype.Kind & 0x1f)).String(), baseSize: uint16(unsafe.Sizeof(rtype)), kindEnum: ((Kind)(rtype.Kind & 0x1f)), flags: tflagNamed} } case "1.6": if is64bit { @@ -1093,11 +1129,11 @@ func (e *Entry) ParseType_impl(runtimeVersion string, moduleData *ModuleData, ty return parsedTypesIn, fmt.Errorf("Failed to parse type") } - name, err := e.readRTypeName(runtimeVersion, 0, uint64(rtype.Str), is64bit, littleendian) + name, tag, err := e.readRTypeName(runtimeVersion, 0, uint64(rtype.Str), is64bit, littleendian) if err != nil { return parsedTypesIn, fmt.Errorf("Failed to read type name") } - _type = &Type{VA: typeAddress, Str: name, CStr: typename_to_c(name), Kind: ((Kind)(rtype.Kind & 0x1f)).String(), baseSize: uint16(unsafe.Sizeof(rtype)), kindEnum: ((Kind)(rtype.Kind & 0x1f)), flags: tflagNamed} + _type = &Type{VA: typeAddress, Str: name, Tag: tag, CStr: typename_to_c(name), Kind: ((Kind)(rtype.Kind & 0x1f)).String(), baseSize: uint16(unsafe.Sizeof(rtype)), kindEnum: ((Kind)(rtype.Kind & 0x1f)), flags: tflagNamed} } else { var rtype Rtype16_32 rtype_raw, err := e.raw.read_memory(typeAddress, uint64(unsafe.Sizeof(rtype))) @@ -1110,11 +1146,11 @@ func (e *Entry) ParseType_impl(runtimeVersion string, moduleData *ModuleData, ty return parsedTypesIn, fmt.Errorf("Failed to parse type") } - name, err := e.readRTypeName(runtimeVersion, 0, uint64(rtype.Str), is64bit, littleendian) + name, tag, err := e.readRTypeName(runtimeVersion, 0, uint64(rtype.Str), is64bit, littleendian) if err != nil { return parsedTypesIn, fmt.Errorf("Failed to read type name") } - _type = &Type{VA: typeAddress, Str: name, CStr: typename_to_c(name), Kind: ((Kind)(rtype.Kind & 0x1f)).String(), baseSize: uint16(unsafe.Sizeof(rtype)), kindEnum: ((Kind)(rtype.Kind & 0x1f)), flags: tflagNamed} + _type = &Type{VA: typeAddress, Str: name, Tag: tag, CStr: typename_to_c(name), Kind: ((Kind)(rtype.Kind & 0x1f)).String(), baseSize: uint16(unsafe.Sizeof(rtype)), kindEnum: ((Kind)(rtype.Kind & 0x1f)), flags: tflagNamed} } case "1.7": fallthrough @@ -1140,11 +1176,11 @@ func (e *Entry) ParseType_impl(runtimeVersion string, moduleData *ModuleData, ty return parsedTypesIn, fmt.Errorf("Failed to parse type") } name_ptr := moduleData.Types + uint64(rtype.Str) - name, err := e.readRTypeName(runtimeVersion, rtype.Tflag, name_ptr, is64bit, littleendian) + name, tag, err := e.readRTypeName(runtimeVersion, rtype.Tflag, name_ptr, is64bit, littleendian) if err != nil { return parsedTypesIn, fmt.Errorf("Failed to read type name") } - _type = &Type{VA: typeAddress, Str: name, CStr: typename_to_c(name), Kind: ((Kind)(rtype.Kind & 0x1f)).String(), baseSize: uint16(unsafe.Sizeof(rtype)), kindEnum: ((Kind)(rtype.Kind & 0x1f)), flags: rtype.Tflag} + _type = &Type{VA: typeAddress, Str: name, Tag: tag, CStr: typename_to_c(name), Kind: ((Kind)(rtype.Kind & 0x1f)).String(), baseSize: uint16(unsafe.Sizeof(rtype)), kindEnum: ((Kind)(rtype.Kind & 0x1f)), flags: rtype.Tflag} } else { var rtype Rtype17_18_19_110_111_112_113_32 rtype_raw, err := e.raw.read_memory(typeAddress, uint64(unsafe.Sizeof(rtype))) @@ -1156,11 +1192,11 @@ func (e *Entry) ParseType_impl(runtimeVersion string, moduleData *ModuleData, ty return parsedTypesIn, fmt.Errorf("Failed to parse type") } name_ptr := moduleData.Types + uint64(rtype.Str) - name, err := e.readRTypeName(runtimeVersion, rtype.Tflag, name_ptr, is64bit, littleendian) + name, tag, err := e.readRTypeName(runtimeVersion, rtype.Tflag, name_ptr, is64bit, littleendian) if err != nil { return parsedTypesIn, fmt.Errorf("Failed to read type name") } - _type = &Type{VA: typeAddress, Str: name, CStr: typename_to_c(name), Kind: ((Kind)(rtype.Kind & 0x1f)).String(), baseSize: uint16(unsafe.Sizeof(rtype)), kindEnum: ((Kind)(rtype.Kind & 0x1f)), flags: rtype.Tflag} + _type = &Type{VA: typeAddress, Str: name, Tag: tag, CStr: typename_to_c(name), Kind: ((Kind)(rtype.Kind & 0x1f)).String(), baseSize: uint16(unsafe.Sizeof(rtype)), kindEnum: ((Kind)(rtype.Kind & 0x1f)), flags: rtype.Tflag} } case "1.14": fallthrough @@ -1186,11 +1222,11 @@ func (e *Entry) ParseType_impl(runtimeVersion string, moduleData *ModuleData, ty return parsedTypesIn, fmt.Errorf("Failed to parse type") } name_ptr := moduleData.Types + uint64(rtype.Str) - name, err := e.readRTypeName(runtimeVersion, rtype.Tflag, name_ptr, is64bit, littleendian) + name, tag, err := e.readRTypeName(runtimeVersion, rtype.Tflag, name_ptr, is64bit, littleendian) if err != nil { return parsedTypesIn, fmt.Errorf("Failed to read type name") } - _type = &Type{VA: typeAddress, Str: name, CStr: typename_to_c(name), Kind: ((Kind)(rtype.Kind & 0x1f)).String(), baseSize: uint16(unsafe.Sizeof(rtype)), kindEnum: ((Kind)(rtype.Kind & 0x1f)), flags: rtype.Tflag} + _type = &Type{VA: typeAddress, Str: name, Tag: tag, CStr: typename_to_c(name), Kind: ((Kind)(rtype.Kind & 0x1f)).String(), baseSize: uint16(unsafe.Sizeof(rtype)), kindEnum: ((Kind)(rtype.Kind & 0x1f)), flags: rtype.Tflag} } else { var rtype Rtype114_115_116_117_118_32 rtype_raw, err := e.raw.read_memory(typeAddress, uint64(unsafe.Sizeof(rtype))) @@ -1202,11 +1238,11 @@ func (e *Entry) ParseType_impl(runtimeVersion string, moduleData *ModuleData, ty return parsedTypesIn, fmt.Errorf("Failed to parse type") } name_ptr := moduleData.Types + uint64(rtype.Str) - name, err := e.readRTypeName(runtimeVersion, rtype.Tflag, name_ptr, is64bit, littleendian) + name, tag, err := e.readRTypeName(runtimeVersion, rtype.Tflag, name_ptr, is64bit, littleendian) if err != nil { return parsedTypesIn, fmt.Errorf("Failed to read type name") } - _type = &Type{VA: typeAddress, Str: name, CStr: typename_to_c(name), Kind: ((Kind)(rtype.Kind & 0x1f)).String(), baseSize: uint16(unsafe.Sizeof(rtype)), kindEnum: ((Kind)(rtype.Kind & 0x1f)), flags: rtype.Tflag} + _type = &Type{VA: typeAddress, Str: name, Tag: tag, CStr: typename_to_c(name), Kind: ((Kind)(rtype.Kind & 0x1f)).String(), baseSize: uint16(unsafe.Sizeof(rtype)), kindEnum: ((Kind)(rtype.Kind & 0x1f)), flags: rtype.Tflag} } default: return parsedTypesIn, fmt.Errorf("Unknown runtime version") @@ -1597,9 +1633,12 @@ func (e *Entry) ParseType_impl(runtimeVersion string, moduleData *ModuleData, ty field, found := parsedTypesIn.Get(typeAddr) if found { typeNameAddr := decodePtrSizeBytes(data[0:ptrSize], is64bit, littleendian) - typeName, err := e.readRTypeName(runtimeVersion, 0, typeNameAddr, is64bit, littleendian) + typeName, tag, err := e.readRTypeName(runtimeVersion, 0, typeNameAddr, is64bit, littleendian) if err == nil { - structDef += fmt.Sprintf("\n %-10s %s", typeName, field.(Type).Str) + if tag != "" { + tag = fmt.Sprintf("`%s`", tag) + } + structDef += fmt.Sprintf("\n %-10s %s %s", typeName, field.(Type).Str, tag) cstructDef += fmt.Sprintf(" %-10s %s;\n", field.(Type).CStr, replace_cpp_keywords(typeName)) } } @@ -1690,9 +1729,12 @@ func (e *Entry) ParseType_impl(runtimeVersion string, moduleData *ModuleData, ty field, found := parsedTypesIn.Get(typeAddr) if found { typeNameAddr := decodePtrSizeBytes(data[0:ptrSize], is64bit, littleendian) - typeName, err := e.readRTypeName(runtimeVersion, 0, typeNameAddr, is64bit, littleendian) + typeName, tag, err := e.readRTypeName(runtimeVersion, 0, typeNameAddr, is64bit, littleendian) if err == nil { - structDef += fmt.Sprintf("\n %-10s %s", typeName, field.(Type).Str) + if tag != "" { + tag = fmt.Sprintf("`%s`", tag) + } + structDef += fmt.Sprintf("\n %-10s %s %s", typeName, field.(Type).Str, tag) cstructDef += fmt.Sprintf(" %-10s %s;\n", field.(Type).CStr, replace_cpp_keywords(typeName)) } }