Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

debug/dwarf - DWARF 调试信息

概述

debug/dwarf 包提供了 DWARF 调试信息的读取器。

DWARF 是什么

  • 📋 调试数据格式:标准的调试信息格式
  • 🔍 用于调试器:GDB、LLVM、Go 调试工具使用
  • 📦 嵌入在可执行文件中:包含类型、变量、函数信息
  • 🛠️ 跨平台标准:广泛用于 Unix/Linux/ macOS 系统

主要用途

  • 🔧 调试工具开发:编写调试器、分析工具
  • 📊 符号信息提取:读取函数、变量、类型信息
  • 🐛 源码映射:地址到源码行的映射
  • 📈 性能分析:profiling 工具的符号解析

重要说明

  • ⚠️ 只读访问:仅用于读取 DWARF 数据
  • ⚠️ 底层格式:需要了解 DWARF 规范
  • 标准库支持:Go 标准库提供完整支持

核心类型

1. Data - DWARF 数据

type Data struct {
    // 包含过滤或未导出的字段
}

功能:表示 DWARF 调试数据。

主要方法

// 获取类型信息
func (d *Data) AddrToPC(addr uint64) (PC, error)
func (d *Data) LineReader(e *Entry) (*LineReader, error)
func (d *Data) LookupType(name string) Offset
func (d *Data) PCToLine(pc uint64) (file string, line int, fn *Func, err error)
func (d *Data) PCToFunc(pc uint64) (*Func, error)
func (d *Data) Ranges(e *Entry) ([]Range, error)
func (d *Data) Type(Offset) (Type, error)
func (d *Data) Types() <-chan Type

// 读取条目
func (d *Data) Reader() *Reader

2. Entry - 调试信息条目

type Entry struct {
    Tag      Tag      // 标签(类型)
    Field    []Field  // 字段列表
    Children bool     // 是否有子条目
}

功能:表示 DWARF 调试信息条目(DIE - Debugging Information Entry)。

字段说明

  • Tag:条目标签(表示条目类型)
  • Field:属性字段列表
  • Children:是否有子条目

常用方法

// 获取字段值
func (e *Entry) AttrField(attr Attr) *Field
func (e *Entry) Val(attr Attr) interface{}

3. Field - 条目字段

type Field struct {
    Attr Attr        // 属性
    Class Class       // 类别
    Val  interface{} // 值
}

功能:表示 Entry 中的一个字段。

字段说明

  • Attr:属性标识符
  • Class:值的类别
  • Val:实际值(不同类型)

4. Reader - 条目读取器

type Reader struct {
    // 包含过滤或未导出的字段
}

功能:遍历 DWARF 条目。

主要方法

// 导航
func (r *Reader) Next() (*Entry, error)
func (r *Reader) Seek(off Offset)
func (r *Reader) AddressSize() int

// 遍历
func (r *Reader) RangeEntries() (first *Entry, last *Entry, err error)

使用模式

reader := data.Reader()
for {
    entry, err := reader.Next()
    if err == io.EOF {
        break
    }
    // 处理 entry
}

5. Type - 类型信息

type Type interface {
    Common() *CommonType
    String() string
    Size() int64
}

功能:表示 DWARF 类型。

实现该接口的具体类型

  • *ArrayType - 数组类型
  • *BaseType - 基本类型
  • *ChanType - Chan 类型
  • *ConstType - Const 限定类型
  • *EnumType - 枚举类型
  • *FuncType - 函数类型
  • *InterfaceType - 接口类型
  • *MapType - Map 类型
  • *PtrType - 指针类型
  • *SliceType - Slice 类型
  • *StructType - 结构体类型
  • *TypedefType - 类型定义

6. CommonType - 通用类型信息

type CommonType struct {
    ByteSize int64
    Name     string
    ReflectType reflect.Type
    Offset   Offset
}

功能:所有类型的通用字段。

字段说明

  • ByteSize:类型大小(字节)
  • Name:类型名称
  • ReflectType:对应的 reflect.Type
  • Offset:在 DWARF 数据中的偏移

7. LineReader - 行号读取器

type LineReader struct {
    // 包含过滤或未导出的字段
}

功能:读取源码行号信息。

主要方法

func (r *LineReader) Next(row *LineRow) error
func (r *LineReader) SeekPC(pc uint64, row *LineRow) error

