Skip to content

Commit 46b335e

Browse files
mknyszekgopherbot
authored andcommitted
gocore: more fixes for Go 1.24
- The isCrashFrame flag during unwinding was never reset, which could be bad. - We're apparently reading a lot of stale constants and not seeing it because a failed read from the constants map just returns the zero value. Oops! Add a much stricter map wrapper type for constants and fix up all the stale constants. This fixes a whole bunch of things, including totally incorrect readings of the liveness maps. - More strict checking of liveness map data. Change-Id: I2cb4901df4e3f473ef8b0c09981ba222e883b0b6 Reviewed-on: https://go-review.googlesource.com/c/debug/+/635835 Reviewed-by: Michael Pratt <[email protected]> Auto-Submit: Nicolas Hillegeer <[email protected]> Commit-Queue: Nicolas Hillegeer <[email protected]> LUCI-TryBot-Result: Go LUCI <[email protected]> Reviewed-by: Nicolas Hillegeer <[email protected]>
1 parent 96bf9a9 commit 46b335e

File tree

4 files changed

+63
-42
lines changed

4 files changed

+63
-42
lines changed

internal/gocore/dwarf.go

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -241,14 +241,28 @@ func gocoreName(dt dwarf.Type) string {
241241
}
242242
}
243243

244-
func readRuntimeConstants(p *core.Process) (map[string]int64, error) {
244+
type constsMap map[string]int64
245+
246+
func (c constsMap) get(s string) int64 {
247+
v, ok := c[s]
248+
if !ok {
249+
panic("failed to find constant " + s)
250+
}
251+
return v
252+
}
253+
254+
func (c constsMap) find(s string) (int64, bool) {
255+
v, ok := c[s]
256+
return v, ok
257+
}
258+
259+
func readConstants(p *core.Process) (constsMap, error) {
245260
d, err := p.DWARF()
246261
if err != nil {
247262
return nil, fmt.Errorf("failed to read DWARF: %v", err)
248263
}
249264
consts := map[string]int64{}
250265

251-
// From 1.10, these constants are recorded in DWARF records.
252266
r := d.Reader()
253267
for e, err := r.Next(); e != nil && err == nil; e, err = r.Next() {
254268
if e.Tag != dwarf.TagConstant {
@@ -259,10 +273,6 @@ func readRuntimeConstants(p *core.Process) (map[string]int64, error) {
259273
continue
260274
}
261275
name := f.Val.(string)
262-
if !strings.HasPrefix(name, "runtime.") {
263-
continue
264-
}
265-
name = name[8:]
266276
c := e.AttrField(dwarf.AttrConstValue)
267277
if c == nil {
268278
continue

internal/gocore/module.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ func readModule(r region, fns *funcTab, rtTypeByName map[string]*Type, rtConsts
7070
// readFunc parses a runtime._func and returns a *Func.
7171
// r must have type runtime._func.
7272
// pcln must have type []byte and represent the module's pcln table region.
73-
func (m *module) readFunc(r region, pctab region, funcnametab region, rtConsts map[string]int64) *Func {
73+
func (m *module) readFunc(r region, pctab region, funcnametab region, rtConsts constsMap) *Func {
7474
f := &Func{module: m, r: r}
7575
f.entry = m.textAddr(r.Field("entryOff").Uint32())
7676
nameOff := r.Field("nameOff").Int32()
@@ -103,7 +103,7 @@ func (m *module) readFunc(r region, pctab region, funcnametab region, rtConsts m
103103
}
104104

105105
// Read pcln tables we need.
106-
if stackmap := int(rtConsts["_PCDATA_StackMapIndex"]); stackmap < len(f.pcdata) {
106+
if stackmap := int(rtConsts.get("internal/abi.PCDATA_StackMapIndex")); stackmap < len(f.pcdata) {
107107
f.stackMap.read(r.p, pctab.SliceIndex(int64(f.pcdata[stackmap])).a)
108108
} else {
109109
f.stackMap.setEmpty()

internal/gocore/process.go

Lines changed: 38 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ type Process struct {
3636

3737
// Runtime info for easier lookup.
3838
rtGlobals map[string]region
39-
rtConsts map[string]int64
39+
rtConsts constsMap
4040

4141
// A module is a loadable unit. Most Go programs have 1, programs
4242
// which load plugins will have more.
@@ -98,7 +98,7 @@ func Core(proc *core.Process) (p *Process, err error) {
9898
}
9999
p.rtTypeByName[name] = t
100100
}
101-
p.rtConsts, err = readRuntimeConstants(proc)
101+
p.rtConsts, err = readConstants(proc)
102102
if err != nil {
103103
return nil, err
104104
}
@@ -201,11 +201,11 @@ func readHeap(p *Process) (*heapTable, *Statistic, error) {
201201
mheap := p.rtGlobals["mheap_"]
202202

203203
var arenas []arena
204-
arenaSize := p.rtConsts["heapArenaBytes"]
204+
arenaSize := p.rtConsts.get("runtime.heapArenaBytes")
205205
if arenaSize%heapInfoSize != 0 {
206206
panic("arenaSize not a multiple of heapInfoSize")
207207
}
208-
arenaBaseOffset := -p.rtConsts["arenaBaseOffsetUintptr"]
208+
arenaBaseOffset := -p.rtConsts.get("runtime.arenaBaseOffsetUintptr")
209209
if p.proc.PtrSize() == 4 && arenaBaseOffset != 0 {
210210
panic("arenaBaseOffset must be 0 for 32-bit inferior")
211211
}
@@ -312,17 +312,17 @@ func readHeap0(p *Process, mheap region, arenas []arena, arenaBaseOffset int64)
312312
return nil, nil, errors.New("weird mapping " + m.Perm().String())
313313
}
314314
}
315-
pageSize := p.rtConsts["_PageSize"]
315+
pageSize := p.rtConsts.get("runtime._PageSize")
316316

317317
// Span types.
318-
spanInUse := uint8(p.rtConsts["mSpanInUse"])
319-
spanManual := uint8(p.rtConsts["mSpanManual"])
320-
spanDead := uint8(p.rtConsts["mSpanDead"])
318+
spanInUse := uint8(p.rtConsts.get("runtime.mSpanInUse"))
319+
spanManual := uint8(p.rtConsts.get("runtime.mSpanManual"))
320+
spanDead := uint8(p.rtConsts.get("runtime.mSpanDead"))
321321

322322
// Malloc header constants (go 1.22+)
323-
minSizeForMallocHeader := int64(p.rtConsts["minSizeForMallocHeader"])
324-
mallocHeaderSize := int64(p.rtConsts["mallocHeaderSize"])
325-
maxSmallSize := int64(p.rtConsts["maxSmallSize"])
323+
minSizeForMallocHeader := int64(p.rtConsts.get("runtime.minSizeForMallocHeader"))
324+
mallocHeaderSize := int64(p.rtConsts.get("runtime.mallocHeaderSize"))
325+
maxSmallSize := int64(p.rtConsts.get("runtime.maxSmallSize"))
326326

327327
abiType := p.tryFindType("internal/abi.Type")
328328

@@ -402,7 +402,7 @@ func readHeap0(p *Process, mheap region, arenas []arena, arenaBaseOffset int64)
402402
// Process special records.
403403
for sp := s.Field("specials"); sp.Address() != 0; sp = sp.Field("next") {
404404
sp = sp.Deref() // *special to special
405-
if sp.Field("kind").Uint8() != uint8(p.rtConsts["_KindSpecialFinalizer"]) {
405+
if sp.Field("kind").Uint8() != uint8(p.rtConsts.get("runtime._KindSpecialFinalizer")) {
406406
// All other specials (just profile records) can't point into the heap.
407407
continue
408408
}
@@ -466,7 +466,8 @@ func readHeap0(p *Process, mheap region, arenas []arena, arenaBaseOffset int64)
466466
}
467467
typ := region{p: p.proc, a: typeAddr, typ: abiType}
468468
nptrs := int64(typ.Field("PtrBytes").Uintptr()) / int64(heap.ptrSize)
469-
if typ.Field("Kind_").Uint8()&uint8(p.rtConsts["kindGCProg"]) != 0 {
469+
kindGCProg, hasGCProgs := p.rtConsts.find("internal/abi.KindGCProg")
470+
if hasGCProgs && typ.Field("Kind_").Uint8()&uint8(kindGCProg) != 0 {
470471
panic("unexpected GC prog on small allocation")
471472
}
472473
gcdata := typ.Field("GCData").Address()
@@ -485,7 +486,8 @@ func readHeap0(p *Process, mheap region, arenas []arena, arenaBaseOffset int64)
485486
// is in use.
486487
typ := s.Field("largeType").Deref()
487488
nptrs := int64(typ.Field("PtrBytes").Uintptr()) / int64(heap.ptrSize)
488-
if typ.Field("Kind_").Uint8()&uint8(p.rtConsts["kindGCProg"]) != 0 {
489+
kindGCProg, hasGCProgs := p.rtConsts.find("internal/abi.KindGCProg")
490+
if hasGCProgs && typ.Field("Kind_").Uint8()&uint8(kindGCProg) != 0 {
489491
panic("large object's GCProg was not unrolled")
490492
}
491493
gcdata := typ.Field("GCData").Address()
@@ -513,9 +515,9 @@ func readHeap0(p *Process, mheap region, arenas []arena, arenaBaseOffset int64)
513515
// Also keep track of how much has been scavenged.
514516
pages := mheap.Field("pages")
515517
chunks := pages.Field("chunks")
516-
pallocChunkBytes := p.rtConsts["pallocChunkBytes"]
517-
pallocChunksL1Bits := p.rtConsts["pallocChunksL1Bits"]
518-
pallocChunksL2Bits := p.rtConsts["pallocChunksL2Bits"]
518+
pallocChunkBytes := p.rtConsts.get("runtime.pallocChunkBytes")
519+
pallocChunksL1Bits := p.rtConsts.get("runtime.pallocChunksL1Bits")
520+
pallocChunksL2Bits := p.rtConsts.get("runtime.pallocChunksL2Bits")
519521
inuse := pages.Field("inUse")
520522
ranges := inuse.Field("ranges")
521523
for i := int64(0); i < ranges.SliceLen(); i++ {
@@ -621,24 +623,24 @@ func readGoroutine(p *Process, r region, dwarfVars map[*Func][]dwarfVar) (*Gorou
621623
}
622624
st := r.Field("atomicstatus").Field("value")
623625
status := st.Uint32()
624-
status &^= uint32(p.rtConsts["_Gscan"])
626+
status &^= uint32(p.rtConsts.get("runtime._Gscan"))
625627
var sp, pc core.Address
626628
switch status {
627-
case uint32(p.rtConsts["_Gidle"]):
629+
case uint32(p.rtConsts.get("runtime._Gidle")):
628630
return g, nil
629-
case uint32(p.rtConsts["_Grunnable"]), uint32(p.rtConsts["_Gwaiting"]):
631+
case uint32(p.rtConsts.get("runtime._Grunnable")), uint32(p.rtConsts.get("runtime._Gwaiting")):
630632
sched := r.Field("sched")
631633
sp = core.Address(sched.Field("sp").Uintptr())
632634
pc = core.Address(sched.Field("pc").Uintptr())
633-
case uint32(p.rtConsts["_Grunning"]):
635+
case uint32(p.rtConsts.get("runtime._Grunning")):
634636
sp = osT.SP()
635637
pc = osT.PC()
636638
// TODO: back up to the calling frame?
637-
case uint32(p.rtConsts["_Gsyscall"]):
639+
case uint32(p.rtConsts.get("runtime._Gsyscall")):
638640
sp = core.Address(r.Field("syscallsp").Uintptr())
639641
pc = core.Address(r.Field("syscallpc").Uintptr())
640642
// TODO: or should we use the osT registers?
641-
case uint32(p.rtConsts["_Gdead"]):
643+
case uint32(p.rtConsts.get("runtime._Gdead")):
642644
return nil, nil
643645
// TODO: copystack, others?
644646
default:
@@ -874,6 +876,8 @@ func readGoroutine(p *Process, r region, dwarfVars map[*Func][]dwarfVar) (*Gorou
874876
} else {
875877
sp = f.max
876878
pc = core.Address(p.proc.ReadUintptr(sp - 8)) // TODO:amd64 only
879+
880+
isCrashFrame = false
877881
}
878882
if pc == 0 {
879883
// TODO: when would this happen?
@@ -905,7 +909,7 @@ func readFrame(p *Process, sp, pc core.Address) (*Frame, error) {
905909

906910
// Find live ptrs in locals
907911
live := map[core.Address]bool{}
908-
if x := int(p.rtConsts["_FUNCDATA_LocalsPointerMaps"]); x < len(f.funcdata) {
912+
if x := int(p.rtConsts.get("internal/abi.FUNCDATA_LocalsPointerMaps")); x < len(f.funcdata) {
909913
addr := f.funcdata[x]
910914
// TODO: Ideally we should have the same frame size check as
911915
// runtime.getStackSize to detect errors when we are missing
@@ -918,7 +922,10 @@ func readFrame(p *Process, sp, pc core.Address) (*Frame, error) {
918922
if err != nil {
919923
return nil, fmt.Errorf("cannot read stack map at pc=%#x: %v", pc, err)
920924
}
921-
if idx < 0 {
925+
if idx < -1 {
926+
return nil, fmt.Errorf("cannot read stack map at pc=%#x: invalid stack map index %d", pc, idx)
927+
}
928+
if idx == -1 {
922929
idx = 0
923930
}
924931
if idx < int64(n) {
@@ -934,7 +941,7 @@ func readFrame(p *Process, sp, pc core.Address) (*Frame, error) {
934941
}
935942
}
936943
// Same for args
937-
if x := int(p.rtConsts["_FUNCDATA_ArgsPointerMaps"]); x < len(f.funcdata) {
944+
if x := int(p.rtConsts.get("internal/abi.FUNCDATA_ArgsPointerMaps")); x < len(f.funcdata) {
938945
addr := f.funcdata[x]
939946
if addr != 0 {
940947
args := region{p: p.proc, a: addr, typ: p.findType("runtime.stackmap")}
@@ -944,11 +951,14 @@ func readFrame(p *Process, sp, pc core.Address) (*Frame, error) {
944951
if err != nil {
945952
return nil, fmt.Errorf("cannot read stack map at pc=%#x: %v", pc, err)
946953
}
947-
if idx < 0 {
954+
if idx < -1 {
955+
return nil, fmt.Errorf("cannot read stack map at pc=%#x: invalid stack map index %d", pc, idx)
956+
}
957+
if idx == -1 {
948958
idx = 0
949959
}
950960
if idx < int64(n) {
951-
bits := args.Field("bytedata").a.Add(int64(nbit+7) / 8 * idx)
961+
bits := args.Field("bytedata").a.Add((int64(nbit+7) / 8) * idx)
952962
base := frame.max
953963
// TODO: add to base for LR archs.
954964
for i := int64(0); i < int64(nbit); i++ {

internal/gocore/type.go

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -224,7 +224,7 @@ func (p *Process) runtimeType2Type(a core.Address, d core.Address) *Type {
224224
b := make([]byte, n)
225225
p.proc.ReadAt(b, x.Add(i+1))
226226
name = string(b)
227-
if r.TFlag()&uint8(p.rtConsts["tflagExtraStar"]) != 0 {
227+
if r.TFlag()&uint8(p.rtConsts.get("internal/abi.TFlagExtraStar")) != 0 {
228228
name = name[1:]
229229
}
230230
} else {
@@ -238,15 +238,16 @@ func (p *Process) runtimeType2Type(a core.Address, d core.Address) *Type {
238238
ptrSize := p.proc.PtrSize()
239239
nptrs := int64(r.PtrBytes()) / ptrSize
240240
var ptrs []int64
241-
if r.Kind_()&uint8(p.rtConsts["kindGCProg"]) == 0 {
241+
kindGCProg, hasGCProgs := p.rtConsts.find("internal/abi.KindGCProg")
242+
if hasGCProgs && r.Kind_()&uint8(kindGCProg) != 0 {
243+
// TODO: run GC program. Go 1.23 and earlier only.
244+
} else {
242245
gcdata := r.GCData()
243246
for i := int64(0); i < nptrs; i++ {
244247
if p.proc.ReadUint8(gcdata.Add(i/8))>>uint(i%8)&1 != 0 {
245248
ptrs = append(ptrs, i*ptrSize)
246249
}
247250
}
248-
} else {
249-
// TODO: run GC program to get ptr indexes
250251
}
251252

252253
// Find a Type that matches this type.
@@ -540,7 +541,7 @@ func (p *Process) doTypeHeap() {
540541
p.typeObject(r.Addr, r.Type, fr, add)
541542
} else if r.Addr == 0 && r.Type.Kind == KindPtr && r.Type.Elem != nil {
542543
p.typeObject(r.RegValue, r.Type.Elem, fr, add)
543-
} else {
544+
} else if r.Addr != 0 {
544545
p.typeObject(r.Addr, r.Type, p.proc, add)
545546
}
546547
return true
@@ -631,7 +632,7 @@ func extractTypeFromFunctionName(method string, p *Process) *Type {
631632
// ifaceIndir reports whether t is stored indirectly in an interface value.
632633
func ifaceIndir(t core.Address, p *Process) bool {
633634
typr := p.findRuntimeType(t)
634-
return typr.Kind_()&uint8(p.rtConsts["kindDirectIface"]) == 0
635+
return typr.Kind_()&uint8(p.rtConsts.get("internal/abi.KindDirectIface")) == 0
635636
}
636637

637638
// typeObject takes an address and a type for the data at that address.

0 commit comments

Comments
 (0)