blob: fb670e680ce55521c8f7841d1909153c03256d16 [file] [log] [blame]
import os
import sys
import subprocess
import re
from threading import Timer
global_front = """
#include "debug-snapshot-log.h"
struct dbg_snapshot_log *p;
void remove_non_ascii(char * s, int len) {
for (int i = 0; i < len; i++) {
if(!s[i]) break;
if(!(32 <= s[i] && s[i] < 127) || s[i] == '\\'') s[i] = ' ';
}
s[len-1] = 0;
}
int main(int argc, char *argv[])
{
FILE *f;
int ch;
long fsize;
char *string;
int i0, i1, i2;
f = fopen(argv[1], "rb");
if (f == NULL) {
fputs("file read error!", stderr);
exit(1);
}
fseek(f, 0, SEEK_END);
fsize = ftell(f);
fseek(f, 0, SEEK_SET); //same as rewind(f);
string = malloc(fsize + 1);
fread(string, fsize, 1, f);
fclose(f);
p = (struct dbg_snapshot_log *)string;
printf("log = []\\n");
"""
global_back = """
return 0;
}
"""
### Below classes substitute global variable.
class Singleton(type):
_instances = {}
def __call__(cls, *args, **kwargs):
if cls not in cls._instances:
cls._instances[cls] = super(Singleton, cls).__call__(*args, **kwargs)
return cls._instances[cls]
def execget(cmd, to=100, printerr=False):
def kill(process):
process.kill();
stdout = ""
stderr = ""
p = subprocess.Popen(cmd, shell="True", stdout=subprocess.PIPE, stderr=subprocess.PIPE, env=os.environ);
my_timer = Timer(to, kill, [p]);
try:
my_timer.start()
stdout, stderr = p.communicate()
finally:
my_timer.cancel()
return stdout;
def expect(current, expect, short_msg):
if current not in expect:
msg = """
Error : %s
Current output: %s
Expect output : %s
""" % (short_msg, current, expect)
raise Exception(msg)
class TypeTable:
__metaclass__ = Singleton
def __init__(self):
if "data" in self.__dict__:
return
self.data = {}
def get(self, key):
return self.data.get(key, None)
def set(self, key, value):
self.data[key] = value
def clear(self):
self.data = {}
def __repr__(self):
ret = ""
for k, v in self.data.items():
ret += "%s\n" % str(v)
return ret
class FieldTable:
__metaclass__ = Singleton
def __init__(self):
if "d" in self.__dict__:
return
self.d = []
def find_typedecl_all(self):
for x in self.d:
x.find_typedecl()
### Primitive Types -----------------------------
class Decl:
@staticmethod
def find_depth(line):
s = 0
while not line[s].isalpha():
s += 1
if s < len(line):
continue
s = -1;
break
return s
class TypeDecl(Decl):
def __init__(self, name, abv):
self.name = name
self.abv = abv
typetab = TypeTable()
typetab.set(self.name, self)
def __repr__(self):
return self.name
@staticmethod
def add_primative():
TypeDecl("short", "%hd")
TypeDecl("unsigned short", "%hu")
TypeDecl("signed short", "%hd")
TypeDecl("int", "%d")
TypeDecl("unsigned int", "%u")
TypeDecl("signed int", "%d")
TypeDecl("unsigned char", "%u")
TypeDecl("signed char", "%d")
TypeDecl("long", "%ld")
TypeDecl("unsigned long", "%lu")
TypeDecl("signed long", "%lu")
TypeDecl("long long", "%lld")
TypeDecl("unsigned long long", "%llu")
TypeDecl("signed long long", "%lld")
TypeDecl("double", "%lf")
TypeDecl("float", "%f")
TypeDecl("pointer", "'%p'")
TypeDecl("char pointer", "'%p'")
TypeDecl("char", "'%s'")
TypeDecl("unknown", "")
### RecordDecl Types -----------------------------
class RecordDecl(TypeDecl):
def __init__(self, line):
self.depth = Decl.find_depth(line)
line = line[self.depth:]
arr = line.strip().split(" ")
self.id = arr[1]
self.name = arr[-2]
self.field = []
typetab = TypeTable()
typetab.set(self.name, self)
def __repr__(self):
ret = "%s %s\n" % (self.id, self.name)
for x in self.field:
ret += " %s\n" % str(x)
return ret
### FieldDecl Types -----------------------------
"""
|-RecordDecl 0x5c53f80 parent 0x5aad4f8 <line:353:2, line:358:2> line:353:9 struct __printk_log definition
| |-FieldDecl 0x5c54058 <line:354:3, col:22> col:22 time 'unsigned long long'
| |-FieldDecl 0x5c540b8 <line:355:3, col:7> col:7 cpu 'int'
| |-FieldDecl 0x5c54178 <line:356:3, col:33> col:8 log 'char [128]'
| `-FieldDecl 0x5c54220 <line:357:3, col:37> col:9 caller 'void *[4]'
"""
class FieldDecl(Decl):
def __init__(self, line, record):
self.record = record
self.depth = Decl.find_depth(line)
line = line[self.depth:]
arr = line.strip().split(" ", 6)
self.id = arr[1]
self.name = arr[-2]
if "':'" in arr[-1]:
self.type = arr[-1].split("':'")[-1].strip().strip("'")
else:
self.type = arr[-1].strip().strip("'")
array = re.findall(r"\[(?P<index>\d+)\]", self.type)
self.array = [int(i) for i in array]
for n in self.array:
self.type = self.type.replace("[%d]" % n ,"").strip()
fieldtab = FieldTable()
fieldtab.d.append(self)
def find_typedecl(self):
typetab = TypeTable()
self.type = self.type.replace("struct ", "")
self.type = self.type.replace("union ", "")
if "*" in self.type and "char" in self.type:
self.type = "char pointer"
if "*" in self.type:
self.type = "pointer"
if typetab.get(self.type):
self.type = typetab.get(self.type)
else:
self.type = typetab.get("unknown")
def __repr__(self):
ret = "%s %s " % (self.id, self.name)
array = ""
for n in self.array:
array += "[%d]" % n
ret += "'%s %s'" % (str(self.type), array)
return ret
def array_printer(self, array):
front_array = "["
for i in range(self.array[0]):
front_array += "%s, " % self.type.abv
front_array = front_array[:-1] + "]"
mid = ""
for i in range(self.array[0]):
if self.type.name == "pointer":
mid += "p->%s.%s[%d] ? p->%s.%s[%d] :(void**)-1,\n" %(array, self.name, i, array, self.name, i)
else:
mid += "p->%s.%s[%d],\n" %(array, self.name, i)
front = "'%s' :%s, " % (self.name, front_array)
return front, mid
def printer(self, printf_obj=None):
## Check printer is called by root.
if not printf_obj:
pf = Printf(self.array, self.name)
else:
pf = printf_obj
## Check this type is primitvie
if hasattr(self.type, "abv"):
pf.add_field(self, pf.ref_name)
else:
## structs are layered like Binder, self.name is cascaded to ref_name
if printf_obj:
temp = pf.ref_name
pf.ref_name = "%s.%s" % (pf.ref_name, self.name)
for f in self.type.field:
f.printer(pf)
if printf_obj:
pf.ref_name = temp
## If printer is succeed in root, save all fields as string
if not printf_obj:
return pf.save_all()
return None
### Printf class --------------------------------
class Printf:
def __init__(self, bounds, name):
self.bounds = bounds
self.name = name
self.ref_name = name
## Arrays for storing fields
self.fields = []
self.pointer_fields = []
self.string_fields = []
self.array_fields = []
self.pointer_array_fields = []
## Result strings will be concatenated right before returing.
self.for_statement = ""
self.for_statement_back = ""
self.for_body = ""
self.printf_front = ""
self.printf_format = ""
self.printf_mid = ""
self.printf_args = ""
self.printf_back = ""
## Makeup default string for 'for statement' & 'printf'
self.make_for_statement()
self.prepare_printf()
## Field is pushed from outside by this method
def add_field(self, x, ref_name):
x.ref_name = ref_name
if x.name == "time" :
pass
elif x.type.name == "char":
self.string_fields.append(x)
elif len(x.array) > 0 and x.type.name != "pointer" :
self.array_fields.append(x)
elif len(x.array) > 0 and x.type.name == "pointer" :
self.pointer_array_fields.append(x)
elif x.type.name == "pointer":
self.pointer_fields.append(x)
else:
self.fields.append(x)
def make_for_statement(self):
for index, n in enumerate(self.bounds):
self.for_statement += "for (i%d = 0; i%d < %d; i%d++) {\n" % (index, index, n, index)
self.for_statement_back += "}\n"
self.ref_name += "[i%d]" % index
self.for_body += "if (p->%s.time == 0) break;\n" % (self.ref_name)
def prepare_printf(self):
self.printf_front += "printf(\"log.append({ 'type' : '%s', " % self.name
self.printf_mid += "})\\n\",\n"
self.printf_back += ");\n"
self.printf_format += "'time' : %lld.%09lld, "
self.printf_args += "p->%s.time/1000000000LL," % self.ref_name
self.printf_args += "p->%s.time%%1000000000LL,\n" % self.ref_name
if len(self.bounds) > 1 and self.bounds[0] == 8:
self.printf_format += "'cpu' : %d, "
self.printf_args += "i0,\n"
## Iterate all fields, and Convert it to C-code
def process_fields(self):
for x in self.fields:
self.print_normal(x)
for x in self.string_fields:
self.print_string(x)
for x in self.array_fields:
self.print_array(x)
for x in self.pointer_array_fields:
self.print_pointer_array(x)
for x in self.pointer_fields:
self.print_pointer(x)
def print_normal(self, x):
self.printf_format += "'%s' : %s, " % (x.name, x.type.abv)
self.printf_args += "p->%s.%s,\n" %(x.ref_name, x.name)
def print_pointer(self, x):
self.printf_format += "'%s' : %s, " % (x.name, x.type.abv)
self.printf_args += "p->%s.%s ? p->%s.%s :(void**)-1,\n" %(x.ref_name, x.name, x.ref_name, x.name)
def print_string(self, x):
self.printf_format += "'%s' : %s, " % (x.name, x.type.abv)
self.printf_args += "p->%s.%s,\n" %(x.ref_name, x.name)
self.for_body += ("remove_non_ascii(p->%s.%s, %d);\n" %(x.ref_name, x.name, x.array[0]))
def print_array(self, x):
front_array = "["
for i in range(x.array[0]):
front_array += "%s, " % x.type.abv
front_array = front_array[:-1] + "]"
for i in range(x.array[0]):
self.printf_args += "p->%s.%s[%d],\n" %(x.ref_name, x.name, i)
self.printf_format += "'%s' :%s, " % (x.name, front_array)
def print_pointer_array(self, x):
front_array = "["
for i in range(x.array[0]):
front_array += "%s, " % x.type.abv
front_array = front_array[:-1] + "]"
for i in range(x.array[0]):
self.printf_args += "p->%s.%s[%d] ? p->%s.%s[%d] :(void**)-1,\n" %(x.ref_name, x.name, i, x.ref_name, x.name, i)
self.printf_format += "'%s' :%s, " % (x.name, front_array)
def save_all(self):
self.process_fields()
ret = ""
ret += self.for_statement
ret += self.for_body
ret += self.printf_front
ret += self.printf_format
ret += self.printf_mid
ret += self.printf_args[:-2]
ret += self.printf_back
ret += self.for_statement_back
return ret
### ASTdump Class -----------------------------
class ASTdump:
def __init__(self):
if "clang" in os.environ["CC"]:
self.clang = os.environ["CC"]
elif "clang" in execget("which clang"):
self.clang = "clang"
def run_inner(self, i, record):
depth = record.depth
ret = []
for line in self.dump[i+1:]:
inner_depth = Decl.find_depth(line)
if depth >= inner_depth:
break
if depth + 2 != inner_depth:
continue
if not "FieldDecl" in line:
continue
ret.append(FieldDecl(line, record))
return ret
def prepare(self):
self.dump = execget("%s -Iinclude -Xclang -ast-dump -fsyntax-only -DDSS_ANALYZER lib/debug-snapshot-log.h" % self.clang)
self.dump = self.dump.strip().split("\n")
for i, line in enumerate(self.dump):
if not "RecordDecl" in line:
continue
record = RecordDecl(line)
record.field = self.run_inner(i, record)
FieldTable().find_typedecl_all()
def run(self):
main_root = TypeTable().get("dbg_snapshot_log")
ret = ""
for r in main_root.field:
ret += r.printer()
return global_front + ret + global_back
if __name__ == "__main__":
TypeDecl.add_primative()
astdump = ASTdump()
astdump.prepare()
ret = astdump.run()
print(ret)