8. LineRow - 行号信息

type LineRow struct {
    Address uint64 // 地址
    File    *FileEntry // 文件
    Line    int    // 行号
    Column  int    // 列号
    IsStmt  bool   // 是否是语句开始
    BasicBlock bool // 是否是基本块开始
    EndSequence bool // 是否是序列结束
}

9. Func - 函数信息

type Func struct {
    Name  string // 函数名
    Entry uint64 // 入口地址
    End   uint64 // 结束地址
}

10. Range - 地址范围

type Range struct {
    Start uint64 // 起始地址
    End   uint64 // 结束地址
}

标签(Tag)

常见 Tag 常量

const (
    TagUnspecified         Tag = 0x00
    TagArray               Tag = 0x01
    TagClassType           Tag = 0x02
    TagEntryPoint          Tag = 0x03
    TagEnumerationType     Tag = 0x04
    TagFormalParameter     Tag = 0x05
    TagImportedDeclaration Tag = 0x08
    TagInheritance         Tag = 0x09
    TagInlinedSubroutine   Tag = 0x0a
    TagMember              Tag = 0x0d
    TagPointerType         Tag = 0x0f
    TagReferenceType       Tag = 0x10
    TagCompileUnit         Tag = 0x11
    TagStringType          Tag = 0x17
    TagStructType          Tag = 0x13
    TagSubroutineType      Tag = 0x15
    TagTypedef             Tag = 0x16
    TagUnionType           Tag = 0x17
    TagUnspecifiedParameters Tag = 0x18
    TagVariant             Tag = 0x19
    TagCommonBlock         Tag = 0x1a
    TagCommonInclusion     Tag = 0x1b
    TagNamespace           Tag = 0x1c
    TagImportedModule      Tag = 0x1d
    TagCondition           Tag = 0x1f
    TagSharedLibrary       Tag = 0x20
    TagSubrangeType        Tag = 0x21
    TagWithStmt            Tag = 0x22
    TagPtrToMemberType     Tag = 0x23
    TagTemplateTypeParameter Tag = 0x2f
    TagTemplateValueParameter Tag = 0x30
    TagTemplateAlias       Tag = 0x31
    TagObjectPointer       Tag = 0x32
    TagTypeUnit            Tag = 0x33
    TagRvalueReferenceType Tag = 0x34
    TagVariantPart         Tag = 0x35
    TagVariable            Tag = 0x34
    TagVolatileType        Tag = 0x35
)

常用 Tag 说明

  • TagCompileUnit:编译单元(根节点)
  • TagSubprogram:函数/过程
  • TagVariable:变量
  • TagStructType:结构体类型
  • TagArrayType:数组类型
  • TagPointerType:指针类型
  • TagTypedef:类型定义
  • TagInlinedSubroutine:内联函数

属性(Attr)

常见 Attr 常量

