pkg/tools/elf/dwarf_init.go (319 lines of code) (raw):
// Licensed to Apache Software Foundation (ASF) under one or more contributor
// license agreements. See the NOTICE file distributed with
// this work for additional information regarding copyright
// ownership. Apache Software Foundation (ASF) licenses this file to you under
// the Apache License, Version 2.0 (the "License"); you may
// not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
package elf
import (
"debug/dwarf"
"fmt"
)
func (r *DwarfReader) processProducer(_ *dwarf.Data, entry *dwarf.Entry) error {
if entry.Tag != dwarf.TagCompileUnit {
return nil
}
producer, ok := entry.Val(dwarf.AttrProducer).(string)
if !ok {
return fmt.Errorf("the producer field not exists")
}
language, ok := entry.Val(dwarf.AttrLanguage).(int64)
if !ok {
return fmt.Errorf("the language field not exists")
}
r.producer = producer
r.language = int(language)
return nil
}
func (r *DwarfReader) processFunctions(funcNames []string, data *dwarf.Data, entry *dwarf.Entry) error {
if entry.Tag != dwarf.TagSubprogram {
return nil
}
name, ok := entry.Val(dwarf.AttrName).(string)
if !ok {
return nil
}
// the function is need to read
found := false
for _, n := range funcNames {
if n == name {
found = true
break
}
}
if !found {
return nil
}
args, err := r.getFunctionArgs(data, entry)
if err != nil {
return err
}
r.functions[name] = &FunctionInfo{
name: name,
args: args,
}
return nil
}
func (r *DwarfReader) processStructure(names []string, data *dwarf.Data, entry *dwarf.Entry) error {
if entry.Tag != dwarf.TagStructType {
return nil
}
name, ok := entry.Val(dwarf.AttrName).(string)
if !ok {
return nil
}
found := false
for _, n := range names {
if n == name {
found = true
break
}
}
if !found {
return nil
}
fields, err := r.getStructureFields(data, entry)
if err != nil {
return err
}
r.structures[name] = &StructureInfo{
name: name,
fields: fields,
}
return nil
}
func (r *DwarfReader) processClass(names []string, data *dwarf.Data, entry *dwarf.Entry) error {
if entry.Tag != dwarf.TagClassType {
return nil
}
name, ok := entry.Val(dwarf.AttrName).(string)
if !ok {
return nil
}
_, ok = entry.Val(dwarf.AttrDeclaration).(bool)
if ok {
return nil
}
found := false
for _, n := range names {
if n == name {
found = true
break
}
}
if !found {
return nil
}
info, err := r.getClassInfo(data, name, entry)
if err != nil {
return err
}
r.classes[name] = info
return nil
}
func (r *DwarfReader) entryType(data *dwarf.Data, entry *dwarf.Entry) (dwarf.Type, error) {
off, ok := entry.Val(dwarf.AttrType).(dwarf.Offset)
if !ok {
return nil, nil
}
return data.Type(off)
}
func (r *DwarfReader) IsRetArgs(entry *dwarf.Entry) (bool, error) {
isRet, ok := entry.Val(dwarf.AttrVarParam).(bool)
if !ok {
return false, nil
}
return isRet, nil
}
func (r *DwarfReader) getClassInfo(data *dwarf.Data, name string, entry *dwarf.Entry) (*ClassInfo, error) {
reader := data.Reader()
reader.Seek(entry.Offset)
_, err := reader.Next()
if err != nil {
return nil, err
}
c := &ClassInfo{
name: name,
}
foundMembers := false
for {
child, err := reader.Next()
if err != nil {
return nil, err
}
if child == nil || child.Tag == 0 {
break
}
if child.Tag == dwarf.TagInheritance {
offset, ok := child.Val(dwarf.AttrDataMemberLoc).(int64)
if !ok {
continue
}
entryType, err1 := r.entryType(data, child)
if err1 != nil {
continue
}
structType, ok := entryType.(*dwarf.StructType)
if !ok {
continue
}
c.inheritances = append(c.inheritances, &ClassInheritance{
name: structType.StructName,
cType: structType,
offset: uint64(offset),
})
}
entryType, err := r.entryType(data, child)
if !foundMembers && err == nil && entryType != nil {
prtType, ok := entryType.(*dwarf.PtrType)
if !ok {
continue
}
structType, ok := prtType.Type.(*dwarf.StructType)
if !ok {
continue
}
c.members = structType.Field
foundMembers = true
}
}
return c, nil
}
func (r *DwarfReader) getStructureFields(data *dwarf.Data, entry *dwarf.Entry) ([]*StructureFieldInfo, error) {
reader := data.Reader()
reader.Seek(entry.Offset)
_, err := reader.Next()
if err != nil {
return nil, err
}
res := make([]*StructureFieldInfo, 0)
for {
child, err := reader.Next()
if err != nil {
return nil, err
}
if child == nil || child.Tag == 0 {
break
}
if child.Tag != dwarf.TagMember {
continue
}
name, ok := child.Val(dwarf.AttrName).(string)
if !ok {
continue
}
offset, ok := child.Val(dwarf.AttrDataMemberLoc).(int64)
if !ok {
continue
}
field := &StructureFieldInfo{
Name: name,
Offset: offset,
}
res = append(res, field)
}
return res, nil
}
func (r *DwarfReader) getFunctionArgs(data *dwarf.Data, entry *dwarf.Entry) (map[string]*FunctionArgsInfo, error) {
reader := data.Reader()
reader.Seek(entry.Offset)
_, err := reader.Next()
if err != nil {
return nil, err
}
locator := NewArgumentLocator(r)
args := make(map[string]*FunctionArgsInfo)
for {
child, err := reader.Next()
if err != nil {
return nil, err
}
if child == nil || child.Tag == 0 {
break
}
if child.Tag != dwarf.TagFormalParameter {
continue
}
name, ok := child.Val(dwarf.AttrName).(string)
if !ok {
continue
}
if existsArgs := args[name]; existsArgs != nil {
continue
}
curArgs := &FunctionArgsInfo{}
// data type
dtyp, err := r.entryType(data, child)
if err != nil {
return nil, err
}
curArgs.tp = dtyp
// Is return value
if r.language == ReaderLanguageGolang {
isRet, err1 := r.IsRetArgs(child)
if err1 != nil {
return nil, err1
}
curArgs.IsRet = isRet
}
// get location
typeClass := r.getArgTypeClass(child, dtyp)
byteSize := r.getArgTypeByteSize(child, dtyp)
alignmentByteSize := r.getArgAlignmentByteSize(child, dtyp)
primitiveFieldCount := r.getPrimitiveFieldCount(child, dtyp)
location, err := locator.GetLocation(typeClass, byteSize, alignmentByteSize, primitiveFieldCount, curArgs.IsRet)
if err != nil {
return nil, err
}
curArgs.Location = location
args[name] = curArgs
}
return args, nil
}
func (r *DwarfReader) getArgTypeClass(_ *dwarf.Entry, tp dwarf.Type) TypeClass {
switch val := tp.(type) {
case *dwarf.FloatType:
return TypeClassFloat
case *dwarf.StructType:
res := TypeClassNone
for _, field := range val.Field {
memberType := r.getArgTypeClass(nil, field.Type)
res = res.Combine(memberType)
}
return res
default:
return TypeClassInteger
}
}
func (r *DwarfReader) getArgTypeByteSize(_ *dwarf.Entry, tp dwarf.Type) uint64 {
basicType, ok := tp.(*dwarf.BasicType)
if ok {
return uint64(basicType.ByteSize)
}
switch val := tp.(type) {
case *dwarf.StructType:
return uint64(val.ByteSize)
default:
return 8
}
}
func (r *DwarfReader) getArgAlignmentByteSize(_ *dwarf.Entry, tp dwarf.Type) uint64 {
basicType, ok := tp.(*dwarf.BasicType)
if ok {
return uint64(basicType.ByteSize)
}
switch val := tp.(type) {
case *dwarf.StructType:
var maxSize uint64 = 1
for _, field := range val.Field {
curSize := r.getArgAlignmentByteSize(nil, field.Type)
if curSize > maxSize {
maxSize = curSize
}
}
return maxSize
default:
return 8
}
}
func (r *DwarfReader) getPrimitiveFieldCount(_ *dwarf.Entry, tp dwarf.Type) int {
structType, ok := tp.(*dwarf.StructType)
if ok {
totalCount := 0
for _, field := range structType.Field {
totalCount += r.getPrimitiveFieldCount(nil, field.Type)
}
return totalCount
}
return 1
}