Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

parse field tag and interface method name #38

Merged
merged 4 commits into from
Oct 6, 2023
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
123 changes: 91 additions & 32 deletions objfile/objfile.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,9 @@ package objfile
import (
"bytes"
"encoding/binary"
"errors"
"fmt"
"github.com/mandiant/GoReSym/objabi"
"io"
"os"
"sort"
Expand Down Expand Up @@ -841,7 +843,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 @@ -874,23 +876,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 @@ -910,22 +913,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 tag")
}

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 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
}
case "1.17":
fallthrough
Expand All @@ -938,22 +960,33 @@ func (e *Entry) readRTypeName(runtimeVersion string, typeFlags tflag, namePtr ui
case "1.21":
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 @@ -1060,7 +1093,7 @@ 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, _, err := e.readRTypeName(runtimeVersion, 0, uint64(rtype.Str), is64bit, littleendian)
if err != nil {
return parsedTypesIn, fmt.Errorf("Failed to read type name")
}
Expand All @@ -1078,7 +1111,7 @@ 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, _, err := e.readRTypeName(runtimeVersion, 0, uint64(rtype.Str), is64bit, littleendian)
if err != nil {
return parsedTypesIn, fmt.Errorf("Failed to read type name")
}
Expand All @@ -1097,7 +1130,7 @@ 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, _, err := e.readRTypeName(runtimeVersion, 0, uint64(rtype.Str), is64bit, littleendian)
if err != nil {
return parsedTypesIn, fmt.Errorf("Failed to read type name")
}
Expand All @@ -1114,7 +1147,7 @@ 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, _, err := e.readRTypeName(runtimeVersion, 0, uint64(rtype.Str), is64bit, littleendian)
if err != nil {
return parsedTypesIn, fmt.Errorf("Failed to read type name")
}
Expand Down Expand Up @@ -1144,7 +1177,7 @@ 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, _, err := e.readRTypeName(runtimeVersion, rtype.Tflag, name_ptr, is64bit, littleendian)
if err != nil {
return parsedTypesIn, fmt.Errorf("Failed to read type name")
}
Expand All @@ -1160,7 +1193,7 @@ 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, _, err := e.readRTypeName(runtimeVersion, rtype.Tflag, name_ptr, is64bit, littleendian)
if err != nil {
return parsedTypesIn, fmt.Errorf("Failed to read type name")
}
Expand Down Expand Up @@ -1192,7 +1225,7 @@ 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, _, err := e.readRTypeName(runtimeVersion, rtype.Tflag, name_ptr, is64bit, littleendian)
if err != nil {
return parsedTypesIn, fmt.Errorf("Failed to read type name")
}
Expand All @@ -1208,7 +1241,7 @@ 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, _, err := e.readRTypeName(runtimeVersion, rtype.Tflag, name_ptr, is64bit, littleendian)
if err != nil {
return parsedTypesIn, fmt.Errorf("Failed to read type name")
}
Expand Down Expand Up @@ -1449,6 +1482,7 @@ func (e *Entry) ParseType_impl(runtimeVersion string, moduleData *ModuleData, ty
parsedTypesIn, _ = e.ParseType_impl(runtimeVersion, moduleData, typeAddr, is64bit, littleendian, parsedTypesIn)
methodfunc, found := parsedTypesIn.Get(typeAddr)
if found {
// TODO: parse method name
interfaceDef += "\nmethod" + strconv.Itoa(i) + " " + methodfunc.(Type).Str
cinterfaceDef += methodfunc.(Type).CStr + "method" + strconv.Itoa(i) + ";\n"
}
Expand Down Expand Up @@ -1538,11 +1572,16 @@ func (e *Entry) ParseType_impl(runtimeVersion string, moduleData *ModuleData, ty

typeAddr := moduleData.Types + uint64(method.Typ)
parsedTypesIn, _ = e.ParseType_impl(runtimeVersion, moduleData, typeAddr, is64bit, littleendian, parsedTypesIn)
name_ptr := moduleData.Types + uint64(method.Name)
name, _, err := e.readRTypeName(runtimeVersion, 0, name_ptr, is64bit, littleendian)
if err != nil {
name = "method" + strconv.Itoa(i)
}

methodfunc, found := parsedTypesIn.Get(typeAddr)
if found {
interfaceDef += "\nmethod" + strconv.Itoa(i) + " " + methodfunc.(Type).Str
cinterfaceDef += methodfunc.(Type).CStr + " method" + strconv.Itoa(i) + ";\n"
interfaceDef += name + strings.TrimPrefix(methodfunc.(Type).Str, "func") + "\n"
cinterfaceDef += methodfunc.(Type).CStr + " " + name + ";\n"
}
}
interfaceDef += "\n}"
Expand Down Expand Up @@ -1605,9 +1644,19 @@ 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)
var fieldStr string
if field.(Type).kindEnum == objabi.KindStruct {
fieldStr = strings.TrimPrefix(field.(Type).Reconstructed, "type ")
} else {
fieldStr = field.(Type).Str
}
if tag != "" {
structDef += fmt.Sprintf("\n %-10s %s `%s`", typeName, fieldStr, tag)
} else {
structDef += fmt.Sprintf("\n %-10s %s", typeName, fieldStr)
}
cstructDef += fmt.Sprintf(" %-10s %s;\n", field.(Type).CStr, replace_cpp_keywords(typeName))
}
}
Expand Down Expand Up @@ -1700,9 +1749,19 @@ 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)
var fieldStr string
if field.(Type).kindEnum == objabi.KindStruct {
fieldStr = strings.TrimPrefix(field.(Type).Reconstructed, "type ")
} else {
fieldStr = field.(Type).Str
}
if tag != "" {
structDef += fmt.Sprintf("\n %-10s %s `%s`", typeName, fieldStr, tag)
} else {
structDef += fmt.Sprintf("\n %-10s %s", typeName, fieldStr)
}
cstructDef += fmt.Sprintf(" %-10s %s;\n", field.(Type).CStr, replace_cpp_keywords(typeName))
}
}
Expand Down