const (
    AttrSibling        Attr = 0x01
    AttrLocation       Attr = 0x02
    AttrName           Attr = 0x03
    AttrOrdering       Attr = 0x09
    AttrByteSize       Attr = 0x0b
    AttrBitOffset      Attr = 0x0c
    AttrBitSize        Attr = 0x0d
    AttrStmtList       Attr = 0x10
    AttrLowpc          Attr = 0x11
    AttrHighpc         Attr = 0x12
    AttrLanguage       Attr = 0x13
    AttrDiscr          Attr = 0x15
    AttrDiscrValue     Attr = 0x16
    AttrVisibility     Attr = 0x17
    AttrImport         Attr = 0x18
    AttrStringLength   Attr = 0x19
    AttrCommon         Attr = 0x1a
    AttrCompDir        Attr = 0x1b
    AttrConstValue     Attr = 0x1c
    AttrContainingType Attr = 0x1d
    AttrDefaultAttr    Attr = 0x1e
    AttrFriends        Attr = 0x1f
    AttrIdentifierCase Attr = 0x20
    AttrMacroInfo      Attr = 0x21
    AttrNamelistItem   Attr = 0x22
    AttrPriority       Attr = 0x23
    AttrProducer       Attr = 0x25
    AttrPrototyped     Attr = 0x27
    AttrReturnAddr     Attr = 0x2a
    AttrStartScope     Attr = 0x2c
    AttrStrideSize     Attr = 0x2e
    AttrUpperBound     Attr = 0x2f
    AttrAbstractOrigin Attr = 0x31
    AttrAccessibility  Attr = 0x32
    AttrAddressClass   Attr = 0x33
    AttrArtificial     Attr = 0x34
    AttrBaseTypes      Attr = 0x35
    AttrCallingConvention Attr = 0x36
    AttrCount          Attr = 0x37
    AttrDataMemberLoc  Attr = 0x38
    AttrDeclColumn     Attr = 0x39
    AttrDeclFile       Attr = 0x3a
    AttrDeclLine       Attr = 0x3b
    AttrDeclaration    Attr = 0x3c
    AttrDiscrList      Attr = 0x3d
    AttrEncoding       Attr = 0x3e
    AttrExternal       Attr = 0x3f
    AttrFrameBase      Attr = 0x40
    AttrFriend         Attr = 0x41
    AttrIdentifierPointer Attr = 0x42
    AttrImplicit       Attr = 0x43
    AttrImportName     Attr = 0x44
    AttrInline         Attr = 0x45
    AttrIsOptional     Attr = 0x46
    AttrLowerBound     Attr = 0x47
    AttrLowerBoundReference Attr = 0x48
    AttrMemberType     Attr = 0x49
    AttrObjectPointer  Attr = 0x4a
    AttrOrdering       Attr = 0x4b
    AttrOwned          Attr = 0x4c
    AttrPictureString  Attr = 0x4d
    AttrPrivate        Attr = 0x4e
    AttrProducer       Attr = 0x4f
    AttrProtected      Attr = 0x50
    AttrPrototyped     Attr = 0x51
    AttrPublic         Attr = 0x52
    AttrPUBNAME        Attr = 0x53
    AttrReturnAddr     Attr = 0x54
    AttrSegment        Attr = 0x55
    AttrSibling        Attr = 0x56
    AttrSignature      Attr = 0x57
    AttrSpecification  Attr = 0x58
    AttrStartScope     Attr = 0x59
    AttrStmtList       Attr = 0x5a
    AttrStride         Attr = 0x5b
    AttrStringLength   Attr = 0x5c
    AttrTrampoline     Attr = 0x5d
    AttrType           Attr = 0x49
    AttrUpperBound     Attr = 0x5f
    AttrUpperBoundReference Attr = 0x60
    AttrVirtuality     Attr = 0x61
    AttrVtableElemLoc Attr = 0x62
    AttrRanges         Attr = 0x64
)

常用 Attr 说明

  • AttrName:名称
  • AttrLowpc / AttrHighpc:地址范围
  • AttrByteSize:字节大小
  • AttrType:类型引用
  • AttrDeclFile / AttrDeclLine:声明位置
  • AttrCompDir:编译目录
  • AttrProducer:编译器信息
  • AttrLanguage:编程语言

完整示例

示例 1:读取 DWARF 数据

package main

import (
    "debug/dwarf"
    "debug/elf"
    "fmt"
    "io"
    "log"
)

func main() {
    // 1. 打开 ELF 文件
    f, err := elf.Open("myprogram")
    if err != nil {
        log.Fatal(err)
    }
    defer f.Close()
    
    // 2. 读取 DWARF 数据
    data, err := f.DWARF()
    if err != nil {
        log.Fatal(err)
    }
    
    // 3. 创建读取器
    reader := data.Reader()
    
    // 4. 遍历所有条目
    for {
        entry, err := reader.Next()
        if err == io.EOF {
            break
        }
        if err != nil {
            log.Fatal(err)
        }
        
        // 跳过没有名称的条目
        name := entry.Val(dwarf.AttrName)
        if name == nil {
            continue
        }
        
        // 显示条目信息
        fmt.Printf("Tag: %s, Name: %v\n", entry.Tag, name)
    }
}

示例 2:提取函数信息

package main

import (
    "debug/dwarf"
    "debug/elf"
    "fmt"
    "io"
    "log"
)

