Initial re-import of the LUA bin parser and disassembler from extras ##arch

This commit is contained in:
pancake 2022-11-21 11:22:51 +01:00 committed by pancake
parent 2d0fb6ea81
commit 4808a2a44a
15 changed files with 1820 additions and 0 deletions

View File

@ -62,6 +62,7 @@ anal.xtensa
anal.z80
arch.amd29k
arch.xap
arch.lua
arch.i4004
arch.jdh8
arch.null
@ -129,6 +130,7 @@ bin.symbols
bin.te
bin.tic
bin.vsf
bin.lua
bin.wad
bin.wasm
bin.xbe

276
libr/arch/p/arch_lua.c Normal file
View File

@ -0,0 +1,276 @@
/* radare2 - BSD - Copyright 2017-2022 - pancake */
#include <r_arch.h>
#include <r_lib.h>
// XXX should be dynlink
#include "lua/lua53.c"
#include "lua/lua53_parser.c"
static bool encode(RArchSession *as, RAnalOp *op, RArchEncodeMask mask) {
int parsed = 0;
ut32 instruction;
current_write_prt = &instruction;
current_write_index = 0;
doParse0 (parsed, parseNextInstruction, op->mnemonic);
free (op->bytes);
op->size = 4;
op->bytes = malloc (4);
if (!op->bytes) {
return false;
}
setInstruction (instruction, op->bytes);
R_LOG_DEBUG ("parsed: %d instruction: %d", parsed, instruction);
return true;
}
static bool decode(RArchSession *as, RAnalOp *op, RArchDecodeMask mask) {
if (!op) {
return 0;
}
const ut8 *data = op->bytes;
const int len = op->size;
const ut32 instruction = getInstruction (data);
ut32 extraArg = 0;
op->size = 4;
op->type = R_ANAL_OP_TYPE_UNK;
op->eob = false;
if (GET_OPCODE (instruction) > OP_EXTRAARG) {
return op->size;
}
if (mask & R_ARCH_OP_MASK_DISASM) {
(void)lua53dissasm (op, data, len);
}
op->mnemonic = strdup (instruction_names[GET_OPCODE (instruction)]);
switch (GET_OPCODE (instruction)) {
case OP_MOVE: /* A B R(A) := R(B) */
op->type = R_ANAL_OP_TYPE_MOV;
break;
case OP_LOADK: /* A Bx R(A) := Kst(Bx) */
op->type = R_ANAL_OP_TYPE_LOAD;
break;
case OP_LOADKX: /* A R(A) := Kst(extra arg) */
op->type = R_ANAL_OP_TYPE_LOAD;
extraArg = getInstruction (data + 4);
if (GET_OPCODE (extraArg) == OP_EXTRAARG) {
op->size = 8;
}
break;
case OP_LOADBOOL:/* A B C R(A) := (Bool)B; if (C) pc++ */
op->type = R_ANAL_OP_TYPE_CJMP;
op->val = !!GETARG_B (instruction);
op->jump = op->addr + 8;
op->fail = op->addr + 4;
break;
case OP_LOADNIL:/* A B R(A), R(A+1), ..., R(A+B) := nil */
break;
case OP_GETUPVAL:/* A B R(A) := UpValue[B] */
case OP_GETTABUP:/* A B C R(A) := UpValue[B][RK(C)] */
op->type = R_ANAL_OP_TYPE_LOAD;
break;
case OP_GETTABLE:/* A B C R(A) := R(B)[RK(C)] */
break;
case OP_SETTABUP:/* A B C UpValue[A][RK(B)] := RK(C) */
case OP_SETUPVAL:/* A B UpValue[B] := R(A) */
op->type = R_ANAL_OP_TYPE_STORE;
break;
case OP_SETTABLE:/* A B C R(A)[RK(B)] := RK(C) */
break;
case OP_NEWTABLE:/* A B C R(A) := {} (size = B,C) */
op->type = R_ANAL_OP_TYPE_NEW;
break;
case OP_SELF: /* A B C R(A+1) := R(B); R(A) := R(B)[RK(C)] */
break;
case OP_ADD: /* A B C R(A) := RK(B) + RK(C) */
op->type = R_ANAL_OP_TYPE_ADD;
break;
case OP_SUB: /* A B C R(A) := RK(B) - RK(C) */
op->type = R_ANAL_OP_TYPE_SUB;
break;
case OP_MUL: /* A B C R(A) := RK(B) * RK(C) */
op->type = R_ANAL_OP_TYPE_MUL;
break;
case OP_MOD: /* A B C R(A) := RK(B) % RK(C) */
op->type = R_ANAL_OP_TYPE_MOD;
break;
case OP_POW: /* A B C R(A) := RK(B) ^ RK(C) */
break;
case OP_DIV: /* A B C R(A) := RK(B) / RK(C) */
op->type = R_ANAL_OP_TYPE_DIV;
break;
case OP_IDIV: /* A B C R(A) := RK(B) // RK(C) */
op->type = R_ANAL_OP_TYPE_DIV;
break;
case OP_BAND: /* A B C R(A) := RK(B) & RK(C) */
op->type = R_ANAL_OP_TYPE_AND;
break;
case OP_BOR: /* A B C R(A) := RK(B) | RK(C) */
op->type = R_ANAL_OP_TYPE_OR;
break;
case OP_BXOR: /* A B C R(A) := RK(B) ~ RK(C) */
op->type = R_ANAL_OP_TYPE_XOR;
break;
case OP_SHL: /* A B C R(A) := RK(B) << RK(C) */
op->type = R_ANAL_OP_TYPE_SHL;
break;
case OP_SHR: /* A B C R(A) := RK(B) >> RK(C) */
op->type = R_ANAL_OP_TYPE_SHR;
break;
case OP_UNM: /* A B R(A) := -R(B) */
break;
case OP_BNOT: /* A B R(A) := ~R(B) */
op->type = R_ANAL_OP_TYPE_CPL;
break;
case OP_NOT: /* A B R(A) := not R(B) */
op->type = R_ANAL_OP_TYPE_NOT;
break;
case OP_LEN: /* A B R(A) := length of R(B) */
break;
case OP_CONCAT: /* A B C R(A) := R(B).. ... ..R(C) */
break;
case OP_JMP: /* A sBx pc+=sBx; if (A) close all upvalues >= R(A - 1) */
op->type = R_ANAL_OP_TYPE_CJMP;
op->jump = op->addr + 4 * (GETARG_sBx (instruction));
op->fail = op->addr + 4;
break;
case OP_EQ: /* A B C if ((RK(B) == RK(C)) ~= A) then pc++ */
op->type = R_ANAL_OP_TYPE_CJMP;
op->jump = op->addr + 8;
op->fail = op->addr + 4;
break;
case OP_LT: /* A B C if ((RK(B) < RK(C)) ~= A) then pc++ */
op->type = R_ANAL_OP_TYPE_CJMP;
op->jump = op->addr + 8;
op->fail = op->addr + 4;
break;
case OP_LE: /* A B C if ((RK(B) <= RK(C)) ~= A) then pc++ */
op->type = R_ANAL_OP_TYPE_CJMP;
op->jump = op->addr + 8;
op->fail = op->addr + 4;
break;
case OP_TEST: /* A C if not (R(A) <=> C) then pc++ */
op->type = R_ANAL_OP_TYPE_CJMP;
op->jump = op->addr + 8;
op->fail = op->addr + 4;
break;
case OP_TESTSET:/* A B C if (R(B) <=> C) then R(A) := R(B) else pc++ */
op->type = R_ANAL_OP_TYPE_CMOV;
op->jump = op->addr + 8;
op->fail = op->addr + 4;
break;
case OP_CALL: /* A B C R(A), ... ,R(A+C-2) := R(A)(R(A+1), ... ,R(A+B-1)) */
op->type = R_ANAL_OP_TYPE_RCALL;
break;
case OP_TAILCALL:/* A B C return R(A)(R(A+1), ... ,R(A+B-1)) */
op->type = R_ANAL_OP_TYPE_RCALL;
op->type2 = R_ANAL_OP_TYPE_RET;
op->eob = true;
op->stackop = R_ANAL_STACK_INC;
op->stackptr = -4;
break;
case OP_RETURN: /* A B return R(A), ... ,R(A+B-2) (see note) */
op->type = R_ANAL_OP_TYPE_RET;
op->eob = true;
op->stackop = R_ANAL_STACK_INC;
op->stackptr = -4;
break;
case OP_FORLOOP:/* A sBx R(A)+=R(A+2);
if R(A) <?= R(A+1) then { pc+=sBx; R(A+3)=R(A) }*/
op->type = R_ANAL_OP_TYPE_CJMP;
op->jump = op->addr + 4 + 4 * (GETARG_sBx (instruction));
op->fail = op->addr + 4;
break;
case OP_FORPREP:/* A sBx R(A)-=R(A+2); pc+=sBx */
op->type = R_ANAL_OP_TYPE_JMP;
op->jump = op->addr + 4 + 4 * (GETARG_sBx (instruction));
op->fail = op->addr + 4;
break;
case OP_TFORCALL:/* A C R(A+3), ... ,R(A+2+C) := R(A)(R(A+1), R(A+2)); */
op->type = R_ANAL_OP_TYPE_RCALL;
break;
case OP_TFORLOOP:/* A sBx if R(A+1) ~= nil then { R(A)=R(A+1); pc += sBx }*/
op->type = R_ANAL_OP_TYPE_CJMP;
op->jump = op->addr + 4 + 4 * (GETARG_sBx (instruction));
op->fail = op->addr + 4;
break;
case OP_SETLIST:/* A B C R(A)[(C-1)*FPF+i] := R(A+i), 1 <= i <= B */
op->type = R_ANAL_OP_TYPE_STORE;
break;
case OP_CLOSURE:/* A Bx R(A) := closure(KPROTO[Bx]) */
case OP_VARARG: /* A B R(A), R(A+1), ..., R(A+B-2) = vararg */
case OP_EXTRAARG:/* Ax extra (larger) argument for previous opcode */
break;
}
return op->size;
}
#if 0
static int lua53_anal_fcn(RAnal *a, RAnalFunction *fcn, ut64 addr, const ut8 *data, int len, int reftype){
Dprintf ("Analyze Function: 0x%"PFMT64x "\n", addr);
LuaFunction *function = lua53findLuaFunctionByCodeAddr (addr);
if (function) {
fcn->maxstack = function->maxStackSize;
fcn->nargs = function->numParams;
}
fcn->addr = addr;
return 0;
}
static int finit(void *user) {
if (lua53_data.functionList) {
r_list_free (lua53_data.functionList);
lua53_data.functionList = 0;
}
return 0;
}
#endif
static int archinfo(RArchSession *cfg, ut32 q) {
return 4;
}
static char *regs(RArchSession *s) {
static const char * const p =
"=PC pc\n"
"=SP sp\n"
"=A0 a\n"
"=A1 b\n"
"=A2 c\n"
"=R0 a\n"
"=R1 b\n"
"gpr pc .32 0 0\n"
"gpr sp .32 4 0\n"
"gpr a .32 8 0\n"
"gpr b .32 12 0\n"
"gpr c .32 16 0\n"
;
return strdup (p);
}
RArchPlugin r_arch_plugin_lua = {
.name = "lua",
.desc = "LUA Bytecode arch plugin",
.license = "MIT",
.author = "pancake",
.arch = "lua",
.bits = R_SYS_BITS_PACK (32),
.addr_bits = R_SYS_BITS_PACK (32),
.info = archinfo,
.encode = &encode,
.decode = &decode,
.regs = regs,
.cpus = "5.3", // ,5.4"
.endian = R_SYS_ENDIAN_LITTLE,
};
#ifndef R2_PLUGIN_INCORE
R_API RLibStruct radare_plugin = {
.type = R_LIB_TYPE_ARCH,
.data = &r_arch_plugin_lua,
.version = R2_VERSION
};
#endif

