Skip to content

Commit b5d3122

Browse files
committed
Figured loc_tab index and source line number
1 parent 8b10cf8 commit b5d3122

File tree

1 file changed

+64
-25
lines changed

1 file changed

+64
-25
lines changed

interpreter/beam/beam.go

Lines changed: 64 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -359,7 +359,7 @@ func (i *beamInstance) Symbolize(symbolReporter reporter.SymbolReporter, frame *
359359
return err
360360
}
361361

362-
moduleID, functionID, arity, err := i.findMFA(pc, codeHeader)
362+
functionIndex, moduleID, functionID, arity, err := i.findMFA(pc, codeHeader)
363363
if err != nil {
364364
return err
365365
}
@@ -382,43 +382,27 @@ func (i *beamInstance) Symbolize(symbolReporter reporter.SymbolReporter, frame *
382382
mfaName = fmt.Sprintf("%s:%s/%d", moduleName, functionName, arity)
383383
}
384384

385-
log.Warnf("BEAM Found function: %s", mfaName)
385+
lineNumber := i.findFileLocation(codeHeader, functionIndex, pc)
386+
387+
log.Warnf("BEAM Found function %s at line %d", mfaName, lineNumber)
386388
frameID := libpf.NewFrameID(libpf.NewFileID(uint64(moduleID), 0x0), libpf.AddressOrLineno((uint64(functionID)<<32)+uint64(arity)))
387389

388390
symbolReporter.FrameMetadata(&reporter.FrameMetadataArgs{
389391
FrameID: frameID,
390392
FunctionName: mfaName,
393+
SourceLine: libpf.SourceLineno(lineNumber),
391394
})
392395
trace.AppendFrameID(libpf.BEAMFrame, frameID)
393396

394-
//lineTable := i.rm.Ptr(codeHeader + libpf.Address(72))
395-
396-
// `lineTable` points to a table of `BeamCodeLineTab_` structs:
397-
// https://github.com/erlang/otp/blob/OTP-27.2.4/erts/emulator/beam/beam_code.h#L130-L138
398-
// (gdb) ptype/o $hdr.line_table
399-
// type = const struct BeamCodeLineTab_ {
400-
// 0 | 8 const Eterm *fname_ptr;
401-
// 8 | 4 int loc_size;
402-
// XXX 4-byte hole
403-
// 16 | 8 union {
404-
// 8 Uint16 *p2;
405-
// 8 Uint32 *p4;
406-
// total size (bytes): 8
407-
// } loc_tab;
408-
// 24 | 8 const void **func_tab[1];
409-
//
410-
// total size (bytes): 32
411397
return nil
412398
}
413399

414-
func (i *beamInstance) findCodeHeader(pc libpf.Address) (libpf.Address, error) {
400+
func (i *beamInstance) findCodeHeader(pc libpf.Address) (codeHeader libpf.Address, err error) {
415401
// Index into the active static `r` variable using the currently-active code index (the size of the `ranges` struct is 32 bytes)
416402
// https://github.com/erlang/otp/blob/OTP-27.2.4/erts/emulator/beam/beam_ranges.c#L62
417403
codeIndex := i.rm.Uint64(i.codeIndexPtr)
418404
activeRanges := i.rangesPtr + libpf.Address(32*codeIndex)
419405

420-
codeHeader := libpf.Address(0)
421-
422406
// Use offsets into the `ranges` struct to get the beginning of the array and the number of entries based on
423407
// https://github.com/erlang/otp/blob/OTP-27.2.4/erts/emulator/beam/beam_ranges.c#L56-L61
424408
modules := i.rm.Ptr(activeRanges)
@@ -443,6 +427,7 @@ func (i *beamInstance) findCodeHeader(pc libpf.Address) (libpf.Address, error) {
443427
lowIdx = midIdx + 1
444428
} else {
445429
codeHeader = midStart
430+
log.Warnf("BEAM codeHeader[%d] range: 0x%x - 0x%x (%d)", midIdx, midStart, midEnd, midEnd-midStart)
446431
break
447432
}
448433
}
@@ -453,7 +438,7 @@ func (i *beamInstance) findCodeHeader(pc libpf.Address) (libpf.Address, error) {
453438
return codeHeader, nil
454439
}
455440

456-
func (i *beamInstance) findMFA(pc libpf.Address, codeHeader libpf.Address) (moduleID uint32, functionID uint32, arity uint32, err error) {
441+
func (i *beamInstance) findMFA(pc libpf.Address, codeHeader libpf.Address) (functionIndex uint64, moduleID uint32, functionID uint32, arity uint32, err error) {
457442
// `codeHeader` points to `BeamCodeHeader` struct, defined here:
458443
// https://github.com/erlang/otp/blob/OTP-27.2.4/erts/emulator/beam/beam_code.h#L56-L125
459444
// Need to figure out a better way to maintain offsets for the `functions` field, but for now...
@@ -515,19 +500,73 @@ func (i *beamInstance) findMFA(pc libpf.Address, codeHeader libpf.Address) (modu
515500
lowIdx = midIdx + 1
516501
} else {
517502
ertsCodeInfo = midStart
503+
functionIndex = midIdx
518504

519505
// `mfa` is defined here:
520506
// https://github.com/erlang/otp/blob/OTP-27.2.4/erts/emulator/beam/code_ix.h#L87-L95
521507
moduleID := i.rm.Uint32(ertsCodeInfo + libpf.Address(16))
522508
functionID := i.rm.Uint32(ertsCodeInfo + libpf.Address(16+8))
523509
arity := i.rm.Uint32(ertsCodeInfo + libpf.Address(16+16))
524510

525-
return moduleID, functionID, arity, nil
511+
log.Warnf("BEAM MFA range: 0x%x - 0x%x (%d)", midStart, midEnd, midEnd-midStart)
512+
return functionIndex, moduleID, functionID, arity, nil
526513
}
527514
}
528515
lowStart := i.rm.Ptr(codeHeader + libpf.Address(136))
529516
highEnd := i.rm.Ptr(codeHeader + libpf.Address(136+(highIdx+1)*8))
530-
return 0, 0, 0, fmt.Errorf("unable to find the MFA for PC 0x%x in expected code range (0x%x - 0x%x)", pc, lowStart, highEnd)
517+
return 0, 0, 0, 0, fmt.Errorf("BEAM unable to find the MFA for PC 0x%x in expected code range (0x%x - 0x%x)", pc, lowStart, highEnd)
518+
}
519+
520+
func (i *beamInstance) findFileLocation(codeHeader libpf.Address, functionIndex uint64, pc libpf.Address) uint64 {
521+
lineTable := i.rm.Ptr(codeHeader + libpf.Address(72))
522+
523+
// `lineTable` points to a table of `BeamCodeLineTab_` structs:
524+
// https://github.com/erlang/otp/blob/OTP-27.2.4/erts/emulator/beam/beam_code.h#L130-L138
525+
// (gdb) ptype/o $hdr.line_table
526+
// type = const struct BeamCodeLineTab_ {
527+
// 0 | 8 const Eterm *fname_ptr;
528+
// 8 | 4 int loc_size;
529+
// XXX 4-byte hole
530+
// 16 | 8 union {
531+
// 8 Uint16 *p2;
532+
// 8 Uint32 *p4;
533+
// total size (bytes): 8
534+
// } loc_tab;
535+
// 24 | 8 const void **func_tab[1];
536+
//
537+
// total size (bytes): 32
538+
539+
lineLow := i.rm.Ptr(lineTable + libpf.Address(8*functionIndex+24))
540+
lineHigh := i.rm.Ptr(lineTable + libpf.Address(8*(functionIndex+1)+24))
541+
542+
log.Warnf("BEAM line range for functionIndex %d: (0x%x - 0x%x)", functionIndex, lineLow, lineHigh)
543+
544+
// We need to align the lineMid values on 8-byte address boundaries
545+
bitmask := libpf.Address(^(uint64(0xf)))
546+
for lineHigh > lineLow {
547+
lineMid := lineLow + ((lineHigh-lineLow)/2)&bitmask
548+
// log.Warnf("BEAM lineMid: 0x%x, midRange: (0x%x - 0x%x)", lineMid, i.rm.Ptr(lineMid), i.rm.Ptr(lineMid+libpf.Address(8)))
549+
550+
if pc < i.rm.Ptr(lineMid) {
551+
lineHigh = lineMid
552+
} else if pc < i.rm.Ptr(lineMid+libpf.Address(8)) {
553+
funcTab := i.rm.Ptr(lineTable + libpf.Address(24))
554+
locIndex := uint32((lineMid - funcTab) / 8)
555+
locSize := i.rm.Uint32(lineTable + libpf.Address(8))
556+
locTab := i.rm.Ptr(lineTable + libpf.Address(16))
557+
locAddr := locTab + libpf.Address(locSize*locIndex)
558+
log.Warnf("BEAM locIndex: %d, locSize: %d, locAddr: %x", locIndex, locSize, locAddr)
559+
if locSize == 2 {
560+
return uint64(i.rm.Uint16(locAddr))
561+
} else {
562+
return uint64(i.rm.Uint32(locAddr))
563+
}
564+
} else {
565+
lineLow = lineMid + 8
566+
}
567+
}
568+
569+
return 0
531570
}
532571

533572
func (i *beamInstance) lookupAtom(index uint32) (string, error) {

0 commit comments

Comments
 (0)