--[[ PROBE v0.5 by SDC
     a very hacky JIT abortion examiner, hastily put together and probably not fully operational
     but it should do the job. tested with luajit 2.0.5

     usage: load the file into a variable, e.g. PROBE = require("probe.lua");
     call PROBE.insert() before the function you want to check out, call PROBE.extract() when
     you are done using it. don't forget to wash your hands after.
  ]]

-- follows the "lmao" license v1.0: 
-- ----------------------------------------------------------------------------------------
-- | use at your own risk. author is in no way responsible for any result of this script, |
-- | or any derivative thereof, including any harm (psychological or otherwise)           |
-- | that may result from the use of this script or derivatives. if you do not agree      |
-- | with any of these terms, turn your eyes away from your screen immediately, close the |
-- | window, and promptly delete this file. any distributed modifications must include    |
-- | this license.                                                                        |
-- |                                                                                      |
-- | includes reproduced code from the LuaJIT source, license here:                       |
-- | https://github.com/LuaJIT/LuaJIT/blob/v2.1/COPYRIGHT                                 |
-- ----------------------------------------------------------------------------------------

-- CACHE
local jit = jit;
local format = string.format;
local finfo = jit.util.funcinfo;
--


local callback, parse_func_info;

local PROBE, traceerr, ffnames;

function callback(trc_event, trc_num, trc_func, pc, trc_abort_code, trc_abort_info)
   if trc_event == "abort" then
      local trace_source_info = finfo(trc_func);
      
      io.write("[abort] in ",trace_source_info.source," line ", pc, ": (");

      if type(trc_abort_info) == "function" then 
         io.write(format(traceerr[trc_abort_code], parse_func_info(trc_abort_info, pc)), ")");
      else
         io.write(format(traceerr[trc_abort_code], trc_abort_info), ")");
      end
      io.write(debug.traceback("", 2), "\n");
   end
end

function parse_func_info(func, pc)
   local fi = finfo(func);

   if fi.loc then
      return fi.loc;
   elseif fi.ffid then
      return ffnames[fi.ffid];
   elseif fi.addr then
      return format("C:%x", fi.addr);
   else
      return "(we just dont know. ?)"
   end
end


traceerr = {
[0]="error thrown or hook called during recording",
"trace too long",
"trace too deep",
"too many snapshots",
"blacklisted",
"NYI: bytecode %d",
"leaving loop in root trace",
"inner loop in root trace",
"loop unroll limit reached",
"bad argument type",
"JIT compilation disabled for function",
"call unroll limit reached",
"down-recursion, restarting",
"NYI: C function %s",
"NYI: FastFunc %s",
"NYI: unsupported variant of FastFunc %s",
"NYI: return to lower frame",
"store with nil or NaN key",
"missing metamethod",
"looping index lookup",
"NYI: mixed sparse/dense table",
"symbol not in cache",
"NYI: unsupported C type conversion",
"NYI: unsupported C function type",
"guard would always fail",
"too many PHIs",
"persistent type instability",
"failed to allocate mcode memory",
"machine code too long",
"hit mcode limit (retrying)",
"too many spill slots",
"inconsistent register allocation",
"NYI: cannot assemble IR instruction %d",
"NYI: PHI shuffling too complex",
"NYI: register coalescing too complex",
}

ffnames = {
[0]="Lua",
"C",
"assert",
"type",
"next",
"pairs",
"ipairs_aux",
"ipairs",
"getmetatable",
"setmetatable",
"getfenv",
"setfenv",
"rawget",
"rawset",
"rawequal",
"unpack",
"select",
"tonumber",
"tostring",
"error",
"pcall",
"xpcall",
"loadfile",
"load",
"loadstring",
"dofile",
"gcinfo",
"collectgarbage",
"newproxy",
"print",
"coroutine.status",
"coroutine.running",
"coroutine.create",
"coroutine.yield",
"coroutine.resume",
"coroutine.wrap_aux",
"coroutine.wrap",
"math.abs",
"math.floor",
"math.ceil",
"math.sqrt",
"math.log10",
"math.exp",
"math.sin",
"math.cos",
"math.tan",
"math.asin",
"math.acos",
"math.atan",
"math.sinh",
"math.cosh",
"math.tanh",
"math.frexp",
"math.modf",
"math.deg",
"math.rad",
"math.log",
"math.atan2",
"math.pow",
"math.fmod",
"math.ldexp",
"math.min",
"math.max",
"math.random",
"math.randomseed",
"bit.tobit",
"bit.bnot",
"bit.bswap",
"bit.lshift",
"bit.rshift",
"bit.arshift",
"bit.rol",
"bit.ror",
"bit.band",
"bit.bor",
"bit.bxor",
"bit.tohex",
"string.len",
"string.byte",
"string.char",
"string.sub",
"string.rep",
"string.reverse",
"string.lower",
"string.upper",
"string.dump",
"string.find",
"string.match",
"string.gmatch_aux",
"string.gmatch",
"string.gsub",
"string.format",
"table.foreachi",
"table.foreach",
"table.getn",
"table.maxn",
"table.insert",
"table.remove",
"table.concat",
"table.sort",
"io.method.close",
"io.method.read",
"io.method.write",
"io.method.flush",
"io.method.seek",
"io.method.setvbuf",
"io.method.lines",
"io.method.__gc",
"io.method.__tostring",
"io.open",
"io.popen",
"io.tmpfile",
"io.close",
"io.read",
"io.write",
"io.flush",
"io.input",
"io.output",
"io.lines",
"io.type",
"os.execute",
"os.remove",
"os.rename",
"os.tmpname",
"os.getenv",
"os.exit",
"os.clock",
"os.date",
"os.time",
"os.difftime",
"os.setlocale",
"debug.getregistry",
"debug.getmetatable",
"debug.setmetatable",
"debug.getfenv",
"debug.setfenv",
"debug.getinfo",
"debug.getlocal",
"debug.setlocal",
"debug.getupvalue",
"debug.setupvalue",
"debug.upvalueid",
"debug.upvaluejoin",
"debug.sethook",
"debug.gethook",
"debug.debug",
"debug.traceback",
"jit.on",
"jit.off",
"jit.flush",
"jit.status",
"jit.attach",
"jit.util.funcinfo",
"jit.util.funcbc",
"jit.util.funck",
"jit.util.funcuvname",
"jit.util.traceinfo",
"jit.util.traceir",
"jit.util.tracek",
"jit.util.tracesnap",
"jit.util.tracemc",
"jit.util.traceexitstub",
"jit.util.ircalladdr",
"jit.opt.start",
"ffi.meta.__index",
"ffi.meta.__newindex",
"ffi.meta.__eq",
"ffi.meta.__len",
"ffi.meta.__lt",
"ffi.meta.__le",
"ffi.meta.__concat",
"ffi.meta.__call",
"ffi.meta.__add",
"ffi.meta.__sub",
"ffi.meta.__mul",
"ffi.meta.__div",
"ffi.meta.__mod",
"ffi.meta.__pow",
"ffi.meta.__unm",
"ffi.meta.__tostring",
"ffi.meta.__pairs",
"ffi.meta.__ipairs",
"ffi.clib.__index",
"ffi.clib.__newindex",
"ffi.clib.__gc",
"ffi.callback.free",
"ffi.callback.set",
"ffi.cdef",
"ffi.new",
"ffi.cast",
"ffi.typeof",
"ffi.istype",
"ffi.sizeof",
"ffi.alignof",
"ffi.offsetof",
"ffi.errno",
"ffi.string",
"ffi.copy",
"ffi.fill",
"ffi.abi",
"ffi.metatype",
"ffi.gc",
"ffi.load",
}


PROBE = {};
PROBE.insert = function()
   jit.attach(callback, "trace");
end

PROBE.extract = function()
   jit.attach(callback);
end


return PROBE;