10
libr/arch/p/lua.mk Normal file
View File

@ -0,0 +1,10 @@
OBJ_LUA=arch_lua.o
STATIC_OBJ+=$(OBJ_LUA)
TARGET_LUA=arch_lua.${EXT_SO}
ALL_TARGETS+=${TARGET_LUA}
${TARGET_LUA}: ${OBJ_LUA}
${CC} $(LDFLAGS) ${CFLAGS} $(call libname,arch_lua) $(CS_CFLAGS) \
-o arch_lua.${EXT_SO} ${OBJ_LUA} $(CS_LDFLAGS)

15
libr/arch/p/lua/Makefile Normal file
View File

@ -0,0 +1,15 @@
LIBEXT=$(shell r2 -H LIBEXT)
R2_LIBR_PLUGINS=$(shell r2 -H R2_LIBR_PLUGINS)
all:
for a in asm anal bin ; do $(MAKE) -C $$a ; done
clean:
for a in asm anal bin ; do $(MAKE) -C $$a clean ; done
install:
mkdir -p $(R2_LIBR_PLUGINS)
cp -f {asm,anal,bin}/*.$(LIBEXT) ${R2_LIBR_PLUGINS}/
uninstall:
rm -f $(R2_LIBR_PLUGINS)/*lua53*.$(LIBEXT)

View File

@ -0,0 +1,8 @@
EXT_SO=$(shell r2 -H LIBEXT)
WITHPIC=1
CFLAGS+=$(shell pkg-config --cflags --libs r_asm)
LDFLAGS+=-shared -fPIC
include lua53.mk
all: $(TARGET_LUA53)

View File

@ -0,0 +1,11 @@
OBJ_LUA53=asm_lua53.o
STATIC_OBJ+=${OBJ_LUA53}
TARGET_LUA53=asm_lua53.${EXT_SO}
ifeq ($(WITHPIC),1)
ALL_TARGETS+=${TARGET_LUA53}
${TARGET_LUA53}: ${OBJ_LUA53}
${CC} $(call libname,asm_lua53) ${LDFLAGS} ${CFLAGS} -o ${TARGET_LUA53} ${OBJ_LUA53}
endif

422
libr/arch/p/lua/lua53.c Normal file
View File

@ -0,0 +1,422 @@
/* radare2 - LGPL - Copyright 2017-2022 - pancake */
#include <r_asm.h>
#include <stdio.h>
#include "lua53.h"
static R_TH_LOCAL ut32 *current_write_prt;
static R_TH_LOCAL ut32 current_write_index;
#define isAlpha(x) (('a' <= (x) && 'z' >= (x)) || ('A' <= (x) && 'Z' >= (x)))
#define isNumeric(x) ('0' <= (x) && '9' >= (x))
#define isWhitespace(x) (' ' == (x) || '\t' == (x))
#define isComment(x) (';' == (x))
#define doParse0(inc, func, str) { \
int temp = func (str + inc); \
if (temp < 0) { \
R_LOG_DEBUG ("%i from %s in String %s", temp,#func, str + inc);\
return -1; \
} \
inc += temp; \
}
#define doParse1(inc, func, str, ...) { \
int temp = func (str + inc, __VA_ARGS__); \
if (temp < 0) { \
R_LOG_DEBUG ("%i from %s in String %s", temp,#func, str + inc);\
return -1; \
} \
inc += temp; \
}
typedef enum {
PARAMETER_A,
PARAMETER_B,
PARAMETER_C,
PARAMETER_Ax,
PARAMETER_Bx,
PARAMETER_sBx
} Parameter;
static int parseParameters(const char *str, OpCode opCode);
static int parseParameter(const char *str, Parameter parameter);
static int parseNextInstruction(const char *str);
static int parseWhitespaces(const char *str);
const char *instruction_names[] = {
"move", "loadk", "loadkx", "loadbool", "loadnil", "getupval", "gettabup", "gettable", "settabup", "setupval", "settable", "newtable", "self", "add", "sub", "mul", "mod",
"pow", "div", "idiv", "band", "bor", "bxor", "shl", "shr", "unm", "bnot", "not", "len", "concat", "jmp", "eq", "lt", "le",
"test", "testset", "call", "tailcall", "return", "forloop", "forprep", "tforcall", "tforloop", "setlist", "closure", "vararg", "extraarg", 0
};
static ut32 getInstruction(const ut8 *data){
ut32 instruction = 0;
instruction |= data[3] << 24;
instruction |= data[2] << 16;
instruction |= data[1] << 8;
instruction |= data[0] << 0;
return instruction;
}
static void setInstruction(ut32 opcode, ut8 *data) {
data[3] = opcode >> 24;
data[2] = opcode >> 16;
data[1] = opcode >> 8;
data[0] = opcode >> 0;
}
static int findNextWordStart(const char *str){
int chars_skipped = 0;
char c;
char comment_char;
while (1) {
doParse0 (chars_skipped, parseWhitespaces, str);
c = str[chars_skipped];
if (isAlpha (c) || isNumeric (c) || c == '-') { // if alphanumeric character return position
return chars_skipped;
} else if (c == ';') { // skip comment
do {
++chars_skipped;
comment_char = str[chars_skipped];
} while (comment_char != '\n'); // if no newline
} else if (c == '\n') { // skip comment
++chars_skipped;
continue;
} else if (c == '\0') {
break;
} else {
R_LOG_DEBUG ("Invalic Char 0x%02x", c);
return -1;
}
}
R_LOG_DEBUG ("Parsed %i empty chars", chars_skipped);
return chars_skipped;
}
static int parseNextInstruction(const char *str) {
int chars_skipped = 0;
doParse0 (chars_skipped, findNextWordStart, str);
const char *str_ptr = str + chars_skipped;
int i;
for (i = 0; instruction_names[i] != 0; i++) { // iterate over instruction strings
bool accepted = true;
int j;
for (j = 0; instruction_names[i][j] != '\0'; j++) { // iterate over characters
if (!((instruction_names[i][j] == str_ptr[j]) || (instruction_names[i][j] == (str_ptr[j] - 'A' + 'a')))) { // if char or uppercase char does not match
accepted = false;
break;
}
}
if (((isWhitespace (str_ptr[j]) || isComment (str_ptr[j])) && accepted)) { // if this is longest match possible
// write operation
chars_skipped += j;
R_LOG_DEBUG ("Opcode %i Instruction %s", i, instruction_names[i]);
SET_OPCODE (current_write_prt[current_write_index], i); // sets the opcode
doParse1 (chars_skipped, parseParameters, str, i); // Parse parameters
current_write_index++; // finished parsing an instruction so increase index
return chars_skipped;
}
}
R_LOG_DEBUG ("Error");
return -1;
}
static int parseWhitespaces(const char *str){
int skipped_whitespace = 0;
char c = str[skipped_whitespace];
while (isWhitespace (c)) {
c = str[++skipped_whitespace];
}
R_LOG_DEBUG ("Parsed %i Whitespaces", skipped_whitespace);
return skipped_whitespace;
}
static int parseParameters(const char *str, OpCode opCode) {
int chars_skipped = 0;
doParse0 (chars_skipped, parseWhitespaces, str);
switch (opCode) {
case OP_LOADKX: /* A R(A) := Kst(extra arg) */
doParse1 (chars_skipped, parseParameter, str, PARAMETER_A);
break;
case OP_MOVE: /* A B R(A) := R(B) */
case OP_LOADNIL: /* A B R(A), R(A+1), ..., R(A+B) := nil */
case OP_GETUPVAL: /* A B R(A) := UpValue[B] */
case OP_SETUPVAL: /* A B UpValue[B] := R(A) */
case OP_UNM: /* A B R(A) := -R(B) */
case OP_BNOT: /* A B R(A) := ~R(B) */
case OP_NOT: /* A B R(A) := not R(B) */
case OP_LEN: /* A B R(A) := length of R(B) */
case OP_RETURN: /* A B return R(A), ... ,R(A+B-2) (see note) */
case OP_VARARG: /* A B R(A), R(A+1), ..., R(A+B-2) = vararg */
doParse1 (chars_skipped, parseParameter, str, PARAMETER_A);
doParse1 (chars_skipped, parseParameter, str, PARAMETER_B);
break;
case OP_TEST: /* A C if not (R(A) <=> C) then pc++ */
case OP_TFORCALL: /* A C R(A+3), ... ,R(A+2+C) := R(A)(R(A+1), R(A+2)); */
doParse1 (chars_skipped, parseParameter, str, PARAMETER_A);
doParse1 (chars_skipped, parseParameter, str, PARAMETER_C);
break;
case OP_LOADK: /* A Bx R(A) := Kst(Bx) */
case OP_CLOSURE: /* A Bx R(A) := closure(KPROTO[Bx]) */
doParse1 (chars_skipped, parseParameter, str, PARAMETER_A);
doParse1 (chars_skipped, parseParameter, str, PARAMETER_Bx);
break;
case OP_LOADBOOL: /* A B C R(A) := (Bool)B; if (C) pc++ */
case OP_GETTABUP: /* A B C R(A) := UpValue[B][RK(C)] */
case OP_GETTABLE: /* A B C R(A) := R(B)[RK(C)] */
case OP_SETTABUP: /* A B C UpValue[A][RK(B)] := RK(C) */
case OP_SETTABLE: /* A B C R(A)[RK(B)] := RK(C) */
case OP_NEWTABLE: /* A B C R(A) := {} (size = B,C) */
case OP_SELF: /* A B C R(A+1) := R(B); R(A) := R(B)[RK(C)] */
case OP_ADD: /* A B C R(A) := RK(B) + RK(C) */
case OP_SUB: /* A B C R(A) := RK(B) - RK(C) */
case OP_MUL: /* A B C R(A) := RK(B) * RK(C) */
case OP_MOD: /* A B C R(A) := RK(B) % RK(C) */
case OP_POW: /* A B C R(A) := RK(B) ^ RK(C) */
case OP_DIV: /* A B C R(A) := RK(B) / RK(C) */
case OP_IDIV: /* A B C R(A) := RK(B) // RK(C) */
case OP_BAND: /* A B C R(A) := RK(B) & RK(C) */
case OP_BOR: /* A B C R(A) := RK(B) | RK(C) */
case OP_BXOR: /* A B C R(A) := RK(B) ~ RK(C) */
case OP_SHL: /* A B C R(A) := RK(B) << RK(C) */
case OP_SHR: /* A B C R(A) := RK(B) >> RK(C) */
case OP_CONCAT: /* A B C R(A) := R(B).. ... ..R(C) */
case OP_EQ: /* A B C if ((RK(B) == RK(C)) ~= A) then pc++ */
case OP_LT: /* A B C if ((RK(B) < RK(C)) ~= A) then pc++ */
case OP_LE: /* A B C if ((RK(B) <= RK(C)) ~= A) then pc++ */
case OP_TESTSET: /* A B C if (R(B) <=> C) then R(A) := R(B) else pc++ */
case OP_CALL: /* A B C R(A), ... ,R(A+C-2) := R(A)(R(A+1), ... ,R(A+B-1)) */
case OP_TAILCALL: /* A B C return R(A)(R(A+1), ... ,R(A+B-1)) */
case OP_SETLIST: /* A B C R(A)[(C-1)*FPF+i] := R(A+i), 1 <= i <= B */
doParse1 (chars_skipped, parseParameter, str, PARAMETER_A);
doParse1 (chars_skipped, parseParameter, str, PARAMETER_B);
doParse1 (chars_skipped, parseParameter, str, PARAMETER_C);
break;
case OP_JMP: /* A sBx pc+=sBx; if (A) close all upvalues >= R(A - 1) */
case OP_FORLOOP: /* A sBx R(A)+=R(A+2);
if R(A) <?= R(A+1) then { pc+=sBx; R(A+3)=R(A) }*/
case OP_FORPREP: /* A sBx R(A)-=R(A+2); pc+=sBx */
case OP_TFORLOOP: /* A sBx if R(A+1) ~= nil then { R(A)=R(A+1); pc += sBx }*/
doParse1 (chars_skipped, parseParameter, str, PARAMETER_A);
doParse1 (chars_skipped, parseParameter, str, PARAMETER_sBx);
break;
case OP_EXTRAARG: /* Ax extra (larger) argument for previous opcode */
doParse1 (chars_skipped, parseParameter, str, PARAMETER_Ax);
break;
}
return chars_skipped;
}
static int parseParameter(const char *str, Parameter parameter) {
int skipped_chars = findNextWordStart (str);
int resultingNumber = 0;
bool negative = false;
if (str[skipped_chars] == '-') {
negative = true;
++skipped_chars;
}
char c = str[skipped_chars];
if (!isNumeric (c)) {
return -1;
}
while (isNumeric (c)) {
resultingNumber *= 10;
resultingNumber += c - '0';
c = str[++skipped_chars];
}
resultingNumber = negative? resultingNumber * (-1): resultingNumber;
R_LOG_DEBUG ("Parsed Parameter %i", resultingNumber);
if (parameter != PARAMETER_sBx && resultingNumber < 0) {
return -1;
}
switch (parameter) {
case PARAMETER_A:
SETARG_A (current_write_prt[current_write_index], resultingNumber);
break;
case PARAMETER_B:
SETARG_B (current_write_prt[current_write_index], resultingNumber);
break;
case PARAMETER_C:
SETARG_C (current_write_prt[current_write_index], resultingNumber);
break;
case PARAMETER_Ax:
SETARG_Ax (current_write_prt[current_write_index], resultingNumber);
break;
case PARAMETER_Bx:
SETARG_Bx (current_write_prt[current_write_index], resultingNumber);
break;
case PARAMETER_sBx:
SETARG_sBx (current_write_prt[current_write_index], resultingNumber);
break;
}
return skipped_chars;
}
#if 0
// XXX
int lua53asm(RAsmOp *op, const char *s) {
int parsed = 0;
eprintf ("%s\n", s);
ut32 instruction;
current_write_prt = &instruction;
current_write_index = 0;
doParse0 (parsed, parseNextInstruction, s);
setInstruction (instruction, op->buf);
eprintf ("%d\n", parsed);
eprintf ("%08x\n", instruction);
return 4;
}
#endif
int lua53dissasm(RAnalOp *op, const ut8 *buf, int len){
if (len < 4) {
op->mnemonic = strdup ("truncated");
op->type = R_ANAL_OP_TYPE_ILL;
return 0;
}
ut32 instruction = getInstruction (buf);
OpCode operator = GET_OPCODE (instruction);
op->mnemonic = strdup ("invalid");
op->size = 4;
switch (operator) {
case OP_LOADKX: /* A R(A) := Kst(extra arg) */
free (op->mnemonic);
op->mnemonic = r_str_newf ("%s %i", instruction_names[GET_OPCODE (instruction)], GETARG_A (instruction));
break;
case OP_MOVE: /* A B R(A) := R(B) */
case OP_LOADNIL: /* A B R(A), R(A+1), ..., R(A+B) := nil */
case OP_GETUPVAL: /* A B R(A) := UpValue[B] */
case OP_SETUPVAL: /* A B UpValue[B] := R(A) */
case OP_UNM: /* A B R(A) := -R(B) */
case OP_BNOT: /* A B R(A) := ~R(B) */
case OP_NOT: /* A B R(A) := not R(B) */
case OP_LEN: /* A B R(A) := length of R(B) */
case OP_RETURN: /* A B return R(A), ... ,R(A+B-2) (see note) */
case OP_VARARG: /* A B R(A), R(A+1), ..., R(A+B-2) = vararg */
free (op->mnemonic);
op->mnemonic = r_str_newf ("%s %i %i", instruction_names[GET_OPCODE (instruction)], GETARG_A (instruction), GETARG_B (instruction));
break;
case OP_TEST: /* A C if not (R(A) <=> C) then pc++ */
case OP_TFORCALL: /* A C R(A+3), ... ,R(A+2+C) := R(A)(R(A+1), R(A+2)); */
free (op->mnemonic);
op->mnemonic = r_str_newf ("%s %i %i", instruction_names[GET_OPCODE (instruction)], GETARG_A (instruction), GETARG_C (instruction));
break;
case OP_LOADK: /* A Bx R(A) := Kst(Bx) */
free (op->mnemonic);
op->mnemonic = r_str_newf ("%s %i Kst(%i)", instruction_names[GET_OPCODE (instruction)], GETARG_A (instruction), GETARG_Bx (instruction));
break;
case OP_CLOSURE: /* A Bx R(A) := closure(KPROTO[Bx]) */
free (op->mnemonic);
op->mnemonic = r_str_newf ("%s %i KPROTO(%i)", instruction_names[GET_OPCODE (instruction)], GETARG_A (instruction), GETARG_Bx (instruction));
break;
case OP_LOADBOOL: /* A B C R(A) := (Bool)B; if (C) pc++ */
case OP_NEWTABLE: /* A B C R(A) := {} (size = B,C) */
case OP_CONCAT: /* A B C R(A) := R(B).. ... ..R(C) */
case OP_TESTSET: /* A B C if (R(B) <=> C) then R(A) := R(B) else pc++ */
case OP_CALL: /* A B C R(A), ... ,R(A+C-2) := R(A)(R(A+1), ... ,R(A+B-1)) */
case OP_TAILCALL: /* A B C return R(A)(R(A+1), ... ,R(A+B-1)) */
case OP_SETLIST: /* A B C R(A)[(C-1)*FPF+i] := R(A+i), 1 <= i <= B */
op->mnemonic = r_str_newf ("%s %i %i %i", instruction_names[GET_OPCODE (instruction)], GETARG_A (instruction), GETARG_B (instruction), GETARG_C (instruction));
break;
case OP_SELF: /* A B C R(A+1) := R(B); R(A) := R(B)[RK(C)] */
case OP_GETTABUP: /* A B C R(A) := UpValue[B][RK(C)] */
case OP_GETTABLE: /* A B C R(A) := R(B)[RK(C)] */
if (GETARG_C (instruction) & 0x100) {
op->mnemonic = r_str_newf ("%s %i %i K(%i)", instruction_names[GET_OPCODE (instruction)], GETARG_A (instruction), GETARG_B (instruction), GETARG_C (instruction) & 0xFF);
} else {
op->mnemonic = r_str_newf ("%s %i %i %i", instruction_names[GET_OPCODE (instruction)], GETARG_A (instruction), GETARG_B (instruction), GETARG_C (instruction));
}
break;
case OP_SETTABUP: /* A B C UpValue[A][RK(B)] := RK(C) */
case OP_SETTABLE: /* A B C R(A)[RK(B)] := RK(C) */
case OP_ADD: /* A B C R(A) := RK(B) + RK(C) */
case OP_SUB: /* A B C R(A) := RK(B) - RK(C) */
case OP_MUL: /* A B C R(A) := RK(B) * RK(C) */
case OP_MOD: /* A B C R(A) := RK(B) % RK(C) */
case OP_POW: /* A B C R(A) := RK(B) ^ RK(C) */
case OP_DIV: /* A B C R(A) := RK(B) / RK(C) */
case OP_IDIV: /* A B C R(A) := RK(B) // RK(C) */
case OP_BAND: /* A B C R(A) := RK(B) & RK(C) */
case OP_BOR: /* A B C R(A) := RK(B) | RK(C) */
case OP_BXOR: /* A B C R(A) := RK(B) ~ RK(C) */
case OP_SHL: /* A B C R(A) := RK(B) << RK(C) */
case OP_SHR: /* A B C R(A) := RK(B) >> RK(C) */
case OP_EQ: /* A B C if ((RK(B) == RK(C)) ~= A) then pc++ */
case OP_LT: /* A B C if ((RK(B) < RK(C)) ~= A) then pc++ */
case OP_LE: /* A B C if ((RK(B) <= RK(C)) ~= A) then pc++ */
free (op->mnemonic);
if (GETARG_B (instruction) & 0x100) {
if (GETARG_C (instruction) & 0x100) {
op->mnemonic = r_str_newf ("%s %i K(%i) K(%i)", instruction_names[GET_OPCODE (instruction)], GETARG_A (instruction), GETARG_B (instruction) & 0xFF, GETARG_C (instruction) & 0xFF);
} else {
op->mnemonic = r_str_newf ("%s %i K(%i) %i", instruction_names[GET_OPCODE (instruction)], GETARG_A (instruction), GETARG_B (instruction) & 0xFF, GETARG_C (instruction));
}
} else {
if (GETARG_C (instruction) & 0x100) {
op->mnemonic = r_str_newf ("%s %i %i K(%i)", instruction_names[GET_OPCODE (instruction)], GETARG_A (instruction), GETARG_B (instruction), GETARG_C (instruction) & 0xFF);
} else {
op->mnemonic = r_str_newf ("%s %i %i %i", instruction_names[GET_OPCODE (instruction)], GETARG_A (instruction), GETARG_B (instruction), GETARG_C (instruction));
}
}
break;
case OP_JMP: /* A sBx pc+=sBx; if (A) close all upvalues >= R(A - 1) */
case OP_FORLOOP: /* A sBx R(A)+=R(A+2);
if R(A) <?= R(A+1) then { pc+=sBx; R(A+3)=R(A) }*/
case OP_FORPREP: /* A sBx R(A)-=R(A+2); pc+=sBx */
case OP_TFORLOOP: /* A sBx if R(A+1) ~= nil then { R(A)=R(A+1); pc += sBx }*/
free (op->mnemonic);
op->mnemonic = r_str_newf ("%s %i %i", instruction_names[GET_OPCODE (instruction)], GETARG_A (instruction), GETARG_sBx (instruction));
break;
case OP_EXTRAARG: /* Ax extra (larger) argument for previous opcode */
free (op->mnemonic);
op->mnemonic = r_str_newf ("%s Kst(%i)", instruction_names[GET_OPCODE (instruction)], GETARG_Ax (instruction));
break;
default:
// invalid
op->size = -1;
break;
}
return true;
}
#ifdef MAIN_ASM
int main(int argc, char **argv) {
char *c = "move 1 2\n forprep 13 -2";
int p = 0;
current_write_prt = malloc (8);
current_write_index = 0;
eprintf ("Parsing String: %s\n", c);
eprintf ("-----------------------\n");
doParse0 (p, parseNextInstruction, c, (int) strlen (c));
eprintf ("Parsed Characters %i\n", p);
eprintf ("%d %08x\n", current_write_index, current_write_prt[current_write_index - 1]);
eprintf ("------------\n");
doParse0 (p, parseNextInstruction, c, (int) strlen (c));
eprintf ("Parsed Characters %i\n", p);
eprintf ("%d %08x\n", current_write_index, current_write_prt[current_write_index - 1]);
eprintf ("------------\n");
RAsmOp *asmOp = (RAsmOp *) malloc (sizeof (RAsmOp));
int advanced = lua53dissasm (asmOp, (const char *) current_write_prt, 4);
eprintf ("%s\n", asmOp->buf_asm);
lua53dissasm (asmOp, (const char *) current_write_prt + advanced, 4);
eprintf ("%s\n", asmOp->buf_asm);
free (current_write_prt);
return 0;
}
#endif // MAIN_ASM