func main() {
    // 打开 ELF 文件
    f, err := elf.Open("myprogram")
    if err != nil {
        log.Fatal(err)
    }
    defer f.Close()
    
    // 读取 DWARF 数据
    data, err := f.DWARF()
    if err != nil {
        log.Fatal(err)
    }
    
    // 创建读取器
    reader := data.Reader()
    
    // 查找所有函数
    for {
        entry, err := reader.Next()
        if err == io.EOF {
            break
        }
        if err != nil {
            log.Fatal(err)
        }
        
        // 查找子程序(函数)
        if entry.Tag == dwarf.TagSubprogram {
            name := entry.Val(dwarf.AttrName)
            lowpc := entry.Val(dwarf.AttrLowpc)
            highpc := entry.Val(dwarf.AttrHighpc)
            
            if name != nil {
                fmt.Printf("函数:%s\n", name)
                if lowpc != nil && highpc != nil {
                    fmt.Printf("  地址范围:0x%x - 0x%x\n", lowpc, highpc)
                }
                
                // 获取声明位置
                declFile := entry.Val(dwarf.AttrDeclFile)
                declLine := entry.Val(dwarf.AttrDeclLine)
                if declLine != nil {
                    fmt.Printf("  声明位置:文件%v, 行%v\n", declFile, declLine)
                }
            }
        }
        
        // 如果有子条目,跳过
        if entry.Children {
            reader.SkipChildren()
        }
    }
}

示例 3:提取类型信息

package main

import (
    "debug/dwarf"
    "debug/elf"
    "fmt"
    "io"
    "log"
)

func main() {
    f, err := elf.Open("myprogram")
    if err != nil {
        log.Fatal(err)
    }
    defer f.Close()
    
    data, err := f.DWARF()
    if err != nil {
        log.Fatal(err)
    }
    
    reader := data.Reader()
    
    // 查找所有类型定义
    for {
        entry, err := reader.Next()
        if err == io.EOF {
            break
        }
        if err != nil {
            log.Fatal(err)
        }
        
        // 查找类型定义
        switch entry.Tag {
        case dwarf.TagStructType:
            name := entry.Val(dwarf.AttrName)
            byteSize := entry.Val(dwarf.AttrByteSize)
            
            if name != nil {
                fmt.Printf("结构体:%v", name)
                if byteSize != nil {
                    fmt.Printf(" (大小:%v 字节)", byteSize)
                }
                fmt.Println()
                
                // 读取成员
                if entry.Children {
                    readStructMembers(reader)
                }
            }
            
        case dwarf.TagTypedef:
            name := entry.Val(dwarf.AttrName)
            if name != nil {
                fmt.Printf("类型定义:%v\n", name)
            }
            
        case dwarf.TagArrayType:
            name := entry.Val(dwarf.AttrName)
            byteSize := entry.Val(dwarf.AttrByteSize)
            
            if name != nil {
                fmt.Printf("数组:%v", name)
                if byteSize != nil {
                    fmt.Printf(" (大小:%v 字节)", byteSize)
                }
                fmt.Println()
            }
        }
        
        // 跳过子条目(已手动处理)
        if entry.Children {
            reader.SkipChildren()
        }
    }
}

// 读取结构体成员
func readStructMembers(reader *dwarf.Reader) {
    depth := 1
    for depth > 0 {
        entry, err := reader.Next()
        if err != nil {
            return
        }
        
        if entry == nil {
            depth--
            continue
        }
        
        // 进入子条目
        if entry.Children {
            depth++
        }
        
        // 处理成员
        if entry.Tag == dwarf.TagMember {
            name := entry.Val(dwarf.AttrName)
            byteSize := entry.Val(dwarf.AttrByteSize)
            
            if name != nil {
                fmt.Printf("  成员:%v", name)
                if byteSize != nil {
                    fmt.Printf(" (%v 字节)", byteSize)
                }
                fmt.Println()
            }
        }
        
        // 退出子条目
        if !entry.Children && depth > 0 {
            // 继续
        }
    }
}

示例 4:地址到源码行映射

package main

import (
    "debug/dwarf"
    "debug/elf"
    "fmt"
    "log"
)

