Skip to content

Conversation

@SSE4
Copy link
Contributor

@SSE4 SSE4 commented Sep 21, 2025

closes: #66

this is heavily work in progress, more like proof of concept, code is totally dirty and incomplete (there are many debug prints, commented code blocks for experiments and so on...).

works only on my version/build of interpreter, offsets are hard-coded (f9140a62)!
it means it obviously won't work on arbitrary version of LuaJIT - if version/flags changed, offsets would likely to change.

mostly inspired by:

heavily based on existing Python and PHP unwind implementations in perforator

what is implemented:

  • unwinding lua stack (still might be buggy)
  • getting name of the Lua file
  • getting line number within Lua file
  • getting number of lua builtin
  • getting name of metamethod

what is not implemented yet, to be implemented:

  • debug_framepc returns NO_BCPOS, check isluafunc fails for some reason, to be debugged and fixed
  • getting name of lua function - lj_debugslotname and its children debug_varname and lj_debug_uvname
  • automatically compute necessary offsets for an arbitrary version of Lua(JIT)
  • handle different kinds of jumps between C code and Lua code, such as cpcall, continuation, ffi callback, errfunc, hook, GC, etc.

@cezarnik
Copy link
Contributor

Hi, thank you for your PR! We will look at it in this state to understand how to proceed and to save your time.

@ayles
Copy link
Collaborator

ayles commented Sep 24, 2025

Nice


TStringBuf symbolName{name.data(), name.size()};
for (const auto& targetSymbol : targetSymbols) {
if (symbolName.find(targetSymbol) == 0) {
Copy link
Contributor

@pashagoose pashagoose Oct 27, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we only match prefix here and avoid using find ?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've changed to StartsWith (hope it's right).

that's some sort of custom STL, and sources appears to be generated from some "pxd" file. it doesn't make development easier, as I struggled to find documentation for these custom TString classes :)

template <typename ELFT>
TMaybe<TParsedLuaVersion> ParseVersion(
const llvm::object::ObjectFile& file,
const TLuaAnalyzer::TSymbols&symbols
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

space between type name and argument name

}
};

enum class EUnicodeType {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should be removed, seems like copy-paste from python

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

indeed, removed


template <typename ELFT>
TMaybe<TParsedLuaVersion> ParseVersion(
const llvm::object::ObjectFile& file,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

no need to pass object file here if ParseVersion just returns version parsed from a symbol name

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes, removed. that was a copy-paste from python.

return false
}
return true
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should add newline between functions


namespace NPerforator::NBinaryProcessing::NLua {

NPerforator::NBinaryProcessing::NLua::LuaConfig BuildLuaConfig(llvm::object::ObjectFile* objectFile) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Lets be consistent with other functions and return TMaybe<NPerforator::NBinaryProcessing::NLua::LuaConfig

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yeah, I've used a python as a base (skeleton), which did:

NPerforator::NBinaryProcessing::NPython::PythonConfig BuildPythonConfig(llvm::object::ObjectFile* objectFile) {

while PHP does:

TMaybe<NPerforator::NBinaryProcessing::NPhp::PhpConfig> BuildPhpConfig(llvm::object::ObjectFile* objectFile) {

I've changed Lua to return TMaybe

*result.MutablePhpConfig() = std::move(phpConfig.GetRef());
}

*result.MutableLuaConfig() = std::move(luaConfig);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Handle null config to be consistent with if statements above

log.String("buildid", buildID),
log.Any("version", analysis.PythonConfig.Version),
)
if analysis.PythonConfig != nil {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why do we need to change it here ?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

was testing something at initial state to see how python initialized. reverted back.

}

// Create Lua symbolizer
if enabled := p.conf.BPF.TraceLua; enabled == nil || *enabled {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Lets consider that if TraceLua is nil it is defaulted to false.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

okay, I've changed

question: python and php/jvm are handled quite a different, are there reasons for that? e.g. php/jvm have their own FeatureFlagsConfig entries, while python doesn't.

until now, I followed more python model while doing LuaJIT code.

@SSE4
Copy link
Contributor Author

SSE4 commented Oct 28, 2025

I'll need to rebase code later and clean up the code.
for the record, I have more local changes (on LuaJIT offsets look up), plus there is a wip branch of my colleague to be merged together with mine changes.

since the time I've opened PR we made some progress on these items:

GitSparTV and others added 17 commits December 19, 2025 18:22
it makes easier to identify Lua frames amongst C

remove some no longer needed prints
they do not expose LuaJIT_version_* symbol
if they happen to expose luaopen_jit, just assume it's 2.1 for now
Formatting, refactoring, new colors, new metrics. Remove debug prints as they no longer useful
…changing BPF_TRACE to BPF_PRINTK for LUA_TRACE
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

LuaJIT support

6 participants