231
libr/arch/p/lua/lua53.h Normal file
View File

@ -0,0 +1,231 @@
/*
** $Id: lopcodes.h,v 1.149 2016/07/19 17:12:21 roberto Exp $
** Opcodes for Lua virtual machine
*/
/******************************************************************************
* Copyright (C) 1994-2017 Lua.org, PUC-Rio.
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
******************************************************************************/
#ifndef lopcodes_h
#define lopcodes_h
#include <limits.h>
#include <stddef.h>
/*===========================================================================
We assume that instructions are unsigned numbers.
All instructions have an opcode in the first 6 bits.
Instructions can have the following fields:
'A' : 8 bits
'B' : 9 bits
'C' : 9 bits
'Ax' : 26 bits ('A', 'B', and 'C' together)
'Bx' : 18 bits ('B' and 'C' together)
'sBx' : signed Bx
A signed argument is represented in excess K; that is, the number
value is the unsigned value minus K. K is exactly the maximum value
for that argument (so that -max is represented by 0, and +max is
represented by 2*max), which is half the maximum for the corresponding
unsigned argument.
===========================================================================*/
enum OpMode {
iABC, iABx, iAsBx, iAx
}; /* basic instruction format */
#define cast(x, y) ((x)(y))
/*
** size and position of opcode arguments.
*/
#define SIZE_C 9
#define SIZE_B 9
#define SIZE_Bx (SIZE_C + SIZE_B)
#define SIZE_A 8
#define SIZE_Ax (SIZE_C + SIZE_B + SIZE_A)
#define SIZE_OP 6
#define POS_OP 0
#define POS_A (POS_OP + SIZE_OP)
#define POS_C (POS_A + SIZE_A)
#define POS_B (POS_C + SIZE_C)
#define POS_Bx POS_C
#define POS_Ax POS_A
#define MAX_INT INT_MAX /* maximum value of an int */
#define LUAI_BITSINT 32
/*
** limits for opcode arguments.
** we use (signed) int to manipulate most arguments,
** so they must fit in LUAI_BITSINT-1 bits (-1 for sign)
*/
#if SIZE_Bx < LUAI_BITSINT - 1
#define MAXARG_Bx ((1 << SIZE_Bx) - 1)
#define MAXARG_sBx (MAXARG_Bx >> 1) /* 'sBx' is signed */
#else
#define MAXARG_Bx MAX_INT
#define MAXARG_sBx MAX_INT
#endif
#if SIZE_Ax < LUAI_BITSINT - 1
#define MAXARG_Ax ((1 << SIZE_Ax) - 1)
#else
#define MAXARG_Ax MAX_INT
#endif
#define MAXARG_A ((1 << SIZE_A) - 1)
#define MAXARG_B ((1 << SIZE_B) - 1)
#define MAXARG_C ((1 << SIZE_C) - 1)
/* creates a mask with 'n' 1 bits at position 'p' */
#define MASK1(n, p) ((~((~(ut32)0) << (ut32)(n))) << (ut32)(p))
/* creates a mask with 'n' 0 bits at position 'p' */
#define MASK0(n, p) (~MASK1(n, p))
static ut32 getInstruction(const ut8 *data);
static void setInstruction(ut32 opcode, ut8 *data);
/*
** the following macros help to manipulate instructions
*/
#define GET_OPCODE(i) (cast (OpCode, ((i) >> POS_OP) & MASK1 (SIZE_OP, 0)))
#define SET_OPCODE(i, o) ((i) = (((i) & MASK0 (SIZE_OP, POS_OP)) |\
((cast (ut32, o) << POS_OP) & MASK1 (SIZE_OP, POS_OP))))
#define getarg(i, pos, size) (cast (int, ((i) >> pos) & MASK1 (size, 0)))
#define setarg(i, v, pos, size) ((i) = (((i) & MASK0 (size, pos)) |\
((cast (ut32, v) << pos) & MASK1 (size, pos))))
#define GETARG_A(i) getarg (i, POS_A, SIZE_A)
#define SETARG_A(i, v) setarg (i, v, POS_A, SIZE_A)
#define GETARG_B(i) getarg (i, POS_B, SIZE_B)
#define SETARG_B(i, v) setarg (i, v, POS_B, SIZE_B)
#define GETARG_C(i) getarg (i, POS_C, SIZE_C)
#define SETARG_C(i, v) setarg (i, v, POS_C, SIZE_C)
#define GETARG_Bx(i) getarg (i, POS_Bx, SIZE_Bx)
#define SETARG_Bx(i, v) setarg (i, v, POS_Bx, SIZE_Bx)
#define GETARG_Ax(i) getarg (i, POS_Ax, SIZE_Ax)
#define SETARG_Ax(i, v) setarg (i, v, POS_Ax, SIZE_Ax)
#define GETARG_sBx(i) (GETARG_Bx (i) - MAXARG_sBx)
#define SETARG_sBx(i, b) SETARG_Bx ((i), cast (unsigned int, (b) + MAXARG_sBx))
#define CREATE_ABC(o, a, b, c) ((cast (ut32, o) << POS_OP) \
| (cast (ut32, a) << POS_A) \
| (cast (ut32, b) << POS_B) \
| (cast (ut32, c) << POS_C))
#define CREATE_ABx(o, a, bc) ((cast (ut32, o) << POS_OP)\
| (cast (ut32, a) << POS_A)\
| (cast (ut32, bc) << POS_Bx))
#define CREATE_Ax(o, a) ((cast (ut32) << POS_OP)\
| (cast (ut32, a) << POS_Ax))
typedef enum {
/*----------------------------------------------------------------------
name args description
------------------------------------------------------------------------*/
OP_MOVE,/* A B R(A) := R(B) */
OP_LOADK,/* A Bx R(A) := Kst(Bx) */
OP_LOADKX, /* A R(A) := Kst(extra arg) */
OP_LOADBOOL, /* A B C R(A) := (Bool)B; if (C) pc++ */
OP_LOADNIL, /* A B R(A), R(A+1), ..., R(A+B) := nil */
OP_GETUPVAL, /* A B R(A) := UpValue[B] */
OP_GETTABUP, /* A B C R(A) := UpValue[B][RK(C)] */
OP_GETTABLE, /* A B C R(A) := R(B)[RK(C)] */
OP_SETTABUP, /* A B C UpValue[A][RK(B)] := RK(C) */
OP_SETUPVAL, /* A B UpValue[B] := R(A) */
OP_SETTABLE, /* A B C R(A)[RK(B)] := RK(C) */
OP_NEWTABLE, /* A B C R(A) := {} (size = B,C) */
OP_SELF,/* A B C R(A+1) := R(B); R(A) := R(B)[RK(C)] */
OP_ADD, /* A B C R(A) := RK(B) + RK(C) */
OP_SUB, /* A B C R(A) := RK(B) - RK(C) */
OP_MUL, /* A B C R(A) := RK(B) * RK(C) */
OP_MOD, /* A B C R(A) := RK(B) % RK(C) */
OP_POW, /* A B C R(A) := RK(B) ^ RK(C) */
OP_DIV, /* A B C R(A) := RK(B) / RK(C) */
OP_IDIV,/* A B C R(A) := RK(B) // RK(C) */
OP_BAND,/* A B C R(A) := RK(B) & RK(C) */
OP_BOR, /* A B C R(A) := RK(B) | RK(C) */
OP_BXOR,/* A B C R(A) := RK(B) ~ RK(C) */
OP_SHL, /* A B C R(A) := RK(B) << RK(C) */
OP_SHR, /* A B C R(A) := RK(B) >> RK(C) */
OP_UNM, /* A B R(A) := -R(B) */
OP_BNOT,/* A B R(A) := ~R(B) */
OP_NOT, /* A B R(A) := not R(B) */
OP_LEN, /* A B R(A) := length of R(B) */
OP_CONCAT, /* A B C R(A) := R(B).. ... ..R(C) */
OP_JMP, /* A sBx pc+=sBx; if (A) close all upvalues >= R(A - 1) */
OP_EQ, /* A B C if ((RK(B) == RK(C)) ~= A) then pc++ */
OP_LT, /* A B C if ((RK(B) < RK(C)) ~= A) then pc++ */
OP_LE, /* A B C if ((RK(B) <= RK(C)) ~= A) then pc++ */
OP_TEST,/* A C if not (R(A) <=> C) then pc++ */
OP_TESTSET, /* A B C if (R(B) <=> C) then R(A) := R(B) else pc++ */
OP_CALL,/* A B C R(A), ... ,R(A+C-2) := R(A)(R(A+1), ... ,R(A+B-1)) */
OP_TAILCALL, /* A B C return R(A)(R(A+1), ... ,R(A+B-1)) */
OP_RETURN, /* A B return R(A), ... ,R(A+B-2) (see note) */
OP_FORLOOP, /* A sBx R(A)+=R(A+2);
if R(A) <?= R(A+1) then { pc+=sBx; R(A+3)=R(A) }*/
OP_FORPREP, /* A sBx R(A)-=R(A+2); pc+=sBx */
OP_TFORCALL, /* A C R(A+3), ... ,R(A+2+C) := R(A)(R(A+1), R(A+2)); */
OP_TFORLOOP, /* A sBx if R(A+1) ~= nil then { R(A)=R(A+1); pc += sBx }*/
OP_SETLIST, /* A B C R(A)[(C-1)*FPF+i] := R(A+i), 1 <= i <= B */
OP_CLOSURE, /* A Bx R(A) := closure(KPROTO[Bx]) */
OP_VARARG, /* A B R(A), R(A+1), ..., R(A+B-2) = vararg */
OP_EXTRAARG /* Ax extra (larger) argument for previous opcode */
} OpCode;
#endif