func main() {
    f, err := elf.Open("myprogram")
    if err != nil {
        log.Fatal(err)
    }
    defer f.Close()
    
    data, err := f.DWARF()
    if err != nil {
        log.Fatal(err)
    }
    
    // 测试地址
    testPC := uint64(0x401000)
    
    // 地址到源码行
    file, line, fn, err := data.PCToLine(testPC)
    if err != nil {
        fmt.Printf("地址 0x%x 无源码信息\n", testPC)
    } else {
        fmt.Printf("地址 0x%x:\n", testPC)
        fmt.Printf("  文件:%s\n", file)
        fmt.Printf("  行号:%d\n", line)
        if fn != nil {
            fmt.Printf("  函数:%s\n", fn.Name)
        }
    }
    
    // 地址到函数
    fn, err := data.PCToFunc(testPC)
    if err != nil {
        fmt.Printf("地址 0x%x 无函数信息\n", testPC)
    } else {
        fmt.Printf("\n函数信息:\n")
        fmt.Printf("  名称:%s\n", fn.Name)
        fmt.Printf("  入口:0x%x\n", fn.Entry)
        fmt.Printf("  结束:0x%x\n", fn.End)
    }
    
    // 获取函数的地址范围
    reader := data.Reader()
    for {
        entry, err := reader.Next()
        if err != nil {
            break
        }
        
        if entry.Tag == dwarf.TagSubprogram {
            ranges, err := data.Ranges(entry)
            if err != nil {
                continue
            }
            
            name := entry.Val(dwarf.AttrName)
            if name != nil && len(ranges) > 0 {
                fmt.Printf("\n函数 %s 的地址范围:\n", name)
                for _, r := range ranges {
                    fmt.Printf("  0x%x - 0x%x\n", r.Start, r.End)
                }
            }
        }
        
        if entry.Children {
            reader.SkipChildren()
        }
    }
}

示例 5:读取行号表

package main

import (
    "debug/dwarf"
    "debug/elf"
    "fmt"
    "io"
    "log"
)

func main() {
    f, err := elf.Open("myprogram")
    if err != nil {
        log.Fatal(err)
    }
    defer f.Close()
    
    data, err := f.DWARF()
    if err != nil {
        log.Fatal(err)
    }
    
    reader := data.Reader()
    
    // 查找编译单元
    for {
        entry, err := reader.Next()
        if err == io.EOF {
            break
        }
        if err != nil {
            log.Fatal(err)
        }
        
        if entry.Tag == dwarf.TagCompileUnit {
            // 获取行号读取器
            lineReader, err := data.LineReader(entry)
            if err != nil {
                continue
            }
            
            // 读取所有行号信息
            var row dwarf.LineRow
            for {
                err := lineReader.Next(&row)
                if err == io.EOF {
                    break
                }
                if err != nil {
                    log.Printf("读取行号失败:%v", err)
                    break
                }
                
                // 显示行号信息
                if row.EndSequence {
                    fmt.Printf("序列结束 at 0x%x\n", row.Address)
                } else {
                    fmt.Printf("0x%x: %s:%d:%d", 
                        row.Address,
                        row.File.Name,
                        row.Line,
                        row.Column)
                    
                    if row.IsStmt {
                        fmt.Printf(" (语句开始)")
                    }
                    if row.BasicBlock {
                        fmt.Printf(" (基本块)")
                    }
                    fmt.Println()
                }
            }
        }
        
        if entry.Children {
            reader.SkipChildren()
        }
    }
}

示例 6:遍历所有类型

package main

import (
    "debug/dwarf"
    "debug/elf"
    "fmt"
    "log"
)

func main() {
    f, err := elf.Open("myprogram")
    if err != nil {
        log.Fatal(err)
    }
    defer f.Close()
    
    data, err := f.DWARF()
    if err != nil {
        log.Fatal(err)
    }
    
    // 获取所有类型
    types := data.Types()
    
    fmt.Println("程序中的类型:")
    count := 0
    
    for typ := range types {
        count++
        
        // 显示类型信息
        fmt.Printf("\n%d. %s\n", count, typ.String())
        
        // 显示通用信息
        common := typ.Common()
        fmt.Printf("   大小:%d 字节\n", common.ByteSize)
        fmt.Printf("   偏移:0x%x\n", common.Offset)
        
        // 根据具体类型显示详细信息
        switch t := typ.(type) {
        case *dwarf.StructType:
            fmt.Printf("   结构体成员:\n")
            for _, field := range t.Field {
                fmt.Printf("     - %s (偏移:%d)\n", 
                    field.Name, field.ByteOffset)
            }
            
        case *dwarf.ArrayType:
            fmt.Printf("   数组:长度=%d, 元素大小=%d\n", 
                t.Count, t.Type.Common().ByteSize)
            
        case *dwarf.PtrType:
            fmt.Printf("   指针类型,指向:%s\n", t.Type.String())
            
        case *dwarf.BaseType:
            fmt.Printf("   基本类型:编码=%d\n", t.Encoding)
        }
    }
    
    fmt.Printf("\n总共 %d 个类型\n", count)
}

