Skip to content

Commit

Permalink
parse field tag
Browse files Browse the repository at this point in the history
  • Loading branch information
virusdefender committed Sep 15, 2023
1 parent 944c2b7 commit 935d76d
Show file tree
Hide file tree
Showing 2 changed files with 81 additions and 38 deletions.
1 change: 1 addition & 0 deletions objfile/internals.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
118 changes: 80 additions & 38 deletions objfile/objfile.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ package objfile
import (
"bytes"
"encoding/binary"
"errors"
"fmt"
"io"
"os"
Expand Down Expand Up @@ -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:
//
Expand Down Expand Up @@ -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
Expand All @@ -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
Expand All @@ -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) {
Expand Down Expand Up @@ -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)))
Expand All @@ -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 {
Expand All @@ -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)))
Expand All @@ -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
Expand All @@ -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)))
Expand All @@ -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
Expand All @@ -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)))
Expand All @@ -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")
Expand Down Expand Up @@ -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))
}
}
Expand Down Expand Up @@ -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))
}
}
Expand Down

0 comments on commit 935d76d

Please sign in to comment.