Skip to content

Commit 6b01ad8

Browse files
committed
Add tests and fixes for FFI including support for coredump tests.
FFI support is not complete, specifically support for callbacks isn't complete.
1 parent 654e5b6 commit 6b01ad8

File tree

14 files changed

+36868
-111
lines changed

14 files changed

+36868
-111
lines changed

interpreter/luajit/luajit.go

Lines changed: 54 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -78,8 +78,7 @@ type luajitInstance struct {
7878
// In order to symbolize frame n we need to know the caller or frame n+1 so we don't
7979
// symbolize frame n until symbolize is called fo frame n+1.
8080
previousFrame *host.Frame
81-
82-
g2Traces uint16
81+
g2Traces uint16
8382
}
8483

8584
var (
@@ -125,7 +124,7 @@ func (l *luajitInstance) Detach(ebpf interpreter.EbpfHandler, pid libpf.PID) err
125124

126125
func Loader(ebpf interpreter.EbpfHandler, info *interpreter.LoaderInfo) (interpreter.Data, error) {
127126
base := path.Base(info.FileName())
128-
if !strings.HasPrefix(base, "libluajit-5.1.so") {
127+
if !strings.HasPrefix(base, "libluajit-5.1.so") && base != "luajit" {
129128
return nil, nil
130129
}
131130

@@ -309,6 +308,9 @@ func (l *luajitInstance) SynchronizeMappings(ebpf interpreter.EbpfHandler,
309308
newPrefixes = append(newPrefixes, p...)
310309
}
311310

311+
logf("lj: new traces detected for pid(%v) added %d new traces with %d prefixes and removed %d prefixes",
312+
pr.PID(), len(traces), len(newPrefixes), len(prefixes))
313+
312314
l.prefixesByG[g] = newPrefixes
313315
l.traceHashes[g] = hash
314316
}
@@ -330,19 +332,25 @@ func (l *luajitInstance) getGCproto(pt libpf.Address) (*proto, error) {
330332
return gc, nil
331333
}
332334

335+
// symbolizeFrame symbolizes the previous (up the stack)
333336
func (l *luajitInstance) symbolizeFrame(symbolReporter reporter.SymbolReporter,
334337
funcName string, trace *libpf.Trace) error {
335338
if l.previousFrame == nil || l.previousFrame.File == 0 {
336339
return errors.New("previous frame not set")
337340
}
338-
pt, err := l.getGCproto(libpf.Address(l.previousFrame.File))
339-
if err != nil {
340-
return err
341-
}
341+
ptAddr := libpf.Address(l.previousFrame.File)
342342
pc := uint32(l.previousFrame.Lineno)
343-
line := pt.getLine(pc)
344-
fileName := pt.getName()
345-
logf("lj: [%x] %v+%v at %v:%v", pt.ptAddr, funcName, pc, fileName, line)
343+
var line uint32
344+
var fileName string
345+
if ptAddr != C.LUAJIT_FFI_FUNC {
346+
pt, err := l.getGCproto(ptAddr)
347+
if err != nil {
348+
return err
349+
}
350+
line = pt.getLine(pc)
351+
fileName = pt.getName()
352+
}
353+
logf("lj: [%x] %v+%v at %v:%v", ptAddr, funcName, pc, fileName, line)
346354
// The fnv hash Write() method calls cannot fail, so it's safe to ignore the errors.
347355
h := fnv.New128a()
348356
_, _ = h.Write([]byte(fileName)) //FIXME: needless allocation
@@ -357,6 +365,10 @@ func (l *luajitInstance) symbolizeFrame(symbolReporter reporter.SymbolReporter,
357365
return nil
358366
}
359367

368+
// Symbolize is a little weird in lua since we need the caller frame to get the name of the
369+
// function being called. So we stash the info for the current frame and each symbolize call
370+
// actually symolizes the previous frame. The unwinder emits a special frame with file 0 to
371+
// indicate the end of the lua stack.
360372
func (l *luajitInstance) Symbolize(symbolReporter reporter.SymbolReporter, frame *host.Frame,
361373
trace *libpf.Trace) error {
362374
if !frame.Type.IsInterpType(libpf.LuaJIT) {
@@ -372,18 +384,40 @@ func (l *luajitInstance) Symbolize(symbolReporter reporter.SymbolReporter, frame
372384
return nil
373385
}
374386

375-
ptaddr := libpf.Address(frame.File)
376-
pc := uint32(frame.Lineno)
377-
pt, err := l.getGCproto(ptaddr)
378-
if err != nil {
379-
return err
380-
}
381-
382387
// The function being invoked at this frame (caller) is the name for the previous
383388
// frame (callee). For the last frame frame.File will be 0 and pt will be nil and funcName
384-
// will be "main".
385-
funcName := pt.getFunctionName(pc)
386-
err = l.symbolizeFrame(symbolReporter, funcName, trace)
389+
// will be "main". Lua is a real deal dynamic functional language, functions don't have
390+
// inherent names they are just values.
391+
var funcName string
392+
if frame.File == C.LUAJIT_FFI_FUNC {
393+
switch frame.Lineno & 7 {
394+
case 1:
395+
funcName = "c-frame"
396+
case 2:
397+
funcName = "cont-frame"
398+
case 3:
399+
panic("unexpected frame type 3")
400+
case 4:
401+
// FIXME: Not yet understood why an FFI frame would have a lua func attached, probably a bug.
402+
funcName = "lua-frame"
403+
case 5:
404+
funcName = "cpcall"
405+
case 6:
406+
funcName = "ff-pcall"
407+
case 7:
408+
funcName = "ff-pcall-hook"
409+
}
410+
} else {
411+
ptaddr := libpf.Address(frame.File)
412+
pc := uint32(frame.Lineno)
413+
pt, err := l.getGCproto(ptaddr)
414+
if err != nil {
415+
return err
416+
}
417+
funcName = pt.getFunctionName(pc)
418+
}
419+
420+
err := l.symbolizeFrame(symbolReporter, funcName, trace)
387421

388422
if frame.File == 0 {
389423
logf("lj: end LuaJIT frame")

interpreter/luajit/proto.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -194,7 +194,7 @@ func (p *proto) getName() string {
194194

195195
// https://github.com/openresty/luajit2/blob/7952882d/src/lj_debug.c#L123
196196
func (p *proto) getLine(pc uint32) uint32 {
197-
if p == nil || p.lineinfo == 0 || pc > p.sizebc {
197+
if p == nil || p.lineinfo == 0 || pc > p.sizebc || pc == 0 {
198198
return 0
199199
}
200200
first := p.firstline

support/ebpf/extmaps.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ extern bpf_map_def ruby_procs;
4848
extern bpf_map_def stack_delta_page_to_info;
4949
extern bpf_map_def unwind_info_array;
5050
extern bpf_map_def v8_procs;
51+
extern bpf_map_def luajit_procs;
5152

5253
#endif // TESTING_COREDUMP
5354

support/ebpf/luajit.h

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1-
21
// Assigned in HA to anonymous executable virtual memory ranges in the nginx process.
3-
#define LUAJIT_JIT_FILE_ID 42
2+
#define LUAJIT_JIT_FILE_ID 42
3+
4+
// Special value for FFI functions
5+
#define LUAJIT_FFI_FUNC 0xff1

0 commit comments

Comments
 (0)