Commit 1bbc044d authored by Russ Cox's avatar Russ Cox

parse and present DWARF type information

R=r
DELTA=940  (929 added, 1 deleted, 10 changed)
OCL=34679
CL=34686
parent f249c411
......@@ -82,7 +82,6 @@ DIRS=\
utf8\
NOTEST=\
debug/dwarf\
debug/proc\
go/ast\
go/doc\
......
......@@ -10,6 +10,7 @@ GOFILES=\
const.go\
entry.go\
open.go\
type.go\
unit.go\
include $(GOROOT)/src/Make.pkg
......@@ -152,6 +152,6 @@ type DecodeError struct {
}
func (e DecodeError) String() string {
return "decoding dwarf section " + e.Name + " at offset " + strconv.Itoa64(int64(e.Offset)) + ": " + e.Error;
return "decoding dwarf section " + e.Name + " at offset 0x" + strconv.Itob64(int64(e.Offset), 16) + ": " + e.Error;
}
......@@ -350,3 +350,84 @@ func (t Tag) GoString() string {
return "dwarf.Tag(" + strconv.Itoa64(int64(t)) + ")";
}
// Location expression operators.
// The debug info encodes value locations like 8(R3)
// as a sequence of these op codes.
// This package does not implement full expressions;
// the opPlusUconst operator is expected by the type parser.
const (
opAddr = 0x03; /* 1 op, const addr */
opDeref = 0x06;
opConst1u = 0x08; /* 1 op, 1 byte const */
opConst1s = 0x09; /* " signed */
opConst2u = 0x0A; /* 1 op, 2 byte const */
opConst2s = 0x0B; /* " signed */
opConst4u = 0x0C; /* 1 op, 4 byte const */
opConst4s = 0x0D; /* " signed */
opConst8u = 0x0E; /* 1 op, 8 byte const */
opConst8s = 0x0F; /* " signed */
opConstu = 0x10; /* 1 op, LEB128 const */
opConsts = 0x11; /* " signed */
opDup = 0x12;
opDrop = 0x13;
opOver = 0x14;
opPick = 0x15; /* 1 op, 1 byte stack index */
opSwap = 0x16;
opRot = 0x17;
opXderef = 0x18;
opAbs = 0x19;
opAnd = 0x1A;
opDiv = 0x1B;
opMinus = 0x1C;
opMod = 0x1D;
opMul = 0x1E;
opNeg = 0x1F;
opNot = 0x20;
opOr = 0x21;
opPlus = 0x22;
opPlusUconst = 0x23; /* 1 op, ULEB128 addend */
opShl = 0x24;
opShr = 0x25;
opShra = 0x26;
opXor = 0x27;
opSkip = 0x2F; /* 1 op, signed 2-byte constant */
opBra = 0x28; /* 1 op, signed 2-byte constant */
opEq = 0x29;
opGe = 0x2A;
opGt = 0x2B;
opLe = 0x2C;
opLt = 0x2D;
opNe = 0x2E;
opLit0 = 0x30;
/* OpLitN = OpLit0 + N for N = 0..31 */
opReg0 = 0x50;
/* OpRegN = OpReg0 + N for N = 0..31 */
opBreg0 = 0x70; /* 1 op, signed LEB128 constant */
/* OpBregN = OpBreg0 + N for N = 0..31 */
opRegx = 0x90; /* 1 op, ULEB128 register */
opFbreg = 0x91; /* 1 op, SLEB128 offset */
opBregx = 0x92; /* 2 op, ULEB128 reg; SLEB128 off */
opPiece = 0x93; /* 1 op, ULEB128 size of piece */
opDerefSize = 0x94; /* 1-byte size of data retrieved */
opXderefSize = 0x95; /* 1-byte size of data retrieved */
opNop = 0x96;
/* next four new in Dwarf v3 */
opPushObjAddr = 0x97;
opCall2 = 0x98; /* 2-byte offset of DIE */
opCall4 = 0x99; /* 4-byte offset of DIE */
opCallRef = 0x9A /* 4- or 8- byte offset of DIE */
/* 0xE0-0xFF reserved for user-specific */
)
// Basic type encodings -- the value for AttrEncoding in a TagBaseType Entry.
const (
encAddress = 0x01;
encBoolean = 0x02;
encComplexFloat = 0x03;
encFloat = 0x04;
encSigned = 0x05;
encSignedChar = 0x06;
encUnsigned = 0x07;
encUnsignedChar = 0x08;
encImaginaryFloat = 0x09;
)
......@@ -107,6 +107,22 @@ type Field struct {
Val interface{};
}
// Val returns the value associated with attribute Attr in Entry,
// or nil if there is no such attribute.
//
// A common idiom is to merge the check for nil return with
// the check that the value has the expected dynamic type, as in:
// v, ok := e.Val(AttrSibling).(int64);
//
func (e *Entry) Val(a Attr) interface{} {
for _, f := range e.Field {
if f.Attr == a {
return f.Val;
}
}
return nil;
}
// An Offset represents the location of an Entry within the DWARF info.
// (See Reader.Seek.)
type Offset uint32
......@@ -157,17 +173,17 @@ func (b *buf) entry(atab abbrevTable, ubase Offset) *Entry {
// constant
case formData1:
val = uint64(b.uint8());
val = int64(b.uint8());
case formData2:
val = uint64(b.uint16());
val = int64(b.uint16());
case formData4:
val = uint64(b.uint32());
val = int64(b.uint32());
case formData8:
val = uint64(b.uint64());
val = int64(b.uint64());
case formSdata:
val = int64(b.int());
case formUdata:
val = uint64(b.uint());
val = int64(b.uint());
// flag
case formFlag:
......@@ -212,11 +228,17 @@ func (b *buf) entry(atab abbrevTable, ubase Offset) *Entry {
}
// A Reader allows reading Entry structures from a DWARF ``info'' section.
// The Entry structures are arranged in a tree. The Reader's Next function
// return successive entries from a pre-order traversal of the tree.
// If an entry has children, its Children field will be true, and the children
// follow, terminated by an Entry with Tag 0.
type Reader struct {
b buf;
d *Data;
err os.Error;
unit int;
lastChildren bool; // .Children of last entry returned by Next
lastSibling Offset; // .Val(AttrSibling) of last entry returned by Next
}
// Reader returns a new Reader for Data.
......@@ -232,6 +254,7 @@ func (d *Data) Reader() *Reader {
func (r *Reader) Seek(off Offset) {
d := r.d;
r.err = nil;
r.lastChildren = false;
if off == 0 {
if len(d.unit) == 0 {
return;
......@@ -258,7 +281,7 @@ func (r *Reader) Seek(off Offset) {
// 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) {
for len(r.b.data) == 0 && r.unit+1 < len(r.d.unit) {
r.unit++;
u := &r.d.unit[r.unit];
r.b = makeBuf(r.d, "info", u.off, u.data, u.addrsize);
......@@ -279,6 +302,46 @@ func (r *Reader) Next() (*Entry, os.Error) {
}
u := &r.d.unit[r.unit];
e := r.b.entry(u.atable, u.base);
r.err = r.b.err;
return e, r.err;
if r.b.err != nil {
r.err = r.b.err;
return nil, r.err;
}
if e != nil {
r.lastChildren = e.Children;
if r.lastChildren {
r.lastSibling, _ = e.Val(AttrSibling).(Offset);
}
} else {
r.lastChildren = false;
}
return e, nil;
}
// SkipChildren skips over the child entries associated with
// the last Entry returned by Next. If that Entry did not have
// children or Next has not been called, SkipChildren is a no-op.
func (r *Reader) SkipChildren() {
if r.err != nil || !r.lastChildren{
return;
}
// If the last entry had a sibling attribute,
// that attribute gives the offset of the next
// sibling, so we can avoid decoding the
// child subtrees.
if r.lastSibling >= r.b.off {
r.Seek(r.lastSibling);
return;
}
for {
e, err := r.Next();
if err != nil || e == nil || e.Tag == 0 {
break;
}
if e.Children {
r.SkipChildren();
}
}
}
......@@ -30,6 +30,7 @@ type Data struct {
abbrevCache map[uint32] abbrevTable;
addrsize int;
order binary.ByteOrder;
typeCache map[Offset] Type;
unit []unit;
}
......@@ -51,6 +52,7 @@ func New(abbrev, aranges, frame, info, line, pubnames, ranges, str []byte) (*Dat
ranges: ranges,
str: str,
abbrevCache: make(map[uint32]abbrevTable),
typeCache: make(map[uint32]Type),
};
// Sniff .debug_info to figure out byte order.
......
// 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.
/*
gcc -gdwarf-2 -c typedef.c && gcc -gdwarf-2 -o typedef.elf typedef.o
*/
typedef volatile int* t_ptr_volatile_int;
typedef const char *t_ptr_const_char;
typedef long t_long;
typedef unsigned short t_ushort;
typedef int t_func_int_of_float_double(float, double);
typedef int (*t_ptr_func_int_of_float_double)(float, double);
typedef int *t_func_ptr_int_of_char_schar_uchar(char, signed char, unsigned char);
typedef void t_func_void_of_char(char);
typedef void t_func_void_of_void(void);
typedef void t_func_void_of_ptr_char_dots(char*, ...);
typedef struct my_struct {
volatile int vi;
char x : 1;
int y : 4;
long long array[40];
} t_my_struct;
typedef union my_union {
volatile int vi;
char x : 1;
int y : 4;
long long array[40];
} t_my_union;
typedef enum my_enum {
e1 = 1,
e2 = 2,
e3 = -5,
e4 = 1000000000000000LL,
} t_my_enum;
typedef struct list t_my_list;
struct list {
short val;
t_my_list *next;
};
typedef struct tree {
struct tree *left, *right;
unsigned long long val;
} t_my_tree;
t_ptr_volatile_int *a2;
t_ptr_const_char **a3a;
t_long *a4;
t_ushort *a5;
t_func_int_of_float_double *a6;
t_ptr_func_int_of_float_double *a7;
t_func_ptr_int_of_char_schar_uchar *a8;
t_func_void_of_char *a9;
t_func_void_of_void *a10;
t_func_void_of_ptr_char_dots *a11;
t_my_struct *a12;
t_my_union *a12a;
t_my_enum *a13;
t_my_list *a14;
t_my_tree *a15;
int main()
{
return 0;
}
This diff is collapsed.
// 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 (
"debug/elf";
"testing";
)
var typedefTests = map[string]string {
"t_ptr_volatile_int": "*volatile int",
"t_ptr_const_char": "*const char",
"t_long": "long int",
"t_ushort": "short unsigned int",
"t_func_int_of_float_double": "func(float, double) int",
"t_ptr_func_int_of_float_double": "*func(float, double) int",
"t_func_ptr_int_of_char_schar_uchar": "func(char, signed char, unsigned char) *int",
"t_func_void_of_char": "func(char)",
"t_func_void_of_void": "func()",
"t_func_void_of_ptr_char_dots": "func(*char, ...)",
"t_my_struct": "struct my_struct {vi volatile int@0; x char@4 : 1@7; y int@4 : 4@27; array [40]long long int@8}",
"t_my_union": "union my_union {vi volatile int@0; x char@0 : 1@7; y int@0 : 4@28; array [40]long long int@0}",
"t_my_enum": "enum my_enum {e1=1; e2=2; e3=-5; e4=1000000000000000}",
"t_my_list": "struct list {val short int@0; next *t_my_list@8}",
"t_my_tree": "struct tree {left *struct tree@0; right *struct tree@8; val long long unsigned int@16}"
};
func elfData(t *testing.T, name string) *Data {
f, err := elf.Open(name);
if err != nil {
t.Fatal(err);
}
dat := func(name string) []byte {
s := f.Section(".debug_" + name);
if s == nil {
return nil
}
b, err := s.Data();
if err != nil {
t.Fatal(".debug_"+name+":", err);
}
return b;
};
d, err := New(dat("abbrev"), nil, nil, dat("info"), nil, nil, nil, dat("str"));
if err != nil {
t.Fatal("New:", err);
}
return d;
}
func TestTypedefs(t *testing.T) {
d := elfData(t, "testdata/typedef.elf");
r := d.Reader();
seen := make(map[string]bool);
for {
e, err := r.Next();
if err != nil {
t.Fatal("r.Next:", err);
}
if e == nil {
break;
}
if e.Tag == TagTypedef {
typ, err := d.Type(e.Offset);
if err != nil {
t.Fatal("d.Type:", err);
}
t1 := typ.(*TypedefType);
var typstr string;
if ts, ok := t1.Type.(*StructType); ok {
typstr = ts.Defn();
} else {
typstr = t1.Type.String();
}
if want, ok := typedefTests[t1.Name]; ok {
if _, ok := seen[t1.Name]; ok {
t.Errorf("multiple definitions for %s", t1.Name);
}
seen[t1.Name] = true;
if typstr != want {
t.Errorf("%s:\n\thave %s\n\twant %s", t1.Name, typstr, want);
}
}
}
if e.Tag != TagCompileUnit {
r.SkipChildren();
}
}
for k := range typedefTests {
if _, ok := seen[k]; !ok {
t.Errorf("missing %s", k);
}
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment