Compare commits

...

5 Commits

Author SHA1 Message Date
Zxilly 1f4758a159
Merge cefd445939 into 8552bcf7c2 2025-06-18 15:32:58 -04:00
Zxilly cefd445939
remove type:string 2025-06-06 04:18:02 +08:00
Zxilly a2c54efd5f
fix type name 2025-06-03 23:40:35 +08:00
Zxilly 182a289ef3
keep type name 2025-06-03 21:32:33 +08:00
Zxilly 900bf7e125
cmd: emit dwarf for string constants 2025-06-02 04:04:02 +08:00
5 changed files with 130 additions and 18 deletions

View File

@ -176,22 +176,34 @@ func dumpGlobalConst(n *ir.Name) {
return
}
// only export integer constants for now
if !t.IsInteger() {
if !t.IsInteger() && !t.IsString() {
return
}
v := n.Val()
if t.IsUntyped() {
// Export untyped integers as int (if they fit).
t = types.Types[types.TINT]
if ir.ConstOverflow(v, t) {
return
if t.IsInteger() {
// Export untyped integers as int (if they fit).
t = types.Types[types.TINT]
if ir.ConstOverflow(v, t) {
return
}
} else {
t = types.Types[types.TSTRING]
}
} else {
// If the type of the constant is an instantiated generic, we need to emit
// that type so the linker knows about it. See issue 51245.
_ = reflectdata.TypeLinksym(t)
if t.IsInteger() {
// If the type of the constant is an instantiated generic, we need to emit
// that type so the linker knows about it. See issue 51245.
_ = reflectdata.TypeLinksym(t)
}
// For const string, type:string isn't the real type.
}
if t.IsInteger() {
base.Ctxt.DwarfIntConst(n.Sym().Name, types.TypeSymName(t), ir.IntVal(t, v))
} else if t.IsString() {
base.Ctxt.DwarfStringConst(n.Sym().Name, types.TypeSymName(t), ir.StringVal(n))
}
base.Ctxt.DwarfIntConst(n.Sym().Name, types.TypeSymName(t), ir.IntVal(t, v))
}
// addGCLocals adds gcargs, gclocals, gcregs, and stack object symbols to Ctxt.Data.

View File

@ -27,6 +27,10 @@ const InfoPrefix = "go:info."
// entries that contain constants.
const ConstInfoPrefix = "go:constinfo."
// ConstStringInfoPrefix is the prefix for all symbols containing
// DWARF info entries that are referred by string constants.
const ConstStringInfoPrefix = "$const."
// CUInfoPrefix is the prefix for symbols containing information to
// populate the DWARF compilation unit info entries.
const CUInfoPrefix = "go:cuinfo."
@ -336,6 +340,7 @@ const (
DW_ABRV_INLINED_SUBROUTINE_RANGES
DW_ABRV_VARIABLE
DW_ABRV_INT_CONSTANT
DW_ABRV_STRING_CONSTANT
DW_ABRV_LEXICAL_BLOCK_RANGES
DW_ABRV_LEXICAL_BLOCK_SIMPLE
DW_ABRV_STRUCTFIELD
@ -354,6 +359,7 @@ const (
DW_ABRV_BARE_PTRTYPE // only for void*, no DW_AT_type attr to please gdb 6.
DW_ABRV_SLICETYPE
DW_ABRV_STRINGTYPE
DW_ABRV_CONSTANT_STRINGTYPE
DW_ABRV_STRUCTTYPE
DW_ABRV_TYPEDECL
DW_ABRV_DICT_INDEX
@ -575,7 +581,7 @@ var abbrevs = []dwAbbrev{
},
},
/* INT CONSTANT */
/* INT_CONSTANT */
{
DW_TAG_constant,
DW_CHILDREN_no,
@ -586,6 +592,17 @@ var abbrevs = []dwAbbrev{
},
},
/* STRING_CONSTANT */
{
DW_TAG_constant,
DW_CHILDREN_no,
[]dwAttrForm{
{DW_AT_name, DW_FORM_string},
{DW_AT_type, DW_FORM_ref_addr},
{DW_AT_const_value, DW_FORM_block1},
},
},
/* LEXICAL_BLOCK_RANGES */
{
DW_TAG_lexical_block,
@ -807,6 +824,16 @@ var abbrevs = []dwAbbrev{
},
},
/* CONSTANT_STRINGTYPE */
{
DW_TAG_string_type,
DW_CHILDREN_no,
[]dwAttrForm{
{DW_AT_name, DW_FORM_string},
{DW_AT_byte_size, DW_FORM_udata},
},
},
/* STRUCTTYPE */
{
DW_TAG_structure_type,
@ -1031,6 +1058,14 @@ func PutIntConst(ctxt Context, info, typ Sym, name string, val int64) {
putattr(ctxt, info, DW_ABRV_INT_CONSTANT, DW_FORM_sdata, DW_CLS_CONSTANT, val, nil)
}
// PutStringConst writes a DIE for a string constant
func PutStringConst(ctxt Context, info, typ Sym, name string, val string) {
Uleb128put(ctxt, info, DW_ABRV_STRING_CONSTANT)
putattr(ctxt, info, DW_ABRV_STRING_CONSTANT, DW_FORM_string, DW_CLS_STRING, int64(len(name)), name)
putattr(ctxt, info, DW_ABRV_STRING_CONSTANT, DW_FORM_ref_addr, DW_CLS_REFERENCE, 0, typ)
putattr(ctxt, info, DW_ABRV_STRING_CONSTANT, DW_FORM_block1, DW_CLS_BLOCK, int64(len(val)), []byte(val))
}
// PutGlobal writes a DIE for a global variable.
func PutGlobal(ctxt Context, info, typ, gvar Sym, name string) {
Uleb128put(ctxt, info, DW_ABRV_VARIABLE)

View File

@ -12,6 +12,7 @@ import (
"cmd/internal/src"
"fmt"
"slices"
"strconv"
"strings"
"sync"
)
@ -393,18 +394,38 @@ func (ctxt *Link) populateDWARF(curfn Func, s *LSym) {
ctxt.generateDebugLinesSymbol(s, lines)
}
// DwarfIntConst creates a link symbol for an integer constant with the
// given name, type and value.
func (ctxt *Link) DwarfIntConst(name, typename string, val int64) {
// ensureConstInfoSym ensures that the DWARF constant info symbol exists
func (ctxt *Link) ensureConstInfoSym() *LSym {
myimportpath := ctxt.Pkgpath
if myimportpath == "" {
return
return nil
}
s := ctxt.LookupInit(dwarf.ConstInfoPrefix+myimportpath, func(s *LSym) {
s.Type = objabi.SDWARFCONST
ctxt.Data = append(ctxt.Data, s)
})
dwarf.PutIntConst(dwCtxt{ctxt}, s, ctxt.Lookup(dwarf.InfoPrefix+typename), myimportpath+"."+name, val)
return s
}
// DwarfIntConst creates a link symbol for an integer constant with the
// given name, type and value.
func (ctxt *Link) DwarfIntConst(name, typename string, val int64) {
s := ctxt.ensureConstInfoSym()
if s == nil {
return
}
dwarf.PutIntConst(dwCtxt{ctxt}, s, ctxt.Lookup(dwarf.InfoPrefix+typename), ctxt.Pkgpath+"."+name, val)
}
// DwarfStringConst creates a link symbol for a string constant with the
// given name and value.
func (ctxt *Link) DwarfStringConst(name, typename, value string) {
s := ctxt.ensureConstInfoSym()
if s == nil {
return
}
typSym := ctxt.Lookup(dwarf.InfoPrefix + dwarf.ConstStringInfoPrefix + typename + "." + strconv.Itoa(len(value)))
dwarf.PutStringConst(dwCtxt{ctxt}, s, typSym, ctxt.Pkgpath+"."+name, value)
}
// DwarfGlobal creates a link symbol containing a DWARF entry for

View File

@ -29,6 +29,7 @@ import (
"path"
"runtime"
"slices"
"strconv"
"strings"
"sync"
)
@ -285,13 +286,16 @@ func (d *dwctxt) newdie(parent *dwarf.DWDie, abbrev int, name string) *dwarf.DWD
die.Link = parent.Child
parent.Child = die
newattr(die, dwarf.DW_AT_name, dwarf.DW_CLS_STRING, int64(len(name)), name)
// Sanity check: all DIEs created in the linker should be named.
if name == "" {
panic("nameless DWARF DIE")
}
// for constant string types, we emit the nams later since it didn't use symbol name as DW_AT_name
if abbrev != dwarf.DW_ABRV_CONSTANT_STRINGTYPE {
newattr(die, dwarf.DW_AT_name, dwarf.DW_CLS_STRING, int64(len(name)), name)
}
var st sym.SymKind
switch abbrev {
case dwarf.DW_ABRV_FUNCTYPEPARAM, dwarf.DW_ABRV_FUNCTYPEOUTPARAM, dwarf.DW_ABRV_DOTDOTDOT, dwarf.DW_ABRV_STRUCTFIELD, dwarf.DW_ABRV_ARRAYRANGE:
@ -1183,6 +1187,24 @@ func getCompilationDir() string {
return "."
}
func (d *dwctxt) genConstStringType(name string) {
if d.find(name) != 0 {
return
}
i := strings.LastIndex(name, ".")
if i < 0 {
log.Fatalf("error: invalid constant string type name %q", name)
}
size, err := strconv.ParseInt(name[i+1:], 10, 64)
if err != nil {
log.Fatalf("error: invalid constant string type name %q: %v", name, err)
}
atname := name[len(dwarf.ConstStringInfoPrefix):i]
die := d.newdie(&dwtypes, dwarf.DW_ABRV_CONSTANT_STRINGTYPE, name)
newattr(die, dwarf.DW_AT_name, dwarf.DW_CLS_STRING, int64(len(atname)), atname)
newattr(die, dwarf.DW_AT_byte_size, dwarf.DW_CLS_CONSTANT, size, 0)
}
func (d *dwctxt) importInfoSymbol(dsym loader.Sym) {
d.ldr.SetAttrReachable(dsym, true)
d.ldr.SetAttrNotInSymbolTable(dsym, true)
@ -1207,6 +1229,15 @@ func (d *dwctxt) importInfoSymbol(dsym loader.Sym) {
// symbol name here?
sn := d.ldr.SymName(rsym)
tn := sn[len(dwarf.InfoPrefix):]
// If the symbol is a constant string type, we generate it
// These types do not exist in go,
// but can tell gdb how to interpret the corresponding values
if strings.HasPrefix(tn, dwarf.ConstStringInfoPrefix) {
d.genConstStringType(tn)
continue
}
ts := d.ldr.Lookup("type:"+tn, 0)
d.defgotype(ts)
}

View File

@ -662,6 +662,9 @@ package main
const aConstant int = 42
const largeConstant uint64 = ^uint64(0)
const minusOne int64 = -1
const typedS string = "typed string"
const untypedS = "untyped string"
const nulS string = "\x00str"
func main() {
println("hello world")
@ -700,6 +703,9 @@ func TestGdbConst(t *testing.T) {
"-ex", "print main.minusOne",
"-ex", "print 'runtime.mSpanInUse'",
"-ex", "print 'runtime._PageSize'",
"-ex", "print main.typedS",
"-ex", "print main.untypedS",
"-ex", "print main.nulS",
filepath.Join(dir, "a.exe"),
}
gdbArgsFixup(args)
@ -711,7 +717,14 @@ func TestGdbConst(t *testing.T) {
sgot := strings.ReplaceAll(string(got), "\r\n", "\n")
if !strings.Contains(sgot, "\n$1 = 42\n$2 = 18446744073709551615\n$3 = -1\n$4 = 1 '\\001'\n$5 = 8192") {
if !strings.Contains(sgot, `$1 = 42
$2 = 18446744073709551615
$3 = -1
$4 = 1 '\001'
$5 = 8192
$6 = "typed string"
$7 = "untyped string"
$8 = "\000str"`) {
t.Fatalf("output mismatch")
}
}