示例 7:查找特定类型

package main

import (
    "debug/dwarf"
    "debug/elf"
    "fmt"
    "log"
)

func findTypeByName(data *dwarf.Data, name string) (dwarf.Type, error) {
    // 方法 1:使用 LookupType
    offset := data.LookupType(name)
    if offset != 0 {
        return data.Type(offset)
    }
    
    // 方法 2:手动查找
    reader := data.Reader()
    for {
        entry, err := reader.Next()
        if err != nil {
            return nil, err
        }
        
        if entry == nil {
            break
        }
        
        entryName := entry.Val(dwarf.AttrName)
        if entryName != nil && entryName.(string) == name {
            // 找到类型
            typeOffset := entry.Val(dwarf.AttrType)
            if typeOffset != nil {
                return data.Type(typeOffset.(dwarf.Offset))
            }
        }
        
        if entry.Children {
            reader.SkipChildren()
        }
    }
    
    return nil, fmt.Errorf("未找到类型:%s", name)
}

func main() {
    f, err := elf.Open("myprogram")
    if err != nil {
        log.Fatal(err)
    }
    defer f.Close()
    
    data, err := f.DWARF()
    if err != nil {
        log.Fatal(err)
    }
    
    // 查找特定类型
    typeName := "main.MyStruct"
    typ, err := findTypeByName(data, typeName)
    if err != nil {
        fmt.Printf("未找到类型:%s\n", typeName)
    } else {
        fmt.Printf("找到类型:%s\n", typ.String())
        fmt.Printf("大小:%d 字节\n", typ.Size())
        
        // 如果是结构体,显示详细信息
        if structType, ok := typ.(*dwarf.StructType); ok {
            fmt.Printf("结构体字段:\n")
            for _, field := range structType.Field {
                fmt.Printf("  - %s: %s (偏移:%d)\n", 
                    field.Name, 
                    field.Type.String(),
                    field.ByteOffset)
            }
        }
    }
}

实用工具函数

示例 8:DWARF 信息提取工具

package main

import (
    "debug/dwarf"
    "debug/elf"
    "fmt"
    "io"
    "log"
    "os"
    "strings"
)

// DWARFInfo DWARF 信息提取器
type DWARFInfo struct {
    data *dwarf.Data
}

// NewDWARFInfo 创建 DWARF 信息提取器
func NewDWARFInfo(filename string) (*DWARFInfo, error) {
    f, err := elf.Open(filename)
    if err != nil {
        return nil, err
    }
    defer f.Close()
    
    data, err := f.DWARF()
    if err != nil {
        return nil, err
    }
    
    return &DWARFInfo{data: data}, nil
}

// ListFunctions 列出所有函数
func (d *DWARFInfo) ListFunctions() error {
    reader := d.data.Reader()
    
    for {
        entry, err := reader.Next()
        if err == io.EOF {
            break
        }
        if err != nil {
            return err
        }
        
        if entry.Tag == dwarf.TagSubprogram {
            name := entry.Val(dwarf.AttrName)
            if name != nil {
                fmt.Printf("函数:%s\n", name)
            }
        }
        
        if entry.Children {
            reader.SkipChildren()
        }
    }
    
    return nil
}

// ListTypes 列出所有类型
func (d *DWARFInfo) ListTypes() error {
    types := d.data.Types()
    
    for typ := range types {
        fmt.Printf("类型:%s (大小:%d 字节)\n", 
            typ.String(), typ.Size())
    }
    
    return nil
}

// ListVariables 列出所有变量
func (d *DWARFInfo) ListVariables() error {
    reader := d.data.Reader()
    
    for {
        entry, err := reader.Next()
        if err == io.EOF {
            break
        }
        if err != nil {
            return err
        }
        
        if entry.Tag == dwarf.TagVariable {
            name := entry.Val(dwarf.AttrName)
            if name != nil {
                fmt.Printf("变量:%s\n", name)
            }
        }
        
        if entry.Children {
            reader.SkipChildren()
        }
    }
    
    return nil
}

