const char symtab_lua[] =
"-- Parser of LuaJIT's symtab binary stream.\n"
"-- The format spec can be found in <src/lj_memprof.h>.\n"
"--\n"
"-- Major portions taken verbatim or adapted from the LuaVela.\n"
"-- Copyright (C) 2015-2019 IPONWEB Ltd.\n"
"\n"
"local bit = require \"bit\"\n"
"\n"
"local band = bit.band\n"
"local string_format = string.format\n"
"\n"
"local LJS_MAGIC = \"ljs\"\n"
"local LJS_CURRENT_VERSION = 1\n"
"local LJS_EPILOGUE_HEADER = 0x80\n"
"local LJS_SYMTYPE_MASK = 0x03\n"
"\n"
"local SYMTAB_LFUNC = 0\n"
"\n"
"local M = {}\n"
"\n"
"-- Parse a single entry in a symtab: lfunc symbol.\n"
"local function parse_sym_lfunc(reader, symtab)\n"
"  local sym_addr = reader:read_uleb128()\n"
"  local sym_chunk = reader:read_string()\n"
"  local sym_line = reader:read_uleb128()\n"
"\n"
"  symtab[sym_addr] = {\n"
"    source = sym_chunk,\n"
"    linedefined = sym_line,\n"
"  }\n"
"end\n"
"\n"
"local parsers = {\n"
"  [SYMTAB_LFUNC] = parse_sym_lfunc,\n"
"}\n"
"\n"
"function M.parse(reader)\n"
"  local symtab = {}\n"
"  local magic = reader:read_octets(3)\n"
"  local version = reader:read_octets(1)\n"
"\n"
"  -- Dummy-consume reserved bytes.\n"
"  local _ = reader:read_octets(3)\n"
"\n"
"  if magic ~= LJS_MAGIC then\n"
"    error(\"Bad LJS format prologue: \"..magic)\n"
"  end\n"
"\n"
"  if string.byte(version) ~= LJS_CURRENT_VERSION then\n"
"    error(string_format(\n"
"         \"LJS format version mismatch:\"..\n"
"         \"the tool expects %d, but your data is %d\",\n"
"         LJS_CURRENT_VERSION,\n"
"         string.byte(version)\n"
"    ))\n"
"\n"
"  end\n"
"\n"
"  while not reader:eof() do\n"
"    local header = reader:read_octet()\n"
"    local is_final = band(header, LJS_EPILOGUE_HEADER) ~= 0\n"
"\n"
"    if is_final then\n"
"      break\n"
"    end\n"
"\n"
"    local sym_type = band(header, LJS_SYMTYPE_MASK)\n"
"    if parsers[sym_type] then\n"
"      parsers[sym_type](reader, symtab)\n"
"    end\n"
"  end\n"
"\n"
"  return symtab\n"
"end\n"
"\n"
"function M.demangle(symtab, loc)\n"
"  local addr = loc.addr\n"
"\n"
"  if addr == 0 then\n"
"    return \"INTERNAL\"\n"
"  end\n"
"\n"
"  if symtab[addr] then\n"
"    return string_format(\"%s:%d\", symtab[addr].source, loc.line)\n"
"  end\n"
"\n"
"  return string_format(\"CFUNC %#x\", addr)\n"
"end\n"
"\n"
"return M\n"
""
;
