Skip to content
Projects
Groups
Snippets
Help
Loading...
Sign in
Toggle navigation
G
golang
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Commits
Issue Boards
Open sidebar
go
golang
Commits
9a71bb00
Commit
9a71bb00
authored
Dec 03, 2010
by
Luuk van Dijk
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
[68]l: generate debug info for builtin structured types. prettyprinting in gdb.
R=rsc CC=golang-dev
https://golang.org/cl/3309041
parent
09e4d860
Hide whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
697 additions
and
106 deletions
+697
-106
dwarf.c
src/cmd/ld/dwarf.c
+523
-106
runtime-gdb.py
src/pkg/runtime/runtime-gdb.py
+174
-0
No files found.
src/cmd/ld/dwarf.c
View file @
9a71bb00
...
...
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// TODO:
// TODO
/NICETOHAVE
:
// - eliminate DW_CLS_ if not used
// - package info in compilation units
// - assign global variables and types to their packages
...
...
@@ -10,6 +10,7 @@
// - gdb uses c syntax, meaning clumsy quoting is needed for go identifiers. eg
// ptype struct '[]uint8' and qualifiers need to be quoted away
// - lexical scoping is lost, so gdb gets confused as to which 'main.i' you mean.
// - file:line info for variables
//
#include "l.h"
#include "lib.h"
...
...
@@ -26,7 +27,7 @@ static vlong abbrevo;
static
vlong
abbrevsize
;
static
vlong
lineo
;
static
vlong
linesize
;
static
vlong
infoo
;
// also the base for DWDie->offs and reference attributes.
static
vlong
infoo
;
// also the base for DWDie->offs and reference attributes.
static
vlong
infosize
;
static
vlong
frameo
;
static
vlong
framesize
;
...
...
@@ -36,6 +37,10 @@ static vlong pubtypeso;
static
vlong
pubtypessize
;
static
vlong
arangeso
;
static
vlong
arangessize
;
static
vlong
gdbscripto
;
static
vlong
gdbscriptsize
;
static
char
gdbscript
[
1024
];
/*
* Basic I/O
...
...
@@ -72,7 +77,6 @@ uleb128enc(uvlong v, char* dst)
return
len
;
};
static
int
sleb128enc
(
vlong
v
,
char
*
dst
)
{
...
...
@@ -133,6 +137,8 @@ enum
DW_ABRV_AUTO
,
DW_ABRV_PARAM
,
DW_ABRV_STRUCTFIELD
,
DW_ABRV_FUNCTYPEPARAM
,
DW_ABRV_DOTDOTDOT
,
DW_ABRV_ARRAYRANGE
,
DW_ABRV_NULLTYPE
,
DW_ABRV_BASETYPE
,
...
...
@@ -203,12 +209,25 @@ static struct DWAbbrev {
},
/* STRUCTFIELD */
{
DW_TAG_member
,
DW_CHILDREN_no
,
DW_AT_name
,
DW_FORM_string
,
DW_AT_data_member_location
,
DW_FORM_block1
,
DW_TAG_member
,
DW_CHILDREN_no
,
DW_AT_name
,
DW_FORM_string
,
DW_AT_data_member_location
,
DW_FORM_block1
,
DW_AT_type
,
DW_FORM_ref_addr
,
0
,
0
},
/* FUNCTYPEPARAM */
{
DW_TAG_formal_parameter
,
DW_CHILDREN_no
,
// No name!
DW_AT_type
,
DW_FORM_ref_addr
,
0
,
0
},
/* DOTDOTDOT */
{
DW_TAG_unspecified_parameters
,
DW_CHILDREN_no
,
0
,
0
},
/* ARRAYRANGE */
{
DW_TAG_subrange_type
,
DW_CHILDREN_no
,
...
...
@@ -246,14 +265,16 @@ static struct DWAbbrev {
/* CHANTYPE */
{
DW_TAG_typedef
,
DW_CHILDREN_no
,
DW_AT_name
,
DW_FORM_string
,
DW_AT_name
,
DW_FORM_string
,
DW_AT_type
,
DW_FORM_ref_addr
,
0
,
0
},
/* FUNCTYPE */
{
DW_TAG_typedef
,
DW_CHILDREN_no
,
DW_AT_name
,
DW_FORM_string
,
DW_TAG_subroutine_type
,
DW_CHILDREN_yes
,
DW_AT_name
,
DW_FORM_string
,
// DW_AT_type, DW_FORM_ref_addr,
0
,
0
},
...
...
@@ -268,6 +289,7 @@ static struct DWAbbrev {
{
DW_TAG_typedef
,
DW_CHILDREN_no
,
DW_AT_name
,
DW_FORM_string
,
DW_AT_type
,
DW_FORM_ref_addr
,
0
,
0
},
...
...
@@ -280,7 +302,6 @@ static struct DWAbbrev {
},
/* SLICETYPE */
// Children are data, len and cap of runtime::struct Slice.
{
DW_TAG_structure_type
,
DW_CHILDREN_yes
,
DW_AT_name
,
DW_FORM_string
,
...
...
@@ -289,7 +310,6 @@ static struct DWAbbrev {
},
/* STRINGTYPE */
// Children are str and len of runtime::struct String.
{
DW_TAG_structure_type
,
DW_CHILDREN_yes
,
DW_AT_name
,
DW_FORM_string
,
...
...
@@ -431,6 +451,19 @@ getattr(DWDie *die, uint8 attr)
return
nil
;
}
static
void
delattr
(
DWDie
*
die
,
uint8
attr
)
{
DWAttr
**
a
;
a
=
&
die
->
attr
;
while
(
*
a
!=
nil
)
if
((
*
a
)
->
atr
==
attr
)
*
a
=
(
*
a
)
->
link
;
else
a
=
&
((
*
a
)
->
link
);
}
// Every DIE has at least a DW_AT_name attribute (but it will only be
// written out if it is listed in the abbrev). If its parent is
// keeping an index, the new DIE will be inserted there.
...
...
@@ -483,6 +516,7 @@ find(DWDie *die, char* name)
if
(
a
==
nil
)
return
nil
;
if
(
strcmp
(
name
,
getattr
(
a
,
DW_AT_name
)
->
data
)
==
0
)
return
a
;
...
...
@@ -505,7 +539,6 @@ static DWDie*
find_or_diag
(
DWDie
*
die
,
char
*
name
)
{
DWDie
*
r
;
r
=
find
(
die
,
name
);
if
(
r
==
nil
)
diag
(
"dwarf find: %s has no %s"
,
getattr
(
die
,
DW_AT_name
)
->
data
,
name
);
...
...
@@ -626,6 +659,7 @@ putattrs(int abbrev, DWAttr* attr)
for
(
;
attr
;
attr
=
attr
->
link
)
if
(
attr
->
atr
<
nelem
(
attrs
))
attrs
[
attr
->
atr
]
=
attr
;
for
(
af
=
abbrevs
[
abbrev
].
attr
;
af
->
attr
;
af
++
)
if
(
attrs
[
af
->
attr
])
putattr
(
af
->
form
,
...
...
@@ -700,6 +734,8 @@ newmemberoffsetattr(DWDie *die, int32 offs)
memmove
(
die
->
attr
->
data
,
block
,
i
);
}
// GDB doesn't like DW_FORM_addr for DW_AT_location, so emit a
// location expression that evals to a const.
static
void
newabslocexprattr
(
DWDie
*
die
,
vlong
addr
)
{
...
...
@@ -750,14 +786,14 @@ enum {
KindNoPointers
=
1
<<
7
,
};
static
Sym
*
static
Reloc
*
decode_reloc
(
Sym
*
s
,
int32
off
)
{
int
i
;
for
(
i
=
0
;
i
<
s
->
nr
;
i
++
)
if
(
s
->
r
[
i
].
off
==
off
)
return
s
->
r
[
i
].
sym
;
return
s
->
r
+
i
;
return
nil
;
}
...
...
@@ -804,11 +840,11 @@ decodetype_size(Sym *s)
return
decode_inuxi
(
s
->
p
+
2
*
PtrSize
,
PtrSize
);
// 0x8 / 0x10
}
// Type.ArrayType.elem
// Type.ArrayType.elem
and Type.SliceType.Elem
static
Sym
*
decodetype_arrayelem
(
Sym
*
s
)
{
return
decode_reloc
(
s
,
5
*
PtrSize
+
8
);
// 0x1c / 0x30
return
decode_reloc
(
s
,
5
*
PtrSize
+
8
)
->
sym
;
// 0x1c / 0x30
}
static
vlong
...
...
@@ -821,7 +857,64 @@ decodetype_arraylen(Sym *s)
static
Sym
*
decodetype_ptrelem
(
Sym
*
s
)
{
return
decode_reloc
(
s
,
5
*
PtrSize
+
8
);
// 0x1c / 0x30
return
decode_reloc
(
s
,
5
*
PtrSize
+
8
)
->
sym
;
// 0x1c / 0x30
}
// Type.MapType.key, elem
static
Sym
*
decodetype_mapkey
(
Sym
*
s
)
{
return
decode_reloc
(
s
,
5
*
PtrSize
+
8
)
->
sym
;
// 0x1c / 0x30
}
static
Sym
*
decodetype_mapvalue
(
Sym
*
s
)
{
return
decode_reloc
(
s
,
6
*
PtrSize
+
8
)
->
sym
;
// 0x20 / 0x38
}
// Type.ChanType.elem
static
Sym
*
decodetype_chanelem
(
Sym
*
s
)
{
return
decode_reloc
(
s
,
5
*
PtrSize
+
8
)
->
sym
;
// 0x1c / 0x30
}
// Type.FuncType.dotdotdot
static
int
decodetype_funcdotdotdot
(
Sym
*
s
)
{
return
s
->
p
[
5
*
PtrSize
+
8
];
}
// Type.FuncType.in.len
static
int
decodetype_funcincount
(
Sym
*
s
)
{
return
decode_inuxi
(
s
->
p
+
7
*
PtrSize
+
8
,
4
);
}
static
int
decodetype_funcoutcount
(
Sym
*
s
)
{
return
decode_inuxi
(
s
->
p
+
8
*
PtrSize
+
16
,
4
);
}
static
Sym
*
decodetype_funcintype
(
Sym
*
s
,
int
i
)
{
Reloc
*
r
;
r
=
decode_reloc
(
s
,
6
*
PtrSize
+
8
);
return
decode_reloc
(
r
->
sym
,
r
->
add
+
i
*
PtrSize
)
->
sym
;
}
static
Sym
*
decodetype_funcouttype
(
Sym
*
s
,
int
i
)
{
Reloc
*
r
;
r
=
decode_reloc
(
s
,
7
*
PtrSize
+
16
);
return
decode_reloc
(
r
->
sym
,
r
->
add
+
i
*
PtrSize
)
->
sym
;
}
// Type.StructType.fields.Slice::len
...
...
@@ -835,20 +928,21 @@ decodetype_structfieldcount(Sym *s)
static
char
*
decodetype_structfieldname
(
Sym
*
s
,
int
i
)
{
Sym
*
p
;
p
=
decode_reloc
(
s
,
6
*
PtrSize
+
0x10
+
i
*
5
*
PtrSize
);
// go.string."foo" 0x28 / 0x40
if
(
p
==
nil
)
// embedded structs have a nil name.
Reloc
*
r
;
r
=
decode_reloc
(
s
,
6
*
PtrSize
+
0x10
+
i
*
5
*
PtrSize
);
// go.string."foo" 0x28 / 0x40
if
(
r
==
nil
)
// embedded structs have a nil name.
return
nil
;
p
=
decode_reloc
(
p
,
0
);
// string."foo"
if
(
p
==
nil
)
// shouldn't happen.
r
=
decode_reloc
(
r
->
sym
,
0
);
// string."foo"
if
(
r
==
nil
)
// shouldn't happen.
return
nil
;
return
(
char
*
)
p
->
p
;
// the c-string
return
(
char
*
)
r
->
sym
->
p
;
// the c-string
}
static
Sym
*
decodetype_structfieldtype
(
Sym
*
s
,
int
i
)
{
return
decode_reloc
(
s
,
8
*
PtrSize
+
0x10
+
i
*
5
*
PtrSize
);
// 0x30 / 0x50
return
decode_reloc
(
s
,
8
*
PtrSize
+
0x10
+
i
*
5
*
PtrSize
)
->
sym
;
// 0x30 / 0x50
}
static
vlong
...
...
@@ -865,13 +959,15 @@ enum {
DW_AT_internal_location
=
253
,
// params and locals
};
static
DWDie
*
defptrto
(
DWDie
*
dwtype
);
// below
// Define gotype, for composite ones recurse into constituents.
static
DWDie
*
defgotype
(
Sym
*
gotype
)
{
DWDie
*
die
,
*
fld
,
*
elem
,
*
ptrelem
;
DWDie
*
die
,
*
fld
;
Sym
*
s
;
char
*
name
,
*
ptrname
,
*
f
;
char
*
name
,
*
f
;
uint8
kind
;
vlong
bytesize
;
int
i
,
nfields
;
...
...
@@ -891,18 +987,18 @@ defgotype(Sym *gotype)
if
(
0
&&
debug
[
'v'
]
>
2
)
{
print
(
"new type: %s @0x%08x [%d]"
,
gotype
->
name
,
gotype
->
value
,
gotype
->
size
);
for
(
i
=
0
;
i
<
gotype
->
size
;
++
i
)
{
for
(
i
=
0
;
i
<
gotype
->
size
;
i
++
)
{
if
(
!
(
i
%
8
))
print
(
"
\n\t
%04x "
,
i
);
print
(
"%02x "
,
gotype
->
p
[
i
]);
}
print
(
"
\n
"
);
for
(
i
=
0
;
i
<
gotype
->
nr
;
++
i
)
{
print
(
"
\t
%02x %d %d %lld %s
\n
"
,
for
(
i
=
0
;
i
<
gotype
->
nr
;
i
++
)
{
print
(
"
\t
0x%02x[%x] %d %s[%llx]
\n
"
,
gotype
->
r
[
i
].
off
,
gotype
->
r
[
i
].
siz
,
gotype
->
r
[
i
].
type
,
gotype
->
r
[
i
].
add
,
gotype
->
r
[
i
].
sym
->
name
);
gotype
->
r
[
i
].
sym
->
name
,
gotype
->
r
[
i
].
add
);
}
}
...
...
@@ -961,25 +1057,46 @@ defgotype(Sym *gotype)
fld
=
newdie
(
die
,
DW_ABRV_ARRAYRANGE
,
"range"
);
newattr
(
fld
,
DW_AT_upper_bound
,
DW_CLS_CONSTANT
,
decodetype_arraylen
(
gotype
),
0
);
newrefattr
(
fld
,
DW_AT_type
,
find_or_diag
(
&
dwtypes
,
"uintptr"
));
break
;
case
KindChan
:
die
=
newdie
(
&
dwtypes
,
DW_ABRV_CHANTYPE
,
name
);
// TODO: describe ../../pkg/runtime/chan.c::struct Hchan
newattr
(
die
,
DW_AT_byte_size
,
DW_CLS_CONSTANT
,
bytesize
,
0
);
s
=
decodetype_chanelem
(
gotype
);
newrefattr
(
die
,
DW_AT_internal_elem_type
,
defgotype
(
s
));
break
;
case
KindFunc
:
die
=
newdie
(
&
dwtypes
,
DW_ABRV_FUNCTYPE
,
name
);
newrefattr
(
die
,
DW_AT_type
,
find_or_diag
(
&
dwtypes
,
"void"
));
nfields
=
decodetype_funcincount
(
gotype
);
for
(
i
=
0
;
i
<
nfields
;
i
++
)
{
s
=
decodetype_funcintype
(
gotype
,
i
);
fld
=
newdie
(
die
,
DW_ABRV_FUNCTYPEPARAM
,
s
->
name
+
5
);
newrefattr
(
fld
,
DW_AT_type
,
defgotype
(
s
));
}
if
(
decodetype_funcdotdotdot
(
gotype
))
newdie
(
die
,
DW_ABRV_DOTDOTDOT
,
"..."
);
nfields
=
decodetype_funcoutcount
(
gotype
);
for
(
i
=
0
;
i
<
nfields
;
i
++
)
{
s
=
decodetype_funcouttype
(
gotype
,
i
);
fld
=
newdie
(
die
,
DW_ABRV_FUNCTYPEPARAM
,
s
->
name
+
5
);
newrefattr
(
fld
,
DW_AT_type
,
defptrto
(
defgotype
(
s
)));
}
die
=
defptrto
(
die
);
break
;
case
KindInterface
:
die
=
newdie
(
&
dwtypes
,
DW_ABRV_IFACETYPE
,
name
);
newattr
(
die
,
DW_AT_byte_size
,
DW_CLS_CONSTANT
,
bytesize
,
0
);
break
;
case
KindMap
:
die
=
newdie
(
&
dwtypes
,
DW_ABRV_MAPTYPE
,
name
);
// TODO: describe ../../pkg/runtime/hashmap.c::struct hash
s
=
decodetype_mapkey
(
gotype
);
newrefattr
(
die
,
DW_AT_internal_key_type
,
defgotype
(
s
));
s
=
decodetype_mapvalue
(
gotype
);
newrefattr
(
die
,
DW_AT_internal_val_type
,
defgotype
(
s
));
break
;
case
KindPtr
:
...
...
@@ -991,48 +1108,20 @@ defgotype(Sym *gotype)
case
KindSlice
:
die
=
newdie
(
&
dwtypes
,
DW_ABRV_SLICETYPE
,
name
);
newattr
(
die
,
DW_AT_byte_size
,
DW_CLS_CONSTANT
,
bytesize
,
0
);
fld
=
newdie
(
die
,
DW_ABRV_STRUCTFIELD
,
"data"
);
// Synthesize *elemtype if not already exists. Maybe
// this should be named '<*T>' to not stand in the way
// of the real definition of *T.
s
=
decodetype_arrayelem
(
gotype
);
elem
=
defgotype
(
s
);
ptrname
=
strdup
(
s
->
name
+
4
);
// skip "type" but leave the '.'
ptrname
[
0
]
=
'*'
;
// .. to stuff in the '*'
ptrelem
=
find
(
&
dwtypes
,
ptrname
);
if
(
ptrelem
==
nil
)
{
ptrelem
=
newdie
(
&
dwtypes
,
DW_ABRV_PTRTYPE
,
ptrname
);
newrefattr
(
ptrelem
,
DW_AT_type
,
elem
);
}
else
{
free
(
ptrname
);
}
newrefattr
(
fld
,
DW_AT_type
,
ptrelem
);
newmemberoffsetattr
(
fld
,
0
);
fld
=
newdie
(
die
,
DW_ABRV_STRUCTFIELD
,
"len"
);
newrefattr
(
fld
,
DW_AT_type
,
find
(
&
dwtypes
,
"<int32>"
));
newmemberoffsetattr
(
fld
,
PtrSize
);
fld
=
newdie
(
die
,
DW_ABRV_STRUCTFIELD
,
"cap"
);
newrefattr
(
fld
,
DW_AT_type
,
find
(
&
dwtypes
,
"<int32>"
));
newmemberoffsetattr
(
fld
,
PtrSize
+
4
);
newrefattr
(
die
,
DW_AT_internal_elem_type
,
defgotype
(
s
));
break
;
case
KindString
:
die
=
newdie
(
&
dwtypes
,
DW_ABRV_STRINGTYPE
,
name
);
newattr
(
die
,
DW_AT_byte_size
,
DW_CLS_CONSTANT
,
bytesize
,
0
);
fld
=
newdie
(
die
,
DW_ABRV_STRUCTFIELD
,
"str"
);
newrefattr
(
fld
,
DW_AT_type
,
find
(
&
dwtypes
,
"<byte*>"
));
newmemberoffsetattr
(
fld
,
0
);
fld
=
newdie
(
die
,
DW_ABRV_STRUCTFIELD
,
"len"
);
newrefattr
(
fld
,
DW_AT_type
,
find
(
&
dwtypes
,
"<int32>"
));
newmemberoffsetattr
(
fld
,
PtrSize
);
break
;
case
KindStruct
:
die
=
newdie
(
&
dwtypes
,
DW_ABRV_STRUCTTYPE
,
name
);
newattr
(
die
,
DW_AT_byte_size
,
DW_CLS_CONSTANT
,
bytesize
,
0
);
nfields
=
decodetype_structfieldcount
(
gotype
);
for
(
i
=
0
;
i
<
nfields
;
++
i
)
{
for
(
i
=
0
;
i
<
nfields
;
i
++
)
{
f
=
decodetype_structfieldname
(
gotype
,
i
);
s
=
decodetype_structfieldtype
(
gotype
,
i
);
if
(
f
==
nil
)
...
...
@@ -1051,11 +1140,274 @@ defgotype(Sym *gotype)
default:
diag
(
"definition of unknown kind %d: %s"
,
kind
,
gotype
->
name
);
die
=
newdie
(
&
dwtypes
,
DW_ABRV_TYPEDECL
,
name
);
newrefattr
(
die
,
DW_AT_type
,
find
(
&
dwtypes
,
"<unspecified>"
));
newrefattr
(
die
,
DW_AT_type
,
find
_or_diag
(
&
dwtypes
,
"<unspecified>"
));
}
return
die
;
}
}
// Find or construct *T given T.
static
DWDie
*
defptrto
(
DWDie
*
dwtype
)
{
char
ptrname
[
1024
];
DWDie
*
die
;
snprint
(
ptrname
,
sizeof
ptrname
,
"*%s"
,
getattr
(
dwtype
,
DW_AT_name
)
->
data
);
die
=
find
(
&
dwtypes
,
ptrname
);
if
(
die
==
nil
)
{
die
=
newdie
(
&
dwtypes
,
DW_ABRV_PTRTYPE
,
strcpy
(
mal
(
strlen
(
ptrname
)
+
1
),
ptrname
));
newrefattr
(
die
,
DW_AT_type
,
dwtype
);
}
return
die
;
}
// Copies src's children into dst. Copies attributes by value.
// DWAttr.data is copied as pointer only.
static
void
copychildren
(
DWDie
*
dst
,
DWDie
*
src
)
{
DWDie
*
c
;
DWAttr
*
a
;
for
(
src
=
src
->
child
;
src
!=
nil
;
src
=
src
->
link
)
{
c
=
newdie
(
dst
,
src
->
abbrev
,
getattr
(
src
,
DW_AT_name
)
->
data
);
for
(
a
=
src
->
attr
;
a
!=
nil
;
a
=
a
->
link
)
newattr
(
c
,
a
->
atr
,
a
->
cls
,
a
->
value
,
a
->
data
);
copychildren
(
c
,
src
);
}
reverselist
(
&
dst
->
child
);
}
// Search children (assumed to have DW_TAG_member) for the one named
// field and set it's DW_AT_type to dwtype
static
void
substitutetype
(
DWDie
*
structdie
,
char
*
field
,
DWDie
*
dwtype
)
{
DWDie
*
child
;
DWAttr
*
a
;
child
=
find_or_diag
(
structdie
,
field
);
if
(
child
==
nil
)
return
;
a
=
getattr
(
child
,
DW_AT_type
);
if
(
a
!=
nil
)
a
->
data
=
(
char
*
)
dwtype
;
else
newrefattr
(
child
,
DW_AT_type
,
dwtype
);
}
static
void
synthesizestringtypes
(
DWDie
*
die
)
{
DWDie
*
prototype
;
prototype
=
defgotype
(
lookup
(
"type.runtime.string_"
,
0
));
if
(
prototype
==
nil
)
return
;
for
(;
die
!=
nil
;
die
=
die
->
link
)
{
if
(
die
->
abbrev
!=
DW_ABRV_STRINGTYPE
)
continue
;
copychildren
(
die
,
prototype
);
}
}
static
void
synthesizeslicetypes
(
DWDie
*
die
)
{
DWDie
*
prototype
,
*
elem
;
prototype
=
defgotype
(
lookup
(
"type.runtime.slice"
,
0
));
if
(
prototype
==
nil
)
return
;
for
(;
die
!=
nil
;
die
=
die
->
link
)
{
if
(
die
->
abbrev
!=
DW_ABRV_SLICETYPE
)
continue
;
copychildren
(
die
,
prototype
);
elem
=
(
DWDie
*
)
getattr
(
die
,
DW_AT_internal_elem_type
)
->
data
;
substitutetype
(
die
,
"array"
,
defptrto
(
elem
));
}
}
static
char
*
mkinternaltypename
(
char
*
base
,
char
*
arg1
,
char
*
arg2
)
{
char
buf
[
1024
];
char
*
n
;
if
(
arg2
==
nil
)
snprint
(
buf
,
sizeof
buf
,
"%s<%s>"
,
base
,
arg1
);
else
snprint
(
buf
,
sizeof
buf
,
"%s<%s,%s>"
,
base
,
arg1
,
arg2
);
n
=
mal
(
strlen
(
buf
)
+
1
);
memmove
(
n
,
buf
,
strlen
(
buf
));
return
n
;
}
// synthesizemaptypes is way too closely married to runtime/hashmap.c
enum
{
MaxValsize
=
256
-
64
};
static
void
synthesizemaptypes
(
DWDie
*
die
)
{
DWDie
*
hash
,
*
hash_subtable
,
*
hash_entry
,
*
dwh
,
*
dwhs
,
*
dwhe
,
*
keytype
,
*
valtype
,
*
fld
;
int
hashsize
,
keysize
,
valsize
,
datsize
,
valsize_in_hash
,
datavo
;
DWAttr
*
a
;
hash
=
defgotype
(
lookup
(
"type.runtime.hash"
,
0
));
hash_subtable
=
defgotype
(
lookup
(
"type.runtime.hash_subtable"
,
0
));
hash_entry
=
defgotype
(
lookup
(
"type.runtime.hash_entry"
,
0
));
if
(
hash
==
nil
||
hash_subtable
==
nil
||
hash_entry
==
nil
)
return
;
dwh
=
(
DWDie
*
)
getattr
(
find_or_diag
(
hash_entry
,
"hash"
),
DW_AT_type
)
->
data
;
if
(
dwh
==
nil
)
return
;
hashsize
=
getattr
(
dwh
,
DW_AT_byte_size
)
->
value
;
for
(;
die
!=
nil
;
die
=
die
->
link
)
{
if
(
die
->
abbrev
!=
DW_ABRV_MAPTYPE
)
continue
;
keytype
=
(
DWDie
*
)
getattr
(
die
,
DW_AT_internal_key_type
)
->
data
;
valtype
=
(
DWDie
*
)
getattr
(
die
,
DW_AT_internal_val_type
)
->
data
;
a
=
getattr
(
keytype
,
DW_AT_byte_size
);
keysize
=
a
?
a
->
value
:
PtrSize
;
// We don't store size with Pointers
a
=
getattr
(
valtype
,
DW_AT_byte_size
);
valsize
=
a
?
a
->
value
:
PtrSize
;
// This is what happens in hash_init and makemap_c
valsize_in_hash
=
valsize
;
if
(
valsize
>
MaxValsize
)
valsize_in_hash
=
PtrSize
;
datavo
=
keysize
;
if
(
valsize_in_hash
>=
PtrSize
)
datavo
=
rnd
(
keysize
,
PtrSize
);
datsize
=
datavo
+
valsize_in_hash
;
if
(
datsize
<
PtrSize
)
datsize
=
PtrSize
;
datsize
=
rnd
(
datsize
,
PtrSize
);
// Construct struct hash_entry<K,V>
dwhe
=
newdie
(
&
dwtypes
,
DW_ABRV_STRUCTTYPE
,
mkinternaltypename
(
"hash_entry"
,
getattr
(
keytype
,
DW_AT_name
)
->
data
,
getattr
(
valtype
,
DW_AT_name
)
->
data
));
copychildren
(
dwhe
,
hash_entry
);
substitutetype
(
dwhe
,
"key"
,
keytype
);
if
(
valsize
>
MaxValsize
)
valtype
=
defptrto
(
valtype
);
substitutetype
(
dwhe
,
"val"
,
valtype
);
fld
=
find_or_diag
(
dwhe
,
"val"
);
delattr
(
fld
,
DW_AT_data_member_location
);
newmemberoffsetattr
(
fld
,
hashsize
+
datavo
);
newattr
(
dwhe
,
DW_AT_byte_size
,
DW_CLS_CONSTANT
,
hashsize
+
datsize
,
NULL
);
// Construct hash_subtable<hash_entry<K,V>>
dwhs
=
newdie
(
&
dwtypes
,
DW_ABRV_STRUCTTYPE
,
mkinternaltypename
(
"hash_subtable"
,
getattr
(
keytype
,
DW_AT_name
)
->
data
,
getattr
(
valtype
,
DW_AT_name
)
->
data
));
copychildren
(
dwhs
,
hash_subtable
);
substitutetype
(
dwhs
,
"end"
,
defptrto
(
dwhe
));
substitutetype
(
dwhs
,
"entry"
,
dwhe
);
// todo: []hash_entry with dynamic size
newattr
(
dwhs
,
DW_AT_byte_size
,
DW_CLS_CONSTANT
,
getattr
(
hash_subtable
,
DW_AT_byte_size
)
->
value
,
NULL
);
// Construct hash<K,V>
dwh
=
newdie
(
&
dwtypes
,
DW_ABRV_STRUCTTYPE
,
mkinternaltypename
(
"hash"
,
getattr
(
keytype
,
DW_AT_name
)
->
data
,
getattr
(
valtype
,
DW_AT_name
)
->
data
));
copychildren
(
dwh
,
hash
);
substitutetype
(
dwh
,
"st"
,
defptrto
(
dwhs
));
newattr
(
dwh
,
DW_AT_byte_size
,
DW_CLS_CONSTANT
,
getattr
(
hash
,
DW_AT_byte_size
)
->
value
,
NULL
);
newrefattr
(
die
,
DW_AT_type
,
defptrto
(
dwh
));
}
}
static
void
synthesizechantypes
(
DWDie
*
die
)
{
DWDie
*
sudog
,
*
waitq
,
*
link
,
*
hchan
,
*
dws
,
*
dww
,
*
dwl
,
*
dwh
,
*
elemtype
;
DWAttr
*
a
;
int
elemsize
,
linksize
,
sudogsize
;
sudog
=
defgotype
(
lookup
(
"type.runtime.sudoG"
,
0
));
waitq
=
defgotype
(
lookup
(
"type.runtime.waitQ"
,
0
));
link
=
defgotype
(
lookup
(
"type.runtime.link"
,
0
));
hchan
=
defgotype
(
lookup
(
"type.runtime.hChan"
,
0
));
if
(
sudog
==
nil
||
waitq
==
nil
||
link
==
nil
||
hchan
==
nil
)
return
;
sudogsize
=
getattr
(
sudog
,
DW_AT_byte_size
)
->
value
;
linksize
=
getattr
(
link
,
DW_AT_byte_size
)
->
value
;
for
(;
die
!=
nil
;
die
=
die
->
link
)
{
if
(
die
->
abbrev
!=
DW_ABRV_CHANTYPE
)
continue
;
elemtype
=
(
DWDie
*
)
getattr
(
die
,
DW_AT_internal_elem_type
)
->
data
;
a
=
getattr
(
elemtype
,
DW_AT_byte_size
);
elemsize
=
a
?
a
->
value
:
PtrSize
;
// sudog<T>
dws
=
newdie
(
&
dwtypes
,
DW_ABRV_STRUCTTYPE
,
mkinternaltypename
(
"sudog"
,
getattr
(
elemtype
,
DW_AT_name
)
->
data
,
NULL
));
copychildren
(
dws
,
sudog
);
substitutetype
(
dws
,
"elem"
,
elemtype
);
newattr
(
dws
,
DW_AT_byte_size
,
DW_CLS_CONSTANT
,
sudogsize
+
(
elemsize
>
8
?
elemsize
-
8
:
0
),
NULL
);
// waitq<T>
dww
=
newdie
(
&
dwtypes
,
DW_ABRV_STRUCTTYPE
,
mkinternaltypename
(
"waitq"
,
getattr
(
elemtype
,
DW_AT_name
)
->
data
,
NULL
));
copychildren
(
dww
,
waitq
);
substitutetype
(
dww
,
"first"
,
defptrto
(
dws
));
substitutetype
(
dww
,
"last"
,
defptrto
(
dws
));
newattr
(
dww
,
DW_AT_byte_size
,
DW_CLS_CONSTANT
,
getattr
(
waitq
,
DW_AT_byte_size
)
->
value
,
NULL
);
// link<T>
dwl
=
newdie
(
&
dwtypes
,
DW_ABRV_STRUCTTYPE
,
mkinternaltypename
(
"link"
,
getattr
(
elemtype
,
DW_AT_name
)
->
data
,
NULL
));
copychildren
(
dwl
,
link
);
substitutetype
(
dwl
,
"link"
,
defptrto
(
dwl
));
substitutetype
(
dwl
,
"elem"
,
elemtype
);
newattr
(
dwl
,
DW_AT_byte_size
,
DW_CLS_CONSTANT
,
linksize
+
(
elemsize
>
8
?
elemsize
-
8
:
0
),
NULL
);
// hchan<T>
dwh
=
newdie
(
&
dwtypes
,
DW_ABRV_STRUCTTYPE
,
mkinternaltypename
(
"hchan"
,
getattr
(
elemtype
,
DW_AT_name
)
->
data
,
NULL
));
copychildren
(
dwh
,
hchan
);
substitutetype
(
dwh
,
"senddataq"
,
defptrto
(
dwl
));
substitutetype
(
dwh
,
"recvdataq"
,
defptrto
(
dwl
));
substitutetype
(
dwh
,
"recvq"
,
dww
);
substitutetype
(
dwh
,
"sendq"
,
dww
);
substitutetype
(
dwh
,
"free"
,
dws
);
newattr
(
dwh
,
DW_AT_byte_size
,
DW_CLS_CONSTANT
,
getattr
(
hchan
,
DW_AT_byte_size
)
->
value
,
NULL
);
newrefattr
(
die
,
DW_AT_type
,
defptrto
(
dwh
));
}
}
// For use with pass.c::genasmsym
static
void
...
...
@@ -1063,15 +1415,20 @@ defdwsymb(Sym* sym, char *s, int t, vlong v, vlong size, int ver, Sym *gotype)
{
DWDie
*
dv
,
*
dt
;
if
(
gotype
==
nil
)
{
if
(
strncmp
(
s
,
"go.string."
,
10
)
==
0
)
return
;
if
(
strncmp
(
s
,
"string."
,
7
)
==
0
)
return
;
if
(
strncmp
(
s
,
"type."
,
5
)
==
0
)
return
;
}
dv
=
nil
;
switch
(
t
)
{
default:
return
;
case
'd'
:
case
'b'
:
case
'D'
:
case
'B'
:
dv
=
newdie
(
&
dwglobals
,
DW_ABRV_VARIABLE
,
s
);
...
...
@@ -1100,7 +1457,6 @@ movetomodule(DWDie *parent)
die
->
link
=
parent
->
child
;
}
/*
* Filename fragments for the line history stack.
*/
...
...
@@ -1211,6 +1567,24 @@ addhistfile(char *zentry)
return
histfilesize
-
1
;
}
// if the histfile stack contains ..../runtime/runtime_defs.go
// use that to set gdbscript
static
void
finddebugruntimepath
()
{
int
i
,
l
;
char
*
c
;
for
(
i
=
1
;
i
<
histfilesize
;
i
++
)
{
if
((
c
=
strstr
(
histfile
[
i
],
"runtime/runtime_defs.go"
))
!=
nil
)
{
l
=
c
-
histfile
[
i
];
memmove
(
gdbscript
,
histfile
[
i
],
l
);
memmove
(
gdbscript
+
l
,
"runtime/runtime-gdb.py"
,
strlen
(
"runtime/runtime-gdb.py"
)
+
1
);
break
;
}
}
}
// Go's runtime C sources are sane, and Go sources nest only 1 level,
// so 16 should be plenty.
static
struct
{
...
...
@@ -1435,14 +1809,14 @@ writelines(void)
Prog
*
q
;
Sym
*
s
;
Auto
*
a
;
vlong
unitstart
;
vlong
unitstart
,
offs
;
vlong
pc
,
epc
,
lc
,
llc
,
lline
;
int
currfile
;
int
i
,
lang
,
da
,
dt
;
Linehist
*
lh
;
DWDie
*
dwinfo
,
*
dwfunc
,
*
dwvar
,
**
dws
;
DWDie
*
varhash
[
HASHSIZE
];
char
*
n
;
char
*
n
,
*
nn
;
unitstart
=
-
1
;
epc
=
pc
=
0
;
...
...
@@ -1471,6 +1845,7 @@ writelines(void)
}
lang
=
guesslang
(
histfile
[
1
]);
finddebugruntimepath
();
dwinfo
=
newdie
(
&
dwroot
,
DW_ABRV_COMPUNIT
,
strdup
(
histfile
[
1
]));
newattr
(
dwinfo
,
DW_AT_language
,
DW_CLS_CONSTANT
,
lang
,
0
);
...
...
@@ -1561,14 +1936,15 @@ writelines(void)
da
=
0
;
dwfunc
->
hash
=
varhash
;
// enable indexing of children by name
memset
(
varhash
,
0
,
sizeof
varhash
);
for
(
a
=
s
->
autom
;
a
;
a
=
a
->
link
)
{
switch
(
a
->
type
)
{
case
D_AUTO
:
dt
=
DW_ABRV_AUTO
;
offs
=
a
->
aoffset
-
PtrSize
;
break
;
case
D_PARAM
:
dt
=
DW_ABRV_PARAM
;
offs
=
a
->
aoffset
;
break
;
default:
continue
;
...
...
@@ -1579,15 +1955,20 @@ writelines(void)
n
=
mkvarname
(
a
->
asym
->
name
,
da
);
else
n
=
a
->
asym
->
name
;
// Drop the package prefix from locals and arguments.
nn
=
strrchr
(
n
,
'.'
);
if
(
nn
)
n
=
nn
+
1
;
dwvar
=
newdie
(
dwfunc
,
dt
,
n
);
newcfaoffsetattr
(
dwvar
,
a
->
aoffset
);
newcfaoffsetattr
(
dwvar
,
offs
);
newrefattr
(
dwvar
,
DW_AT_type
,
defgotype
(
a
->
gotype
));
// push dwvar down dwfunc->child to keep order
newattr
(
dwvar
,
DW_AT_internal_location
,
DW_CLS_CONSTANT
,
a
->
aoffset
,
NULL
);
// push dwvar down dwfunc->child to preserve order
newattr
(
dwvar
,
DW_AT_internal_location
,
DW_CLS_CONSTANT
,
offs
,
NULL
);
dwfunc
->
child
=
dwvar
->
link
;
// take dwvar out from the top of the list
for
(
dws
=
&
dwfunc
->
child
;
*
dws
!=
nil
;
dws
=
&
(
*
dws
)
->
link
)
if
(
a
->
aoffset
>
getattr
(
*
dws
,
DW_AT_internal_location
)
->
value
)
if
(
offs
>
getattr
(
*
dws
,
DW_AT_internal_location
)
->
value
)
break
;
dwvar
->
link
=
*
dws
;
*
dws
=
dwvar
;
...
...
@@ -1818,7 +2199,7 @@ writepub(int (*ispub)(DWDie*))
* because we need die->offs of dw_globals.
*/
static
vlong
writearanges
()
writearanges
(
void
)
{
DWDie
*
compunit
;
DWAttr
*
b
,
*
e
;
...
...
@@ -1853,6 +2234,21 @@ writearanges()
return
sectionstart
;
}
static
vlong
writegdbscript
(
void
)
{
vlong
sectionstart
;
sectionstart
=
cpos
();
if
(
gdbscript
[
0
])
{
cput
(
1
);
// magic 1 byte?
strnput
(
gdbscript
,
strlen
(
gdbscript
)
+
1
);
cflush
();
}
return
sectionstart
;
}
/*
* This is the main entry point for generating dwarf. After emitting
* the mandatory debug_abbrev section, it calls writelines() to set up
...
...
@@ -1866,7 +2262,10 @@ void
dwarfemitdebugsections
(
void
)
{
vlong
infoe
;
DWDie
*
die
;
DWDie
*
die
;
// For diagnostic messages.
newattr
(
&
dwtypes
,
DW_AT_name
,
DW_CLS_STRING
,
strlen
(
"dwtypes"
),
"dwtypes"
);
mkindex
(
&
dwroot
);
mkindex
(
&
dwtypes
);
...
...
@@ -1875,39 +2274,33 @@ dwarfemitdebugsections(void)
// Some types that must exist to define other ones.
newdie
(
&
dwtypes
,
DW_ABRV_NULLTYPE
,
"<unspecified>"
);
newdie
(
&
dwtypes
,
DW_ABRV_NULLTYPE
,
"void"
);
die
=
newdie
(
&
dwtypes
,
DW_ABRV_PTRTYPE
,
"unsafe.Pointer"
);
newrefattr
(
die
,
DW_AT_type
,
find
(
&
dwtypes
,
"void"
));
newrefattr
(
newdie
(
&
dwtypes
,
DW_ABRV_PTRTYPE
,
"unsafe.Pointer"
),
DW_AT_type
,
find
(
&
dwtypes
,
"void"
));
die
=
newdie
(
&
dwtypes
,
DW_ABRV_BASETYPE
,
"uintptr"
);
// needed for array size
newattr
(
die
,
DW_AT_encoding
,
DW_CLS_CONSTANT
,
DW_ATE_unsigned
,
0
);
newattr
(
die
,
DW_AT_byte_size
,
DW_CLS_CONSTANT
,
PtrSize
,
0
);
die
=
newdie
(
&
dwtypes
,
DW_ABRV_BASETYPE
,
"<int32>"
);
newattr
(
die
,
DW_AT_encoding
,
DW_CLS_CONSTANT
,
DW_ATE_signed
,
0
);
newattr
(
die
,
DW_AT_byte_size
,
DW_CLS_CONSTANT
,
4
,
0
);
die
=
newdie
(
&
dwtypes
,
DW_ABRV_BASETYPE
,
"<byte>"
);
newattr
(
die
,
DW_AT_encoding
,
DW_CLS_CONSTANT
,
DW_ATE_unsigned
,
0
);
newattr
(
die
,
DW_AT_byte_size
,
DW_CLS_CONSTANT
,
1
,
0
);
die
=
newdie
(
&
dwtypes
,
DW_ABRV_PTRTYPE
,
"<byte*>"
);
newrefattr
(
die
,
DW_AT_type
,
find
(
&
dwtypes
,
"<byte>"
));
genasmsym
(
defdwsymb
);
reversetree
(
&
dwtypes
.
child
);
reversetree
(
&
dwglobals
.
child
);
writeabbrev
();
writelines
();
writeframes
();
synthesizestringtypes
(
dwtypes
.
child
);
synthesizeslicetypes
(
dwtypes
.
child
);
synthesizemaptypes
(
dwtypes
.
child
);
synthesizechantypes
(
dwtypes
.
child
);
reversetree
(
&
dwroot
.
child
);
movetomodule
(
&
dwtypes
);
// TODO: put before functions
movetomodule
(
&
dwglobals
);
reversetree
(
&
dwtypes
.
child
);
reversetree
(
&
dwglobals
.
child
);
movetomodule
(
&
dwtypes
);
movetomodule
(
&
dwglobals
);
infoo
=
cpos
();
writeinfo
();
arangeso
=
pubtypeso
=
pubnameso
=
infoe
=
cpos
();
gdbscripto
=
arangeso
=
pubtypeso
=
pubnameso
=
infoe
=
cpos
();
if
(
fwdcount
>
0
)
{
if
(
debug
[
'v'
])
...
...
@@ -1925,13 +2318,15 @@ dwarfemitdebugsections(void)
}
infosize
=
infoe
-
infoo
;
pubnameso
=
writepub
(
ispubname
);
pubtypeso
=
writepub
(
ispubtype
);
arangeso
=
writearanges
();
pubnameso
=
writepub
(
ispubname
);
pubtypeso
=
writepub
(
ispubtype
);
arangeso
=
writearanges
();
gdbscripto
=
writegdbscript
();
pubnamessize
=
pubtypeso
-
pubnameso
;
pubtypessize
=
arangeso
-
pubtypeso
;
arangessize
=
cpos
()
-
arangeso
;
pubnamessize
=
pubtypeso
-
pubnameso
;
pubtypessize
=
arangeso
-
pubtypeso
;
arangessize
=
gdbscripto
-
arangeso
;
gdbscriptsize
=
cpos
()
-
gdbscripto
;
}
/*
...
...
@@ -1950,6 +2345,7 @@ enum
ElfStrDebugPubTypes
,
ElfStrDebugRanges
,
ElfStrDebugStr
,
ElfStrGDBScripts
,
NElfStrDbg
};
...
...
@@ -1969,6 +2365,7 @@ dwarfaddshstrings(Sym *shstrtab)
elfstrdbg
[
ElfStrDebugPubTypes
]
=
addstring
(
shstrtab
,
".debug_pubtypes"
);
elfstrdbg
[
ElfStrDebugRanges
]
=
addstring
(
shstrtab
,
".debug_ranges"
);
elfstrdbg
[
ElfStrDebugStr
]
=
addstring
(
shstrtab
,
".debug_str"
);
elfstrdbg
[
ElfStrGDBScripts
]
=
addstring
(
shstrtab
,
".debug_gdb_scripts"
);
}
void
...
...
@@ -2023,6 +2420,14 @@ dwarfaddelfheaders(void)
sh
->
size
=
arangessize
;
sh
->
addralign
=
1
;
}
if
(
gdbscriptsize
)
{
sh
=
newElfShdr
(
elfstrdbg
[
ElfStrGDBScripts
]);
sh
->
type
=
SHT_PROGBITS
;
sh
->
off
=
gdbscripto
;
sh
->
size
=
gdbscriptsize
;
sh
->
addralign
=
1
;
}
}
/*
...
...
@@ -2033,7 +2438,6 @@ dwarfaddmachoheaders(void)
{
MachoSect
*
msect
;
MachoSeg
*
ms
;
vlong
fakestart
;
int
nsect
;
...
...
@@ -2042,9 +2446,14 @@ dwarfaddmachoheaders(void)
fakestart
=
abbrevo
&
~
0xfff
;
nsect
=
4
;
if
(
pubnamessize
>
0
)
nsect
++
;
if
(
pubtypessize
>
0
)
nsect
++
;
if
(
arangessize
>
0
)
nsect
++
;
if
(
pubnamessize
>
0
)
nsect
++
;
if
(
pubtypessize
>
0
)
nsect
++
;
if
(
arangessize
>
0
)
nsect
++
;
if
(
gdbscriptsize
>
0
)
nsect
++
;
ms
=
newMachoSeg
(
"__DWARF"
,
nsect
);
ms
->
fileoffset
=
fakestart
;
...
...
@@ -2090,4 +2499,12 @@ dwarfaddmachoheaders(void)
msect
->
size
=
arangessize
;
ms
->
filesize
+=
msect
->
size
;
}
// TODO(lvd) fix gdb/python to load MachO (16 char section name limit)
if
(
gdbscriptsize
>
0
)
{
msect
=
newMachoSect
(
ms
,
"__debug_gdb_scripts"
);
msect
->
off
=
gdbscripto
;
msect
->
size
=
gdbscriptsize
;
ms
->
filesize
+=
msect
->
size
;
}
}
src/pkg/runtime/runtime-gdb.py
0 → 100644
View file @
9a71bb00
# Copyright 2010 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.
"""GDB Pretty printers and convencience functions for Go's runtime structures.
This script is loaded by GDB when it finds a .debug_gdb_scripts
section in the compiled binary. The [68]l linkers emit this with a
path to this file based on the path to the runtime package.
"""
import
sys
,
re
print
>>
sys
.
stderr
,
"Loading Go Runtime support."
#
# Pretty Printers
#
class
StringTypePrinter
:
"Pretty print Go strings."
pattern
=
re
.
compile
(
r'^struct string$'
)
def
__init__
(
self
,
val
):
self
.
val
=
val
def
display_hint
(
self
):
return
'string'
def
to_string
(
self
):
return
self
.
val
[
'str'
]
class
SliceTypePrinter
:
"Pretty print slices."
pattern
=
re
.
compile
(
r'^struct \[\]'
)
def
__init__
(
self
,
val
):
self
.
val
=
val
def
display_hint
(
self
):
return
'array'
def
to_string
(
self
):
return
str
(
self
.
val
.
type
)[
6
:]
# skip 'struct '
def
children
(
self
):
ptr
=
self
.
val
[
"array"
]
for
idx
in
range
(
self
.
val
[
"len"
]):
yield
(
'[
%
d]'
%
idx
,
(
ptr
+
idx
)
.
dereference
())
class
MapTypePrinter
:
"""Pretty print map[K]V types.
Map-typed go variables are really pointers. dereference them in gdb
to inspect their contents with this pretty printer.
"""
pattern
=
re
.
compile
(
r'^struct hash<.*>$'
)
def
__init__
(
self
,
val
):
self
.
val
=
val
def
display_hint
(
self
):
return
'map'
def
to_string
(
self
):
return
str
(
self
.
val
.
type
)
def
children
(
self
):
stab
=
self
.
val
[
'st'
]
i
=
0
for
v
in
self
.
traverse_hash
(
stab
):
yield
(
"[
%
d]"
%
i
,
v
[
'key'
])
yield
(
"[
%
d]"
%
(
i
+
1
),
v
[
'val'
])
i
+=
2
def
traverse_hash
(
self
,
stab
):
ptr
=
stab
[
'entry'
]
.
address
end
=
stab
[
'end'
]
while
ptr
<
end
:
v
=
ptr
.
dereference
()
ptr
=
ptr
+
1
if
v
[
'hash'
]
==
0
:
continue
if
v
[
'hash'
]
&
63
==
63
:
# subtable
for
v
in
self
.
traverse_hash
(
v
[
'key'
]
.
cast
(
self
.
val
[
'st'
]
.
type
)):
yield
v
else
:
yield
v
class
ChanTypePrinter
:
"""Pretty print chan[T] types.
Map-typed go variables are really pointers. dereference them in gdb
to inspect their contents with this pretty printer.
"""
pattern
=
re
.
compile
(
r'^struct hchan<.*>$'
)
def
__init__
(
self
,
val
):
self
.
val
=
val
def
display_hint
(
self
):
return
'array'
def
to_string
(
self
):
return
str
(
self
.
val
.
type
)
def
children
(
self
):
ptr
=
self
.
val
[
'recvdataq'
]
for
idx
in
range
(
self
.
val
[
"qcount"
]):
yield
(
'[
%
d]'
%
idx
,
ptr
[
'elem'
])
ptr
=
ptr
[
'link'
]
#
# Register all the *Printer classes
#
def
makematcher
(
klass
):
def
matcher
(
val
):
try
:
if
klass
.
pattern
.
match
(
str
(
val
.
type
)):
return
klass
(
val
)
except
:
pass
return
matcher
gdb
.
current_objfile
()
.
pretty_printers
.
extend
([
makematcher
(
k
)
for
k
in
vars
()
.
values
()
if
hasattr
(
k
,
'pattern'
)])
#
# Convenience Functions
#
class
GoLenFunc
(
gdb
.
Function
):
"Length of strings, slices, maps or channels"
how
=
((
StringTypePrinter
,
'len'
),
(
SliceTypePrinter
,
'len'
),
(
MapTypePrinter
,
'count'
),
(
ChanTypePrinter
,
'qcount'
))
def
__init__
(
self
):
super
(
GoLenFunc
,
self
)
.
__init__
(
"len"
)
def
invoke
(
self
,
obj
):
typename
=
str
(
obj
.
type
)
for
klass
,
fld
in
self
.
how
:
if
klass
.
pattern
.
match
(
typename
):
return
obj
[
fld
]
class
GoCapFunc
(
gdb
.
Function
):
"Capacity of slices or channels"
how
=
((
SliceTypePrinter
,
'cap'
),
(
ChanTypePrinter
,
'dataqsiz'
))
def
__init__
(
self
):
super
(
GoCapFunc
,
self
)
.
__init__
(
"cap"
)
def
invoke
(
self
,
obj
):
typename
=
str
(
obj
.
type
)
for
klass
,
fld
in
self
.
how
:
if
klass
.
pattern
.
match
(
typename
):
return
obj
[
fld
]
#
# Register all convience functions and CLI commands
#
for
k
in
vars
()
.
values
():
if
hasattr
(
k
,
'invoke'
):
k
()
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment