3

I'm working on a system for serialization/deserialization, and I'm trying to get some really fancy stuff going with functions. My goal is to serialize objects containing functions in a human-readable and reversible manner (the serialized files will need processing after the loadfile() step). I need a way to get the actual source of a function, and it looks like I can't always do that with debug.getinfo().

I know that debug.getinfo() will give be the file and line where it was defined (or the source of the function, depending on its origin). Is there a way I can read the function text from that file? I'd be willing to use some kind of parser utilities to do so. Maybe there are Lua packages for parsing Lua code?

Perhaps there's a way I can get loadfile() or require() to automatically retain function source somewhere?

Yes, I know you can get all sorts of information out of debug.getinfo, but it was unable to deal with functions loaded through stdin...

uberblah@glade-m:~$ lua
Lua 5.1.5  Copyright (C) 1994-2012 Lua.org, PUC-Rio
> a = function() print("hello, world!") end
> require("serpent")
> s = require("serpent")
> =s.block(debug.getinfo(a))
{
  currentline = -1,
  func = loadstring("LuaQ\000\000\000\000\000\000\000\000\000=stdin\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000A@\000\000@\000\000�\000\000\000\000\000\000\000\000\000\000\000print\000\000\000\000\000\000\000\000hello, world!\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000",'@serialized') --[[function: 0x2068a30]],
  lastlinedefined = 1,
  linedefined = 1,
  namewhat = "",
  nups = 0,
  short_src = "stdin",
  source = "=stdin",
  what = "Lua"
} --[[table: 0x206cf80]]
> f = io.open("stdin", "r")
> =f
nil

SOLUTION FOR SOURCE FROM STDIN... 1) Capture all STDIN, write it to a file 2) Load the information from that file, instead of from stdin 3) debug will track the function line numbers in that file

Miles
  • 1,858
  • 1
  • 21
  • 34
  • You really going to use stdin (which is console input, so io.open("stdin") does not do what you want)? or a script that loads modules? If latter it may be easier. Why do you need this capability? Maybe there is another way. Also, if you use lhf's answer, you can read in the file specified in "source" and read the source directly (since you have linedefined etc). – Oliver Dec 06 '13 at 04:49
  • I'm aware that if it were not for this annoying need to get functions off of stdin I could load the functions with relative ease. However, I plan on using functions read from stdin because I'm writing a debug console for a videogame, and input from that console (written in C) is being redirected to stdin. I guess very few other people will need to read from stdin, and I can get some kind of buffer between the debug console and Lua (that buffer could be saved to a file for debug-ability). Sorry about the confusion – Miles Dec 06 '13 at 04:56
  • @Schollii The edits I made should clearly illustrate: io.open("stdin") returns nil because there is no such file! I am also aware that I can read the function if it came from a file, but this does not cover the stdin case. I accepted the answer because I can capture stdin myself, and copy its contents to a file I can later refer to. – Miles Dec 11 '13 at 18:11
  • OK, sounds like a good approach. – Oliver Dec 13 '13 at 21:29

2 Answers2

5

Using debug.getinfo you can get source, linedefined, and lastlinedefined. Unless you format your code really weirdly you should be able to extract the complete code of your function from this info. There is no need to parse code, just to get the correct set of lines.

lhf
  • 70,581
  • 9
  • 108
  • 149
  • This method can't always get the source of the specified function. For example, if the function was entered through stdin, the source line shows STDIN or something like that. Maybe if there was a way to read STDIN's history? I actually didn't realise there was a "lastlinedefined", which is why I thought I needed a parser. Thanks for helping me figure that out. The only thing left is figuring out how to get at stuff entered through STDIN – Miles Dec 06 '13 at 01:33
1

You want to disasseble the bytecode into Lua statements and expressions. Try http://chunkspy.luaforge.net/. Or maybe http://luadec.luaforge.net/ but I haven't used them so can't give much more info. Luac (Lua compiler) also has -l switch which produces assembly listing that could potentially be parsed. Then there is lbci (bhttp://www.tecgraf.puc-rio.br/~lhf/ftp/lua/#lbci). You might find Getting the AST of a function useful. Finally, I suggest you do a search for "lua decompiler".

Community
  • 1
  • 1
Oliver
  • 27,510
  • 9
  • 72
  • 103
  • this solution might technically work, but it can't always produce the original source of the function (although what it does give you will always be exactly equivalent). There must be some way I can cause things like the require() function to automatically load the source somewhere in Lua-accessible memory? – Miles Dec 06 '13 at 01:35
  • @MilesRufat-Latre Why doesn't lhf's answer work for you? If you just want the source, you could use the file and line # where the function's source is defined (using debug module), but this might not always work. You probably can intercept require via the debug module. Perhaps if you posted an example of i/o in your question you could get more answers. – Oliver Dec 06 '13 at 03:19