aboutsummaryrefslogtreecommitdiff
path: root/src/pkg/debug
diff options
context:
space:
mode:
authorRuss Cox <rsc@golang.org>2009-09-15 21:58:45 -0700
committerRuss Cox <rsc@golang.org>2009-09-15 21:58:45 -0700
commitf249c4114c11b2f236395b08c66afc2a2be4c303 (patch)
tree3b579bd5c89109761cd6d7dbe293397fffbfab03 /src/pkg/debug
parentaaaa1fc69b33e39284df07d09047494d824395f3 (diff)
downloadgo-f249c4114c11b2f236395b08c66afc2a2be4c303.tar.xz
basic DWARF reading.
R=r DELTA=949 (949 added, 0 deleted, 0 changed) OCL=34676 CL=34678
Diffstat (limited to 'src/pkg/debug')
-rw-r--r--src/pkg/debug/dwarf/Makefile15
-rw-r--r--src/pkg/debug/dwarf/buf.go157
-rw-r--r--src/pkg/debug/dwarf/const.go352
-rw-r--r--src/pkg/debug/dwarf/entry.go284
-rw-r--r--src/pkg/debug/dwarf/open.go79
-rw-r--r--src/pkg/debug/dwarf/unit.go63
6 files changed, 950 insertions, 0 deletions
diff --git a/src/pkg/debug/dwarf/Makefile b/src/pkg/debug/dwarf/Makefile
new file mode 100644
index 0000000000..dfa0d90099
--- /dev/null
+++ b/src/pkg/debug/dwarf/Makefile
@@ -0,0 +1,15 @@
+# Copyright 2009 The Go Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style
+# license that can be found in the LICENSE file.
+
+include $(GOROOT)/src/Make.$(GOARCH)
+
+TARG=debug/dwarf
+GOFILES=\
+ buf.go\
+ const.go\
+ entry.go\
+ open.go\
+ unit.go\
+
+include $(GOROOT)/src/Make.pkg
diff --git a/src/pkg/debug/dwarf/buf.go b/src/pkg/debug/dwarf/buf.go
new file mode 100644
index 0000000000..a9d45e527f
--- /dev/null
+++ b/src/pkg/debug/dwarf/buf.go
@@ -0,0 +1,157 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Buffered reading and decoding of DWARF data streams.
+
+package dwarf
+
+import (
+ "debug/binary";
+ "os";
+ "strconv";
+)
+
+// Data buffer being decoded.
+type buf struct {
+ dwarf *Data;
+ order binary.ByteOrder;
+ name string;
+ off Offset;
+ data []byte;
+ addrsize int;
+ err os.Error;
+}
+
+func makeBuf(d *Data, name string, off Offset, data []byte, addrsize int) buf {
+ return buf{d, d.order, name, off, data, addrsize, nil}
+}
+
+func (b *buf) uint8() uint8 {
+ if len(b.data) < 1 {
+ b.error("underflow");
+ return 0;
+ }
+ val := b.data[0];
+ b.data = b.data[1:len(b.data)];
+ b.off++;
+ return val;
+}
+
+func (b *buf) bytes(n int) []byte {
+ if len(b.data) < n {
+ b.error("underflow");
+ return nil;
+ }
+ data := b.data[0:n];
+ b.data = b.data[n:len(b.data)];
+ b.off += Offset(n);
+ return data;
+}
+
+func (b *buf) skip(n int) {
+ b.bytes(n);
+}
+
+func (b *buf) string() string {
+ for i := 0; i < len(b.data); i++ {
+ if b.data[i] == 0 {
+ s := string(b.data[0:i]);
+ b.data = b.data[i+1:len(b.data)];
+ b.off += Offset(i+1);
+ return s;
+ }
+ }
+ b.error("underflow");
+ return "";
+}
+
+func (b *buf) uint16() uint16{
+ a := b.bytes(2);
+ if a == nil {
+ return 0;
+ }
+ return b.order.Uint16(a);
+}
+
+func (b *buf) uint32() uint32 {
+ a := b.bytes(4);
+ if a == nil {
+ return 0;
+ }
+ return b.order.Uint32(a);
+}
+
+func (b *buf) uint64() uint64 {
+ a := b.bytes(8);
+ if a == nil {
+ return 0;
+ }
+ return b.order.Uint64(a);
+}
+
+// Read a varint, which is 7 bits per byte, little endian.
+// the 0x80 bit means read another byte.
+func (b *buf) varint() (c uint64, bits uint) {
+ for i := 0; i < len(b.data); i++ {
+ byte := b.data[i];
+ c |= uint64(byte&0x7F) << bits;
+ bits += 7;
+ if byte&0x80 == 0 {
+ b.off += Offset(i+1);
+ b.data = b.data[i+1:len(b.data)];
+ return c, bits;
+ }
+ }
+ return 0, 0;
+}
+
+// Unsigned int is just a varint.
+func (b *buf) uint() uint64 {
+ x, _ := b.varint();
+ return x;
+}
+
+// Signed int is a sign-extended varint.
+func (b *buf) int() int64 {
+ ux, bits := b.varint();
+ x := int64(ux);
+ if x & (1<<(bits-1)) != 0 {
+ x |= -1<<bits;
+ }
+ return x;
+}
+
+// Address-sized uint.
+func (b *buf) addr() uint64 {
+ switch b.addrsize {
+ case 1:
+ return uint64(b.uint8());
+ case 2:
+ return uint64(b.uint16());
+ case 4:
+ return uint64(b.uint32());
+ case 8:
+ return uint64(b.uint64());
+ }
+ b.error("unknown address size");
+ return 0;
+}
+
+func (b *buf) error(s string) {
+ if b.err == nil {
+ b.data = nil;
+ b.err = DecodeError{b.name, b.off, s}
+ }
+}
+
+type DecodeError struct {
+ Name string;
+ Offset Offset;
+ Error string;
+}
+
+func (e DecodeError) String() string {
+ return "decoding dwarf section " + e.Name + " at offset " + strconv.Itoa64(int64(e.Offset)) + ": " + e.Error;
+}
+
diff --git a/src/pkg/debug/dwarf/const.go b/src/pkg/debug/dwarf/const.go
new file mode 100644
index 0000000000..73abdb66a2
--- /dev/null
+++ b/src/pkg/debug/dwarf/const.go
@@ -0,0 +1,352 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Constants
+
+package dwarf
+
+import "strconv"
+
+// An Attr identifies the attribute type in a DWARF Entry's Field.
+type Attr uint32
+
+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;
+ AttrCommonRef Attr = 0x1A;
+ AttrCompDir Attr = 0x1B;
+ AttrConstValue Attr = 0x1C;
+ AttrContainingType Attr = 0x1D;
+ AttrDefaultValue Attr = 0x1E;
+ AttrInline Attr = 0x20;
+ AttrIsOptional Attr = 0x21;
+ AttrLowerBound Attr = 0x22;
+ AttrProducer Attr = 0x25;
+ AttrPrototyped Attr = 0x27;
+ AttrReturnAddr Attr = 0x2A;
+ AttrStartScope Attr = 0x2C;
+ AttrStrideSize Attr = 0x2E;
+ AttrUpperBound Attr = 0x2F;
+ AttrAbstractOrigin Attr = 0x31;
+ AttrAccessibility Attr = 0x32;
+ AttrAddrClass Attr = 0x33;
+ AttrArtificial Attr = 0x34;
+ AttrBaseTypes Attr = 0x35;
+ AttrCalling 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;
+ AttrIdentifierCase Attr = 0x42;
+ AttrMacroInfo Attr = 0x43;
+ AttrNamelistItem Attr = 0x44;
+ AttrPriority Attr = 0x45;
+ AttrSegment Attr = 0x46;
+ AttrSpecification Attr = 0x47;
+ AttrStaticLink Attr = 0x48;
+ AttrType Attr = 0x49;
+ AttrUseLocation Attr = 0x4A;
+ AttrVarParam Attr = 0x4B;
+ AttrVirtuality Attr = 0x4C;
+ AttrVtableElemLoc Attr = 0x4D;
+ AttrAllocated Attr = 0x4E;
+ AttrAssociated Attr = 0x4F;
+ AttrDataLocation Attr = 0x50;
+ AttrStride Attr = 0x51;
+ AttrEntrypc Attr = 0x52;
+ AttrUseUTF8 Attr = 0x53;
+ AttrExtension Attr = 0x54;
+ AttrRanges Attr = 0x55;
+ AttrTrampoline Attr = 0x56;
+ AttrCallColumn Attr = 0x57;
+ AttrCallFile Attr = 0x58;
+ AttrCallLine Attr = 0x59;
+ AttrDescription Attr = 0x5A;
+)
+
+var attrNames = [...]string {
+ AttrSibling: "Sibling",
+ AttrLocation: "Location",
+ AttrName: "Name",
+ AttrOrdering: "Ordering",
+ AttrByteSize: "ByteSize",
+ AttrBitOffset: "BitOffset",
+ AttrBitSize: "BitSize",
+ AttrStmtList: "StmtList",
+ AttrLowpc: "Lowpc",
+ AttrHighpc: "Highpc",
+ AttrLanguage: "Language",
+ AttrDiscr: "Discr",
+ AttrDiscrValue: "DiscrValue",
+ AttrVisibility: "Visibility",
+ AttrImport: "Import",
+ AttrStringLength: "StringLength",
+ AttrCommonRef: "CommonRef",
+ AttrCompDir: "CompDir",
+ AttrConstValue: "ConstValue",
+ AttrContainingType: "ContainingType",
+ AttrDefaultValue: "DefaultValue",
+ AttrInline: "Inline",
+ AttrIsOptional: "IsOptional",
+ AttrLowerBound: "LowerBound",
+ AttrProducer: "Producer",
+ AttrPrototyped: "Prototyped",
+ AttrReturnAddr: "ReturnAddr",
+ AttrStartScope: "StartScope",
+ AttrStrideSize: "StrideSize",
+ AttrUpperBound: "UpperBound",
+ AttrAbstractOrigin: "AbstractOrigin",
+ AttrAccessibility: "Accessibility",
+ AttrAddrClass: "AddrClass",
+ AttrArtificial: "Artificial",
+ AttrBaseTypes: "BaseTypes",
+ AttrCalling: "Calling",
+ AttrCount: "Count",
+ AttrDataMemberLoc: "DataMemberLoc",
+ AttrDeclColumn: "DeclColumn",
+ AttrDeclFile: "DeclFile",
+ AttrDeclLine: "DeclLine",
+ AttrDeclaration: "Declaration",
+ AttrDiscrList: "DiscrList",
+ AttrEncoding: "Encoding",
+ AttrExternal: "External",
+ AttrFrameBase: "FrameBase",
+ AttrFriend: "Friend",
+ AttrIdentifierCase: "IdentifierCase",
+ AttrMacroInfo: "MacroInfo",
+ AttrNamelistItem: "NamelistItem",
+ AttrPriority: "Priority",
+ AttrSegment: "Segment",
+ AttrSpecification: "Specification",
+ AttrStaticLink: "StaticLink",
+ AttrType: "Type",
+ AttrUseLocation: "UseLocation",
+ AttrVarParam: "VarParam",
+ AttrVirtuality: "Virtuality",
+ AttrVtableElemLoc: "VtableElemLoc",
+ AttrAllocated: "Allocated",
+ AttrAssociated: "Associated",
+ AttrDataLocation: "DataLocation",
+ AttrStride: "Stride",
+ AttrEntrypc: "Entrypc",
+ AttrUseUTF8: "UseUTF8",
+ AttrExtension: "Extension",
+ AttrRanges: "Ranges",
+ AttrTrampoline: "Trampoline",
+ AttrCallColumn: "CallColumn",
+ AttrCallFile: "CallFile",
+ AttrCallLine: "CallLine",
+ AttrDescription: "Description",
+}
+
+func (a Attr) String() string {
+ if int(a) < len(attrNames) {
+ s := attrNames[a];
+ if s != "" {
+ return s;
+ }
+ }
+ return strconv.Itoa(int(a));
+}
+
+func (a Attr) GoString() string {
+ if int(a) < len(attrNames) {
+ s := attrNames[a];
+ if s != "" {
+ return "dwarf.Attr" + s;
+ }
+ }
+ return "dwarf.Attr(" + strconv.Itoa64(int64(a)) + ")";
+}
+
+// A format is a DWARF data encoding format.
+type format uint32
+
+const (
+ // value formats
+ formAddr format = 0x01;
+ formDwarfBlock2 format = 0x03;
+ formDwarfBlock4 format = 0x04;
+ formData2 format = 0x05;
+ formData4 format = 0x06;
+ formData8 format = 0x07;
+ formString format = 0x08;
+ formDwarfBlock format = 0x09;
+ formDwarfBlock1 format = 0x0A;
+ formData1 format = 0x0B;
+ formFlag format = 0x0C;
+ formSdata format = 0x0D;
+ formStrp format = 0x0E;
+ formUdata format = 0x0F;
+ formRefAddr format = 0x10;
+ formRef1 format = 0x11;
+ formRef2 format = 0x12;
+ formRef4 format = 0x13;
+ formRef8 format = 0x14;
+ formRefUdata format = 0x15;
+ formIndirect format = 0x16;
+)
+
+// A Tag is the classification (the type) of an Entry.
+type Tag uint32
+
+const (
+ TagArrayType Tag = 0x01;
+ TagClassType Tag = 0x02;
+ TagEntryPoint Tag = 0x03;
+ TagEnumerationType Tag = 0x04;
+ TagFormalParameter Tag = 0x05;
+ TagImportedDeclaration Tag = 0x08;
+ TagLabel Tag = 0x0A;
+ TagLexDwarfBlock Tag = 0x0B;
+ TagMember Tag = 0x0D;
+ TagPointerType Tag = 0x0F;
+ TagReferenceType Tag = 0x10;
+ TagCompileUnit Tag = 0x11;
+ TagStringType Tag = 0x12;
+ TagStructType Tag = 0x13;
+ TagSubroutineType Tag = 0x15;
+ TagTypedef Tag = 0x16;
+ TagUnionType Tag = 0x17;
+ TagUnspecifiedParameters Tag = 0x18;
+ TagVariant Tag = 0x19;
+ TagCommonDwarfBlock Tag = 0x1A;
+ TagCommonInclusion Tag = 0x1B;
+ TagInheritance Tag = 0x1C;
+ TagInlinedSubroutine Tag = 0x1D;
+ TagModule Tag = 0x1E;
+ TagPtrToMemberType Tag = 0x1F;
+ TagSetType Tag = 0x20;
+ TagSubrangeType Tag = 0x21;
+ TagWithStmt Tag = 0x22;
+ TagAccessDeclaration Tag = 0x23;
+ TagBaseType Tag = 0x24;
+ TagCatchDwarfBlock Tag = 0x25;
+ TagConstType Tag = 0x26;
+ TagConstant Tag = 0x27;
+ TagEnumerator Tag = 0x28;
+ TagFileType Tag = 0x29;
+ TagFriend Tag = 0x2A;
+ TagNamelist Tag = 0x2B;
+ TagNamelistItem Tag = 0x2C;
+ TagPackedType Tag = 0x2D;
+ TagSubprogram Tag = 0x2E;
+ TagTemplateTypeParameter Tag = 0x2F;
+ TagTemplateValueParameter Tag = 0x30;
+ TagThrownType Tag = 0x31;
+ TagTryDwarfBlock Tag = 0x32;
+ TagVariantPart Tag = 0x33;
+ TagVariable Tag = 0x34;
+ TagVolatileType Tag = 0x35;
+ TagDwarfProcedure Tag = 0x36;
+ TagRestrictType Tag = 0x37;
+ TagInterfaceType Tag = 0x38;
+ TagNamespace Tag = 0x39;
+ TagImportedModule Tag = 0x3A;
+ TagUnspecifiedType Tag = 0x3B;
+ TagPartialUnit Tag = 0x3C;
+ TagImportedUnit Tag = 0x3D;
+ TagMutableType Tag = 0x3E;
+)
+
+var tagNames = [...]string {
+ TagArrayType: "ArrayType",
+ TagClassType: "ClassType",
+ TagEntryPoint: "EntryPoint",
+ TagEnumerationType: "EnumerationType",
+ TagFormalParameter: "FormalParameter",
+ TagImportedDeclaration: "ImportedDeclaration",
+ TagLabel: "Label",
+ TagLexDwarfBlock: "LexDwarfBlock",
+ TagMember: "Member",
+ TagPointerType: "PointerType",
+ TagReferenceType: "ReferenceType",
+ TagCompileUnit: "CompileUnit",
+ TagStringType: "StringType",
+ TagStructType: "StructType",
+ TagSubroutineType: "SubroutineType",
+ TagTypedef: "Typedef",
+ TagUnionType: "UnionType",
+ TagUnspecifiedParameters: "UnspecifiedParameters",
+ TagVariant: "Variant",
+ TagCommonDwarfBlock: "CommonDwarfBlock",
+ TagCommonInclusion: "CommonInclusion",
+ TagInheritance: "Inheritance",
+ TagInlinedSubroutine: "InlinedSubroutine",
+ TagModule: "Module",
+ TagPtrToMemberType: "PtrToMemberType",
+ TagSetType: "SetType",
+ TagSubrangeType: "SubrangeType",
+ TagWithStmt: "WithStmt",
+ TagAccessDeclaration: "AccessDeclaration",
+ TagBaseType: "BaseType",
+ TagCatchDwarfBlock: "CatchDwarfBlock",
+ TagConstType: "ConstType",
+ TagConstant: "Constant",
+ TagEnumerator: "Enumerator",
+ TagFileType: "FileType",
+ TagFriend: "Friend",
+ TagNamelist: "Namelist",
+ TagNamelistItem: "NamelistItem",
+ TagPackedType: "PackedType",
+ TagSubprogram: "Subprogram",
+ TagTemplateTypeParameter: "TemplateTypeParameter",
+ TagTemplateValueParameter: "TemplateValueParameter",
+ TagThrownType: "ThrownType",
+ TagTryDwarfBlock: "TryDwarfBlock",
+ TagVariantPart: "VariantPart",
+ TagVariable: "Variable",
+ TagVolatileType: "VolatileType",
+ TagDwarfProcedure: "DwarfProcedure",
+ TagRestrictType: "RestrictType",
+ TagInterfaceType: "InterfaceType",
+ TagNamespace: "Namespace",
+ TagImportedModule: "ImportedModule",
+ TagUnspecifiedType: "UnspecifiedType",
+ TagPartialUnit: "PartialUnit",
+ TagImportedUnit: "ImportedUnit",
+ TagMutableType: "MutableType",
+}
+
+func (t Tag) String() string {
+ if int(t) < len(tagNames) {
+ s := tagNames[t];
+ if s != "" {
+ return s;
+ }
+ }
+ return strconv.Itoa(int(t));
+}
+
+func (t Tag) GoString() string {
+ if int(t) < len(tagNames) {
+ s := tagNames[t];
+ if s != "" {
+ return "dwarf.Tag" + s;
+ }
+ }
+ return "dwarf.Tag(" + strconv.Itoa64(int64(t)) + ")";
+}
+
diff --git a/src/pkg/debug/dwarf/entry.go b/src/pkg/debug/dwarf/entry.go
new file mode 100644
index 0000000000..472ee91d8a
--- /dev/null
+++ b/src/pkg/debug/dwarf/entry.go
@@ -0,0 +1,284 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// DWARF debug information entry parser.
+// An entry is a sequence of data items of a given format.
+// The first word in the entry is an index into what DWARF
+// calls the ``abbreviation table.'' An abbreviation is really
+// just a type descriptor: it's an array of attribute tag/value format pairs.
+
+package dwarf
+
+import (
+ "os";
+ "strconv";
+)
+
+// a single entry's description: a sequence of attributes
+type abbrev struct {
+ tag Tag;
+ children bool;
+ field []afield;
+}
+
+type afield struct {
+ attr Attr;
+ fmt format;
+}
+
+// a map from entry format ids to their descriptions
+type abbrevTable map[uint32]abbrev
+
+// ParseAbbrev returns the abbreviation table that starts at byte off
+// in the .debug_abbrev section.
+func (d *Data) parseAbbrev(off uint32) (abbrevTable, os.Error) {
+ if m, ok := d.abbrevCache[off]; ok {
+ return m, nil;
+ }
+
+ data := d.abbrev;
+ if off > uint32(len(data)) {
+ data = nil;
+ } else {
+ data = data[off:len(data)];
+ }
+ b := makeBuf(d, "abbrev", 0, data, 0);
+
+ // Error handling is simplified by the buf getters
+ // returning an endless stream of 0s after an error.
+ m := make(abbrevTable);
+ for {
+ // Table ends with id == 0.
+ id := uint32(b.uint());
+ if id == 0 {
+ break;
+ }
+
+ // Walk over attributes, counting.
+ n := 0;
+ b1 := b; // Read from copy of b.
+ b1.uint();
+ b1.uint8();
+ for {
+ tag := b1.uint();
+ fmt := b1.uint();
+ if tag == 0 && fmt == 0 {
+ break;
+ }
+ n++;
+ }
+ if b1.err != nil {
+ return nil, b1.err;
+ }
+
+ // Walk over attributes again, this time writing them down.
+ var a abbrev;
+ a.tag = Tag(b.uint());
+ a.children = b.uint8() != 0;
+ a.field = make([]afield, n);
+ for i := range a.field {
+ a.field[i].attr = Attr(b.uint());
+ a.field[i].fmt = format(b.uint());
+ }
+ b.uint();
+ b.uint();
+
+ m[id] = a;
+ }
+ if b.err != nil {
+ return nil, b.err;
+ }
+ d.abbrevCache[off] = m;
+ return m, nil;
+}
+
+// An entry is a sequence of attribute/value pairs.
+type Entry struct {
+ Offset Offset; // offset of Entry in DWARF info
+ Tag Tag; // tag (kind of Entry)
+ Children bool; // whether Entry is followed by children
+ Field []Field;
+}
+
+// A Field is a single attribute/value pair in an Entry.
+type Field struct {
+ Attr Attr;
+ Val interface{};
+}
+
+// An Offset represents the location of an Entry within the DWARF info.
+// (See Reader.Seek.)
+type Offset uint32
+
+// Entry reads a single entry from buf, decoding
+// according to the given abbreviation table.
+func (b *buf) entry(atab abbrevTable, ubase Offset) *Entry {
+ off := b.off;
+ id := uint32(b.uint());
+ if id == 0 {
+ return &Entry{};
+ }
+ a, ok := atab[id];
+ if !ok {
+ b.error("unknown abbreviation table index");
+ return nil;
+ }
+ e := &Entry{
+ Offset: off,
+ Tag: a.tag,
+ Children: a.children,
+ Field: make([]Field, len(a.field))
+ };
+ for i := range e.Field {
+ e.Field[i].Attr = a.field[i].attr;
+ fmt := a.field[i].fmt;
+ if fmt == formIndirect {
+ fmt = format(b.uint());
+ }
+ var val interface{};
+ switch fmt {
+ default:
+ b.error("unknown entry attr format");
+
+ // address
+ case formAddr:
+ val = b.addr();
+
+ // block
+ case formDwarfBlock1:
+ val = b.bytes(int(b.uint8()));
+ case formDwarfBlock2:
+ val = b.bytes(int(b.uint16()));
+ case formDwarfBlock4:
+ val = b.bytes(int(b.uint32()));
+ case formDwarfBlock:
+ val = b.bytes(int(b.uint()));
+
+ // constant
+ case formData1:
+ val = uint64(b.uint8());
+ case formData2:
+ val = uint64(b.uint16());
+ case formData4:
+ val = uint64(b.uint32());
+ case formData8:
+ val = uint64(b.uint64());
+ case formSdata:
+ val = int64(b.int());
+ case formUdata:
+ val = uint64(b.uint());
+
+ // flag
+ case formFlag:
+ val = b.uint8() == 1;
+
+ // reference to other entry
+ case formRefAddr:
+ val = Offset(b.addr());
+ case formRef1:
+ val = Offset(b.uint8()) + ubase;
+ case formRef2:
+ val = Offset(b.uint16()) + ubase;
+ case formRef4:
+ val = Offset(b.uint32()) + ubase;
+ case formRef8:
+ val = Offset(b.uint64()) + ubase;
+ case formRefUdata:
+ val = Offset(b.uint()) + ubase;
+
+ // string
+ case formString:
+ val = b.string();
+ case formStrp:
+ off := b.uint32(); // offset into .debug_str
+ if b.err != nil {
+ return nil;
+ }
+ b1 := makeBuf(b.dwarf, "str", 0, b.dwarf.str, 0);
+ b1.skip(int(off));
+ val = b1.string();
+ if b1.err != nil {
+ b.err = b1.err;
+ return nil;
+ }
+ }
+ e.Field[i].Val = val;
+ }
+ if b.err != nil {
+ return nil;
+ }
+ return e;
+}
+
+// A Reader allows reading Entry structures from a DWARF ``info'' section.
+type Reader struct {
+ b buf;
+ d *Data;
+ err os.Error;
+ unit int;
+}
+
+// Reader returns a new Reader for Data.
+// The reader is positioned at byte offset 0 in the DWARF ``info'' section.
+func (d *Data) Reader() *Reader {
+ r := &Reader{d: d};
+ r.Seek(0);
+ return r;
+}
+
+// Seek positions the Reader at offset off in the encoded entry stream.
+// Offset 0 can be used to denote the first entry.
+func (r *Reader) Seek(off Offset) {
+ d := r.d;
+ r.err = nil;
+ if off == 0 {
+ if len(d.unit) == 0 {
+ return;
+ }
+ u := &d.unit[0];
+ r.unit = 0;
+ r.b = makeBuf(r.d, "info", u.off, u.data, u.addrsize);
+ return;
+ }
+
+ // TODO(rsc): binary search (maybe a new package)
+ var i int;
+ var u *unit;
+ for i = range d.unit {
+ u = &d.unit[i];
+ if u.off <= off && off < u.off+Offset(len(u.data)) {
+ r.unit = i;
+ r.b = makeBuf(r.d, "info", off, u.data[off-u.off:len(u.data)], u.addrsize);
+ return;
+ }
+ }
+ r.err = os.NewError("offset out of range");
+}
+
+// maybeNextUnit advances to the next unit if this one is finished.
+func (r *Reader) maybeNextUnit() {
+ for len(r.b.data) == 0 && r.unit < len(r.d.unit) {
+ r.unit++;
+ u := &r.d.unit[r.unit];
+ r.b = makeBuf(r.d, "info", u.off, u.data, u.addrsize);
+ }
+}
+
+// Next reads the next entry from the encoded entry stream.
+// It returns nil, nil when it reaches the end of the section.
+// It returns an error if the current offset is invalid or the data at the
+// offset cannot be decoded as a valid Entry.
+func (r *Reader) Next() (*Entry, os.Error) {
+ if r.err != nil {
+ return nil, r.err;
+ }
+ r.maybeNextUnit();
+ if len(r.b.data) == 0 {
+ return nil, nil;
+ }
+ u := &r.d.unit[r.unit];
+ e := r.b.entry(u.atable, u.base);
+ r.err = r.b.err;
+ return e, r.err;
+}
diff --git a/src/pkg/debug/dwarf/open.go b/src/pkg/debug/dwarf/open.go
new file mode 100644
index 0000000000..8694508386
--- /dev/null
+++ b/src/pkg/debug/dwarf/open.go
@@ -0,0 +1,79 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// This package provides access to DWARF debugging information
+// loaded from executable files, as defined in the DWARF 2.0 Standard
+// at http://dwarfstd.org/dwarf-2.0.0.pdf.
+package dwarf
+
+import (
+ "debug/binary";
+ "fmt";
+ "os";
+)
+
+// Data represents the DWARF debugging information
+// loaded from an executable file (for example, an ELF or Mach-O executable).
+type Data struct {
+ // raw data
+ abbrev []byte;
+ aranges []byte;
+ frame []byte;
+ info []byte;
+ line []byte;
+ pubnames []byte;
+ ranges []byte;
+ str []byte;
+
+ // parsed data
+ abbrevCache map[uint32] abbrevTable;
+ addrsize int;
+ order binary.ByteOrder;
+ unit []unit;
+}
+
+// New returns a new Data object initialized from the given parameters.
+// Clients should typically use [TODO(rsc): method to be named later] instead of calling
+// New directly.
+//
+// The []byte arguments are the data from the corresponding debug section
+// in the object file; for example, for an ELF object, abbrev is the contents of
+// the ".debug_abbrev" section.
+func New(abbrev, aranges, frame, info, line, pubnames, ranges, str []byte) (*Data, os.Error) {
+ d := &Data{
+ abbrev: abbrev,
+ aranges: aranges,
+ frame: frame,
+ info: info,
+ line: line,
+ pubnames: pubnames,
+ ranges: ranges,
+ str: str,
+ abbrevCache: make(map[uint32]abbrevTable),
+ };
+
+ // Sniff .debug_info to figure out byte order.
+ // bytes 4:6 are the version, a tiny 16-bit number (1, 2, 3).
+ if len(d.info) < 6 {
+ return nil, DecodeError{"info", Offset(len(d.info)), "too short"};
+ }
+ x, y := d.info[4], d.info[5];
+ switch {
+ case x == 0 && y == 0:
+ return nil, DecodeError{"info", 4, "unsupported version 0"};
+ case x == 0:
+ d.order = binary.BigEndian;
+ case y == 0:
+ d.order = binary.LittleEndian;
+ default:
+ return nil, DecodeError{"info", 4, "cannot determine byte order"};
+ }
+
+ u, err := d.parseUnits();
+ if err != nil {
+ return nil, err;
+ }
+ d.unit = u;
+ return d, nil;
+}
diff --git a/src/pkg/debug/dwarf/unit.go b/src/pkg/debug/dwarf/unit.go
new file mode 100644
index 0000000000..040151f39d
--- /dev/null
+++ b/src/pkg/debug/dwarf/unit.go
@@ -0,0 +1,63 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package dwarf
+
+import (
+ "os";
+ "strconv";
+)
+
+// DWARF debug info is split into a sequence of compilation units.
+// Each unit has its own abbreviation table and address size.
+
+type unit struct {
+ base Offset; // byte offset of header within the aggregate info
+ off Offset; // byte offset of data within the aggregate info
+ data []byte;
+ atable abbrevTable;
+ addrsize int;
+}
+
+func (d *Data) parseUnits() ([]unit, os.Error) {
+ // Count units.
+ nunit := 0;
+ b := makeBuf(d, "info", 0, d.info, 0);
+ for len(b.data) > 0 {
+ b.skip(int(b.uint32()));
+ nunit++;
+ }
+ if b.err != nil {
+ return nil, b.err;
+ }
+
+ // Again, this time writing them down.
+ b = makeBuf(d, "info", 0, d.info, 0);
+ units := make([]unit, nunit);
+ for i := range units {
+ u := &units[i];
+ u.base = b.off;
+ n := b.uint32();
+ if vers := b.uint16(); vers != 2 {
+ b.error("unsupported DWARF version " + strconv.Itoa(int(vers)));
+ break;
+ }
+ atable, err := d.parseAbbrev(b.uint32());
+ if err != nil {
+ if b.err == nil {
+ b.err = err;
+ }
+ break;
+ }
+ u.atable = atable;
+ u.addrsize = int(b.uint8());
+ u.off = b.off;
+ u.data = b.bytes(int(n - (2+4+1)));
+ }
+ if b.err != nil {
+ return nil, b.err;
+ }
+ return units, nil;
+}
+