commit fe54bdd511b34c48d67eb1382c4c2a6c80f909ab
parent b303c8d5268297ee642f012fa81b4c5172ad21b4
Author: deurzen <m.deurzen@tum.de>
Date: Wed, 3 Feb 2021 01:05:31 +0100
adds project scripts
Diffstat:
3 files changed, 223 insertions(+), 0 deletions(-)
diff --git a/project/extract_sizeret.py b/project/extract_sizeret.py
@@ -0,0 +1,78 @@
+#!/usr/bin/python3
+
+import gdb
+
+# allocator mapped to register containing size argument
+break_arg = {
+ "kmem_cache_alloc_trace": "$rdx",
+ "kmalloc_order": "$rdi",
+ "__kmalloc": "$rdi",
+}
+
+# allocator mapped to offset to retq
+break_retq = {
+ "kmem_cache_alloc_trace": 232,
+ "kmalloc_order": 47,
+ "__kmalloc": 265,
+}
+
+entries = set()
+exits = set()
+
+prev_entry = None
+
+class EntryExitBreakpoint(gdb.Breakpoint):
+ def __init__(self, b):
+ gdb.Breakpoint.__init__(self, b)
+
+ def stop(self):
+ global break_arg
+ global args
+ global entries
+ global exits
+ global prev_entry
+
+ f = gdb.newest_frame()
+
+ if not f.is_valid():
+ return False
+
+ if f.unwind_stop_reason() != gdb.FRAME_UNWIND_NO_REASON:
+ return False
+
+ if self.number in entries:
+ # extract size from correct register, print for now
+ prev_entry = f"size={gdb.parse_and_eval(break_arg[f.name()])}"
+
+ elif self.number in exits:
+ if prev_entry is None:
+ return False
+
+ # extract return value, print for now
+ print(f"f{prev_entry}, ret={hex(int(str(gdb.parse_and_eval('$rax')), 10) & (2 ** 64 - 1))}", flush=True)
+ prev_entry = None
+
+ # TODO: extract filename
+
+ return False
+
+class Stage3():
+ breakpoints = []
+
+ def __init__(self):
+ global break_retq
+ global entries
+ global exits
+
+ for b, retq in break_retq.items():
+ # set breakpoint at function entry, to extract size
+ b_entry = EntryExitBreakpoint(b)
+ self.breakpoints.append(b_entry)
+ entries.add(b_entry.number)
+
+ # set breakpoint at function exit (retq), to extract return value
+ b_exit = EntryExitBreakpoint(f"*{hex(int(str(gdb.parse_and_eval(b).address).split(' ')[0], 16) + retq)}")
+ self.breakpoints.append(b_exit)
+ exits.add(b_exit.number)
+
+Stage3()
diff --git a/project/occ.sh b/project/occ.sh
@@ -0,0 +1,59 @@
+#!/bin/bash
+#Extract all occurences of function calls and the assigned variables from kernel sources
+funcs=("kmalloc" "kzalloc" "kfree")
+out=".funcs"
+
+rm -f cscope.out cscope.files $out
+
+for f in ${funcs[@]}; do
+ rm -f $f
+done
+
+if [ $# -eq 0 ]; then
+ echo "Usage: $0 <kernel src dir>"
+ exit 0
+fi
+
+if ! [ -x "$(command -v cscope)" ]; then
+ echo 'Dependency cscope is missing.' >&2
+ exit 1
+fi
+
+echo "Generating file cscope.files.."
+find $1 \
+ -path "$1arch/alpha*" -prune -o \
+ -path "$1arch/arc*" -prune -o \
+ -path "$1arch/arm*" -prune -o \
+ -path "$1arch/arm64*" -prune -o \
+ -path "$1arch/c6x*" -prune -o \
+ -path "$1arch/h8300*" -prune -o \
+ -path "$1arch/hexagon*" -prune -o \
+ -path "$1arch/ia64*" -prune -o \
+ -path "$1arch/m68k*" -prune -o \
+ -path "$1arch/microblaze*" -prune -o \
+ -path "$1arch/mips*" -prune -o \
+ -path "$1arch/nds32*" -prune -o \
+ -path "$1arch/nios2*" -prune -o \
+ -path "$1arch/openrisc*" -prune -o \
+ -path "$1arch/parisc*" -prune -o \
+ -path "$1arch/powerpc*" -prune -o \
+ -path "$1arch/riscv*" -prune -o \
+ -path "$1arch/s390*" -prune -o \
+ -path "$1arch/sh*" -prune -o \
+ -path "$1arch/sparc*" -prune -o \
+ -path "$1arch/um*" -prune -o \
+ -path "$1arch/unicore32*" -prune -o \
+ -path "$1arch/xtensa*" -prune -o \
+ -path "$1drivers*" -prune -o \
+ -path "$1Documentation*" -prune -o \
+ -path "$1scripts*" -prune -o \
+ -path "$1tools*" -prune -o \
+ -name "*.[chxsS]" -print > ./cscope.files
+echo "Done!"
+
+echo "Generating occurence database.."
+echo "$1" >> $out
+for f in ${funcs[@]}; do
+ cscope -L -0 $f >> $out
+done
+echo "Done!"
+\ No newline at end of file
diff --git a/project/type_dict.py b/project/type_dict.py
@@ -0,0 +1,85 @@
+###################################################################
+# Format of input file:
+# First line:
+# directory prefix to prune
+#
+# Rest of lines:
+# <filename> <func or global> <line> <var or call to free>
+###################################################################
+
+###################################################################
+# Format of dictionary:
+# ('filename:line') |-> ('type')
+###################################################################
+
+import json
+import os, errno
+import gdb
+
+def delfile(name):
+ try:
+ os.remove(name)
+ except OSError as err:
+ if err.errno != errno.ENOENT:
+ raise
+
+class CodeDict():
+ in_n = ".funcs"
+ out_n = ".dict"
+
+ inf = None
+ outf = None
+
+ dict = {}
+
+ def __init__(self):
+ self.setup()
+ self.parse()
+
+ self.outf.write(json.dumps(self.dict))
+
+ def setup(self):
+ try:
+ self.inf = open(self.in_n, "r")
+ except:
+ print(f"No file {in_n} found! Run occ.sh first")
+ raise
+
+ delfile(self.out_n)
+ self.outf = open(self.out_n, "w+")
+
+ def parse(self):
+ ignore = ["*", "->", "(", ")", "[", "]"]
+
+ dir = len(self.inf.readline()) - 1
+
+ for line in self.inf.readlines():
+ # Remove directory prefix, insert ./ to reflect the frame representation of source file in gdb
+ l = ("./" + (line[dir:])).split(" ")
+
+ src = l[0]
+ fn = l[1]
+ lnr = l[2]
+ var = l[3]
+
+ if any(s in var for s in ignore):
+ continue
+
+ if fn == "<global>":
+ try:
+ type_info = gdb.execute(f"whatis '{src}'::{var}", to_string = True)
+ except:
+ continue
+ else:
+ try:
+ type_info = gdb.execute(f"whatis '{fn}'::{var}", to_string = True)
+ except:
+ continue
+
+ if type_info is not None:
+ key = f"{src}:{lnr}"
+ self.dict[key] = type_info
+
+ print(self.dict)
+
+CodeDict()