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.TypeOffset:在 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()
}
}
安全最佳实践
✅ 推荐做法
-
始终检查错误
entry, err := reader.Next() if err == io.EOF { break } if err != nil { return err } -
处理 nil 值
name := entry.Val(dwarf.AttrName) if name != nil { fmt.Printf("名称:%v\n", name) } -
类型断言检查
if name, ok := name.(string); ok { fmt.Printf("名称:%s\n", name) } -
正确跳过子条目
if entry.Children { reader.SkipChildren() }
❌ 不安全做法
-
不要忽略错误
// ❌ 错误 entry, _ := reader.Next() // ✅ 正确 entry, err := reader.Next() if err != nil { // 处理错误 } -
不要假设字段存在
// ❌ 错误 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 // 地址范围
使用场景
| 场景 | 推荐方法 | 说明 |
|---|---|---|
| 读取 DWARF | elf.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+