10
libr/arch/p/lua/lua53.mk Normal file
View File

@ -0,0 +1,10 @@
OBJ_LUA53=anal_lua53.o
STATIC_OBJ+=$(OBJ_LUA53)
TARGET_LUA53=anal_lua53.${EXT_SO}
ALL_TARGETS+=${TARGET_LUA53}
${TARGET_LUA53}: ${OBJ_LUA53}
${CC} $(LDFLAGS) ${CFLAGS} $(call libname,anal_lua53) $(CS_CFLAGS) \
-o anal_lua53.${EXT_SO} ${OBJ_LUA53} $(CS_LDFLAGS)

View File

@ -0,0 +1,441 @@
/* radare - LGPL - Copyright 2009-2022 - pancake */
#include <r_types.h>
// XXX global
// R_UNUSED static RList *lua53_function_list = NULL;
struct {
int intSize;
int sizeSize;
int instructionSize;
int luaIntSize;
int luaNumberSize;
RList *functionList;
} lua53_data;
static ut64 parseNumber(const ut8 *data, ut64 bytesize){
int i;
ut64 res = 0;
for (i = 0; i < bytesize; i++) {
res |= ((ut64) data[i]) << (8 * i);
}
return res;
}
#define parseInt(data) parseNumber (data, lua53_data.intSize)
#define parseSize(data) parseNumber (data, lua53_data.sizeSize)
#define parseInstruction(data) parseNumber (data, lua53_data.instructionSize)
#define parseLuaInt(data) parseNumber (data, lua53_data.luaIntSize)
#define parseLuaNumber(data) parseNumber (data, lua53_data.luaNumberSize)
typedef struct lua_function {
ut64 offset;
char *name_ptr; // only valid in onFunction methon
ut64 name_size;
ut64 lineDefined;
ut64 lastLineDefined;
ut8 numParams;
ut8 isVarArg;
ut8 maxStackSize;
struct lua_function *parent_func;// if != NULL, should always be valid
ut64 const_size;
ut64 code_size;
ut64 upvalue_size;
ut64 protos_size;
ut64 const_offset;
ut64 code_offset;
ut64 upvalue_offset;
ut64 protos_offset;
ut64 debug_offset;
ut64 size;
} LuaFunction;
typedef struct lua_parse_struct ParseStruct;
typedef void (*OnFunction) (LuaFunction *function, struct lua_parse_struct *parseStruct);
typedef void (*OnString) (const ut8 *data, ut64 offset, ut64 size, struct lua_parse_struct *parseStruct);
typedef void (*OnConst) (const ut8 *data, ut64 offset, ut64 size, struct lua_parse_struct *parseStruct);
typedef struct lua_parse_struct {
OnString onString;
OnFunction onFunction;
OnConst onConst;
void *data;
} ParseStruct;
LuaFunction *lua53findLuaFunctionByCodeAddr(ut64 addr){
if (!lua53_data.functionList) {
return NULL;
}
LuaFunction *function = NULL;
RListIter *iter = NULL;
r_list_foreach (lua53_data.functionList, iter, function) {
if (function->code_offset + lua53_data.intSize <= addr && addr < function->const_offset) {
return function;
}
}
return NULL;
}
static int storeLuaFunction(LuaFunction *function){
if (!lua53_data.functionList) {
lua53_data.functionList = r_list_new ();
if (!lua53_data.functionList) {
return 0;
}
}
r_list_append (lua53_data.functionList, function);
return 1;
}
static LuaFunction *findLuaFunction(ut64 addr){
if (!lua53_data.functionList) {
return NULL;
}
LuaFunction *function = NULL;
RListIter *iter = NULL;
r_list_foreach (lua53_data.functionList, iter, function) {
R_LOG_DEBUG ("Search 0x%"PFMT64x, function->offset);
if (function->offset == addr) {
return function;
}
}
return NULL;
}
ut64 lua53parseHeader(const ut8 *data, ut64 offset, const ut64 size, ParseStruct *parseStruct);
ut64 lua53parseFunction(const ut8 *data, ut64 offset, const ut64 size, LuaFunction *parent_func, ParseStruct *parseStruct);
static ut64 parseString(const ut8 *data, ut64 offset, const ut64 size, ParseStruct *parseStruct);
static ut64 parseStringR(const ut8 *data, ut64 offset, const ut64 size, char **str_ptr, ut64 *str_len, ParseStruct *parseStruct);
static ut64 parseCode(const ut8 *data, ut64 offset, const ut64 size, ParseStruct *parseStruct);
static ut64 parseConstants(const ut8 *data, ut64 offset, const ut64 size, ParseStruct *parseStruct);
static ut64 parseUpvalues(const ut8 *data, ut64 offset, const ut64 size, ParseStruct *parseStruct);
static ut64 parseProtos(const ut8 *data, ut64 offset, const ut64 size, LuaFunction *func, ParseStruct *parseStruct);
static ut64 parseDebug(const ut8 *data, ut64 offset, const ut64 size, ParseStruct *parseStruct);
ut64 lua53parseHeader(const ut8 *data, ut64 offset, const ut64 size, ParseStruct *parseStruct) {
if (data && offset + 16 <= size && !memcmp (data + offset, "\x1bLua", 4)) { // check the header
offset += 4;
if (data[offset + 0] != '\x53') {// check version
return 0;
}
// skip format byte
offset += 2;
if (memcmp (data + offset, "\x19\x93\r\n\x1a\n", 6)) { // for version 5.3
return 0;
}
offset += 6;
lua53_data.intSize = data[offset + 0];
lua53_data.sizeSize = data[offset + 1];
lua53_data.instructionSize = data[offset + 2];
lua53_data.luaIntSize = data[offset + 3];
lua53_data.luaNumberSize = data[offset + 4];
R_LOG_DEBUG ("Int Size: %i", lua53_data.intSize);
R_LOG_DEBUG ("Size Size: %i", lua53_data.sizeSize);
R_LOG_DEBUG ("Instruction Size: %i", lua53_data.instructionSize);
R_LOG_DEBUG ("Lua Int Size: %i", lua53_data.luaIntSize);
R_LOG_DEBUG ("Lua Number Size: %i", lua53_data.luaNumberSize);
offset += 5;
if (offset + lua53_data.luaIntSize + lua53_data.luaNumberSize >= size) {// check again the remainingsize because an int and number is appended to the header
return 0;
}
if (parseLuaInt (data + offset) != 0x5678) { // check the appended integer
return 0;
}
offset += lua53_data.luaIntSize;
ut64 num = parseLuaNumber (data + offset);
double d = 0;
memcpy (&d, &num, sizeof (double));
// if (*((double *) &num) != 370.5) { // check the appended number
if (d != 370.5) { // check the appended number
return 0;
}
offset += lua53_data.luaNumberSize;
R_LOG_DEBUG ("Is a Lua Binary");
return offset;
}
return 0;
}
ut64 lua53parseFunction(const ut8 *data, ut64 offset, const ut64 size, LuaFunction *parent_func, ParseStruct *parseStruct){
R_LOG_DEBUG ("Function 0x%"PFMT64x, offset);
LuaFunction *function = findLuaFunction (offset);
if (function) { // if a function object was cached
R_LOG_DEBUG ("Found cached Functione: 0x%"PFMT64x, function->offset);
if (parseStruct != NULL && parseStruct->onString != NULL) {
parseConstants (data, function->const_offset, size, parseStruct);
}
parseProtos (data, function->protos_offset, size, function, parseStruct);
if (parseStruct != NULL && parseStruct->onString != NULL) {
parseDebug (data, function->debug_offset, size, parseStruct);
}
if (parseStruct != NULL && parseStruct->onFunction != NULL) {
parseStruct->onFunction (function, parseStruct);
}
return offset + function->size;
} else {
ut64 baseoffset = offset;
function = R_NEW0 (LuaFunction);
function->parent_func = parent_func;
function->offset = offset;
offset = parseStringR (data, offset, size, &function->name_ptr, &function->name_size, parseStruct);
if (offset == 0) {
free (function);
return 0;
}
function->lineDefined = parseInt (data + offset);
R_LOG_DEBUG ("Line Defined: %"PFMT64x, function->lineDefined);
function->lastLineDefined = parseInt (data + offset + lua53_data.intSize);
R_LOG_DEBUG ("Last Line Defined: %"PFMT64x, function->lastLineDefined);
offset += lua53_data.intSize * 2;
function->numParams = data[offset + 0];
R_LOG_DEBUG ("Param Count: %d", function->numParams);
function->isVarArg = data[offset + 1];
R_LOG_DEBUG ("Is VarArgs: %d", function->isVarArg);
function->maxStackSize = data[offset + 2];
R_LOG_DEBUG ("Max Stack Size: %d", function->maxStackSize);
offset += 3;
function->code_offset = offset;
function->code_size = parseInt (data + offset);
offset = parseCode (data, offset, size, parseStruct);
if (offset == 0) {
free (function);
return 0;
}
function->const_offset = offset;
function->const_size = parseInt (data + offset);
offset = parseConstants (data, offset, size, parseStruct);
if (offset == 0) {
free (function);
return 0;
}
function->upvalue_offset = offset;
function->upvalue_size = parseInt (data + offset);
offset = parseUpvalues (data, offset, size, parseStruct);
if (offset == 0) {
free (function);
return 0;
}
function->protos_offset = offset;
function->protos_size = parseInt (data + offset);
offset = parseProtos (data, offset, size, function, parseStruct);
if (offset == 0) {
free (function);
return 0;
}
function->debug_offset = offset;
offset = parseDebug (data, offset, size, parseStruct);
if (offset == 0) {
free (function);
return 0;
}
function->size = offset - baseoffset;
if (parseStruct && parseStruct->onFunction) {
parseStruct->onFunction (function, parseStruct);
}
if (!storeLuaFunction (function)) {
free (function);
}
return offset;
}
}
static ut64 parseCode(const ut8 *data, ut64 offset, const ut64 size, ParseStruct *parseStruct){
if (offset + lua53_data.intSize >= size) {
return 0;
}
ut64 length = parseInt (data + offset);
offset += lua53_data.intSize;
if (offset + length * lua53_data.instructionSize >= size) {
return 0;
}
R_LOG_DEBUG ("Function has %"PFMT64x " Instructions", length);
return offset + length * lua53_data.instructionSize;
}
static ut64 parseConstants(const ut8 *data, ut64 offset, const ut64 size, ParseStruct *parseStruct){
if (offset + lua53_data.intSize >= size) {
return 0;
}
ut64 length = parseInt (data + offset);
offset += lua53_data.intSize;
R_LOG_DEBUG ("Function has %"PFMT64x " Constants", length);
int i;
for (i = 0; i < length; i++) {
R_LOG_DEBUG ("%d: ", i);
ut8 type = data[offset + 0];
offset += 1;
switch (type) {
case 0: // Nil
R_LOG_DEBUG ("Nil");
break;
case 1: // Boolean
R_LOG_DEBUG ("Boolean %d", data[offset + 0]);
offset += 1;
break;
case (3 | (0 << 4)): // Number
{
#ifdef LUA_DEBUG
ut64 num = parseLuaNumber (data + offset);
R_LOG_DEBUG ("Number %f", *((double *) &num));
#endif
offset += lua53_data.luaNumberSize;
}
break;
case (3 | (1 << 4)): // Integer
R_LOG_DEBUG ("Integer %"PFMT64x, parseLuaInt (data + offset));
offset += lua53_data.luaIntSize;
break;
case (4 | (0 << 4)): // Short String
case (4 | (1 << 4)): // Long String
offset = parseString (data, offset, size, parseStruct);
break;
default:
R_LOG_DEBUG ("Invalid");
return 0;
}
}
return offset;
}
static ut64 parseUpvalues(const ut8 *data, ut64 offset, const ut64 size, ParseStruct *parseStruct){
if (offset + lua53_data.intSize >= size) {
return 0;
}
ut64 length = parseInt (data + offset);
offset += lua53_data.intSize;
R_LOG_DEBUG ("Function has %"PFMT64x " Upvalues", length);
int i;
for (i = 0; i < length; i++) {
R_LOG_DEBUG ("%d: inStack: %d id: %d", i, data[offset + 0], data[offset + 1]);
offset += 2;
}
return offset;
}
static ut64 parseProtos(const ut8 *data, ut64 offset, const ut64 size, LuaFunction *func, ParseStruct *parseStruct){
if (offset + lua53_data.intSize >= size) {
return 0;
}
ut64 length = parseInt (data + offset);
offset += lua53_data.intSize;
R_LOG_DEBUG ("Function has %"PFMT64x " Prototypes", length);
int i;
for (i = 0; i < length; i++) {
offset = lua53parseFunction (data, offset, size, func, parseStruct);
if (offset == 0) {
return 0;
}
}
return offset;
}
static ut64 parseDebug(const ut8 *data, ut64 offset, const ut64 size, ParseStruct *parseStruct){
if (offset + lua53_data.intSize >= size) {
return 0;
}
ut64 length = parseInt (data + offset);
offset += lua53_data.intSize;
if (length != 0) {
R_LOG_DEBUG ("Instruction-Line Mappings %"PFMT64x, length);
if (offset + lua53_data.intSize * length >= size) {
return 0;
}
int i;
for (i = 0; i < length; i++) {
R_LOG_DEBUG ("Instruction %d Line %"PFMT64x, i, parseInt (data + offset));
offset += lua53_data.intSize;
}
}
if (offset + lua53_data.intSize >= size) {
return 0;
}
length = parseInt (data + offset);
offset += lua53_data.intSize;
if (length != 0) {
R_LOG_DEBUG ("LiveRanges: %"PFMT64x, length);
int i;
for (i = 0; i < length; i++) {
R_LOG_DEBUG ("LiveRange %d:", i);
offset = parseString (data, offset, size, parseStruct);
if (offset == 0) {
return 0;
}
#ifdef LUA_DEBUG
ut64 num1 = parseInt (data + offset);
#endif
offset += lua53_data.intSize;
#ifdef LUA_DEBUG
ut64 num2 = parseInt (data + offset);
#endif
offset += lua53_data.intSize;
}
}
if (offset + lua53_data.intSize >= size) {
return 0;
}
length = parseInt (data + offset);
offset += lua53_data.intSize;
if (length != 0) {
R_LOG_DEBUG ("Up-Values: %"PFMT64x, length);
int i;
for (i = 0; i < length; i++) {
R_LOG_DEBUG ("Up-Value %d:", i);
offset = parseString (data, offset, size, parseStruct);
if (offset == 0) {
return 0;
}
}
}
return offset;
}
static ut64 parseString(const ut8 *data, ut64 offset, const ut64 size, ParseStruct *parseStruct){
return parseStringR (data, offset, size, 0, 0, parseStruct);
}
static ut64 parseStringR(const ut8 *data, ut64 offset, const ut64 size, char **str_ptr, ut64 *str_len, ParseStruct *parseStruct){
ut64 functionNameSize = data[offset + 0];
offset += 1;
if (functionNameSize == 0xFF) {
functionNameSize = parseSize (data + offset);
offset += lua53_data.sizeSize;
}
if (functionNameSize != 0) {
if (str_ptr) {
*str_ptr = (char *) data + offset;
}
if (str_len) {
*str_len = functionNameSize - 1;
}
if (parseStruct && parseStruct->onString) {
parseStruct->onString (data, offset, functionNameSize - 1, parseStruct);
}
R_LOG_DEBUG ("String %.*s", (int) (functionNameSize - 1), data + offset);
offset += functionNameSize - 1;
}
return offset;
}

