}
}
+func dumpGlobal(n *Node) {
+ if n.Type == nil {
+ Fatalf("external %v nil type\n", n)
+ }
+ if n.Class() == PFUNC {
+ return
+ }
+ if n.Sym.Pkg != localpkg {
+ return
+ }
+ dowidth(n.Type)
+ ggloblnod(n)
+}
+
+func dumpGlobalConst(n *Node) {
+ // only export typed constants
+ if n.Type == nil {
+ return
+ }
+ if n.Sym.Pkg != localpkg {
+ return
+ }
+ // only export integer constants for now
+ switch n.Type.Etype {
+ case TINT8:
+ case TINT16:
+ case TINT32:
+ case TINT64:
+ case TINT:
+ case TUINT8:
+ case TUINT16:
+ case TUINT32:
+ case TUINT64:
+ case TUINT:
+ case TUINTPTR:
+ // ok
+ default:
+ return
+ }
+ Ctxt.DwarfIntConst(myimportpath, n.Sym.Name, typesymname(n.Type), n.Int64())
+}
+
func dumpglobls() {
// add globals
for _, n := range externdcl {
- if n.Op != ONAME {
- continue
- }
-
- if n.Type == nil {
- Fatalf("external %v nil type\n", n)
- }
- if n.Class() == PFUNC {
- continue
- }
- if n.Sym.Pkg != localpkg {
- continue
+ switch n.Op {
+ case ONAME:
+ dumpGlobal(n)
+ case OLITERAL:
+ dumpGlobalConst(n)
}
- dowidth(n.Type)
- ggloblnod(n)
}
obj.SortSlice(funcsyms, func(i, j int) bool {
// For package runtime, this writes go_asm.h, which
// the assembly files will need.
pkg := dir
- if strings.HasPrefix(dir, "cmd/") {
+ if strings.HasPrefix(dir, "cmd/") && strings.Count(dir, "/") == 1 {
pkg = "main"
}
b := pathf("%s/_go_.a", workdir)
// RangePrefix is the prefix for all the symbols containing DWARF range lists.
const RangePrefix = "go.range."
+// InfoConstPrefix is the prefix for all symbols containing DWARF info
+// entries that contain constants.
+const ConstInfoPrefix = "go.constinfo."
+
// Sym represents a symbol.
type Sym interface {
Len() int64
DW_ABRV_COMPUNIT
DW_ABRV_FUNCTION
DW_ABRV_VARIABLE
+ DW_ABRV_INT_CONSTANT
DW_ABRV_AUTO
DW_ABRV_AUTO_LOCLIST
DW_ABRV_PARAM
},
},
+ /* INT 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_sdata},
+ },
+ },
+
/* AUTO */
{
DW_TAG_variable,
return abbrevs[die.Abbrev].children != 0
}
+// PutIntConst writes a DIE for an integer constant
+func PutIntConst(ctxt Context, info, typ Sym, name string, val int64) {
+ Uleb128put(ctxt, info, DW_ABRV_INT_CONSTANT)
+ putattr(ctxt, info, DW_ABRV_INT_CONSTANT, DW_FORM_string, DW_CLS_STRING, int64(len(name)), name)
+ putattr(ctxt, info, DW_ABRV_INT_CONSTANT, DW_FORM_ref_addr, DW_CLS_REFERENCE, 0, typ)
+ putattr(ctxt, info, DW_ABRV_INT_CONSTANT, DW_FORM_sdata, DW_CLS_CONSTANT, val, nil)
+}
+
// PutFunc writes a DIE for a function to s.
// It also writes child DIEs for each variable in vars.
func PutFunc(ctxt Context, info, loc, ranges Sym, name string, external bool, startPC Sym, size int64, scopes []Scope) error {
ctxt.Diag("emitting DWARF for %s failed: %v", s.Name, err)
}
}
+
+// DwarfIntConst creates a link symbol for an integer constant with the
+// given name, type and value.
+func (ctxt *Link) DwarfIntConst(myimportpath, name, typename string, val int64) {
+ if myimportpath == "" {
+ return
+ }
+ s := ctxt.LookupInit(dwarf.ConstInfoPrefix+myimportpath, func(s *LSym) {
+ s.Type = objabi.SDWARFINFO
+ ctxt.Data = append(ctxt.Data, s)
+ })
+ dwarf.PutIntConst(dwCtxt{ctxt}, s, ctxt.Lookup(dwarf.InfoPrefix+typename), myimportpath+"."+name, val)
+}
return "/"
}
+func importInfoSymbol(ctxt *Link, dsym *Symbol) {
+ dsym.Attr |= AttrNotInSymbolTable | AttrReachable
+ dsym.Type = SDWARFINFO
+ for _, r := range dsym.R {
+ if r.Type == objabi.R_DWARFREF && r.Sym.Size == 0 {
+ if Buildmode == BuildmodeShared {
+ // These type symbols may not be present in BuildmodeShared. Skip.
+ continue
+ }
+ n := nameFromDIESym(r.Sym)
+ defgotype(ctxt, ctxt.Syms.Lookup("type."+n, 0))
+ }
+ }
+}
+
func writelines(ctxt *Link, syms []*Symbol) ([]*Symbol, []*Symbol) {
var dwarfctxt dwarf.Context = dwctxt{ctxt}
ls := ctxt.Syms.Lookup(".debug_line", 0)
epcs = s
dsym := ctxt.Syms.Lookup(dwarf.InfoPrefix+s.Name, int(s.Version))
- dsym.Attr |= AttrNotInSymbolTable | AttrReachable
- dsym.Type = SDWARFINFO
- for _, r := range dsym.R {
- if r.Type == objabi.R_DWARFREF && r.Sym.Size == 0 {
- if Buildmode == BuildmodeShared {
- // These type symbols may not be present in BuildmodeShared. Skip.
- continue
- }
- n := nameFromDIESym(r.Sym)
- defgotype(ctxt, ctxt.Syms.Lookup("type."+n, 0))
- }
- }
+ importInfoSymbol(ctxt, dsym)
funcs = append(funcs, dsym)
finddebugruntimepath(s)
COMPUNITHEADERSIZE = 4 + 2 + 4 + 1
)
-func writeinfo(ctxt *Link, syms []*Symbol, funcs []*Symbol, abbrevsym *Symbol) []*Symbol {
+func writeinfo(ctxt *Link, syms []*Symbol, funcs, consts []*Symbol, abbrevsym *Symbol) []*Symbol {
infosec := ctxt.Syms.Lookup(".debug_info", 0)
infosec.R = infosec.R[:0]
infosec.Type = SDWARFINFO
cu = append(cu, funcs...)
funcs = nil
}
+ if consts != nil {
+ cu = append(cu, consts...)
+ consts = nil
+ }
cu = putdies(ctxt, dwarfctxt, cu, compunit.Child)
var cusize int64
for _, child := range cu {
genasmsym(ctxt, defdwsymb)
+ var consts []*Symbol
+ for _, lib := range ctxt.Library {
+ if s := ctxt.Syms.Lookup(dwarf.ConstInfoPrefix+lib.Pkg, 0); s != nil {
+ importInfoSymbol(ctxt, s)
+ consts = append(consts, s)
+ }
+ }
+
abbrev := writeabbrev(ctxt)
syms := []*Symbol{abbrev}
syms, funcs := writelines(ctxt, syms)
// Need to reorder symbols so SDWARFINFO is after all SDWARFSECT
// (but we need to generate dies before writepub)
- infosyms := writeinfo(ctxt, nil, funcs, abbrev)
+ infosyms := writeinfo(ctxt, nil, funcs, consts, abbrev)
syms = writepub(ctxt, ".debug_pubnames", ispubname, syms)
syms = writepub(ctxt, ".debug_pubtypes", ispubtype, syms)
}
}
}
+
+const constsSource = `
+package main
+
+const aConstant int = 42
+const largeConstant uint64 = ^uint64(0)
+const minusOne int64 = -1
+
+func main() {
+ println("hello world")
+}
+`
+
+func TestGdbConst(t *testing.T) {
+ t.Parallel()
+ checkGdbEnvironment(t)
+ checkGdbVersion(t)
+
+ dir, err := ioutil.TempDir("", "go-build")
+ if err != nil {
+ t.Fatalf("failed to create temp directory: %v", err)
+ }
+ defer os.RemoveAll(dir)
+
+ // Build the source code.
+ src := filepath.Join(dir, "main.go")
+ err = ioutil.WriteFile(src, []byte(constsSource), 0644)
+ if err != nil {
+ t.Fatalf("failed to create file: %v", err)
+ }
+ cmd := exec.Command(testenv.GoToolPath(t), "build", "-gcflags=-N -l", "-o", "a.exe")
+ cmd.Dir = dir
+ out, err := testenv.CleanCmdEnv(cmd).CombinedOutput()
+ if err != nil {
+ t.Fatalf("building source %v\n%s", err, out)
+ }
+
+ // Execute gdb commands.
+ args := []string{"-nx", "-batch",
+ "-ex", "set startup-with-shell off",
+ "-ex", "break main.main",
+ "-ex", "run",
+ "-ex", "print main.aConstant",
+ "-ex", "print main.largeConstant",
+ "-ex", "print main.minusOne",
+ "-ex", "print 'runtime._MSpanInUse'",
+ filepath.Join(dir, "a.exe"),
+ }
+ got, _ := exec.Command("gdb", args...).CombinedOutput()
+
+ sgot := string(got)
+
+ t.Logf("output %q", sgot)
+
+ if strings.Index(sgot, "\n$1 = 42\n$2 = 18446744073709551615\n$3 = -1\n$4 = 1 '\\001'") < 0 {
+ t.Fatalf("output mismatch")
+ }
+}