This first edition was written for Lua 5.0. While still largely relevant for later versions, there are some differences.
The fourth edition targets Lua 5.3 and is available at Amazon and other bookstores.
By buying the book, you also help to support the Lua project.

23.1 – Introspective Facilities

The main introspective function in the debug library is the debug.getinfo function. Its first parameter may be a function or a stack level. When you call debug.getinfo(foo) for some function foo, you get a table with some data about that function. The table may have the following fields:

When foo is a C function, Lua does not have much data about it. For such functions, only the fields what, name, and namewhat are relevant.

When you call debug.getinfo(n) for some number n, you get data about the function active at that stack level. For instance, if n is 1, you get data about the function doing the call. (When n is 0, you get data about getinfo itself, a C function.) If n is larger than the number of active functions in the stack, debug.getinfo returns nil. When you query an active function, calling debug.getinfo with a number, the result table has an extra field, currentline, with the line where the function is at that moment. Moreover, func has the function that is active at that level.

The field name is tricky. Remember that, because functions are first-class values in Lua, a function may not have a name, or may have several names. Lua tries to find a name for a function by looking for a global variable with that value, or else looking into the code that called the function, to see how it was called. This second option works only when we call getinfo with a number, that is, we get information about a particular invocation.

The getinfo function is not efficient. Lua keeps debug information in a form that does not impair program execution; efficient retrieval is a secondary goal here. To achieve better performance, getinfo has an optional second parameter that selects what information to get. With this parameter, it does not waste time collecting data that the user does not need. The format of this parameter is a string, where each letter selects a group of data, according to the following table:
`n´selects fields name and namewhat
`f´selects field func
`S´selects fields source, short_src, what, and linedefined
`l´selects field currentline
`u´selects field nup

The following function illustrates the use of debug.getinfo. It prints a primitive traceback of the active stack:

    function traceback ()
      local level = 1
      while true do
        local info = debug.getinfo(level, "Sl")
        if not info then break end
        if info.what == "C" then   -- is a C function?
          print(level, "C function")
        else   -- a Lua function
                              info.short_src, info.currentline))
        level = level + 1
It is not difficult to improve this function, including more data from getinfo. Actually, the debug library offers such an improved version, debug.traceback. Unlike our version, debug.traceback does not print its result; instead, it returns a string.