Skip to content

Commit 900bf7e

Browse files
committed
cmd: emit dwarf for string constants
1 parent c0e149b commit 900bf7e

File tree

5 files changed

+113
-13
lines changed

5 files changed

+113
-13
lines changed

src/cmd/compile/internal/gc/obj.go

Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -176,22 +176,31 @@ func dumpGlobalConst(n *ir.Name) {
176176
return
177177
}
178178
// only export integer constants for now
179-
if !t.IsInteger() {
179+
if !t.IsInteger() && !t.IsString() {
180180
return
181181
}
182182
v := n.Val()
183183
if t.IsUntyped() {
184-
// Export untyped integers as int (if they fit).
185-
t = types.Types[types.TINT]
186-
if ir.ConstOverflow(v, t) {
187-
return
184+
if t.IsInteger() {
185+
// Export untyped integers as int (if they fit).
186+
t = types.Types[types.TINT]
187+
if ir.ConstOverflow(v, t) {
188+
return
189+
}
190+
} else {
191+
t = types.Types[types.TSTRING]
188192
}
189193
} else {
190194
// If the type of the constant is an instantiated generic, we need to emit
191195
// that type so the linker knows about it. See issue 51245.
192196
_ = reflectdata.TypeLinksym(t)
193197
}
194-
base.Ctxt.DwarfIntConst(n.Sym().Name, types.TypeSymName(t), ir.IntVal(t, v))
198+
199+
if t.IsInteger() {
200+
base.Ctxt.DwarfIntConst(n.Sym().Name, types.TypeSymName(t), ir.IntVal(t, v))
201+
} else if t.IsString() {
202+
base.Ctxt.DwarfStringConst(n.Sym().Name, ir.StringVal(n))
203+
}
195204
}
196205

197206
// addGCLocals adds gcargs, gclocals, gcregs, and stack object symbols to Ctxt.Data.

src/cmd/internal/dwarf/dwarf.go

Lines changed: 36 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,10 @@ const InfoPrefix = "go:info."
2727
// entries that contain constants.
2828
const ConstInfoPrefix = "go:constinfo."
2929

30+
// ConstStringInfoPrefix is the prefix for all symbols containing
31+
// DWARF info entries that referred by string constants.
32+
const ConstStringInfoPrefix = "string$const."
33+
3034
// CUInfoPrefix is the prefix for symbols containing information to
3135
// populate the DWARF compilation unit info entries.
3236
const CUInfoPrefix = "go:cuinfo."
@@ -336,6 +340,7 @@ const (
336340
DW_ABRV_INLINED_SUBROUTINE_RANGES
337341
DW_ABRV_VARIABLE
338342
DW_ABRV_INT_CONSTANT
343+
DW_ABRV_STRING_CONSTANT
339344
DW_ABRV_LEXICAL_BLOCK_RANGES
340345
DW_ABRV_LEXICAL_BLOCK_SIMPLE
341346
DW_ABRV_STRUCTFIELD
@@ -354,6 +359,7 @@ const (
354359
DW_ABRV_BARE_PTRTYPE // only for void*, no DW_AT_type attr to please gdb 6.
355360
DW_ABRV_SLICETYPE
356361
DW_ABRV_STRINGTYPE
362+
DW_ABRV_CONSTANT_STRINGTYPE
357363
DW_ABRV_STRUCTTYPE
358364
DW_ABRV_TYPEDECL
359365
DW_ABRV_DICT_INDEX
@@ -575,7 +581,7 @@ var abbrevs = []dwAbbrev{
575581
},
576582
},
577583

578-
/* INT CONSTANT */
584+
/* INT_CONSTANT */
579585
{
580586
DW_TAG_constant,
581587
DW_CHILDREN_no,
@@ -586,6 +592,17 @@ var abbrevs = []dwAbbrev{
586592
},
587593
},
588594

595+
/* STRING_CONSTANT */
596+
{
597+
DW_TAG_constant,
598+
DW_CHILDREN_no,
599+
[]dwAttrForm{
600+
{DW_AT_name, DW_FORM_string},
601+
{DW_AT_type, DW_FORM_ref_addr},
602+
{DW_AT_const_value, DW_FORM_block1},
603+
},
604+
},
605+
589606
/* LEXICAL_BLOCK_RANGES */
590607
{
591608
DW_TAG_lexical_block,
@@ -807,6 +824,16 @@ var abbrevs = []dwAbbrev{
807824
},
808825
},
809826

827+
/* CONSTANT_STRINGTYPE */
828+
{
829+
DW_TAG_string_type,
830+
DW_CHILDREN_no,
831+
[]dwAttrForm{
832+
{DW_AT_name, DW_FORM_string},
833+
{DW_AT_byte_size, DW_FORM_udata},
834+
},
835+
},
836+
810837
/* STRUCTTYPE */
811838
{
812839
DW_TAG_structure_type,
@@ -1031,6 +1058,14 @@ func PutIntConst(ctxt Context, info, typ Sym, name string, val int64) {
10311058
putattr(ctxt, info, DW_ABRV_INT_CONSTANT, DW_FORM_sdata, DW_CLS_CONSTANT, val, nil)
10321059
}
10331060

1061+
// PutStringConst writes a DIE for a string constant
1062+
func PutStringConst(ctxt Context, info, typ Sym, name string, val string) {
1063+
Uleb128put(ctxt, info, DW_ABRV_STRING_CONSTANT)
1064+
putattr(ctxt, info, DW_ABRV_STRING_CONSTANT, DW_FORM_string, DW_CLS_STRING, int64(len(name)), name)
1065+
putattr(ctxt, info, DW_ABRV_STRING_CONSTANT, DW_FORM_ref_addr, DW_CLS_REFERENCE, 0, typ)
1066+
putattr(ctxt, info, DW_ABRV_STRING_CONSTANT, DW_FORM_block1, DW_CLS_BLOCK, int64(len(val)), []byte(val))
1067+
}
1068+
10341069
// PutGlobal writes a DIE for a global variable.
10351070
func PutGlobal(ctxt Context, info, typ, gvar Sym, name string) {
10361071
Uleb128put(ctxt, info, DW_ABRV_VARIABLE)

src/cmd/internal/obj/dwarf.go

Lines changed: 26 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import (
1212
"cmd/internal/src"
1313
"fmt"
1414
"slices"
15+
"strconv"
1516
"strings"
1617
"sync"
1718
)
@@ -393,18 +394,38 @@ func (ctxt *Link) populateDWARF(curfn Func, s *LSym) {
393394
ctxt.generateDebugLinesSymbol(s, lines)
394395
}
395396

396-
// DwarfIntConst creates a link symbol for an integer constant with the
397-
// given name, type and value.
398-
func (ctxt *Link) DwarfIntConst(name, typename string, val int64) {
397+
// ensureConstInfoSym ensures that the DWARF constant info symbol exists
398+
func (ctxt *Link) ensureConstInfoSym() *LSym {
399399
myimportpath := ctxt.Pkgpath
400400
if myimportpath == "" {
401-
return
401+
return nil
402402
}
403403
s := ctxt.LookupInit(dwarf.ConstInfoPrefix+myimportpath, func(s *LSym) {
404404
s.Type = objabi.SDWARFCONST
405405
ctxt.Data = append(ctxt.Data, s)
406406
})
407-
dwarf.PutIntConst(dwCtxt{ctxt}, s, ctxt.Lookup(dwarf.InfoPrefix+typename), myimportpath+"."+name, val)
407+
return s
408+
}
409+
410+
// DwarfIntConst creates a link symbol for an integer constant with the
411+
// given name, type and value.
412+
func (ctxt *Link) DwarfIntConst(name, typename string, val int64) {
413+
s := ctxt.ensureConstInfoSym()
414+
if s == nil {
415+
return
416+
}
417+
dwarf.PutIntConst(dwCtxt{ctxt}, s, ctxt.Lookup(dwarf.InfoPrefix+typename), ctxt.Pkgpath+"."+name, val)
418+
}
419+
420+
// DwarfStringConst creates a link symbol for a string constant with the
421+
// given name and value.
422+
func (ctxt *Link) DwarfStringConst(name, value string) {
423+
s := ctxt.ensureConstInfoSym()
424+
if s == nil {
425+
return
426+
}
427+
typSym := ctxt.Lookup(dwarf.InfoPrefix + dwarf.ConstStringInfoPrefix + strconv.Itoa(len(value)))
428+
dwarf.PutStringConst(dwCtxt{ctxt}, s, typSym, ctxt.Pkgpath+"."+name, value)
408429
}
409430

410431
// DwarfGlobal creates a link symbol containing a DWARF entry for

src/cmd/link/internal/ld/dwarf.go

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ import (
2929
"path"
3030
"runtime"
3131
"slices"
32+
"strconv"
3233
"strings"
3334
"sync"
3435
)
@@ -1183,6 +1184,18 @@ func getCompilationDir() string {
11831184
return "."
11841185
}
11851186

1187+
func (d *dwctxt) genConstStringType(name string) {
1188+
if d.find(name) != 0 {
1189+
return
1190+
}
1191+
size, err := strconv.Atoi(name[len(dwarf.ConstStringInfoPrefix):])
1192+
if err != nil {
1193+
log.Fatalf("error: invalid constant string size %q: %v", name, err)
1194+
}
1195+
die := d.newdie(&dwtypes, dwarf.DW_ABRV_CONSTANT_STRINGTYPE, name)
1196+
newattr(die, dwarf.DW_AT_byte_size, dwarf.DW_CLS_CONSTANT, int64(size), 0)
1197+
}
1198+
11861199
func (d *dwctxt) importInfoSymbol(dsym loader.Sym) {
11871200
d.ldr.SetAttrReachable(dsym, true)
11881201
d.ldr.SetAttrNotInSymbolTable(dsym, true)
@@ -1207,6 +1220,15 @@ func (d *dwctxt) importInfoSymbol(dsym loader.Sym) {
12071220
// symbol name here?
12081221
sn := d.ldr.SymName(rsym)
12091222
tn := sn[len(dwarf.InfoPrefix):]
1223+
1224+
// If the symbol is a constant string type, we generate it
1225+
// These types do not exist in go,
1226+
// but can tell gdb how to interpret the corresponding values
1227+
if strings.HasPrefix(tn, dwarf.ConstStringInfoPrefix) {
1228+
d.genConstStringType(tn)
1229+
continue
1230+
}
1231+
12101232
ts := d.ldr.Lookup("type:"+tn, 0)
12111233
d.defgotype(ts)
12121234
}

src/runtime/runtime-gdb_test.go

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -662,6 +662,9 @@ package main
662662
const aConstant int = 42
663663
const largeConstant uint64 = ^uint64(0)
664664
const minusOne int64 = -1
665+
const typedS string = "typed string"
666+
const untypedS = "untyped string"
667+
const nulS string = "\x00str"
665668
666669
func main() {
667670
println("hello world")
@@ -700,6 +703,9 @@ func TestGdbConst(t *testing.T) {
700703
"-ex", "print main.minusOne",
701704
"-ex", "print 'runtime.mSpanInUse'",
702705
"-ex", "print 'runtime._PageSize'",
706+
"-ex", "print main.typedS",
707+
"-ex", "print main.untypedS",
708+
"-ex", "print main.nulS",
703709
filepath.Join(dir, "a.exe"),
704710
}
705711
gdbArgsFixup(args)
@@ -711,7 +717,14 @@ func TestGdbConst(t *testing.T) {
711717

712718
sgot := strings.ReplaceAll(string(got), "\r\n", "\n")
713719

714-
if !strings.Contains(sgot, "\n$1 = 42\n$2 = 18446744073709551615\n$3 = -1\n$4 = 1 '\\001'\n$5 = 8192") {
720+
if !strings.Contains(sgot, `$1 = 42
721+
$2 = 18446744073709551615
722+
$3 = -1
723+
$4 = 1 '\001'
724+
$5 = 8192
725+
$6 = "typed string"
726+
$7 = "untyped string"
727+
$8 = "\000str"`) {
715728
t.Fatalf("output mismatch")
716729
}
717730
}

0 commit comments

Comments
 (0)