2
votes

My game engine pushes a value on to the lua stack as a parameter to a function and then invokes it using lua_pcall. The lua code will run and call additional lua functions. Eventually this lua code will invoke a C function. Is it possible for this function to retrieve the value that was originally pushed on to the stack?

Its like this:

<engine function A>
  pushes parameter value X on to stack for lua
<lua func>
<lua func>
<lua func>
<engine function B>
  can I extract the values X that was pushed by function A here?
1
You could probably do it with the debug interface, but it would be a horrible kludge. Why not pass the value down the stack, or make it accessible some other way (global, method call, etc.)?Mud
For now I'm just saving the value in C with a global variable. In my diagram above, FUNCTION A, is the game's common entry point for running LUA code and I'm not happy to add that global variable because the value is only ever needed when lua calls in to FUNCTION BMatt Kimberling
...another limitation is I want to alter the behavior of FUNCTION B in a limited context. There are already 100+ invocations of it in Lua and I can't push an additional parameter through all of them just so the parameter pushed by FUNCTION A can become available to FUNCTION B. The cleaning thing would be if there is a straightforward way to access the very first variable on the stack of the first lua function in my callstackMatt Kimberling

1 Answers

2
votes

Yes, with a combination of getinfo, getlocal and getupvalue you can get all that information (you can even change those values using set* functions).

Here is a fragment from MobDebug that returns stack information along with a table of locals and upvalues at each level. The variables at each level will be indexed in the same order they appear in the code (starting from parameters). For each get* function you can use their C equivalents (lua_getinfo, lua_getlocal, and lua_getupvalue), but the logic should be exactly the same.

local function stack(start)
  local function vars(f)
    local func = debug.getinfo(f, "f").func
    local i = 1
    local locals = {}
    while true do
      local name, value = debug.getlocal(f, i)
      if not name then break end
      if string.sub(name, 1, 1) ~= '(' then locals[name] = {value, tostring(value)} end
      i = i + 1
    end
    i = 1
    local ups = {}
    while func and true do -- check for func as it may be nil for tail calls
      local name, value = debug.getupvalue(func, i)
      if not name then break end
      ups[name] = {value, tostring(value)}
      i = i + 1
    end
    return locals, ups
  end

  local stack = {}
  for i = (start or 0), 100 do
    local source = debug.getinfo(i, "Snl")
    if not source then break end
    table.insert(stack, {
      {source.name, source.source, source.linedefined,
       source.currentline, source.what, source.namewhat, source.short_src},
      vars(i+1)})
    if source.what == 'main' then break end
  end
  return stack
end