379
libr/bin/p/bin_lua.c Normal file
View File

@ -0,0 +1,379 @@
/* radare - LGPL - Copyright 2009-2022 - pancake */
#include <r_types.h>
#include <r_util.h>
#include <r_lib.h>
#include <r_bin.h>
#include "../arch/p/lua/lua53_parser.c"
#if 0
static int finit(void *user) {
if (lua53_data.functionList) {
r_list_free (lua53_data.functionList);
lua53_data.functionList = 0;
}
return 0;
}
static bool check_bytes(const ut8 *buf, ut64 length);
static bool check(RBinFile *bf) {
Dprintf ("Check\n");
const ut8 *bytes = bf? r_buf_buffer (bf->buf): NULL;
ut64 sz = bf? r_buf_size (bf->buf): 0;
return check_bytes (bytes, sz);
}
#endif
static bool check_buffer(RBinFile *bf, RBuffer *b) {
if (r_buf_size (b) > 4) {
ut8 buf[4];
r_buf_read_at (b, 0, buf, sizeof (buf));
if (!memcmp (buf, "\x1b\x4c\x75\x61", 4)) {
return true;
}
#if 0
ParseStruct parseStruct;
ut64 parsedbytes = lua53parseHeader (buf, 0, sizeof (buf), &parseStruct);
return parsedbytes != 0;
#endif
}
return false;
}
static bool load_buffer(RBinFile *bf, void **bin_obj, RBuffer *b, ut64 loadaddr, Sdb *sdb) {
ut8 *buf = malloc (bf->size);
if (!buf) {
R_LOG_ERROR ("cannot malloc filesize");
return false;
}
r_buf_read_at (b, 0, buf, bf->size);
ParseStruct parseStruct;
ut64 parsedbytes = lua53parseHeader (buf, 0, sizeof (buf), &parseStruct);
free (buf);
// eprintf ("PAr %"PFMT64d"\n", parsedbytes);
return true;
return parsedbytes != 0;
#if 0
const ut8 *bytes = bf? r_buf_buffer (bf->buf): NULL;
ut64 sz = bf? r_buf_size (bf->buf): 0;
return check_bytes (bytes, sz);
#endif
}
static void addSection(RList *list, const char *name, ut64 addr, ut32 size, bool isFunc) {
RBinSection *bs = R_NEW0 (RBinSection);
if (!bs) {
return;
}
bs->name = strdup (name);
bs->vaddr = bs->paddr = addr;
bs->size = bs->vsize = size;
bs->add = true;
bs->is_data = false;
bs->bits = isFunc? 8 * lua53_data.instructionSize: 8;
if (bs->bits == 0) {
bs->bits = 32;
}
bs->has_strings = !isFunc;
bs->arch = strdup ("lua"); // maybe add bs->cpu or use : to separate arch:cpu
// bs->cpu = strdup ("5.4"); // maybe add bs->cpu or use : to separate arch:cpu
if (isFunc) {
bs->perm = R_PERM_RX;
} else {
bs->perm = R_PERM_R;
}
bs->is_segment = true;
r_list_append (list, bs);
}
static void addSections(LuaFunction *func, ParseStruct *parseStruct){
char *string;
if (func->name_size == 0 || func->name_ptr == 0) {
string = r_str_newf ("0x%"PFMT64x, func->offset);
} else {
string = r_str_ndup (func->name_ptr, func->name_size);
}
char sb[R_BIN_SIZEOF_STRINGS + 1];
snprintf (sb, sizeof (sb), "header.%s", string);
addSection (parseStruct->data, sb, func->offset, func->code_offset - func->offset, false);
snprintf (sb, sizeof (sb), "code.%s", string);
addSection (parseStruct->data, sb, func->code_offset, func->const_offset - func->code_offset, true); // code section also holds codesize
snprintf (sb, sizeof (sb), "consts.%s", string);
addSection (parseStruct->data, sb, func->const_offset, func->upvalue_offset - func->const_offset, false);
snprintf (sb, sizeof (sb), "upvalues.%s", string);
addSection (parseStruct->data, sb, func->upvalue_offset, func->protos_offset - func->upvalue_offset, false);
snprintf (sb, sizeof (sb), "debuginfo.%s", string);
addSection (parseStruct->data, sb, func->debug_offset, func->offset + func->size - func->debug_offset, false);
free (string);
}
static RList *sections(RBinFile *bf) {
ParseStruct parseStruct = {0};
if (!bf) {
return NULL;
}
#if 1
ut8 *bytes = malloc (bf->size);
if (!bytes) {
return NULL;
}
r_buf_read_at (bf->buf, 0, bytes, bf->size);
ut64 sz = bf? r_buf_size (bf->buf): 0;
memset (&parseStruct, 0, sizeof (parseStruct));
parseStruct.onFunction = addSections;
parseStruct.data = r_list_newf ((RListFree) free);
if (!parseStruct.data) {
return NULL;
}
ut64 headersize = 4 + 1 + 1 + 6 + 5 + bytes[15] + bytes[16] + 1;// header + version + format + stringterminators + sizes + integer + number + upvalues
addSection (parseStruct.data, "lua-header", 0, headersize, false);
// parse functions
lua53parseFunction (bytes, headersize, sz, 0, &parseStruct);
#endif
return parseStruct.data;
}
static void addString(const ut8 *buf, ut64 offset, ut64 length, ParseStruct *parseStruct){
RBinString *binstring = R_NEW0 (RBinString);
if (binstring == NULL) {
return;
}
binstring->string = r_str_newlen ((char *) buf + offset, length);
binstring->vaddr = binstring->paddr = offset;
binstring->ordinal = 0;
binstring->size = length;
binstring->length = length;
r_list_append (parseStruct->data, binstring);
}
static void addSymbol(RList *list, char *name, ut64 addr, ut32 size, const char *type) {
RBinSymbol *binSymbol = R_NEW0 (RBinSymbol);
if (binSymbol) {
binSymbol->name = strdup (name);
if (!binSymbol->name) {
free (binSymbol);
return;
}
binSymbol->vaddr = binSymbol->paddr = addr;
binSymbol->size = size;
binSymbol->ordinal = 0;
binSymbol->type = type;
r_list_append (list, binSymbol);
}
}
static void handleFuncSymbol(LuaFunction *func, ParseStruct *parseStruct){
RBinSymbol *binSymbol = R_NEW0 (RBinSymbol);
if (!binSymbol) {
return;
}
char *string;
if (!func->name_ptr || !func->name_size) {
string = malloc (11);
sprintf (string, "0x%"PFMT64x, func->offset);
} else {
string = malloc (func->name_size + 1);
memcpy (string, func->name_ptr, func->name_size);
int i;
for (i = 0; i < func->name_size; i++) {
if (string[i] == '@') {
string[i] = '_';
}
}
string[func->name_size] = '\0';
}
char sb[R_BIN_SIZEOF_STRINGS + 1];
snprintf (sb, sizeof (sb), "lineDefined.%s", string);
addSymbol (parseStruct->data, sb, func->code_offset - 3 - 2 * lua53_data.intSize, lua53_data.intSize, "NUM");
snprintf (sb, sizeof (sb), "lastLineDefined.%s", string);
addSymbol (parseStruct->data, sb, func->code_offset - 3 - lua53_data.intSize, lua53_data.intSize, "NUM");
snprintf (sb, sizeof (sb), "numParams.%s", string);
addSymbol (parseStruct->data, sb, func->code_offset - 3, 1, "NUM");
snprintf (sb, sizeof (sb), "isVarArg.%s", string);
addSymbol (parseStruct->data, sb, func->code_offset - 2, 1, "BOOL");
snprintf (sb, sizeof (sb), "maxStackSize.%s", string);
addSymbol (parseStruct->data, sb, func->code_offset - 1, 1, "BOOL");
snprintf (sb, sizeof (sb), "codesize.%s", string);
addSymbol (parseStruct->data, sb, func->code_offset, lua53_data.intSize, "NUM");
snprintf (sb, sizeof (sb), "func.%s", string);
addSymbol (parseStruct->data, sb, func->code_offset + lua53_data.intSize, lua53_data.instructionSize * func->code_size, "FUNC");
snprintf (sb, sizeof (sb), "constsize.%s", string);
addSymbol (parseStruct->data, sb, func->const_offset, lua53_data.intSize, "NUM");
snprintf (sb, sizeof (sb), "upvaluesize.%s", string);
addSymbol (parseStruct->data, sb, func->upvalue_offset, lua53_data.intSize, "NUM");
snprintf (sb, sizeof (sb), "prototypesize.%s", string);
addSymbol (parseStruct->data, sb, func->protos_offset, lua53_data.intSize, "NUM");
free (string);
}
static RList *strings(RBinFile *bf) {
ut8 *bytes = malloc (bf->size);
if (bytes) {
r_buf_read_at (bf->buf, 0, bytes, bf->size);
}
ut64 headersize = 4 + 1 + 1 + 6 + 5 + bytes[15] + bytes[16] + 1;// header + version + format + stringterminators + sizes + integer + number + upvalues
ParseStruct parseStruct;
memset (&parseStruct, 0, sizeof (parseStruct));
parseStruct.onString = addString;
parseStruct.data = r_list_new ();
if (!parseStruct.data) {
free (bytes);
return NULL;
}
lua53parseFunction (bytes, headersize, bf->size, 0, &parseStruct);
free (bytes);
return parseStruct.data;
}
static RList *symbols(RBinFile *bf) {
if (!bf) {
return NULL;
}
ut8 *bytes = malloc (bf->size);
if (bytes) {
r_buf_read_at (bf->buf, 0, bytes, bf->size);
}
ut64 sz = bf? r_buf_size (bf->buf): 0;
ut64 headersize = 4 + 1 + 1 + 6 + 5 + bytes[15] + bytes[16] + 1;
// header + version + format + stringterminators + sizes + integer + number + upvalues
ParseStruct parseStruct = {0};
parseStruct.onFunction = handleFuncSymbol;
parseStruct.data = NULL;
RList *list = r_list_new ();
parseStruct.data = list;
if (!parseStruct.data) {
return NULL;
}
addSymbol (list, "lua-header", 0, 4, "NOTYPE");
addSymbol (list, "lua-version", 4, 1, "NOTYPE");
addSymbol (list, "lua-format", 5, 1, "NOTYPE");
addSymbol (list, "stringterminators", 6, 6, "NOTYPE");
addSymbol (list, "int-size", 12, 1, "NUM");
addSymbol (list, "size-size", 13, 1, "NUM");
addSymbol (list, "instruction-size", 14, 1, "NUM");
addSymbol (list, "lua-int-size", 15, 1, "NUM");
addSymbol (list, "lua-number-size", 16, 1, "NUM");
addSymbol (list, "check-int", 17, bytes[15], "NUM");
addSymbol (list, "check-number", 17 + bytes[15], bytes[16], "FLOAT");
addSymbol (list, "upvalues", 17 + bytes[15] + bytes[16], 1, "NUM");
lua53parseFunction (bytes, headersize, sz, 0, &parseStruct);
return list;
}
static RBinInfo *info(RBinFile *bf) {
RBinInfo *ret = NULL;
if (!(ret = R_NEW0 (RBinInfo))) {
return NULL;
}
ret->file = strdup (bf->file);
ret->type = strdup ("lua");
ret->os = strdup ("any");
ret->machine = strdup ("LUA 5.3 VM");
ret->arch = strdup ("lua");
ret->bits = lua53_data.instructionSize * 8;
if (ret->bits < 1) {
ret->bits = 32;
} else if (ret->bits != 32) {
R_LOG_WARN ("lua vm using %d bits registers is not well tested", ret->bits);
}
ret->has_va = true;
ret->big_endian = false;
return ret;
}
static void addEntry(LuaFunction *func, ParseStruct *parseStruct){
if (!func->parent_func) {
RBinAddr *ptr = NULL;
if ((ptr = R_NEW0 (RBinAddr))) {
ptr->paddr = ptr->vaddr = func->code_offset + lua53_data.intSize;
r_list_append (parseStruct->data, ptr);
}
}
}
static RList *entries(RBinFile *bf) {
r_return_val_if_fail (bf, NULL);
if (bf->size < 20) {
return NULL;
}
ut8 *buf = malloc (bf->size);
if (!buf) {
R_LOG_ERROR ("cannot malloc filesize");
return false;
}
r_buf_read_at (bf->buf, 0, buf, bf->size);
// header + version + format + stringterminators + sizes + integer + number + upvalues
ut64 headersize = 4 + 1 + 1 + 6 + 5 + buf[15] + buf[16] + 1;
ParseStruct parseStruct;
memset (&parseStruct, 0, sizeof (parseStruct));
parseStruct.onFunction = addEntry;
parseStruct.data = NULL;
parseStruct.data = r_list_new ();
if (!parseStruct.data) {
free (buf);
return NULL;
}
lua53parseFunction (buf, headersize, bf->size, 0, &parseStruct);
free (buf);
return parseStruct.data;
}
RBinPlugin r_bin_plugin_lua = {
.name = "lua",
.desc = "Compiled LUA bin plugin (lua 5.3)",
.license = "MIT",
.author = "pancake",
.sections = &sections,
.load_buffer = &load_buffer,
.check_buffer = &check_buffer,
.symbols = &symbols,
.strings = &strings,
.info = &info,
.entries = &entries,
};
#ifndef CORELIB
RLibStruct radare_plugin = {
.type = R_LIB_TYPE_BIN,
.data = &r_bin_plugin_lua,
.version = R2_VERSION
};
#endif

10
libr/bin/p/lua.mk Normal file
View File

@ -0,0 +1,10 @@
OBJ_LUA=bin_lua.o
STATIC_OBJ+=${OBJ_LUA}
TARGET_LUA=bin_lua.${EXT_SO}
ALL_TARGETS+=${TARGET_LUA}
${TARGET_LUA}: ${OBJ_LUA}
${CC} $(call libname,bin_lua) -shared ${CFLAGS} \
-o ${TARGET_LUA} ${OBJ_LUA} $(LINK) $(LDFLAGS)

View File

@ -273,6 +273,7 @@ extern RArchPlugin r_arch_plugin_nios2;
extern RArchPlugin r_arch_plugin_or1k;
extern RArchPlugin r_arch_plugin_evm;
extern RArchPlugin r_arch_plugin_ws;
extern RArchPlugin r_arch_plugin_lua;
#ifdef __cplusplus
}

View File

@ -901,8 +901,10 @@ extern RBinPlugin r_bin_plugin_dmp64;
extern RBinPlugin r_bin_plugin_pyc;
extern RBinPlugin r_bin_plugin_off;
extern RBinPlugin r_bin_plugin_tic;
extern RBinPlugin r_bin_plugin_lua;
extern RBinPlugin r_bin_plugin_hunk;
extern RBinPlugin r_bin_plugin_xalz;
extern RBinPlugin r_bin_plugin_lua;
#ifdef __cplusplus
}

View File

@ -30,6 +30,8 @@ cd "$(dirname $0)"/..
(git grep -n 'for(' libr | grep -v _for | grep -v colorfor) && exit 1
(git grep -n 'for (' libr | grep "; ++" | grep -v arch ) && exit 1
(git grep -n 'for (int' | grep -v sys/) && exit 1
# (git grep -n '){' libr) && exit 1
# (git grep -n 'for(' | grep -v test | grep -v shlr | grep -v sys/) && exit 1
(git grep -n 'for (long' | grep -v sys/) && exit 1
(git grep -n 'for (ut' | grep -v sys/) && exit 1
(git grep -n 'for (size_t' | grep -v sys/) && exit 1