// GetFunctionByAddress 根据地址获取函数
func (d *DWARFInfo) GetFunctionByAddress(pc uint64) error {
    fn, err := d.data.PCToFunc(pc)
    if err != nil {
        return fmt.Errorf("未找到函数:0x%x", pc)
    }
    
    fmt.Printf("地址 0x%x 属于函数:%s\n", pc, fn.Name)
    fmt.Printf("  范围:0x%x - 0x%x\n", fn.Entry, fn.End)
    
    return nil
}

// GetSourceLine 根据地址获取源码行
func (d *DWARFInfo) GetSourceLine(pc uint64) error {
    file, line, fn, err := d.data.PCToLine(pc)
    if err != nil {
        return fmt.Errorf("无源码信息:0x%x", pc)
    }
    
    fmt.Printf("地址 0x%x:\n", pc)
    fmt.Printf("  文件:%s\n", file)
    fmt.Printf("  行号:%d\n", line)
    if fn != nil {
        fmt.Printf("  函数:%s\n", fn.Name)
    }
    
    return nil
}

func main() {
    if len(os.Args) < 2 {
        log.Fatal("用法:program <elf-file>")
    }
    
    filename := os.Args[1]
    
    info, err := NewDWARFInfo(filename)
    if err != nil {
        log.Fatal(err)
    }
    
    // 命令行参数
    if len(os.Args) > 2 {
        command := os.Args[2]
        
        switch command {
        case "functions":
            info.ListFunctions()
        case "types":
            info.ListTypes()
        case "variables":
            info.ListVariables()
        default:
            // 假设是地址
            if strings.HasPrefix(command, "0x") {
                var pc uint64
                fmt.Sscanf(command, "0x%x", &pc)
                
                fmt.Println("函数信息:")
                info.GetFunctionByAddress(pc)
                
                fmt.Println("\n源码信息:")
                info.GetSourceLine(pc)
            }
        }
    } else {
        // 显示所有信息
        fmt.Println("=== 函数列表 ===")
        info.ListFunctions()
        
        fmt.Println("\n=== 类型列表 ===")
        info.ListTypes()
        
        fmt.Println("\n=== 变量列表 ===")
        info.ListVariables()
    }
}

安全最佳实践

✅ 推荐做法

  1. 始终检查错误

    entry, err := reader.Next()
    if err == io.EOF {
        break
    }
    if err != nil {
        return err
    }
    
  2. 处理 nil 值

    name := entry.Val(dwarf.AttrName)
    if name != nil {
        fmt.Printf("名称:%v\n", name)
    }
    
  3. 类型断言检查

    if name, ok := name.(string); ok {
        fmt.Printf("名称:%s\n", name)
    }
    
  4. 正确跳过子条目

    if entry.Children {
        reader.SkipChildren()
    }
    

❌ 不安全做法

  1. 不要忽略错误

    // ❌ 错误
    entry, _ := reader.Next()
    
    // ✅ 正确
    entry, err := reader.Next()
    if err != nil {
        // 处理错误
    }
    
  2. 不要假设字段存在

    // ❌ 错误
    name := entry.Val(dwarf.AttrName).(string)
    
    // ✅ 正确
    name := entry.Val(dwarf.AttrName)
    if name != nil {
        // 使用 name
    }
    

总结

核心类型

Data         // DWARF 数据
Entry        // 调试信息条目
Field        // 条目字段
Reader       // 条目读取器
Type         // 类型接口
CommonType   // 通用类型信息
LineReader   // 行号读取器
LineRow      // 行号信息
Func         // 函数信息
Range        // 地址范围

使用场景

场景推荐方法说明
读取 DWARFelf.DWARF()从 ELF 文件读取
遍历条目Reader.Next()遍历所有 DIE
获取类型Data.Types()获取所有类型
地址映射Data.PCToLine()地址到源码
函数查找Data.PCToFunc()地址到函数
类型查找Data.LookupType()按名称查找类型

DWARF 标签分类

分类Tag用途
编译单元TagCompileUnit根节点
函数TagSubprogram函数/过程
变量TagVariable变量
类型TagStructType结构体
类型TagArrayType数组
类型TagPointerType指针
类型TagTypedef类型定义

参考资料


最后更新:2026-04-03
Go 版本:Go 1.23+