Skip to content

LuaJIT: Get function name and the currently executing line - #123

Open
GitSparTV wants to merge 6 commits into
yandex:mainfrom
GitSparTV:luajit-current-line-name
Open

GitSparTV wants to merge 6 commits into
yandex:mainfrom
GitSparTV:luajit-current-line-name

Conversation

@GitSparTV

Copy link
Copy Markdown
Contributor

This PR adds current source-line tracking and infers function names from callers, making profiles easier to interpret. Before this only in main chunk function had names, others were <no name> and profiler used first line where the function was defined instead of using current line when the sample happened. This PR also fixes some bugs.

Changes

  • Recover bytecode positions from interpreter registers or saved frames and map them to source lines.
  • Capture prototype fields in the symbol cache and read remaining metadata in the Go agent, with bounded reads and caches scoped to process lifetimes and prototype snapshots.
  • Resolve local, global, field, upvalue, and metamethod names using LuaJIT’s debug lookup rules on Go side.
  • Preserve caller-dependent names when deduplicating profile locations.
  • Handle partially initialized vararg frames and add Lua logging levels and optional development assertions.

How it works

  1. Collect the frame and source position in eBPF. Now Lua frame contains its prototype address, definition line, current line, and bytecode index where it stopped (depends on the next upper frame). Nextframe is required to get bytecode PC from it, but if sample happened during execution of Lua function (that is it's on top), the unwinder obtains the bytecode PC from rbx. This part allow to get current source line when the top frames!

  2. Capture metadata for later name lookup. The interpreter symbol cache stores the whole GCproto struct (104 bytes) and chunk filename. The header occupies the existing symbol-name field as binary data, so the Lua symbolizer preserves it without treating embedded NUL bytes as terminators (probably needs redoing, because it looks like a monkey patching). The Go agent uses this captured data to read the prototype’s bytecode, constants, and debug metadata from process memory. Go doesn't read GCproto which means it cheaper, basically comes for free!

  3. Infer the callee’s name from its caller. Frames arrive from callee to caller. The caller’s bytecode identifies the operation that entered the callee. For ordinary calls, name lookup checks local-variable scopes and walks backward through register assignments to find a global, field, or upvalue name. Metamethod calls derive their names directly from the caller’s opcode. Basically, what LuaJIT does in its source code.

  4. Cache metadata and preserve distinct names. Reads and caches are bounded. Cached string names belong to a specific decoded prototype snapshot, preventing fresh snapshots from inheriting names through reused addresses. Profile location keys include the current line and resolved name, preserving different caller-derived names for the same function. And each read is guarded by checks to make sure it's still valid.

Unavailable bytecode positions fall back to the definition line and unresolved names still use <no name>. This usually happens when Lua function was called by a C function. pcall/xpcall also loses information but we might have a fix for this later :-)

Synthetic JIT PCs and some hook/error paths remain unsupported.

image

@robot-magpie

robot-magpie Bot commented Oct 9, 2026

Copy link
Copy Markdown

✅ All contributors are covered under a CLA with Yandex

See CONTRIBUTING.md for more info about Yandex Contributor License Agreement.


The following contributors were found:
✅ 854eac4 Author: @GitSparTV (dev*******rtv@gmail.com)

(Only the first commit for a unique contributor is listed)

@MikailBag MikailBag added the ok-to-test Precommit checks are enabled only for PRs with this label label Oct 9, 2026
@GitSparTV
GitSparTV force-pushed the luajit-current-line-name branch from 056d81d to 7920ea9 Compare October 9, 2026 17:40
@robot-magpie

robot-magpie Bot commented Oct 9, 2026

Copy link
Copy Markdown

✅ All contributors are covered under a CLA with Yandex

See CONTRIBUTING.md for more info about Yandex Contributor License Agreement.


The following contributors were found:
✅ 9783090 Author: @GitSparTV (dev*******rtv@gmail.com)

(Only the first commit for a unique contributor is listed)

@GitSparTV
GitSparTV force-pushed the luajit-current-line-name branch from 4a222bc to 7920ea9 Compare October 9, 2026 21:29
@GitSparTV
GitSparTV force-pushed the luajit-current-line-name branch from 7920ea9 to 96f837a Compare November 9, 2026 13:01
@robot-magpie

robot-magpie Bot commented Nov 9, 2026

Copy link
Copy Markdown

✅ All contributors are covered under a CLA with Yandex

See CONTRIBUTING.md for more info about Yandex Contributor License Agreement.


The following contributors were found:
✅ 8c355cd Author: @GitSparTV (dev*******rtv@gmail.com)

(Only the first commit for a unique contributor is listed)

@GitSparTV
GitSparTV force-pushed the luajit-current-line-name branch from 96f837a to 2839b46 Compare November 12, 2026 14:17
@robot-magpie

robot-magpie Bot commented Nov 12, 2026

Copy link
Copy Markdown

✅ All contributors are covered under a CLA with Yandex

See CONTRIBUTING.md for more info about Yandex Contributor License Agreement.


The following contributors were found:
✅ 9a38844 Author: @GitSparTV (dev*******rtv@gmail.com)

(Only the first commit for a unique contributor is listed)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ok-to-test Precommit checks are enabled only for PRs with this label

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants