From 4bf55f45d2caa74ddd251347d2aa7c20b57a0214 Mon Sep 17 00:00:00 2001 From: Alexander Wagner Date: Thu, 2 Mar 2023 11:36:09 +0100 Subject: [PATCH 1/4] Make black happy --- analysis/analyze.py | 6 +++--- analysis/datastub/printer.py | 6 +++--- analysis/leakage_models/dsa_nonce.py | 2 +- report/report.py | 4 ++-- 4 files changed, 9 insertions(+), 9 deletions(-) diff --git a/analysis/analyze.py b/analysis/analyze.py index 9457a9f8..b637bca6 100755 --- a/analysis/analyze.py +++ b/analysis/analyze.py @@ -392,7 +392,7 @@ def read_and_advance(chunk, idx, format_type, length): # This parsing requires a naming scheme like: `key1.key` key_index = int(set(keys).pop().replace("key", "").replace(".", "")) - for (trace_file, key_file) in zip(files, keys): + for trace_file, key_file in zip(files, keys): with open(trace_file, "rb") as tf, open(key_file, "rb") as kf: trace = tf.read() key = kf.read() @@ -508,7 +508,7 @@ def _glt_sort_and_map(mapping_table, data): # Sort data from big to little wrt to the counts data = sorted(data.items(), key=lambda kv: kv[1], reverse=True) # Map addr to new value - for (address, count) in data: + for address, count in data: if address not in mapping_table: mapping_table[address] = len(mapping_table.keys()) tmp_data[mapping_table[address]] = count @@ -612,7 +612,7 @@ def generic_leakage_test(fixed, random): # iterate over leaks debug(0, "Got %d trace differences.", (len(fixedleaks))) sys.stdout.flush() - for (idx, (fl, rl)) in enumerate(zip(fixedleaks, randomleaks)): + for idx, (fl, rl) in enumerate(zip(fixedleaks, randomleaks)): msg = {"warning": "", "leak": ""} assert fl.ip == rl.ip diff --git a/analysis/datastub/printer.py b/analysis/datastub/printer.py index 85cd31ad..388f9998 100644 --- a/analysis/datastub/printer.py +++ b/analysis/datastub/printer.py @@ -193,10 +193,10 @@ def doprint_generic(self, obj, param1=False): key_indxs = [e.key.index for e in obj.evidence] evidences = [[] for _ in range(max(key_indxs) + 1)] - for (idx, key_indx) in enumerate(key_indxs): + for idx, key_indx in enumerate(key_indxs): evidences[key_indx].append(obj.evidence[idx]) - for (idx, evidence) in enumerate(evidences): + for idx, evidence in enumerate(evidences): entries = Counter( [entry for ee in evidence for entry in ee.entries] ) @@ -209,7 +209,7 @@ def doprint_generic(self, obj, param1=False): else: node = f"{node_plain} origin='fixed' {str(evidence[0].key)}" self.startNode(node) - for (key, value) in entries.items(): + for key, value in entries.items(): self.doprint_line(f"{format(key, 'x')}: {value}") self.endNode(node_plain) diff --git a/analysis/leakage_models/dsa_nonce.py b/analysis/leakage_models/dsa_nonce.py index 4ad4c338..7ee731d1 100644 --- a/analysis/leakage_models/dsa_nonce.py +++ b/analysis/leakage_models/dsa_nonce.py @@ -49,7 +49,7 @@ def input_to_lines(input): num_lines_per_input = len(input_to_lines(inputs[0])) result = numpy.ndarray((len(inputs), num_lines_per_input), dtype=numpy.int) - for (i, input) in enumerate(inputs): + for i, input in enumerate(inputs): result[i][:] = [v for k, v in input_to_lines(input)] return (result, labels) diff --git a/report/report.py b/report/report.py index da70be37..436d9684 100644 --- a/report/report.py +++ b/report/report.py @@ -223,7 +223,7 @@ def parse_leaks(lib_hierarchy): fl_entries = createLibFunctionItems(lib, lib_item) # tuple (ip, fl_item) - for (addr, lib_tree_item) in fl_entries: + for addr, lib_tree_item in fl_entries: if addr not in short_info_map: debug(0, "Cannot find addr in short_info_map") debug(0, "(Could be a wrong combination of pickle and zip file?)") @@ -429,7 +429,7 @@ def generate_leak_page(self, leak_docs): def generate(self, leaks_docs, libs_leaks_docs): self.leak_overview_table(leaks_docs) - for (lib_name, leaks_docs) in libs_leaks_docs.items(): + for lib_name, leaks_docs in libs_leaks_docs.items(): with self.doc.create(Section(f"Binary: {lib_name}")): self.leak_overview_table(leaks_docs) From f0c6eaeb0ff8de0b83f1dd1808d4f13a68b31049 Mon Sep 17 00:00:00 2001 From: Alexander Wagner Date: Thu, 2 Mar 2023 11:39:51 +0100 Subject: [PATCH 2/4] Make flake8 happy --- analysis/datastub/leaks.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/analysis/datastub/leaks.py b/analysis/datastub/leaks.py index 7202e8e2..939470d8 100644 --- a/analysis/datastub/leaks.py +++ b/analysis/datastub/leaks.py @@ -492,12 +492,12 @@ def is_specific_leak(self): def max_leak(self): max_leak = None if self.is_generic_leak(): - max_leak_ns = max(self.nsleak, key=lambda l: l.normalized()) + max_leak_ns = max(self.nsleak, key=lambda leak: leak.normalized()) # Remove M_pos, as it does not work properly # normalized = max(normalized, max(self.nsleak, key=lambda l: 0 if l.nstype == NSPType.Type3 else l.normalized()).normalized()) max_leak = max_leak_ns if self.is_specific_leak(): - max_leak_sp = max(self.spleak, key=lambda l: l.normalized()) + max_leak_sp = max(self.spleak, key=lambda leak: leak.normalized()) # Remove M_pos, as it does not work properly # normalized = max(normalized, max(self.spleak, key=lambda l: 0 if l.sptype == NSPType.Type3 else l.normalized()).normalized()) max_leak = max_leak_sp if max_leak_sp.normalized() > max_leak.normalized() else max_leak From 9202df427aa0d8d935fe5aa24d697ad665a6dbe2 Mon Sep 17 00:00:00 2001 From: Alexander Wagner Date: Mon, 16 May 2022 18:46:37 +0200 Subject: [PATCH 3/4] GHA: Add clang-format stage --- .github/workflows/lint.yml | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index 7fbfeaa3..285c88d2 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -2,7 +2,7 @@ name: lint on: pull_request: - branches: [ master ] + branches: [ "**" ] push: branches: [ master ] @@ -30,3 +30,11 @@ jobs: - run: | black --version black --check --diff . + clang-format: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - run: sudo apt-get install clang-format + - run: | + clang-format -style="{IndentWidth: 4}" --dry-run --Werror -i *.cpp *.H + working-directory: pintool From 9b0dc38988a42ee02fd7fb57a0ee3660796b4e4d Mon Sep 17 00:00:00 2001 From: Alexander Wagner Date: Thu, 2 Mar 2023 11:38:43 +0100 Subject: [PATCH 4/4] Make clang-format happy --- pintool/addrtrace.cpp | 2355 +++++++++++++++++++++-------------------- 1 file changed, 1230 insertions(+), 1125 deletions(-) diff --git a/pintool/addrtrace.cpp b/pintool/addrtrace.cpp index ece02e81..8ce6922f 100644 --- a/pintool/addrtrace.cpp +++ b/pintool/addrtrace.cpp @@ -25,23 +25,22 @@ /***********************************************************************/ -#include -#include -#include +#include "pin.H" +#include #include +#include +#include +#include #include #include -#include -#include -#include #include #include -#include -#include +#include #include +#include +#include #include -#include -#include "pin.H" +#include /** * Pin 3.11 Documentation: @@ -49,69 +48,77 @@ */ // Pin above 3.7.97720 deprecates some functions -#if (PIN_PRODUCT_VERSION_MAJOR > 3) || \ - (PIN_PRODUCT_VERSION_MAJOR == 3 && PIN_PRODUCT_VERSION_MINOR > 7) || \ - (PIN_PRODUCT_VERSION_MAJOR == 3 && PIN_PRODUCT_VERSION_MINOR == 7 && PIN_BUILD_NUMBER > 97720) - #define INS_IS_INDIRECT INS_IsIndirectControlFlow - #define INS_HAS_TAKEN_BRANCH INS_IsValidForIpointTakenBranch - #define INS_HAS_IPOINT_AFTER INS_IsValidForIpointAfter +#if (PIN_PRODUCT_VERSION_MAJOR > 3) || \ + (PIN_PRODUCT_VERSION_MAJOR == 3 && PIN_PRODUCT_VERSION_MINOR > 7) || \ + (PIN_PRODUCT_VERSION_MAJOR == 3 && PIN_PRODUCT_VERSION_MINOR == 7 && \ + PIN_BUILD_NUMBER > 97720) +#define INS_IS_INDIRECT INS_IsIndirectControlFlow +#define INS_HAS_TAKEN_BRANCH INS_IsValidForIpointTakenBranch +#define INS_HAS_IPOINT_AFTER INS_IsValidForIpointAfter #else - #define INS_IS_INDIRECT INS_IsIndirectBranchOrCall - #define INS_HAS_TAKEN_BRANCH INS_IsBranchOrCall - #define INS_HAS_IPOINT_AFTER INS_HasFallThrough +#define INS_IS_INDIRECT INS_IsIndirectBranchOrCall +#define INS_HAS_TAKEN_BRANCH INS_IsBranchOrCall +#define INS_HAS_IPOINT_AFTER INS_HasFallThrough #endif using namespace std; /***********************************************************************/ -VOID RecordFunctionEntry(THREADID threadid, ADDRINT bbl, ADDRINT bp, BOOL indirect, ADDRINT target, bool report_as_cfleak); -VOID RecordFunctionExit(THREADID threadid, ADDRINT bbl, ADDRINT bp, const CONTEXT* ctxt, bool report_as_cfleak); +VOID RecordFunctionEntry(THREADID threadid, ADDRINT bbl, ADDRINT bp, + BOOL indirect, ADDRINT target, bool report_as_cfleak); +VOID RecordFunctionExit(THREADID threadid, ADDRINT bbl, ADDRINT bp, + const CONTEXT *ctxt, bool report_as_cfleak); /***********************************************************************/ -KNOB KnobRawFile(KNOB_MODE_WRITEONCE, "pintool", - "raw", "", "Raw output file."); +KNOB KnobRawFile(KNOB_MODE_WRITEONCE, "pintool", "raw", "", + "Raw output file."); -KNOB KnobFunc(KNOB_MODE_WRITEONCE, "pintool", - "func", "0", "Trace function calls and returns."); +KNOB KnobFunc(KNOB_MODE_WRITEONCE, "pintool", "func", "0", + "Trace function calls and returns."); -KNOB KnobBbl(KNOB_MODE_WRITEONCE, "pintool", - "bbl", "0", "Trace basic blocks."); +KNOB KnobBbl(KNOB_MODE_WRITEONCE, "pintool", "bbl", "0", + "Trace basic blocks."); -KNOB KnobMem(KNOB_MODE_WRITEONCE, "pintool", - "mem", "0", "Trace data memory accesses."); +KNOB KnobMem(KNOB_MODE_WRITEONCE, "pintool", "mem", "0", + "Trace data memory accesses."); -KNOB KnobTrackHeap(KNOB_MODE_WRITEONCE, "pintool", - "heap", "0", "Track heap usage (malloc, free)."); +KNOB KnobTrackHeap(KNOB_MODE_WRITEONCE, "pintool", "heap", "0", + "Track heap usage (malloc, free)."); -KNOB KnobSyms(KNOB_MODE_WRITEONCE, "pintool", - "syms", "", "Output file for image information."); +KNOB KnobSyms(KNOB_MODE_WRITEONCE, "pintool", "syms", "", + "Output file for image information."); -KNOB KnobVDSO(KNOB_MODE_WRITEONCE, "pintool", - "vdso", "vdso.so", "Output file for the vdso shared library."); +KNOB KnobVDSO(KNOB_MODE_WRITEONCE, "pintool", "vdso", "vdso.so", + "Output file for the vdso shared library."); -KNOB KnobLeaks(KNOB_MODE_WRITEONCE, "pintool", - "leaks", "0", "Enable fast recording of leaks, provided via leakin."); +KNOB KnobLeaks(KNOB_MODE_WRITEONCE, "pintool", "leaks", "0", + "Enable fast recording of leaks, provided via leakin."); -KNOB KnobLeakIn(KNOB_MODE_WRITEONCE, "pintool", - "leakin", "", "Binary input file containing all leaks to trace." - "If empty, all selected instructions are traced. " - "In any case specify -func, -bbl, -mem -heap accordingly!" - "This means that instructions in the -bin file are only traced," - "if also the corresponding flag (e.g. -mem, -bbl) is set"); +KNOB + KnobLeakIn(KNOB_MODE_WRITEONCE, "pintool", "leakin", "", + "Binary input file containing all leaks to trace." + "If empty, all selected instructions are traced. " + "In any case specify -func, -bbl, -mem -heap accordingly!" + "This means that instructions in the -bin file are only traced," + "if also the corresponding flag (e.g. -mem, -bbl) is set"); -KNOB KnobLeakOut(KNOB_MODE_WRITEONCE, "pintool", - "leakout", "", "Hierarchical output file of all leaks. Only useful with -bin option."); +KNOB KnobLeakOut( + KNOB_MODE_WRITEONCE, "pintool", "leakout", "", + "Hierarchical output file of all leaks. Only useful with -bin option."); -KNOB KnobCallstack(KNOB_MODE_WRITEONCE, "pintool", - "cs", "0", "Take callstack into account and trace leaks only in the correct calling context. Only useful with -bin option."); +KNOB + KnobCallstack(KNOB_MODE_WRITEONCE, "pintool", "cs", "0", + "Take callstack into account and trace leaks only in the " + "correct calling context. Only useful with -bin option."); -KNOB KnobMain(KNOB_MODE_WRITEONCE, "pintool", - "main", "main", "Main method to start tracing. Defaults to 'main'. Provide ALL to trace from the beginning."); +KNOB KnobMain(KNOB_MODE_WRITEONCE, "pintool", "main", "main", + "Main method to start tracing. Defaults to 'main'. " + "Provide ALL to trace from the beginning."); -KNOB KnobDebug(KNOB_MODE_WRITEONCE, "pintool", - "debug", "0", "Enable debugging output."); +KNOB KnobDebug(KNOB_MODE_WRITEONCE, "pintool", "debug", "0", + "Enable debugging output."); /***********************************************************************/ /** Recording */ @@ -123,7 +130,7 @@ KNOB KnobDebug(KNOB_MODE_WRITEONCE, "pintool", #define REALLOC "realloc" #define CALLOC "calloc" #define FREE "free" -#define DEBUG(x) if(KnobDebug.Value() >= x) +#define DEBUG(x) if (KnobDebug.Value() >= x) int alloc_instrumented = 0; @@ -136,48 +143,46 @@ bool use_callstack = false; * Traces are stored in a binary format, containing a sequence of * entry_t entries. */ -typedef struct __attribute__((packed)) -{ - uint8_t type; /* holds values of entry_type_t */ - uint64_t ip; /* instruction pointer */ - uint64_t data; /* additional data, depending on type */ -} -entry_t; +typedef struct __attribute__((packed)) { + uint8_t type; /* holds values of entry_type_t */ + uint64_t ip; /* instruction pointer */ + uint64_t data; /* additional data, depending on type */ +} entry_t; /** * Entry types. */ enum entry_type_t { - /* Dummy types */ - A = 0, - B = 1, - C = 2, - D = 3, - - MASK_NONE = 0, - /* Instructions doing memory reads/writes */ - READ = MASK_NONE | A, - WRITE = MASK_NONE | B, - - MASK_BRANCH = 4, - /* Branching instructions */ - BRANCH = MASK_BRANCH | A, - FUNC_ENTRY = MASK_BRANCH | B, - FUNC_EXIT = MASK_BRANCH | C, - FUNC_BBL = MASK_BRANCH | D, - - MASK_HEAP = 8, - /* Instructions doing memory reads/writes on heap objects */ - HREAD = MASK_HEAP | READ, - HWRITE = MASK_HEAP | WRITE, - /* Heap alloc/free calls */ - HALLOC = MASK_HEAP | C, - HFREE = MASK_HEAP | D, - - MASK_LEAK = 16, - /* Dataleaks and Controlflow leaks, used for fast recording */ - DLEAK = MASK_LEAK | A, - CFLEAK = MASK_LEAK | B, + /* Dummy types */ + A = 0, + B = 1, + C = 2, + D = 3, + + MASK_NONE = 0, + /* Instructions doing memory reads/writes */ + READ = MASK_NONE | A, + WRITE = MASK_NONE | B, + + MASK_BRANCH = 4, + /* Branching instructions */ + BRANCH = MASK_BRANCH | A, + FUNC_ENTRY = MASK_BRANCH | B, + FUNC_EXIT = MASK_BRANCH | C, + FUNC_BBL = MASK_BRANCH | D, + + MASK_HEAP = 8, + /* Instructions doing memory reads/writes on heap objects */ + HREAD = MASK_HEAP | READ, + HWRITE = MASK_HEAP | WRITE, + /* Heap alloc/free calls */ + HALLOC = MASK_HEAP | C, + HFREE = MASK_HEAP | D, + + MASK_LEAK = 16, + /* Dataleaks and Controlflow leaks, used for fast recording */ + DLEAK = MASK_LEAK | A, + CFLEAK = MASK_LEAK | B, }; std::vector trace; /* Contains all traced instructions */ @@ -188,14 +193,14 @@ ofstream vdsofile; /* Holds vdso shared library */ /* Heap tracking */ typedef struct { - uint32_t id; - size_t size; - uint64_t base; - bool used; + uint32_t id; + size_t size; + uint64_t base; + bool used; } memobj_t; uint32_t nextheapid = 1; -memobj_t* heapcache; +memobj_t *heapcache; typedef std::vector HEAPVEC; HEAPVEC heap; @@ -203,24 +208,25 @@ HEAPVEC heap; /* Multithreading */ /* Global lock to protect trace buffer */ -//PIN_MUTEX lock; +// PIN_MUTEX lock; typedef struct { - ADDRINT size; + ADDRINT size; } alloc_state_t; typedef struct { - ADDRINT old; - ADDRINT size; + ADDRINT old; + ADDRINT size; } realloc_state_t; typedef struct { - /* allocation routines sometimes call themselves in a nested way during initialization */ - std::vector malloc_state; - std::vector calloc_state; - std::vector realloc_state; - ADDRINT RetIP; - int newbbl; + /* allocation routines sometimes call themselves in a nested way during + * initialization */ + std::vector malloc_state; + std::vector calloc_state; + std::vector realloc_state; + ADDRINT RetIP; + int newbbl; } thread_state_t; std::vector thread_state; @@ -267,42 +273,43 @@ std::vector thread_state; class DataLeak { private: std::vector data; /* Holds evidences */ - uint64_t ip; /* The leaking instruction */ + uint64_t ip; /* The leaking instruction */ public: - DataLeak(uint64_t ip = 0) : ip(ip) { - } + DataLeak(uint64_t ip = 0) : ip(ip) {} /** * Add evidence * @param d The evidence to add */ void append(uint64_t d) { - ASSERT(ip, "[pintool] Error: IP not set"); - DEBUG(1) printf("[pintool] DLEAK@%" PRIx64 ": %" PRIx64 " appended\n", ip, d); - data.push_back(d); + ASSERT(ip, "[pintool] Error: IP not set"); + DEBUG(1) + printf("[pintool] DLEAK@%" PRIx64 ": %" PRIx64 " appended\n", ip, d); + data.push_back(d); } void print() { - for (std::vector::iterator it = data.begin(); it != data.end(); it++) { - printf(" %" PRIx64 " ", *it); - } - printf("\n"); + for (std::vector::iterator it = data.begin(); + it != data.end(); it++) { + printf(" %" PRIx64 " ", *it); + } + printf("\n"); } /** * Export evidence to binary format * @param f The file to export to */ - void doexport(FILE* f) { - uint8_t type = DLEAK; - uint64_t len = data.size(); - uint8_t res = 0; - res += fwrite(&type, sizeof(type), 1, f) != 1; - res += fwrite(&ip, sizeof(ip), 1, f) != 1; - res += fwrite(&len, sizeof(len), 1, f) != 1; - res += fwrite(&data[0], sizeof(uint64_t), len, f) != len; - ASSERT(!res, "[pintool] Error: Unable to write file"); + void doexport(FILE *f) { + uint8_t type = DLEAK; + uint64_t len = data.size(); + uint8_t res = 0; + res += fwrite(&type, sizeof(type), 1, f) != 1; + res += fwrite(&ip, sizeof(ip), 1, f) != 1; + res += fwrite(&len, sizeof(len), 1, f) != 1; + res += fwrite(&data[0], sizeof(uint64_t), len, f) != len; + ASSERT(!res, "[pintool] Error: Unable to write file"); } }; @@ -311,44 +318,45 @@ class DataLeak { */ class CFLeak { private: - std::vector targets; /* Holds evidences */ + std::vector targets; /* Holds evidences */ std::vector mergepoints; /* unused */ - uint64_t bp; /* The leaking instruction */ + uint64_t bp; /* The leaking instruction */ public: - CFLeak(uint64_t bp = 0) : bp(bp) { - } + CFLeak(uint64_t bp = 0) : bp(bp) {} /** * Add evidence * @param ip The evidence to add */ void append(uint64_t ip) { - ASSERT(bp, "[pintool] Error: BP not set"); - DEBUG(1) printf("[pintool] CFLEAK@%" PRIx64 ": %" PRIx64 " appended\n", bp, ip); - targets.push_back(ip); + ASSERT(bp, "[pintool] Error: BP not set"); + DEBUG(1) + printf("[pintool] CFLEAK@%" PRIx64 ": %" PRIx64 " appended\n", bp, ip); + targets.push_back(ip); } void print() { - for (std::vector::iterator it = targets.begin(); it != targets.end(); it++) { - printf(" %" PRIx64 " ", *it); - } - printf("\n"); + for (std::vector::iterator it = targets.begin(); + it != targets.end(); it++) { + printf(" %" PRIx64 " ", *it); + } + printf("\n"); } /** * Export evidence to binary format * @param f The file to export to */ - void doexport(FILE* f) { - uint8_t type = CFLEAK; - uint64_t len = targets.size(); - uint8_t res = 0; - res += fwrite(&type, sizeof(type), 1, f) != 1; - res += fwrite(&bp, sizeof(bp), 1, f) != 1; - res += fwrite(&len, sizeof(len), 1, f) != 1; - res += fwrite(&targets[0], sizeof(uint64_t), len, f) != len; - ASSERT(!res, "[pintool] Error: Unable to write file"); + void doexport(FILE *f) { + uint8_t type = CFLEAK; + uint64_t len = targets.size(); + uint8_t res = 0; + res += fwrite(&type, sizeof(type), 1, f) != 1; + res += fwrite(&bp, sizeof(bp), 1, f) != 1; + res += fwrite(&len, sizeof(len), 1, f) != 1; + res += fwrite(&targets[0], sizeof(uint64_t), len, f) != len; + ASSERT(!res, "[pintool] Error: Unable to write file"); } }; @@ -365,19 +373,19 @@ class Context { cfleaks_t cfleaks; public: - Context() { - } + Context() {} /** * Add a new dataleak to trace during execution * @param ip The instruction to trace */ virtual void dleak_create(uint64_t ip) { - if (dleaks.find(ip) == dleaks.end()) { - dleaks.insert(std::pair(ip, DataLeak(ip))); - } else { - DEBUG(1) printf("[pintool] Warning: DLEAK: %" PRIx64 " not created\n", ip); - } + if (dleaks.find(ip) == dleaks.end()) { + dleaks.insert(std::pair(ip, DataLeak(ip))); + } else { + DEBUG(1) + printf("[pintool] Warning: DLEAK: %" PRIx64 " not created\n", ip); + } } /** @@ -386,12 +394,13 @@ class Context { * @param mp The merge point (unused) * @param len The length of the branch (branch point-> merge point) (unused) */ - virtual void cfleak_create(uint64_t ip, uint64_t* mp, uint8_t len) { - if (cfleaks.find(ip) == cfleaks.end()) { - cfleaks.insert(std::pair(ip, CFLeak(ip))); - } else { - DEBUG(1) printf("[pintool] Warning: CFLEAK: %" PRIx64 " not created\n", ip); - } + virtual void cfleak_create(uint64_t ip, uint64_t *mp, uint8_t len) { + if (cfleaks.find(ip) == cfleaks.end()) { + cfleaks.insert(std::pair(ip, CFLeak(ip))); + } else { + DEBUG(1) + printf("[pintool] Warning: CFLEAK: %" PRIx64 " not created\n", ip); + } } /** @@ -401,11 +410,12 @@ class Context { * We do not (need to) distinguish between read and write here. */ virtual void dleak_append(uint64_t ip, uint64_t data) { - if (dleaks.find(ip) == dleaks.end()) { - DEBUG(1) printf("[pintool] Warning: DLEAK: %" PRIx64 " not appended\n", ip); - } else { - dleaks[ip].append(data); - } + if (dleaks.find(ip) == dleaks.end()) { + DEBUG(1) + printf("[pintool] Warning: DLEAK: %" PRIx64 " not appended\n", ip); + } else { + dleaks[ip].append(data); + } } /** @@ -414,106 +424,120 @@ class Context { * @param target The taken branch target (the evidence) */ virtual void cfleak_append(uint64_t bbl, uint64_t target) { - if (cfleaks.find(bbl) == cfleaks.end()) { - DEBUG(1) printf("[pintool] Warning: CFLEAK: %" PRIx64 " not appended\n", bbl); - } else { - cfleaks[bbl].append(target); - } + if (cfleaks.find(bbl) == cfleaks.end()) { + DEBUG(1) + printf("[pintool] Warning: CFLEAK: %" PRIx64 " not appended\n", + bbl); + } else { + cfleaks[bbl].append(target); + } } virtual void print() { - for (dleaks_t::iterator it = dleaks.begin(); it != dleaks.end(); it++) { - printf("[pintool] DLEAK %" PRIx64 ": ", it->first); - it->second.print(); - } - for (cfleaks_t::iterator it = cfleaks.begin(); it != cfleaks.end(); it++) { - printf("[pintool] CFLEAK %" PRIx64 ": ", it->first); - it->second.print(); - } + for (dleaks_t::iterator it = dleaks.begin(); it != dleaks.end(); it++) { + printf("[pintool] DLEAK %" PRIx64 ": ", it->first); + it->second.print(); + } + for (cfleaks_t::iterator it = cfleaks.begin(); it != cfleaks.end(); + it++) { + printf("[pintool] CFLEAK %" PRIx64 ": ", it->first); + it->second.print(); + } } /** * Export evidence to binary format * @param f The file to export to */ - virtual void doexport(FILE* f) { - for (dleaks_t::iterator it = dleaks.begin(); it != dleaks.end(); it++) { - it->second.doexport(f); - } - for (cfleaks_t::iterator it = cfleaks.begin(); it != cfleaks.end(); it++) { - it->second.doexport(f); - } + virtual void doexport(FILE *f) { + for (dleaks_t::iterator it = dleaks.begin(); it != dleaks.end(); it++) { + it->second.doexport(f); + } + for (cfleaks_t::iterator it = cfleaks.begin(); it != cfleaks.end(); + it++) { + it->second.doexport(f); + } } }; class CallContext; class CallStack; -typedef std::map children_t; +typedef std::map children_t; /** * Wraps class Context for use in class CallStack */ class CallContext : public Context { - friend class CallStack; + friend class CallStack; + private: uint64_t caller; uint64_t callee; - CallContext* parent; + CallContext *parent; children_t children; int unknown_child_depth; bool used; public: CallContext(uint64_t caller = 0, uint64_t callee = 0) - : Context(), caller(caller), callee(callee), parent(NULL), unknown_child_depth(0), used(false) { - } + : Context(), caller(caller), callee(callee), parent(NULL), + unknown_child_depth(0), used(false) {} virtual void dleak_append(uint64_t ip, uint64_t data) { - if (used == false || unknown_child_depth) { - DEBUG(1) printf("[pintool] Warning: DLEAK %" PRIx64 ": skipping due to %d %d\n", ip, used, unknown_child_depth); - } else { - Context::dleak_append(ip, data); - } + if (used == false || unknown_child_depth) { + DEBUG(1) + printf("[pintool] Warning: DLEAK %" PRIx64 + ": skipping due to %d %d\n", + ip, used, unknown_child_depth); + } else { + Context::dleak_append(ip, data); + } } virtual void cfleak_append(uint64_t bbl, uint64_t target) { - if (used == false || unknown_child_depth) { - DEBUG(1) printf("[pintool] Warning: CFLEAK %" PRIx64 ": skipping due to %d %d\n", bbl, used, unknown_child_depth); - } else { - Context::cfleak_append(bbl, target); - } + if (used == false || unknown_child_depth) { + DEBUG(1) + printf("[pintool] Warning: CFLEAK %" PRIx64 + ": skipping due to %d %d\n", + bbl, used, unknown_child_depth); + } else { + Context::cfleak_append(bbl, target); + } } - virtual void print(Context* currentContext = NULL) { - if (this == currentContext) { - printf("*"); + virtual void print(Context *currentContext = NULL) { + if (this == currentContext) { + printf("*"); + } + printf("%" PRIx64 "-->%" PRIx64 " (%d)(%d)\n", this->caller, + this->callee, this->unknown_child_depth, this->used); + Context::print(); + for (children_t::iterator it = children.begin(); it != children.end(); + it++) { + it->second->print(currentContext); } - printf("%" PRIx64 "-->%" PRIx64 " (%d)(%d)\n", this->caller, this->callee, this->unknown_child_depth, this->used); - Context::print(); - for (children_t::iterator it = children.begin(); it != children.end(); it++) { - it->second->print(currentContext); - } - printf("<\n"); + printf("<\n"); } /** * Export evidence to binary format * @param f The file to export to */ - virtual void doexport(FILE* f) { - uint8_t type = FUNC_ENTRY; - uint8_t res = 0; - res += fwrite(&type, sizeof(type), 1, f) != 1; - res += fwrite(&caller, sizeof(caller), 1, f) != 1; - res += fwrite(&callee, sizeof(callee), 1, f) != 1; - ASSERT(!res, "[pintool] Error: Unable to write file"); - Context::doexport(f); - for (children_t::iterator it = children.begin(); it != children.end(); it++) { - it->second->doexport(f); - } - type = FUNC_EXIT; - res = fwrite(&type, sizeof(type), 1, f) != 1; - ASSERT(!res, "[pintool] Error: Unable to write file"); + virtual void doexport(FILE *f) { + uint8_t type = FUNC_ENTRY; + uint8_t res = 0; + res += fwrite(&type, sizeof(type), 1, f) != 1; + res += fwrite(&caller, sizeof(caller), 1, f) != 1; + res += fwrite(&callee, sizeof(callee), 1, f) != 1; + ASSERT(!res, "[pintool] Error: Unable to write file"); + Context::doexport(f); + for (children_t::iterator it = children.begin(); it != children.end(); + it++) { + it->second->doexport(f); + } + type = FUNC_EXIT; + res = fwrite(&type, sizeof(type), 1, f) != 1; + ASSERT(!res, "[pintool] Error: Unable to write file"); } }; @@ -522,20 +546,20 @@ class CallContext : public Context { */ class AbstractLeakContainer { protected: - std::set traced_dataleaks; /* List of data leaks which shall be instrumented */ - std::set traced_cfleaks; /* List of control-flow leaks which shall be instrumented */ - std::set erased_dataleaks; /* List of data leaks which are already instrumented */ - std::set erased_cfleaks; /* List of control-flow leaks which are already instrumented */ - Context* currentContext; + std::set + traced_dataleaks; /* List of data leaks which shall be instrumented */ + std::set traced_cfleaks; /* List of control-flow leaks which shall + be instrumented */ + std::set erased_dataleaks; /* List of data leaks which are already + instrumented */ + std::set erased_cfleaks; /* List of control-flow leaks which are + already instrumented */ + Context *currentContext; public: - size_t get_uninstrumented_dleak_size() { - return traced_dataleaks.size(); - } + size_t get_uninstrumented_dleak_size() { return traced_dataleaks.size(); } - size_t get_uninstrumented_cfleak_size() { - return traced_cfleaks.size(); - } + size_t get_uninstrumented_cfleak_size() { return traced_cfleaks.size(); } /** * Checks whether an instruction shall be instrumented and if yes, @@ -544,20 +568,18 @@ class AbstractLeakContainer { * @return a value != 0 if successful */ size_t get_erase_dleak(uint64_t ip) { - size_t er = traced_dataleaks.erase(ip); - if (er) { - erased_dataleaks.insert(ip); - } - return er; + size_t er = traced_dataleaks.erase(ip); + if (er) { + erased_dataleaks.insert(ip); + } + return er; } /** * Returns whether an instruction was previously * instrumented and, thus, erased. */ - bool was_erased_dleak(uint64_t ip) { - return erased_dataleaks.count(ip); - } + bool was_erased_dleak(uint64_t ip) { return erased_dataleaks.count(ip); } /** * Checks whether an instruction shall be instrumented and if yes, @@ -566,34 +588,34 @@ class AbstractLeakContainer { * @return a value != 0 if successful */ size_t get_erase_cfleak(uint64_t ip) { - size_t er = traced_cfleaks.erase(ip); - if (er) { - erased_cfleaks.insert(ip); - } - return er; + size_t er = traced_cfleaks.erase(ip); + if (er) { + erased_cfleaks.insert(ip); + } + return er; } /** * Returns whether an instruction was previously * instrumented and, thus, erased. */ - bool was_erased_cfleak(uint64_t ip) { - return erased_cfleaks.count(ip); - } + bool was_erased_cfleak(uint64_t ip) { return erased_cfleaks.count(ip); } void print_uninstrumented_leaks() { - if (traced_dataleaks.size() > 0) { - printf("[pintool] Uninstrumented DLEAKS:\n"); - for (std::set::iterator it = traced_dataleaks.begin(); it != traced_dataleaks.end(); it++) { - printf(" %" PRIx64 "\n", *it); + if (traced_dataleaks.size() > 0) { + printf("[pintool] Uninstrumented DLEAKS:\n"); + for (std::set::iterator it = traced_dataleaks.begin(); + it != traced_dataleaks.end(); it++) { + printf(" %" PRIx64 "\n", *it); + } } - } - if (traced_cfleaks.size() > 0) { - printf("[pintool] Uninstrumented CFLEAKS:\n"); - for (std::set::iterator it = traced_cfleaks.begin(); it != traced_cfleaks.end(); it++) { - printf(" %" PRIx64 "\n", *it); + if (traced_cfleaks.size() > 0) { + printf("[pintool] Uninstrumented CFLEAKS:\n"); + for (std::set::iterator it = traced_cfleaks.begin(); + it != traced_cfleaks.end(); it++) { + printf(" %" PRIx64 "\n", *it); + } } - } } /** @@ -631,9 +653,9 @@ class AbstractLeakContainer { * @param ip The instruction to trace */ virtual void dleak_create(uint64_t ip) { - ASSERT(currentContext, "[pintool] Error: Context not initialized"); - traced_dataleaks.insert(ip); - currentContext->dleak_create(ip); + ASSERT(currentContext, "[pintool] Error: Context not initialized"); + traced_dataleaks.insert(ip); + currentContext->dleak_create(ip); } /** @@ -642,10 +664,10 @@ class AbstractLeakContainer { * @param mp The merge point (unused) * @param len The length of the branch (branch point-> merge point) (unused) */ - virtual void cfleak_create(uint64_t bp, uint64_t* mp, uint8_t len) { - ASSERT(currentContext, "[pintool] Error: Context not initialized"); - traced_cfleaks.insert(bp); - currentContext->cfleak_create(bp, mp, len); + virtual void cfleak_create(uint64_t bp, uint64_t *mp, uint8_t len) { + ASSERT(currentContext, "[pintool] Error: Context not initialized"); + traced_cfleaks.insert(bp); + currentContext->cfleak_create(bp, mp, len); } /** @@ -655,9 +677,9 @@ class AbstractLeakContainer { * We do not (need to) distinguish between read and write here. */ virtual void dleak_consume(uint64_t ip, uint64_t data) { - ASSERT(currentContext, "[pintool] Error: Context not initialized"); - DEBUG(1) printf("[pintool] Consuming DLEAK %" PRIx64 "\n", ip); - currentContext->dleak_append(ip, data); + ASSERT(currentContext, "[pintool] Error: Context not initialized"); + DEBUG(1) printf("[pintool] Consuming DLEAK %" PRIx64 "\n", ip); + currentContext->dleak_append(ip, data); } /** @@ -666,9 +688,9 @@ class AbstractLeakContainer { * @param target The taken branch target (the evidence) */ virtual void cfleak_consume(uint64_t bbl, uint64_t target) { - ASSERT(currentContext, "[pintool] Error: Context not initialized"); - DEBUG(1) printf("[pintool] Consuming CFLEAK %" PRIx64 "\n", bbl); - currentContext->cfleak_append(bbl, target); + ASSERT(currentContext, "[pintool] Error: Context not initialized"); + DEBUG(1) printf("[pintool] Consuming CFLEAK %" PRIx64 "\n", bbl); + currentContext->cfleak_append(bbl, target); } virtual void print_all() = 0; @@ -677,9 +699,9 @@ class AbstractLeakContainer { * Export evidence to binary format * @param f The file to export to */ - virtual void doexport(FILE* f) { - ASSERT(currentContext, "[pintool] Error: Context not initialized"); - currentContext->doexport(f); + virtual void doexport(FILE *f) { + ASSERT(currentContext, "[pintool] Error: Context not initialized"); + currentContext->doexport(f); } }; @@ -691,25 +713,17 @@ class AbstractLeakContainer { class Flat : public AbstractLeakContainer { public: - Flat() { - currentContext = new Context(); - } + Flat() { currentContext = new Context(); } - virtual void call_create(uint64_t caller, uint64_t callee) { - } + virtual void call_create(uint64_t caller, uint64_t callee) {} - virtual void ret_create(uint64_t ip) { - } + virtual void ret_create(uint64_t ip) {} - virtual void call_consume(uint64_t caller, uint64_t callee) { - } + virtual void call_consume(uint64_t caller, uint64_t callee) {} - virtual void ret_consume(uint64_t ip) { - } + virtual void ret_consume(uint64_t ip) {} - virtual void print_all() { - currentContext->print(); - } + virtual void print_all() { currentContext->print(); } }; /** @@ -730,94 +744,99 @@ class Flat : public AbstractLeakContainer { class CallStack : public AbstractLeakContainer { protected: - /* Generate a hash of caller and callee by swapping callee's DWORDS and XORING both. */ + /* Generate a hash of caller and callee by swapping callee's DWORDS and + * XORING both. */ uint64_t get_call_id(uint64_t caller, uint64_t callee) { - uint64_t id = caller; - uint32_t lower = callee & 0x00000000FFFFFFFFULL; - uint32_t upper = callee >> 32ULL; - id ^= upper | ((uint64_t)lower << 32ULL); - return id; + uint64_t id = caller; + uint32_t lower = callee & 0x00000000FFFFFFFFULL; + uint32_t upper = callee >> 32ULL; + id ^= upper | ((uint64_t)lower << 32ULL); + return id; } + public: - CallStack() { - } + CallStack() {} void call_create(uint64_t caller, uint64_t callee) { - ASSERT(use_callstack, "[pintool] Error: Wrong usage of callstack"); - DEBUG(2) printf("[pintool] Building callstack %" PRIx64 " --> %" PRIx64 "\n", caller, callee); - uint64_t id = get_call_id(caller, callee); - if (currentContext == NULL) { - currentContext = new CallContext(caller, callee); - } else { - CallContext* top = static_cast(currentContext); - if (top->children.find(id) == top->children.end()) { - CallContext* newcs = new CallContext(caller, callee); - newcs->used = true; - newcs->parent = top; - top->children[id] = newcs; + ASSERT(use_callstack, "[pintool] Error: Wrong usage of callstack"); + DEBUG(2) + printf("[pintool] Building callstack %" PRIx64 " --> %" PRIx64 "\n", + caller, callee); + uint64_t id = get_call_id(caller, callee); + if (currentContext == NULL) { + currentContext = new CallContext(caller, callee); + } else { + CallContext *top = static_cast(currentContext); + if (top->children.find(id) == top->children.end()) { + CallContext *newcs = new CallContext(caller, callee); + newcs->used = true; + newcs->parent = top; + top->children[id] = newcs; + } + CallContext *move = top->children[id]; + currentContext = top = move; } - CallContext* move = top->children[id]; - currentContext = top = move; - } } void call_consume(uint64_t caller, uint64_t callee) { - ASSERT(use_callstack, "[pintool] Error: Wrong usage of callstack"); - ASSERT(currentContext, "[pintool] Error: Callstack is not initialized"); - DEBUG(3) print_all(); - DEBUG(2) printf("[pintool] Calling %" PRIx64 " --> %" PRIx64 "\n", caller, callee); - uint64_t id = get_call_id(caller, callee); - CallContext* top = static_cast(currentContext); - if (!top->used) { - if (top->caller == caller && top->callee == callee) { - DEBUG(2) printf("[pintool] Entered first leaking callstack\n"); - top->used = true; - } - } else { - if (top->unknown_child_depth || top->children.find(id) == top->children.end()) { - top->unknown_child_depth++; + ASSERT(use_callstack, "[pintool] Error: Wrong usage of callstack"); + ASSERT(currentContext, "[pintool] Error: Callstack is not initialized"); + DEBUG(3) print_all(); + DEBUG(2) + printf("[pintool] Calling %" PRIx64 " --> %" PRIx64 "\n", caller, + callee); + uint64_t id = get_call_id(caller, callee); + CallContext *top = static_cast(currentContext); + if (!top->used) { + if (top->caller == caller && top->callee == callee) { + DEBUG(2) printf("[pintool] Entered first leaking callstack\n"); + top->used = true; + } } else { - CallContext* move = top->children[id]; - currentContext = top = move; + if (top->unknown_child_depth || + top->children.find(id) == top->children.end()) { + top->unknown_child_depth++; + } else { + CallContext *move = top->children[id]; + currentContext = top = move; + } } - } - DEBUG(3) print_all(); + DEBUG(3) print_all(); } void ret_consume(uint64_t ip) { - ASSERT(use_callstack, "[pintool] Error: Wrong usage of callstack"); - ASSERT(currentContext, "[pintool] Error: Callstack is not initialized"); - DEBUG(2) printf("[pintool] Returning %" PRIx64 "\n", ip); - CallContext* top = static_cast(currentContext); - if (top->unknown_child_depth) { - top->unknown_child_depth--; - } else { - if (top->parent) { - ASSERT(top->parent, "[pintool] Error: Callstack parent is empty"); - currentContext = top = top->parent; + ASSERT(use_callstack, "[pintool] Error: Wrong usage of callstack"); + ASSERT(currentContext, "[pintool] Error: Callstack is not initialized"); + DEBUG(2) printf("[pintool] Returning %" PRIx64 "\n", ip); + CallContext *top = static_cast(currentContext); + if (top->unknown_child_depth) { + top->unknown_child_depth--; } else { - DEBUG(2) printf("[pintool] Warning: Ignoring return\n"); + if (top->parent) { + ASSERT(top->parent, + "[pintool] Error: Callstack parent is empty"); + currentContext = top = top->parent; + } else { + DEBUG(2) printf("[pintool] Warning: Ignoring return\n"); + } } - } } - void ret_create(uint64_t ip) { - ret_consume(ip); - } + void ret_create(uint64_t ip) { ret_consume(ip); } bool empty() { - ASSERT(use_callstack, "[pintool] Error: Wrong usage of callstack"); - CallContext* top = static_cast(currentContext); - return top == NULL || top->used == false; + ASSERT(use_callstack, "[pintool] Error: Wrong usage of callstack"); + CallContext *top = static_cast(currentContext); + return top == NULL || top->used == false; } - CallContext* get_begin() { - ASSERT(use_callstack, "[pintool] Error: Wrong usage of callstack"); - CallContext* c = static_cast(currentContext); - while(c && c->parent) { - c = c->parent; - } - return c; + CallContext *get_begin() { + ASSERT(use_callstack, "[pintool] Error: Wrong usage of callstack"); + CallContext *c = static_cast(currentContext); + while (c && c->parent) { + c = c->parent; + } + return c; } /** @@ -825,41 +844,38 @@ class CallStack : public AbstractLeakContainer { * initial context */ void rewind() { - ASSERT(use_callstack, "[pintool] Error: Wrong usage of callstack"); - CallContext* top = get_begin(); - ASSERT(top, "[pintool] Error: Leaks not initialized"); - top->used = false; - currentContext = top; + ASSERT(use_callstack, "[pintool] Error: Wrong usage of callstack"); + CallContext *top = get_begin(); + ASSERT(top, "[pintool] Error: Leaks not initialized"); + top->used = false; + currentContext = top; } void print_all() { - ASSERT(use_callstack, "[pintool] Error: Wrong usage of callstack"); - CallContext* top = get_begin(); - if (top) { - printf("[pintool] Callstack:\n"); - top->print(currentContext); - } + ASSERT(use_callstack, "[pintool] Error: Wrong usage of callstack"); + CallContext *top = get_begin(); + if (top) { + printf("[pintool] Callstack:\n"); + top->print(currentContext); + } } }; -AbstractLeakContainer* leaks = NULL; +AbstractLeakContainer *leaks = NULL; /***********************************************************************/ /** Thread/Main recording and initialization */ /***********************************************************************/ void init() { - //ASSERT(PIN_MutexInit(&lock), "[pintool] Error: Mutex init failed"); + // ASSERT(PIN_MutexInit(&lock), "[pintool] Error: Mutex init failed"); } /** * Add an entry to the trace * This function is not thread-safe. Lock first. */ -VOID record_entry(entry_t entry) -{ - trace.push_back(entry); -} +VOID record_entry(entry_t entry) { trace.push_back(entry); } /** * Start recording. @@ -867,9 +883,9 @@ VOID record_entry(entry_t entry) * @param ins The first recorded instruction */ VOID RecordMainBegin(THREADID threadid, ADDRINT ins) { - Record = true; - DEBUG(1) printf("[pintool] Start main() %lx\n", (long unsigned int)ins); - RecordFunctionEntry(threadid, 0, 0, false, ins, false); + Record = true; + DEBUG(1) printf("[pintool] Start main() %lx\n", (long unsigned int)ins); + RecordFunctionEntry(threadid, 0, 0, false, ins, false); } /** @@ -878,9 +894,9 @@ VOID RecordMainBegin(THREADID threadid, ADDRINT ins) { * @param ins The last recorded instruction */ VOID RecordMainEnd(THREADID threadid, ADDRINT ins) { - Record = false; - DEBUG(1) printf("[pintool] End main()\n"); - RecordFunctionExit(threadid, ins, ins, NULL, false); + Record = false; + DEBUG(1) printf("[pintool] End main()\n"); + RecordFunctionExit(threadid, ins, ins, NULL, false); } /** @@ -892,22 +908,23 @@ VOID RecordMainEnd(THREADID threadid, ADDRINT ins) { * @param flags Unused * @param v Unused */ -VOID ThreadStart(THREADID threadid, CONTEXT *ctxt, INT32 flags, VOID *v) -{ - ASSERT(threadid == 0, "[pintool] Error: Multithreading detected but not supported!"); - DEBUG(1) printf("[pintool] Thread begin %d\n",threadid); - //PIN_MutexLock(&lock); +VOID ThreadStart(THREADID threadid, CONTEXT *ctxt, INT32 flags, VOID *v) { + ASSERT(threadid == 0, + "[pintool] Error: Multithreading detected but not supported!"); + DEBUG(1) printf("[pintool] Thread begin %d\n", threadid); + // PIN_MutexLock(&lock); if (thread_state.size() <= threadid) { - thread_state_t newstate; - newstate.RetIP = 0; - newstate.newbbl = 0; - thread_state.push_back(newstate); + thread_state_t newstate; + newstate.RetIP = 0; + newstate.newbbl = 0; + thread_state.push_back(newstate); } else { - thread_state[threadid].RetIP = 0; - thread_state[threadid].newbbl = 0; + thread_state[threadid].RetIP = 0; + thread_state[threadid].newbbl = 0; } - ASSERT(thread_state.size() > threadid, "[pintool] Error: thread_state corrupted"); - //PIN_MutexUnlock(&lock); + ASSERT(thread_state.size() > threadid, + "[pintool] Error: thread_state corrupted"); + // PIN_MutexUnlock(&lock); } /** @@ -917,11 +934,10 @@ VOID ThreadStart(THREADID threadid, CONTEXT *ctxt, INT32 flags, VOID *v) * @param code Unused * @param v Unused */ -VOID ThreadFini(THREADID threadid, const CONTEXT *ctxt, INT32 code, VOID *v) -{ - //PIN_MutexLock(&lock); - DEBUG(1) printf("[pintool] Thread end %d code %d\n",threadid, code); - //PIN_MutexUnlock(&lock); +VOID ThreadFini(THREADID threadid, const CONTEXT *ctxt, INT32 code, VOID *v) { + // PIN_MutexLock(&lock); + DEBUG(1) printf("[pintool] Thread end %d code %d\n", threadid, code); + // PIN_MutexUnlock(&lock); } /***********************************************************************/ @@ -929,46 +945,50 @@ VOID ThreadFini(THREADID threadid, const CONTEXT *ctxt, INT32 code, VOID *v) /***********************************************************************/ void printheap() { - std::cout << "[pintool] Heap:" << std::endl; - for(HEAPVEC::iterator it = heap.begin(); it != heap.end(); ++it) { - std::cout << std::hex << it->id << ":" << it->base << "-" << it->size << " used:" << it->used << std::endl; - } + std::cout << "[pintool] Heap:" << std::endl; + for (HEAPVEC::iterator it = heap.begin(); it != heap.end(); ++it) { + std::cout << std::hex << it->id << ":" << it->base << "-" << it->size + << " used:" << it->used << std::endl; + } } -memobj_t* lookup_heap(uint64_t addr) { - uint64_t paddr = addr; - if (heapcache) { - ASSERT(heapcache->used, "[pintool] Error: Heapcache corrupt"); - if (paddr >= heapcache->base && paddr < heapcache->base + heapcache->size) { - return heapcache; +memobj_t *lookup_heap(uint64_t addr) { + uint64_t paddr = addr; + if (heapcache) { + ASSERT(heapcache->used, "[pintool] Error: Heapcache corrupt"); + if (paddr >= heapcache->base && + paddr < heapcache->base + heapcache->size) { + return heapcache; + } } - } - for(HEAPVEC::reverse_iterator it = heap.rbegin(); it != heap.rend(); ++it) { - if (!it->used) { - continue; - } - if (paddr >= it->base) { - if (paddr < it->base + it->size) { - return heapcache = &(*it); - } else { - break; - } + for (HEAPVEC::reverse_iterator it = heap.rbegin(); it != heap.rend(); + ++it) { + if (!it->used) { + continue; + } + if (paddr >= it->base) { + if (paddr < it->base + it->size) { + return heapcache = &(*it); + } else { + break; + } + } } - } - return NULL; + return NULL; } -VOID test_mem_heap(entry_t* pentry) { - memobj_t* obj = lookup_heap(pentry->data); - if (obj) { - uint64_t pdata = pentry->data; - pdata -= obj->base; - ASSERT((pdata & 0xFFFFFFFF00000000ULL) == 0, "[pintool] Error: Heap object too big"); - pdata |= (uint64_t)obj->id << 32ULL; - pentry->data = pdata; - pentry->type |= MASK_HEAP; - } +VOID test_mem_heap(entry_t *pentry) { + memobj_t *obj = lookup_heap(pentry->data); + if (obj) { + uint64_t pdata = pentry->data; + pdata -= obj->base; + ASSERT((pdata & 0xFFFFFFFF00000000ULL) == 0, + "[pintool] Error: Heap object too big"); + pdata |= (uint64_t)obj->id << 32ULL; + pentry->data = pdata; + pentry->type |= MASK_HEAP; + } } /** @@ -976,11 +996,11 @@ VOID test_mem_heap(entry_t* pentry) { * This function is not thread-safe. Lock first. */ void record_heap_op(memobj_t *obj, ADDRINT addr) { - entry_t entry; - entry.type = obj->used ? HALLOC : HFREE; - entry.ip = (((uint64_t)obj->id << 32ULL) | obj->size); - entry.data = addr; - record_entry(entry); + entry_t entry; + entry.type = obj->used ? HALLOC : HFREE; + entry.ip = (((uint64_t)obj->id << 32ULL) | obj->size); + entry.data = addr; + record_entry(entry); } /** @@ -988,58 +1008,64 @@ void record_heap_op(memobj_t *obj, ADDRINT addr) { * This function is not thread-safe. Lock first. */ void domalloc(ADDRINT addr, ADDRINT size, uint32_t objid) { - heapcache = NULL; - memobj_t obj; - if (objid) { - obj.id = objid; - } else { - obj.id = nextheapid++; - } - - obj.base = addr; - obj.size = size; - obj.used = true; - record_heap_op(&obj, addr); - - DEBUG(2) std::cout << "[pintool] Domalloc " << std::hex << addr << " " << size << std::endl; - /* Keep heap vector sorted */ - HEAPVEC::iterator prev = heap.end(); - HEAPVEC::iterator found = heap.end(); - for(HEAPVEC::iterator it = heap.begin(); it != heap.end(); ++it) { - if (it->used) { - if (it->base >= obj.base) { - /* insert before*/ - if (obj.base + obj.size > it->base) { - DEBUG(2) printheap(); - DEBUG(2) std::cout << "[pintool] Inserting new object" << std::hex << obj.base << "-" << obj.size << std::endl; - ASSERT(false, "[pintool] Error: Corrupted heap A?!"); - } - found = it; - break; - } - } - prev = it; - } - - if (found == heap.end()) { - /* no match found, append to the end */ - heap.push_back(obj); - } else { - if (prev == heap.end()) { - heap.insert(found, obj); - } else if (prev->used) { - /* We cannot reuse prev, insert at 'found' */ - if(prev->used && prev->base + prev->size > obj.base) { - DEBUG(2) printheap(); - DEBUG(2) std::cout << "[pintool] Inserting new object" << std::hex << obj.base << "-" << obj.size << std::endl; - ASSERT(false, "[pintool] Error: Corrupted heap B?!"); + heapcache = NULL; + memobj_t obj; + if (objid) { + obj.id = objid; + } else { + obj.id = nextheapid++; + } + + obj.base = addr; + obj.size = size; + obj.used = true; + record_heap_op(&obj, addr); + + DEBUG(2) + std::cout << "[pintool] Domalloc " << std::hex << addr << " " << size + << std::endl; + /* Keep heap vector sorted */ + HEAPVEC::iterator prev = heap.end(); + HEAPVEC::iterator found = heap.end(); + for (HEAPVEC::iterator it = heap.begin(); it != heap.end(); ++it) { + if (it->used) { + if (it->base >= obj.base) { + /* insert before*/ + if (obj.base + obj.size > it->base) { + DEBUG(2) printheap(); + DEBUG(2) + std::cout << "[pintool] Inserting new object" << std::hex + << obj.base << "-" << obj.size << std::endl; + ASSERT(false, "[pintool] Error: Corrupted heap A?!"); + } + found = it; + break; + } } - heap.insert(found, obj); + prev = it; + } + + if (found == heap.end()) { + /* no match found, append to the end */ + heap.push_back(obj); } else { - /* prev is unused, reuse it */ - *prev = obj; + if (prev == heap.end()) { + heap.insert(found, obj); + } else if (prev->used) { + /* We cannot reuse prev, insert at 'found' */ + if (prev->used && prev->base + prev->size > obj.base) { + DEBUG(2) printheap(); + DEBUG(2) + std::cout << "[pintool] Inserting new object" << std::hex + << obj.base << "-" << obj.size << std::endl; + ASSERT(false, "[pintool] Error: Corrupted heap B?!"); + } + heap.insert(found, obj); + } else { + /* prev is unused, reuse it */ + *prev = obj; + } } - } } /** @@ -1047,24 +1073,24 @@ void domalloc(ADDRINT addr, ADDRINT size, uint32_t objid) { * This function is not thread-safe. Lock first. */ uint32_t dofree(ADDRINT addr) { - heapcache = NULL; - DEBUG(2) std::cout << "[pintool] Dofree " << std::hex << addr << std::endl; - if (!addr) { + heapcache = NULL; + DEBUG(2) std::cout << "[pintool] Dofree " << std::hex << addr << std::endl; + if (!addr) { + return 0; + } + for (HEAPVEC::iterator it = heap.begin(); it != heap.end(); ++it) { + if (!it->used) { + continue; + } + if (it->base == addr) { + it->used = false; + record_heap_op(it, addr); + return it->id; + } + } + std::cout << "[pintool] Warning: Invalid free!" << std::endl; + DEBUG(2) printheap(); return 0; - } - for(HEAPVEC::iterator it = heap.begin(); it != heap.end(); ++it) { - if (!it->used) { - continue; - } - if (it->base == addr) { - it->used = false; - record_heap_op(it, addr); - return it->id; - } - } - std::cout << "[pintool] Warning: Invalid free!" << std::endl; - DEBUG(2) printheap(); - return 0; } /** @@ -1072,17 +1098,22 @@ uint32_t dofree(ADDRINT addr) { * @param threadid The thread * @param size The size parameter passed to malloc */ -VOID RecordMallocBefore(THREADID threadid, VOID* ip, ADDRINT size) { - if (!Record) return; - //PIN_MutexLock(&lock); - if (thread_state[threadid].realloc_state.size() == 0) { - DEBUG(1) std::cout << "[pintool] Malloc called with " << std::hex << size << " at " << ip << std::endl; - alloc_state_t state = { .size = size }; - thread_state[threadid].malloc_state.push_back(state); - } else { - DEBUG(1) std::cout << "[pintool] Malloc ignored due to realloc_pending (size= " << std::hex << size << ") at " << ip << std::endl; - } - //PIN_MutexUnlock(&lock); +VOID RecordMallocBefore(THREADID threadid, VOID *ip, ADDRINT size) { + if (!Record) + return; + // PIN_MutexLock(&lock); + if (thread_state[threadid].realloc_state.size() == 0) { + DEBUG(1) + std::cout << "[pintool] Malloc called with " << std::hex << size + << " at " << ip << std::endl; + alloc_state_t state = {.size = size}; + thread_state[threadid].malloc_state.push_back(state); + } else { + DEBUG(1) + std::cout << "[pintool] Malloc ignored due to realloc_pending (size= " + << std::hex << size << ") at " << ip << std::endl; + } + // PIN_MutexUnlock(&lock); } /** @@ -1090,15 +1121,18 @@ VOID RecordMallocBefore(THREADID threadid, VOID* ip, ADDRINT size) { * @param threadid The thread * @param addr The allocated heap pointer */ -VOID RecordMallocAfter(THREADID threadid, VOID* ip, ADDRINT addr) { - if (!Record) return; - //PIN_MutexLock(&lock); - DEBUG(1) std::cout << "[pintool] Malloc returned " << std::hex << addr << std::endl; - ASSERT(thread_state[threadid].malloc_state.size() > 0, "[pintool] Error: Malloc returned but not called"); - alloc_state_t state = thread_state[threadid].malloc_state.back(); - thread_state[threadid].malloc_state.pop_back(); - domalloc(addr, state.size, 0); - //PIN_MutexUnlock(&lock); +VOID RecordMallocAfter(THREADID threadid, VOID *ip, ADDRINT addr) { + if (!Record) + return; + // PIN_MutexLock(&lock); + DEBUG(1) + std::cout << "[pintool] Malloc returned " << std::hex << addr << std::endl; + ASSERT(thread_state[threadid].malloc_state.size() > 0, + "[pintool] Error: Malloc returned but not called"); + alloc_state_t state = thread_state[threadid].malloc_state.back(); + thread_state[threadid].malloc_state.pop_back(); + domalloc(addr, state.size, 0); + // PIN_MutexUnlock(&lock); } /** @@ -1107,15 +1141,19 @@ VOID RecordMallocAfter(THREADID threadid, VOID* ip, ADDRINT addr) { * @param addr The heap pointer param of realloc * @param size The size parameter passed to realloc */ -VOID RecordReallocBefore(THREADID threadid, VOID* ip, ADDRINT addr, ADDRINT size) { - if (!Record) return; - //PIN_MutexLock(&lock); - DEBUG(1) std::cout << "[pintool] Realloc called with " << std::hex << addr << " " << size << " at " << ip << std::endl; - realloc_state_t state; - state.size = size; - state.old = addr; - thread_state[threadid].realloc_state.push_back(state); - //PIN_MutexUnlock(&lock); +VOID RecordReallocBefore(THREADID threadid, VOID *ip, ADDRINT addr, + ADDRINT size) { + if (!Record) + return; + // PIN_MutexLock(&lock); + DEBUG(1) + std::cout << "[pintool] Realloc called with " << std::hex << addr << " " + << size << " at " << ip << std::endl; + realloc_state_t state; + state.size = size; + state.old = addr; + thread_state[threadid].realloc_state.push_back(state); + // PIN_MutexUnlock(&lock); } /** @@ -1123,20 +1161,24 @@ VOID RecordReallocBefore(THREADID threadid, VOID* ip, ADDRINT addr, ADDRINT size * @param threadid The thread * @param addr The allocated heap pointer */ -VOID RecordReallocAfter(THREADID threadid, VOID* ip, ADDRINT addr) { - if (!Record) return; - //PIN_MutexLock(&lock); - DEBUG(1) std::cout << "[pintool] Realloc returned " << std::hex << addr << " at " << ip << std::endl; - ASSERT(thread_state[threadid].realloc_state.size() > 0, "[pintool] Error: Realloc returned but not called"); - realloc_state_t state = thread_state[threadid].realloc_state.back(); - thread_state[threadid].realloc_state.pop_back(); - - uint32_t objid = 0; - if (state.old) { - objid = dofree(state.old); - } - domalloc(addr, state.size, objid); - //PIN_MutexUnlock(&lock); +VOID RecordReallocAfter(THREADID threadid, VOID *ip, ADDRINT addr) { + if (!Record) + return; + // PIN_MutexLock(&lock); + DEBUG(1) + std::cout << "[pintool] Realloc returned " << std::hex << addr << " at " + << ip << std::endl; + ASSERT(thread_state[threadid].realloc_state.size() > 0, + "[pintool] Error: Realloc returned but not called"); + realloc_state_t state = thread_state[threadid].realloc_state.back(); + thread_state[threadid].realloc_state.pop_back(); + + uint32_t objid = 0; + if (state.old) { + objid = dofree(state.old); + } + domalloc(addr, state.size, objid); + // PIN_MutexUnlock(&lock); } /** @@ -1145,13 +1187,17 @@ VOID RecordReallocAfter(THREADID threadid, VOID* ip, ADDRINT addr) { * @param nelem The number of elements parameter passed to calloc * @param size The size parameter passed to calloc */ -VOID RecordCallocBefore(THREADID threadid, VOID* ip, ADDRINT nelem, ADDRINT size) { - if (!Record) return; - //PIN_MutexLock(&lock); - DEBUG(1) std::cout << "[pintool] Calloc called with " << std::hex << nelem << " " << size << " at " << ip << std::endl; - alloc_state_t state = { .size = size }; - thread_state[threadid].calloc_state.push_back(state); - //PIN_MutexUnlock(&lock); +VOID RecordCallocBefore(THREADID threadid, VOID *ip, ADDRINT nelem, + ADDRINT size) { + if (!Record) + return; + // PIN_MutexLock(&lock); + DEBUG(1) + std::cout << "[pintool] Calloc called with " << std::hex << nelem << " " + << size << " at " << ip << std::endl; + alloc_state_t state = {.size = size}; + thread_state[threadid].calloc_state.push_back(state); + // PIN_MutexUnlock(&lock); } /** @@ -1159,15 +1205,19 @@ VOID RecordCallocBefore(THREADID threadid, VOID* ip, ADDRINT nelem, ADDRINT size * @param threadid The thread * @param addr The allocated heap pointer */ -VOID RecordCallocAfter(THREADID threadid, VOID* ip, ADDRINT addr) { - if (!Record) return; - //PIN_MutexLock(&lock); - DEBUG(1) std::cout << "[pintool] Calloc returned " << std::hex << addr << " at " << ip << std::endl; - ASSERT(thread_state[threadid].calloc_state.size() > 0, "[pintool] Error: Calloc returned but not called"); - alloc_state_t state = thread_state[threadid].calloc_state.back(); - thread_state[threadid].calloc_state.pop_back(); - domalloc(addr, state.size, 0); - //PIN_MutexUnlock(&lock); +VOID RecordCallocAfter(THREADID threadid, VOID *ip, ADDRINT addr) { + if (!Record) + return; + // PIN_MutexLock(&lock); + DEBUG(1) + std::cout << "[pintool] Calloc returned " << std::hex << addr << " at " + << ip << std::endl; + ASSERT(thread_state[threadid].calloc_state.size() > 0, + "[pintool] Error: Calloc returned but not called"); + alloc_state_t state = thread_state[threadid].calloc_state.back(); + thread_state[threadid].calloc_state.pop_back(); + domalloc(addr, state.size, 0); + // PIN_MutexUnlock(&lock); } /** @@ -1175,12 +1225,15 @@ VOID RecordCallocAfter(THREADID threadid, VOID* ip, ADDRINT addr) { * @param threadid The thread * @param addr The heap pointer which is freed */ -VOID RecordFreeBefore(THREADID threadid, VOID* ip, ADDRINT addr) { - if (!Record) return; - //PIN_MutexLock(&lock); - DEBUG(1) std::cout << "[pintool] Free called with " << std::hex << addr << " at " << ip << std::endl; - dofree(addr); - //PIN_MutexUnlock(&lock); +VOID RecordFreeBefore(THREADID threadid, VOID *ip, ADDRINT addr) { + if (!Record) + return; + // PIN_MutexLock(&lock); + DEBUG(1) + std::cout << "[pintool] Free called with " << std::hex << addr << " at " + << ip << std::endl; + dofree(addr); + // PIN_MutexUnlock(&lock); } /***********************************************************************/ @@ -1194,22 +1247,25 @@ VOID RecordFreeBefore(THREADID threadid, VOID* ip, ADDRINT addr) { * @param addr The data address being read * @param fast_recording For fast recording */ -VOID RecordMemRead(THREADID threadid, VOID * ip, VOID * addr, bool fast_recording) -{ - if (!Record) return; - //PIN_MutexLock(&lock); - entry_t entry; - entry.type = READ; - entry.ip = (uint64_t)((uintptr_t)ip); - entry.data = (uint64_t)((uintptr_t)addr); - test_mem_heap(&entry); - DEBUG(3) printf("[pintool] Read %" PRIx64 " to %" PRIx64 "\n", (uint64_t)entry.ip, (uint64_t)entry.data); - if (fast_recording) { - leaks->dleak_consume((uint64_t)entry.ip, (uint64_t)entry.data); - } else { - record_entry(entry); - } - //PIN_MutexUnlock(&lock); +VOID RecordMemRead(THREADID threadid, VOID *ip, VOID *addr, + bool fast_recording) { + if (!Record) + return; + // PIN_MutexLock(&lock); + entry_t entry; + entry.type = READ; + entry.ip = (uint64_t)((uintptr_t)ip); + entry.data = (uint64_t)((uintptr_t)addr); + test_mem_heap(&entry); + DEBUG(3) + printf("[pintool] Read %" PRIx64 " to %" PRIx64 "\n", (uint64_t)entry.ip, + (uint64_t)entry.data); + if (fast_recording) { + leaks->dleak_consume((uint64_t)entry.ip, (uint64_t)entry.data); + } else { + record_entry(entry); + } + // PIN_MutexUnlock(&lock); } /** @@ -1219,22 +1275,25 @@ VOID RecordMemRead(THREADID threadid, VOID * ip, VOID * addr, bool fast_recordin * @param addr The data address being written * @param fast_recording For fast recording */ -VOID RecordMemWrite(THREADID threadid, VOID * ip, VOID * addr, bool fast_recording) -{ - if (!Record) return; - //PIN_MutexLock(&lock); - entry_t entry; - entry.type = WRITE; - entry.ip = (uint64_t)((uintptr_t)ip); - entry.data = (uint64_t)((uintptr_t)addr); - test_mem_heap(&entry); - DEBUG(3) printf("[pintool] Write %" PRIx64 " to %" PRIx64 "\n", (uint64_t)entry.ip, (uint64_t)entry.data); - if (fast_recording) { - leaks->dleak_consume((uint64_t)entry.ip, (uint64_t)entry.data); - } else { - record_entry(entry); - } - //PIN_MutexUnlock(&lock); +VOID RecordMemWrite(THREADID threadid, VOID *ip, VOID *addr, + bool fast_recording) { + if (!Record) + return; + // PIN_MutexLock(&lock); + entry_t entry; + entry.type = WRITE; + entry.ip = (uint64_t)((uintptr_t)ip); + entry.data = (uint64_t)((uintptr_t)addr); + test_mem_heap(&entry); + DEBUG(3) + printf("[pintool] Write %" PRIx64 " to %" PRIx64 "\n", (uint64_t)entry.ip, + (uint64_t)entry.data); + if (fast_recording) { + leaks->dleak_consume((uint64_t)entry.ip, (uint64_t)entry.data); + } else { + record_entry(entry); + } + // PIN_MutexUnlock(&lock); } /** @@ -1245,14 +1304,14 @@ VOID RecordMemWrite(THREADID threadid, VOID * ip, VOID * addr, bool fast_recordi * @param ins The branching instruction * @param target The next instruction (e.g. branch target) */ -VOID RecordBranch_unlocked(THREADID threadid, ADDRINT ins, ADDRINT target) -{ - if (!Record) return; - entry_t entry; - entry.type = BRANCH; - entry.ip = ins; - entry.data = target; - record_entry(entry); +VOID RecordBranch_unlocked(THREADID threadid, ADDRINT ins, ADDRINT target) { + if (!Record) + return; + entry_t entry; + entry.type = BRANCH; + entry.ip = ins; + entry.data = target; + record_entry(entry); } /** @@ -1263,36 +1322,40 @@ VOID RecordBranch_unlocked(THREADID threadid, ADDRINT ins, ADDRINT target) * @param ctxt The CPU context of bp * @param fast_recording For fast recording */ -VOID RecordBranch(THREADID threadid, ADDRINT bbl, ADDRINT bp, const CONTEXT * ctxt, bool fast_recording) -{ - //PIN_MutexLock(&lock); - ADDRINT target = (ADDRINT)PIN_GetContextReg( ctxt, REG_INST_PTR ); - DEBUG(3) std::cout << "[pintool] Branch " << std::hex << bp << " to " << target << std::endl; - RecordBranch_unlocked(threadid, bp, target); - if (fast_recording) { - leaks->cfleak_consume(bp, target); - } - //PIN_MutexUnlock(&lock); +VOID RecordBranch(THREADID threadid, ADDRINT bbl, ADDRINT bp, + const CONTEXT *ctxt, bool fast_recording) { + // PIN_MutexLock(&lock); + ADDRINT target = (ADDRINT)PIN_GetContextReg(ctxt, REG_INST_PTR); + DEBUG(3) + std::cout << "[pintool] Branch " << std::hex << bp << " to " << target + << std::endl; + RecordBranch_unlocked(threadid, bp, target); + if (fast_recording) { + leaks->cfleak_consume(bp, target); + } + // PIN_MutexUnlock(&lock); } /** - * Record conditional branch due to REP-prefix. + * Record conditional branch due to REP-prefix. * @param threadid The thread * @param bbl The basic block containing the branch * @param bp The branching instruction * @param ctxt The CPU context of bp * @param fast_recording For fast recording */ -VOID RecordRep(THREADID threadid, ADDRINT bbl, ADDRINT bp, const CONTEXT * ctxt, bool fast_recording) -{ - //PIN_MutexLock(&lock); - ADDRINT target = (ADDRINT)PIN_GetContextReg( ctxt, REG_INST_PTR ); - DEBUG(3) std::cout << "[pintool] REP-branch " << std::hex << bp << " to " << target << std::endl; - RecordBranch_unlocked(threadid, bp, target); - if (fast_recording) { - leaks->cfleak_consume(bp, target); - } - //PIN_MutexUnlock(&lock); +VOID RecordRep(THREADID threadid, ADDRINT bbl, ADDRINT bp, const CONTEXT *ctxt, + bool fast_recording) { + // PIN_MutexLock(&lock); + ADDRINT target = (ADDRINT)PIN_GetContextReg(ctxt, REG_INST_PTR); + DEBUG(3) + std::cout << "[pintool] REP-branch " << std::hex << bp << " to " << target + << std::endl; + RecordBranch_unlocked(threadid, bp, target); + if (fast_recording) { + leaks->cfleak_consume(bp, target); + } + // PIN_MutexUnlock(&lock); } /** @@ -1304,16 +1367,19 @@ VOID RecordRep(THREADID threadid, ADDRINT bbl, ADDRINT bp, const CONTEXT * ctxt, * @param indirect For indirect calls * @param target The called function's entry */ -VOID RecordFunctionEntry_unlocked(THREADID threadid, ADDRINT ins, BOOL indirect, ADDRINT target) -{ - if (!Record) return; - entry_t entry; - entry.type = FUNC_ENTRY; - entry.ip = ins; - entry.data = target; - DEBUG(3) std::cout << "[pintool] Call " << std::hex << ins << " to " << target << std::endl; - leaks->call_consume(ins, target); - record_entry(entry); +VOID RecordFunctionEntry_unlocked(THREADID threadid, ADDRINT ins, BOOL indirect, + ADDRINT target) { + if (!Record) + return; + entry_t entry; + entry.type = FUNC_ENTRY; + entry.ip = ins; + entry.data = target; + DEBUG(3) + std::cout << "[pintool] Call " << std::hex << ins << " to " << target + << std::endl; + leaks->call_consume(ins, target); + record_entry(entry); } /** @@ -1326,24 +1392,26 @@ VOID RecordFunctionEntry_unlocked(THREADID threadid, ADDRINT ins, BOOL indirect, * @param target The called function's entry * @param fast_recording For fast recording */ -VOID RecordFunctionEntry(THREADID threadid, ADDRINT bbl, ADDRINT ins, BOOL indirect, ADDRINT target, bool fast_recording) -{ - if (WaitForFirstFunction) { - Record = true; - WaitForFirstFunction = false; - } - if (!Record) return; - //PIN_MutexLock(&lock); - if (indirect) { - DEBUG(2) std::cout << "[pintool] Icall to " << std::hex << target << std::endl; - } - if (KnobFunc.Value()) { - RecordFunctionEntry_unlocked(threadid, ins, indirect, target); - } - if (fast_recording) { - leaks->cfleak_consume(ins, target); - } - //PIN_MutexUnlock(&lock); +VOID RecordFunctionEntry(THREADID threadid, ADDRINT bbl, ADDRINT ins, + BOOL indirect, ADDRINT target, bool fast_recording) { + if (WaitForFirstFunction) { + Record = true; + WaitForFirstFunction = false; + } + if (!Record) + return; + // PIN_MutexLock(&lock); + if (indirect) { + DEBUG(2) + std::cout << "[pintool] Icall to " << std::hex << target << std::endl; + } + if (KnobFunc.Value()) { + RecordFunctionEntry_unlocked(threadid, ins, indirect, target); + } + if (fast_recording) { + leaks->cfleak_consume(ins, target); + } + // PIN_MutexUnlock(&lock); } /** @@ -1354,16 +1422,19 @@ VOID RecordFunctionEntry(THREADID threadid, ADDRINT bbl, ADDRINT ins, BOOL indir * @param ins The ret instruction * @param target The instruction to continue after ret */ -VOID RecordFunctionExit_unlocked(THREADID threadid, ADDRINT ins, ADDRINT target) -{ - if (!Record) return; - entry_t entry; - entry.type = FUNC_EXIT; - entry.ip = ins; - entry.data = target; - DEBUG(2) std::cout << "[pintool] Ret " << std::hex << ins << " to " << target << std::endl; - leaks->ret_consume(ins); - record_entry(entry); +VOID RecordFunctionExit_unlocked(THREADID threadid, ADDRINT ins, + ADDRINT target) { + if (!Record) + return; + entry_t entry; + entry.type = FUNC_EXIT; + entry.ip = ins; + entry.data = target; + DEBUG(2) + std::cout << "[pintool] Ret " << std::hex << ins << " to " << target + << std::endl; + leaks->ret_consume(ins); + record_entry(entry); } /** @@ -1375,162 +1446,176 @@ VOID RecordFunctionExit_unlocked(THREADID threadid, ADDRINT ins, ADDRINT target) * @param ctxt The CPU context of ins * @param fast_recording For fast recording */ -VOID RecordFunctionExit(THREADID threadid, ADDRINT bbl, ADDRINT ins, const CONTEXT * ctxt, bool fast_recording) -{ - if (!Record) return; - ADDRINT target = ctxt != NULL ? (ADDRINT)PIN_GetContextReg( ctxt, REG_INST_PTR ) : 0; - //PIN_MutexLock(&lock); - if (KnobFunc.Value()) { - RecordFunctionExit_unlocked(threadid, ins, target); - } - if (fast_recording) { - leaks->cfleak_consume(ins, target); - } - //PIN_MutexUnlock(&lock); +VOID RecordFunctionExit(THREADID threadid, ADDRINT bbl, ADDRINT ins, + const CONTEXT *ctxt, bool fast_recording) { + if (!Record) + return; + ADDRINT target = + ctxt != NULL ? (ADDRINT)PIN_GetContextReg(ctxt, REG_INST_PTR) : 0; + // PIN_MutexLock(&lock); + if (KnobFunc.Value()) { + RecordFunctionExit_unlocked(threadid, ins, target); + } + if (fast_recording) { + leaks->cfleak_consume(ins, target); + } + // PIN_MutexUnlock(&lock); } /***********************************************************************/ /** Instrumentation Code */ /***********************************************************************/ - /** * Instruments program entry and exit as well as heap functions of libc. * @param img The loaded image * @param v UNUSED */ -VOID instrumentMainAndAlloc(IMG img, VOID *v) -{ - string name = IMG_Name(img); - DEBUG(1) std::cout << "[pintool] Instrumenting " << name << std::endl; - if (imgfile.is_open()) { - uint64_t high = IMG_HighAddress(img); - uint64_t low = IMG_LowAddress(img); - - if (vdsofile.is_open() && IMG_IsVDSO(img)) { - /* For VDSO, the HighAddress does not point to end of ELF file, - * leading to a truncated ELF file. We over-approximate the ELF size - * with IMG_SizeMapped instead. - */ - high = low + IMG_SizeMapped(img); - DEBUG(1) std::cout << "[pintool] VDSO low: 0x" << std::hex << low << std::endl; - DEBUG(1) std::cout << "[pintool] VDSO high: 0x" << std::hex << high << std::endl; - DEBUG(1) std::cout << "[pintool] VDSO size mapped: 0x" << std::hex << IMG_SizeMapped(img) << std::endl; - vdsofile.write((const char*)low, IMG_SizeMapped(img)); - vdsofile.close(); - name = KnobVDSO.Value(); - } - - imgfile << "Image:" << std::endl; - imgfile << name << std::endl; - imgfile << std::hex << low << ":" << high << std::endl; - } - - if (IMG_Valid(img)) { +VOID instrumentMainAndAlloc(IMG img, VOID *v) { + string name = IMG_Name(img); + DEBUG(1) std::cout << "[pintool] Instrumenting " << name << std::endl; if (imgfile.is_open()) { - for( SYM sym = IMG_RegsymHead(img); SYM_Valid(sym); sym = SYM_Next(sym) ) { - imgfile << std::hex << SYM_Address(sym) << ":" + SYM_Name(sym) << std::endl; - } - } - DEBUG(1) std::cout << "[pintool] KnobMain: " << KnobMain.Value() << std::endl; - if (KnobMain.Value().compare("ALL") != 0) { - RTN mainRtn = RTN_FindByName(img, KnobMain.Value().c_str()); - if (mainRtn.is_valid()) { - RTN_Open(mainRtn); - RTN_InsertCall(mainRtn, IPOINT_BEFORE, (AFUNPTR)RecordMainBegin, - IARG_THREAD_ID, - IARG_ADDRINT, RTN_Address(mainRtn), IARG_END); - RTN_InsertCall(mainRtn, IPOINT_AFTER, (AFUNPTR)RecordMainEnd, - IARG_THREAD_ID, - IARG_ADDRINT, RTN_Address(mainRtn), IARG_END); - RTN_Close(mainRtn); - } - } else { - DEBUG(1) std::cout << "[pintool] Recording all" << std::endl; - if (!Record) { - WaitForFirstFunction = true; - } - } - - if (name.find("alloc.so") != std::string::npos || - name.find("libc.so") != std::string::npos) { - /* If alloc.so is pre-loaded, it will always be before libc - * We only instrument once - */ - if (alloc_instrumented) { - DEBUG(1) std::cout << "[pintool] Allocation already instrumented" << std::endl; - } else { - DEBUG(1) std::cout << "[pintool] Instrumenting allocation" << std::endl; - if (KnobTrackHeap.Value()) { - RTN mallocRtn = RTN_FindByName(img, MALLOC); - if (mallocRtn.is_valid()) { - DEBUG(1) std::cout << "[pintool] Malloc found in " << IMG_Name(img) << std::endl; - RTN_Open(mallocRtn); - RTN_InsertCall(mallocRtn, IPOINT_BEFORE, (AFUNPTR)RecordMallocBefore, - IARG_THREAD_ID, - IARG_INST_PTR, - IARG_FUNCARG_ENTRYPOINT_VALUE, 0, - IARG_END); - RTN_InsertCall(mallocRtn, IPOINT_AFTER, (AFUNPTR)RecordMallocAfter, - IARG_THREAD_ID, - IARG_INST_PTR, - IARG_FUNCRET_EXITPOINT_VALUE, - IARG_END); - RTN_Close(mallocRtn); - } - - RTN reallocRtn = RTN_FindByName(img, REALLOC); - if (reallocRtn.is_valid()) { - DEBUG(1) std::cout << "[pintool] Realloc found in " << IMG_Name(img) << std::endl; - RTN_Open(reallocRtn); - RTN_InsertCall(reallocRtn, IPOINT_BEFORE, (AFUNPTR)RecordReallocBefore, - IARG_THREAD_ID, - IARG_INST_PTR, - IARG_FUNCARG_ENTRYPOINT_VALUE, 0, - IARG_FUNCARG_ENTRYPOINT_VALUE, 1, - IARG_END); - RTN_InsertCall(reallocRtn, IPOINT_AFTER, (AFUNPTR)RecordReallocAfter, - IARG_THREAD_ID, - IARG_INST_PTR, - IARG_FUNCRET_EXITPOINT_VALUE, - IARG_END); - RTN_Close(reallocRtn); - } - - RTN callocRtn = RTN_FindByName(img, CALLOC); - if (callocRtn.is_valid()) { - DEBUG(1) std::cout << "[pintool] Calloc found in " << IMG_Name(img) << std::endl; - RTN_Open(callocRtn); - RTN_InsertCall(callocRtn, IPOINT_BEFORE, (AFUNPTR)RecordCallocBefore, - IARG_THREAD_ID, - IARG_INST_PTR, - IARG_FUNCARG_ENTRYPOINT_VALUE, 0, - IARG_FUNCARG_ENTRYPOINT_VALUE, 1, - IARG_END); - RTN_InsertCall(callocRtn, IPOINT_AFTER, (AFUNPTR)RecordCallocAfter, - IARG_THREAD_ID, - IARG_INST_PTR, - IARG_FUNCRET_EXITPOINT_VALUE, - IARG_END); - RTN_Close(callocRtn); - } - - RTN freeRtn = RTN_FindByName(img, FREE); - if (freeRtn.is_valid()) { - DEBUG(1) std::cout << "[pintool] Free found in " << IMG_Name(img) << std::endl; - RTN_Open(freeRtn); - RTN_InsertCall(freeRtn, IPOINT_BEFORE, (AFUNPTR)RecordFreeBefore, - IARG_THREAD_ID, - IARG_INST_PTR, - IARG_FUNCARG_ENTRYPOINT_VALUE, 0, - IARG_END); - RTN_Close(freeRtn); - } + uint64_t high = IMG_HighAddress(img); + uint64_t low = IMG_LowAddress(img); + + if (vdsofile.is_open() && IMG_IsVDSO(img)) { + /* For VDSO, the HighAddress does not point to end of ELF file, + * leading to a truncated ELF file. We over-approximate the ELF size + * with IMG_SizeMapped instead. + */ + high = low + IMG_SizeMapped(img); + DEBUG(1) + std::cout << "[pintool] VDSO low: 0x" << std::hex << low + << std::endl; + DEBUG(1) + std::cout << "[pintool] VDSO high: 0x" << std::hex << high + << std::endl; + DEBUG(1) + std::cout << "[pintool] VDSO size mapped: 0x" << std::hex + << IMG_SizeMapped(img) << std::endl; + vdsofile.write((const char *)low, IMG_SizeMapped(img)); + vdsofile.close(); + name = KnobVDSO.Value(); + } + + imgfile << "Image:" << std::endl; + imgfile << name << std::endl; + imgfile << std::hex << low << ":" << high << std::endl; + } + + if (IMG_Valid(img)) { + if (imgfile.is_open()) { + for (SYM sym = IMG_RegsymHead(img); SYM_Valid(sym); + sym = SYM_Next(sym)) { + imgfile << std::hex << SYM_Address(sym) << ":" + SYM_Name(sym) + << std::endl; + } + } + DEBUG(1) + std::cout << "[pintool] KnobMain: " << KnobMain.Value() << std::endl; + if (KnobMain.Value().compare("ALL") != 0) { + RTN mainRtn = RTN_FindByName(img, KnobMain.Value().c_str()); + if (mainRtn.is_valid()) { + RTN_Open(mainRtn); + RTN_InsertCall(mainRtn, IPOINT_BEFORE, (AFUNPTR)RecordMainBegin, + IARG_THREAD_ID, IARG_ADDRINT, + RTN_Address(mainRtn), IARG_END); + RTN_InsertCall(mainRtn, IPOINT_AFTER, (AFUNPTR)RecordMainEnd, + IARG_THREAD_ID, IARG_ADDRINT, + RTN_Address(mainRtn), IARG_END); + RTN_Close(mainRtn); + } + } else { + DEBUG(1) std::cout << "[pintool] Recording all" << std::endl; + if (!Record) { + WaitForFirstFunction = true; + } } - alloc_instrumented = 1; - } - } /* alloc.so or libc */ - } + + if (name.find("alloc.so") != std::string::npos || + name.find("libc.so") != std::string::npos) { + /* If alloc.so is pre-loaded, it will always be before libc + * We only instrument once + */ + if (alloc_instrumented) { + DEBUG(1) + std::cout << "[pintool] Allocation already instrumented" + << std::endl; + } else { + DEBUG(1) + std::cout << "[pintool] Instrumenting allocation" << std::endl; + if (KnobTrackHeap.Value()) { + RTN mallocRtn = RTN_FindByName(img, MALLOC); + if (mallocRtn.is_valid()) { + DEBUG(1) + std::cout << "[pintool] Malloc found in " + << IMG_Name(img) << std::endl; + RTN_Open(mallocRtn); + RTN_InsertCall(mallocRtn, IPOINT_BEFORE, + (AFUNPTR)RecordMallocBefore, + IARG_THREAD_ID, IARG_INST_PTR, + IARG_FUNCARG_ENTRYPOINT_VALUE, 0, + IARG_END); + RTN_InsertCall(mallocRtn, IPOINT_AFTER, + (AFUNPTR)RecordMallocAfter, + IARG_THREAD_ID, IARG_INST_PTR, + IARG_FUNCRET_EXITPOINT_VALUE, IARG_END); + RTN_Close(mallocRtn); + } + + RTN reallocRtn = RTN_FindByName(img, REALLOC); + if (reallocRtn.is_valid()) { + DEBUG(1) + std::cout << "[pintool] Realloc found in " + << IMG_Name(img) << std::endl; + RTN_Open(reallocRtn); + RTN_InsertCall( + reallocRtn, IPOINT_BEFORE, + (AFUNPTR)RecordReallocBefore, IARG_THREAD_ID, + IARG_INST_PTR, IARG_FUNCARG_ENTRYPOINT_VALUE, 0, + IARG_FUNCARG_ENTRYPOINT_VALUE, 1, IARG_END); + RTN_InsertCall(reallocRtn, IPOINT_AFTER, + (AFUNPTR)RecordReallocAfter, + IARG_THREAD_ID, IARG_INST_PTR, + IARG_FUNCRET_EXITPOINT_VALUE, IARG_END); + RTN_Close(reallocRtn); + } + + RTN callocRtn = RTN_FindByName(img, CALLOC); + if (callocRtn.is_valid()) { + DEBUG(1) + std::cout << "[pintool] Calloc found in " + << IMG_Name(img) << std::endl; + RTN_Open(callocRtn); + RTN_InsertCall( + callocRtn, IPOINT_BEFORE, + (AFUNPTR)RecordCallocBefore, IARG_THREAD_ID, + IARG_INST_PTR, IARG_FUNCARG_ENTRYPOINT_VALUE, 0, + IARG_FUNCARG_ENTRYPOINT_VALUE, 1, IARG_END); + RTN_InsertCall(callocRtn, IPOINT_AFTER, + (AFUNPTR)RecordCallocAfter, + IARG_THREAD_ID, IARG_INST_PTR, + IARG_FUNCRET_EXITPOINT_VALUE, IARG_END); + RTN_Close(callocRtn); + } + + RTN freeRtn = RTN_FindByName(img, FREE); + if (freeRtn.is_valid()) { + DEBUG(1) + std::cout << "[pintool] Free found in " << IMG_Name(img) + << std::endl; + RTN_Open(freeRtn); + RTN_InsertCall( + freeRtn, IPOINT_BEFORE, (AFUNPTR)RecordFreeBefore, + IARG_THREAD_ID, IARG_INST_PTR, + IARG_FUNCARG_ENTRYPOINT_VALUE, 0, IARG_END); + RTN_Close(freeRtn); + } + } + alloc_instrumented = 1; + } + } /* alloc.so or libc */ + } } /** @@ -1539,40 +1624,33 @@ VOID instrumentMainAndAlloc(IMG img, VOID *v) * @param fast_recording Fast recording * @return True if the instruction could be instrumented */ -BOOL instrumentMemIns(INS ins, bool fast_recording) -{ - if (KnobMem.Value()) { - UINT32 memOperands = INS_MemoryOperandCount(ins); - bool found = false; - ADDRINT ip = INS_Address(ins); - DEBUG(1) printf("[pintool] Adding %lx to instrumentation\n", (long unsigned int)ip); - - for (UINT32 memOp = 0; memOp < memOperands; memOp++) { - if (INS_MemoryOperandIsRead(ins, memOp)) { - INS_InsertCall( - ins, IPOINT_BEFORE, (AFUNPTR) RecordMemRead, - IARG_THREAD_ID, - IARG_INST_PTR, - IARG_MEMORYOP_EA, memOp, - IARG_BOOL, fast_recording, - IARG_END); - found = true; - } - if (INS_MemoryOperandIsWritten(ins, memOp)) { - INS_InsertCall( - ins, IPOINT_BEFORE, (AFUNPTR) RecordMemWrite, - IARG_THREAD_ID, - IARG_INST_PTR, - IARG_MEMORYOP_EA, memOp, - IARG_BOOL, fast_recording, - IARG_END); - found = true; - } - } - return found; - } else { - return false; - } +BOOL instrumentMemIns(INS ins, bool fast_recording) { + if (KnobMem.Value()) { + UINT32 memOperands = INS_MemoryOperandCount(ins); + bool found = false; + ADDRINT ip = INS_Address(ins); + DEBUG(1) + printf("[pintool] Adding %lx to instrumentation\n", + (long unsigned int)ip); + + for (UINT32 memOp = 0; memOp < memOperands; memOp++) { + if (INS_MemoryOperandIsRead(ins, memOp)) { + INS_InsertCall(ins, IPOINT_BEFORE, (AFUNPTR)RecordMemRead, + IARG_THREAD_ID, IARG_INST_PTR, IARG_MEMORYOP_EA, + memOp, IARG_BOOL, fast_recording, IARG_END); + found = true; + } + if (INS_MemoryOperandIsWritten(ins, memOp)) { + INS_InsertCall(ins, IPOINT_BEFORE, (AFUNPTR)RecordMemWrite, + IARG_THREAD_ID, IARG_INST_PTR, IARG_MEMORYOP_EA, + memOp, IARG_BOOL, fast_recording, IARG_END); + found = true; + } + } + return found; + } else { + return false; + } } /** @@ -1581,90 +1659,95 @@ BOOL instrumentMemIns(INS ins, bool fast_recording) * @param bp The branch point. Same as bbl, except for fast_recording * @param fast_recording Fast recording */ -bool instrumentCallBranch(INS bbl, INS bp, bool fast_recording) -{ - bool instrumented = false; - if (INS_IsCall(bp)) { - if (KnobFunc.Value() || KnobBbl.Value()) { - INS_InsertCall(bp, IPOINT_BEFORE, AFUNPTR(RecordFunctionEntry), - IARG_THREAD_ID, - IARG_ADDRINT, INS_Address(bbl), - IARG_ADDRINT, INS_Address(bp), - IARG_BOOL, INS_IS_INDIRECT(bp), - IARG_BRANCH_TARGET_ADDR, - IARG_BOOL, fast_recording, - IARG_END); - DEBUG(1) printf("[pintool] Instrumented call@%lx\n", (long unsigned int)INS_Address(bp)); - instrumented = true; - } - } else if (INS_IsRet(bp)) { - /* RET would be also detected as branch, therefore we use 'else if' */ - if (KnobFunc.Value() || KnobBbl.Value()) { - ASSERT(INS_HAS_TAKEN_BRANCH(bp), "[pintool] Error: Return instruction should support taken branch."); - INS_InsertCall(bp, IPOINT_TAKEN_BRANCH, AFUNPTR(RecordFunctionExit), - IARG_THREAD_ID, - IARG_ADDRINT, INS_Address(bbl), - IARG_ADDRINT, INS_Address(bp), - IARG_CONTEXT, - IARG_BOOL, fast_recording, - IARG_END); - DEBUG(1) printf("[pintool] Instrumented ret@%lx\n", (long unsigned int)INS_Address(bp)); - instrumented = true; - } - } else if (INS_IsBranch(bp)) { - if (KnobBbl.Value()) { - if (!INS_HAS_TAKEN_BRANCH(bp)) { - std::cout << "[pintool] Warning: Branch instruction " << INS_Mnemonic(bp) << "@ 0x" << std::hex << INS_Address(bp) << " does not support taken branch. Ignoring." << std::endl; - // TODO: test for leaks in XBEGIN/XEND/XABORT - } else { - /* unconditional jumps */ - INS_InsertCall(bp, IPOINT_TAKEN_BRANCH, AFUNPTR(RecordBranch), - IARG_THREAD_ID, - IARG_ADDRINT, INS_Address(bbl), - IARG_ADDRINT, INS_Address(bp), - IARG_CONTEXT, - IARG_BOOL, fast_recording, - IARG_END); - DEBUG(1) printf("[pintool] Instrumented jump@%lx\n", (long unsigned int)INS_Address(bp)); - instrumented = true; - } - - if (INS_HAS_IPOINT_AFTER(bp)) { - /* conditional/indirect jumps */ - INS_InsertCall(bp, IPOINT_AFTER, AFUNPTR(RecordBranch), - IARG_THREAD_ID, - IARG_ADDRINT, INS_Address(bbl), - IARG_ADDRINT, INS_Address(bp), - IARG_CONTEXT, - IARG_BOOL, fast_recording, - IARG_END); - DEBUG(1) printf("[pintool] Instrumented indirect jump@%lx\n", (long unsigned int)INS_Address(bp)); - instrumented = true; - } - } - } else if (INS_RepPrefix(bp)) { - ADDRINT ip = INS_Address(bp); - DEBUG(2) printf("[pintool] REP@%lx: REP-predicated instruction\n", (long unsigned int)ip); - - /* Rep-prefix does not necessarily show architectural effect - * E.g. repz retq (see http://pages.cs.wisc.edu/~lena/repzret.php) - */ +bool instrumentCallBranch(INS bbl, INS bp, bool fast_recording) { + bool instrumented = false; + if (INS_IsCall(bp)) { + if (KnobFunc.Value() || KnobBbl.Value()) { + INS_InsertCall(bp, IPOINT_BEFORE, AFUNPTR(RecordFunctionEntry), + IARG_THREAD_ID, IARG_ADDRINT, INS_Address(bbl), + IARG_ADDRINT, INS_Address(bp), IARG_BOOL, + INS_IS_INDIRECT(bp), IARG_BRANCH_TARGET_ADDR, + IARG_BOOL, fast_recording, IARG_END); + DEBUG(1) + printf("[pintool] Instrumented call@%lx\n", + (long unsigned int)INS_Address(bp)); + instrumented = true; + } + } else if (INS_IsRet(bp)) { + /* RET would be also detected as branch, therefore we use 'else if' */ + if (KnobFunc.Value() || KnobBbl.Value()) { + ASSERT(INS_HAS_TAKEN_BRANCH(bp), + "[pintool] Error: Return instruction should support taken " + "branch."); + INS_InsertCall(bp, IPOINT_TAKEN_BRANCH, AFUNPTR(RecordFunctionExit), + IARG_THREAD_ID, IARG_ADDRINT, INS_Address(bbl), + IARG_ADDRINT, INS_Address(bp), IARG_CONTEXT, + IARG_BOOL, fast_recording, IARG_END); + DEBUG(1) + printf("[pintool] Instrumented ret@%lx\n", + (long unsigned int)INS_Address(bp)); + instrumented = true; + } + } else if (INS_IsBranch(bp)) { + if (KnobBbl.Value()) { + if (!INS_HAS_TAKEN_BRANCH(bp)) { + std::cout << "[pintool] Warning: Branch instruction " + << INS_Mnemonic(bp) << "@ 0x" << std::hex + << INS_Address(bp) + << " does not support taken branch. Ignoring." + << std::endl; + // TODO: test for leaks in XBEGIN/XEND/XABORT + } else { + /* unconditional jumps */ + INS_InsertCall(bp, IPOINT_TAKEN_BRANCH, AFUNPTR(RecordBranch), + IARG_THREAD_ID, IARG_ADDRINT, INS_Address(bbl), + IARG_ADDRINT, INS_Address(bp), IARG_CONTEXT, + IARG_BOOL, fast_recording, IARG_END); + DEBUG(1) + printf("[pintool] Instrumented jump@%lx\n", + (long unsigned int)INS_Address(bp)); + instrumented = true; + } + + if (INS_HAS_IPOINT_AFTER(bp)) { + /* conditional/indirect jumps */ + INS_InsertCall(bp, IPOINT_AFTER, AFUNPTR(RecordBranch), + IARG_THREAD_ID, IARG_ADDRINT, INS_Address(bbl), + IARG_ADDRINT, INS_Address(bp), IARG_CONTEXT, + IARG_BOOL, fast_recording, IARG_END); + DEBUG(1) + printf("[pintool] Instrumented indirect jump@%lx\n", + (long unsigned int)INS_Address(bp)); + instrumented = true; + } + } + } else if (INS_RepPrefix(bp)) { + ADDRINT ip = INS_Address(bp); + DEBUG(2) + printf("[pintool] REP@%lx: REP-predicated instruction\n", + (long unsigned int)ip); + + /* Rep-prefix does not necessarily show architectural effect + * E.g. repz retq (see http://pages.cs.wisc.edu/~lena/repzret.php) + */ - if (INS_HAS_IPOINT_AFTER(bp)) { - DEBUG(2) printf("[pintool] REP@%lx has fall-through\n", (long unsigned int)ip); - /* REP-prefixed instruction where REP is in effect (e.g. rep stos) */ - INS_InsertCall(bp, IPOINT_AFTER, AFUNPTR(RecordRep), - IARG_THREAD_ID, - IARG_ADDRINT, INS_Address(bbl), - IARG_ADDRINT, INS_Address(bp), - IARG_CONTEXT, - IARG_BOOL, fast_recording, - IARG_END); - instrumented = true; - DEBUG(1) printf("[pintool] Instrumented rep@%lx\n", (long unsigned int)INS_Address(bp)); - } - } - return instrumented; + if (INS_HAS_IPOINT_AFTER(bp)) { + DEBUG(2) + printf("[pintool] REP@%lx has fall-through\n", + (long unsigned int)ip); + /* REP-prefixed instruction where REP is in effect (e.g. rep stos) + */ + INS_InsertCall(bp, IPOINT_AFTER, AFUNPTR(RecordRep), IARG_THREAD_ID, + IARG_ADDRINT, INS_Address(bbl), IARG_ADDRINT, + INS_Address(bp), IARG_CONTEXT, IARG_BOOL, + fast_recording, IARG_END); + instrumented = true; + DEBUG(1) + printf("[pintool] Instrumented rep@%lx\n", + (long unsigned int)INS_Address(bp)); + } + } + return instrumented; } /** @@ -1672,10 +1755,9 @@ bool instrumentCallBranch(INS bbl, INS bp, bool fast_recording) * @param ins The instruction to trace * @param v UNUSED */ -VOID instrumentAnyInstructions(INS ins, VOID *v) -{ - instrumentMemIns(ins, false); - instrumentCallBranch(ins, ins, false); +VOID instrumentAnyInstructions(INS ins, VOID *v) { + instrumentMemIns(ins, false); + instrumentCallBranch(ins, ins, false); } /** @@ -1684,233 +1766,256 @@ VOID instrumentAnyInstructions(INS ins, VOID *v) * @param ins The instruction to trace * @param v UNUSED */ -VOID instrumentLeakingInstructions(INS ins, VOID *v) -{ - ADDRINT ip = INS_Address(ins); - - if (leaks->get_erase_dleak(ip) || leaks->was_erased_dleak(ip)) { - /* Instrument dataleaking instruction */ - DEBUG(1) printf("[pintool] Tracing DLEAK %lx\n", (long unsigned int)ip); - bool found = instrumentMemIns(ins, true); - ASSERT(found, "[pintool] Error: Memory instruction to instument not found. Have you provided the flag -mem?"); - } - - if (KnobFunc.Value()) { - /* Instrument call/ret for generating call stack */ - if (INS_IsCall(ins)) { - INS_InsertCall(ins, IPOINT_BEFORE, AFUNPTR(RecordFunctionEntry), - IARG_THREAD_ID, - IARG_ADDRINT, INS_Address(ins), - IARG_ADDRINT, INS_Address(ins), - IARG_BOOL, INS_IS_INDIRECT(ins), - IARG_BRANCH_TARGET_ADDR, - IARG_BOOL, false, - IARG_END); - DEBUG(1) printf("[pintool] Instrumented call stack call@%lx\n", (long unsigned int)INS_Address(ins)); - } else if (INS_IsRet(ins)) { - ASSERT(INS_HAS_TAKEN_BRANCH(ins), "[pintool] Error: Return instruction should support taken branch."); - INS_InsertCall(ins, IPOINT_TAKEN_BRANCH, AFUNPTR(RecordFunctionExit), - IARG_THREAD_ID, - IARG_ADDRINT, INS_Address(ins), - IARG_ADDRINT, INS_Address(ins), - IARG_CONTEXT, - IARG_BOOL, false, - IARG_END); - DEBUG(1) printf("[pintool] Instrumented call stack ret@%lx\n", (long unsigned int)INS_Address(ins)); - } - } - - if (leaks->get_erase_cfleak(ip) || leaks->was_erased_cfleak(ip)) { - /* Instrument cfleaking instruction */ - DEBUG(1) printf("[pintool] Tracing CFLEAK %lx\n", (long unsigned int)ip); - - /* Need to find actual branch inside BBL, since ins is start address of the whole BBL - * Therefore, we assume that the *first* branch/call inside the BBL is our conditional branch/call of interest. - * Unconditional branches must therefore have started a new BBL. - */ - INS bp = ins; - bool found = false; - while (bp != INS_Invalid()) { - DEBUG(2) printf("[pintool] Testing ins %lx\n", (long unsigned int)INS_Address(bp)); - if (instrumentCallBranch(ins, bp, true)) { - DEBUG(2) printf("[pintool] Found bp %lx\n", (long unsigned int)INS_Address(bp)); - /* We instrument the actual branch point (bp) but report leaks - * with respect to the BBL (ins) +VOID instrumentLeakingInstructions(INS ins, VOID *v) { + ADDRINT ip = INS_Address(ins); + + if (leaks->get_erase_dleak(ip) || leaks->was_erased_dleak(ip)) { + /* Instrument dataleaking instruction */ + DEBUG(1) printf("[pintool] Tracing DLEAK %lx\n", (long unsigned int)ip); + bool found = instrumentMemIns(ins, true); + ASSERT(found, "[pintool] Error: Memory instruction to instument not " + "found. Have you provided the flag -mem?"); + } + + if (KnobFunc.Value()) { + /* Instrument call/ret for generating call stack */ + if (INS_IsCall(ins)) { + INS_InsertCall(ins, IPOINT_BEFORE, AFUNPTR(RecordFunctionEntry), + IARG_THREAD_ID, IARG_ADDRINT, INS_Address(ins), + IARG_ADDRINT, INS_Address(ins), IARG_BOOL, + INS_IS_INDIRECT(ins), IARG_BRANCH_TARGET_ADDR, + IARG_BOOL, false, IARG_END); + DEBUG(1) + printf("[pintool] Instrumented call stack call@%lx\n", + (long unsigned int)INS_Address(ins)); + } else if (INS_IsRet(ins)) { + ASSERT(INS_HAS_TAKEN_BRANCH(ins), + "[pintool] Error: Return instruction should support taken " + "branch."); + INS_InsertCall( + ins, IPOINT_TAKEN_BRANCH, AFUNPTR(RecordFunctionExit), + IARG_THREAD_ID, IARG_ADDRINT, INS_Address(ins), IARG_ADDRINT, + INS_Address(ins), IARG_CONTEXT, IARG_BOOL, false, IARG_END); + DEBUG(1) + printf("[pintool] Instrumented call stack ret@%lx\n", + (long unsigned int)INS_Address(ins)); + } + } + + if (leaks->get_erase_cfleak(ip) || leaks->was_erased_cfleak(ip)) { + /* Instrument cfleaking instruction */ + DEBUG(1) + printf("[pintool] Tracing CFLEAK %lx\n", (long unsigned int)ip); + + /* Need to find actual branch inside BBL, since ins is start address of + * the whole BBL Therefore, we assume that the *first* branch/call + * inside the BBL is our conditional branch/call of interest. + * Unconditional branches must therefore have started a new BBL. */ - found = true; - break; - } - bp = INS_Next(bp); + INS bp = ins; + bool found = false; + while (bp != INS_Invalid()) { + DEBUG(2) + printf("[pintool] Testing ins %lx\n", + (long unsigned int)INS_Address(bp)); + if (instrumentCallBranch(ins, bp, true)) { + DEBUG(2) + printf("[pintool] Found bp %lx\n", + (long unsigned int)INS_Address(bp)); + /* We instrument the actual branch point (bp) but report leaks + * with respect to the BBL (ins) + */ + found = true; + break; + } + bp = INS_Next(bp); + } + ASSERT(found, "[pintool] Error: Instruction to instument not found"); } - ASSERT(found, "[pintool] Error: Instruction to instument not found"); - } } /***********************************************************************/ /** CLI and Pin framework functions */ /***********************************************************************/ typedef struct __attribute__((packed)) { - uint8_t type; - uint64_t ip; - uint8_t nopt; + uint8_t type; + uint64_t ip; + uint8_t nopt; } leakfmt_t; /** * Loads leaks as exported by analyze.py show --leakout */ -VOID loadLeaks(VOID* v) { - FILE *f = NULL; - f = fopen(KnobLeakIn.Value().c_str(), "r"); - ASSERT(f, "[pintool] Error: Leak file does not exist"); - fseek(f, 0, SEEK_END); - long len = ftell(f); - rewind(f); - - DEBUG(1) printf("[pintool] Reading leaks from %s, size %ld bytes\n", KnobLeakIn.Value().c_str(), len); - ASSERT(leaks, "[pintool] Error: Leaks not initialized"); - while(ftell(f) < len) { - leakfmt_t elem; - ASSERT(fread(&elem, sizeof(elem), 1, f) == 1, "[pintool] Error: Failed reading leak file"); - uint64_t callee = 0; - DEBUG(1) printf("[pintool] Loading leak element %x, %" PRIx64 ", %d\n", elem.type, elem.ip, elem.nopt); - switch(elem.type) { - case FUNC_ENTRY: - ASSERT(elem.nopt == 1, "[pintool] Error: Trace format corrupt"); - ASSERT(fread(&callee, sizeof(callee), 1, f) == 1, "[pintool] Error: Failed reading leak file"); - if (KnobCallstack.Value()) { - leaks->call_create(elem.ip, callee); - } - DEBUG(1) printf("[pintool] Func entry %" PRIx64 "\n", callee); - break; - case FUNC_EXIT: - ASSERT(fseek(f, elem.nopt * sizeof(uint64_t), SEEK_CUR) == 0, "[pintool] Error: Failed reading leak file"); - if (KnobCallstack.Value()) { - leaks->ret_create(elem.ip); +VOID loadLeaks(VOID *v) { + FILE *f = NULL; + f = fopen(KnobLeakIn.Value().c_str(), "r"); + ASSERT(f, "[pintool] Error: Leak file does not exist"); + fseek(f, 0, SEEK_END); + long len = ftell(f); + rewind(f); + + DEBUG(1) + printf("[pintool] Reading leaks from %s, size %ld bytes\n", + KnobLeakIn.Value().c_str(), len); + ASSERT(leaks, "[pintool] Error: Leaks not initialized"); + while (ftell(f) < len) { + leakfmt_t elem; + ASSERT(fread(&elem, sizeof(elem), 1, f) == 1, + "[pintool] Error: Failed reading leak file"); + uint64_t callee = 0; + DEBUG(1) + printf("[pintool] Loading leak element %x, %" PRIx64 ", %d\n", + elem.type, elem.ip, elem.nopt); + switch (elem.type) { + case FUNC_ENTRY: + ASSERT(elem.nopt == 1, "[pintool] Error: Trace format corrupt"); + ASSERT(fread(&callee, sizeof(callee), 1, f) == 1, + "[pintool] Error: Failed reading leak file"); + if (KnobCallstack.Value()) { + leaks->call_create(elem.ip, callee); + } + DEBUG(1) printf("[pintool] Func entry %" PRIx64 "\n", callee); + break; + case FUNC_EXIT: + ASSERT(fseek(f, elem.nopt * sizeof(uint64_t), SEEK_CUR) == 0, + "[pintool] Error: Failed reading leak file"); + if (KnobCallstack.Value()) { + leaks->ret_create(elem.ip); + } + DEBUG(1) printf("[pintool] Func exit\n"); + break; + case DLEAK: + ASSERT(elem.nopt == 0, "[pintool] Error: Trace format corrupt"); + leaks->dleak_create(elem.ip); + DEBUG(1) printf("[pintool] Adding Dleak: %" PRIx64 "\n", elem.ip); + break; + case CFLEAK: + ASSERT(elem.nopt > 0, "[pintool] Error: Trace format corrupt"); + ASSERT(fseek(f, elem.nopt * sizeof(uint64_t), SEEK_CUR) == 0, + "[pintool] Error: Failed reading leak file"); + leaks->cfleak_create(elem.ip, NULL, 0); + DEBUG(1) printf("[pintool] Adding CFleak: %" PRIx64 "\n", elem.ip); + break; + default: + ASSERT(false, "[pintool] Error: Invalid leak type"); } - DEBUG(1) printf("[pintool] Func exit\n"); - break; - case DLEAK: - ASSERT(elem.nopt == 0, "[pintool] Error: Trace format corrupt"); - leaks->dleak_create(elem.ip); - DEBUG(1) printf("[pintool] Adding Dleak: %" PRIx64 "\n", elem.ip); - break; - case CFLEAK: - ASSERT(elem.nopt > 0, "[pintool] Error: Trace format corrupt"); - ASSERT(fseek(f, elem.nopt * sizeof(uint64_t), SEEK_CUR) == 0, "[pintool] Error: Failed reading leak file"); - leaks->cfleak_create(elem.ip, NULL, 0); - DEBUG(1) printf("[pintool] Adding CFleak: %" PRIx64 "\n", elem.ip); - break; - default: - ASSERT(false, "[pintool] Error: Invalid leak type"); - } - } - ASSERT(ftell(f) == len, "[pintool] Error: Trace format corrupt"); - DEBUG(2) leaks->print_all(); - fflush(stdout); - - if (use_callstack) { - static_cast(leaks)->rewind(); - } + } + ASSERT(ftell(f) == len, "[pintool] Error: Trace format corrupt"); + DEBUG(2) leaks->print_all(); + fflush(stdout); + + if (use_callstack) { + static_cast(leaks)->rewind(); + } } /** * Write traces to files */ -VOID Fini(INT32 code, VOID *v) -{ - if (!KnobLeaks.Value()) { - if (!KnobRawFile.Value().empty()) { - FILE* ftrace = fopen(KnobRawFile.Value().c_str(), "w"); - if (!ftrace) { - std::cout << "[pintool] Error: Unable to open file " << KnobRawFile.Value() << std::endl; - } else { - std::cout << "[pintool] Writing raw results to " << KnobRawFile.Value() << std::endl; - bool res; - res = fwrite(&trace[0], sizeof(entry_t), trace.size(), ftrace) == trace.size(); - fclose(ftrace); - ASSERT(res, "[pintool] Error: Unable to write complete trace file. Out of disk memory?"); - } - } - /* KnobLeaks is set */ - } else { - DEBUG(1) leaks->print_all(); - DEBUG(1) printf("[pintool] Number of uninstrumented data leaks: %zu\n", leaks->get_uninstrumented_dleak_size()); - DEBUG(1) printf("[pintool] Number of uninstrumented cflow leaks: %zu\n", leaks->get_uninstrumented_cfleak_size()); - DEBUG(1) leaks->print_uninstrumented_leaks(); - - if (!KnobLeakOut.Value().empty()) { - ASSERT(!KnobLeakIn.Value().empty(), "[pintool] Error: leakout requires leakin"); - ASSERT(leaks, "[pintool] Error: Leaks not initialized"); - FILE* fleaks = fopen(KnobLeakOut.Value().c_str(), "w"); - if (!fleaks) { - std::cout << "[pintool] Unable to open file " << KnobLeakOut.Value() << std::endl; - } else { - std::cout << "[pintool] Writing leak results to " << KnobLeakOut.Value() << std::endl; - if (use_callstack) { - static_cast(leaks)->rewind(); +VOID Fini(INT32 code, VOID *v) { + if (!KnobLeaks.Value()) { + if (!KnobRawFile.Value().empty()) { + FILE *ftrace = fopen(KnobRawFile.Value().c_str(), "w"); + if (!ftrace) { + std::cout << "[pintool] Error: Unable to open file " + << KnobRawFile.Value() << std::endl; + } else { + std::cout << "[pintool] Writing raw results to " + << KnobRawFile.Value() << std::endl; + bool res; + res = fwrite(&trace[0], sizeof(entry_t), trace.size(), + ftrace) == trace.size(); + fclose(ftrace); + ASSERT(res, "[pintool] Error: Unable to write complete trace " + "file. Out of disk memory?"); + } + } + /* KnobLeaks is set */ + } else { + DEBUG(1) leaks->print_all(); + DEBUG(1) + printf("[pintool] Number of uninstrumented data leaks: %zu\n", + leaks->get_uninstrumented_dleak_size()); + DEBUG(1) + printf("[pintool] Number of uninstrumented cflow leaks: %zu\n", + leaks->get_uninstrumented_cfleak_size()); + DEBUG(1) leaks->print_uninstrumented_leaks(); + + if (!KnobLeakOut.Value().empty()) { + ASSERT(!KnobLeakIn.Value().empty(), + "[pintool] Error: leakout requires leakin"); + ASSERT(leaks, "[pintool] Error: Leaks not initialized"); + FILE *fleaks = fopen(KnobLeakOut.Value().c_str(), "w"); + if (!fleaks) { + std::cout << "[pintool] Unable to open file " + << KnobLeakOut.Value() << std::endl; + } else { + std::cout << "[pintool] Writing leak results to " + << KnobLeakOut.Value() << std::endl; + if (use_callstack) { + static_cast(leaks)->rewind(); + } + leaks->doexport(fleaks); + fclose(fleaks); + } } - leaks->doexport(fleaks); - fclose(fleaks); - } } - } - if (imgfile.is_open()) { - imgfile.close(); - } + if (imgfile.is_open()) { + imgfile.close(); + } } -INT32 Usage() -{ - PIN_ERROR("Address Leak Detector\n" - + KNOB_BASE::StringKnobSummary() + "\n"); - return -1; +INT32 Usage() { + PIN_ERROR("Address Leak Detector\n" + KNOB_BASE::StringKnobSummary() + + "\n"); + return -1; } -int main(int argc, char *argv[]) -{ - if (PIN_Init(argc, argv)) return Usage(); - - PIN_InitSymbols(); - - if (KnobLeaks.Value() && KnobCallstack.Value()) { - leaks = new CallStack(); - use_callstack = true; - } else { - leaks = new Flat(); - use_callstack = false; - } - IMG_AddInstrumentFunction(instrumentMainAndAlloc, 0); - if (!KnobSyms.Value().empty()) { - imgfile.open(KnobSyms.Value().c_str()); - } - if (!KnobVDSO.Value().empty()) { - vdsofile.open(KnobVDSO.Value().c_str()); - } - - if (!KnobLeaks.Value()) { - /* Traditional tracing */ - if (KnobBbl.Value() || KnobMem.Value() || KnobFunc.Value()) { - INS_AddInstrumentFunction(instrumentAnyInstructions, 0); - } - } else { - /* Tracing only leaks specified by leak file */ - DEBUG(1) std::cout << "[pintool] Tracing leaks" << std::endl; - /* calling loadLeaks via PIN_AddApplicationStartFunction. - * This ensures the program under instrumentation is already completely loaded - * before loadLeaks is called, thus preserving the order (and thus - * the memory layout) in which shared libraries are loaded. - */ - PIN_AddApplicationStartFunction(loadLeaks, 0); - INS_AddInstrumentFunction(instrumentLeakingInstructions, 0); - } +int main(int argc, char *argv[]) { + if (PIN_Init(argc, argv)) + return Usage(); + + PIN_InitSymbols(); + + if (KnobLeaks.Value() && KnobCallstack.Value()) { + leaks = new CallStack(); + use_callstack = true; + } else { + leaks = new Flat(); + use_callstack = false; + } + IMG_AddInstrumentFunction(instrumentMainAndAlloc, 0); + if (!KnobSyms.Value().empty()) { + imgfile.open(KnobSyms.Value().c_str()); + } + if (!KnobVDSO.Value().empty()) { + vdsofile.open(KnobVDSO.Value().c_str()); + } - PIN_AddThreadStartFunction(ThreadStart, 0); - PIN_AddThreadFiniFunction(ThreadFini, 0); - PIN_AddFiniFunction(Fini, 0); + if (!KnobLeaks.Value()) { + /* Traditional tracing */ + if (KnobBbl.Value() || KnobMem.Value() || KnobFunc.Value()) { + INS_AddInstrumentFunction(instrumentAnyInstructions, 0); + } + } else { + /* Tracing only leaks specified by leak file */ + DEBUG(1) std::cout << "[pintool] Tracing leaks" << std::endl; + /* calling loadLeaks via PIN_AddApplicationStartFunction. + * This ensures the program under instrumentation is already completely + * loaded before loadLeaks is called, thus preserving the order (and + * thus the memory layout) in which shared libraries are loaded. + */ + PIN_AddApplicationStartFunction(loadLeaks, 0); + INS_AddInstrumentFunction(instrumentLeakingInstructions, 0); + } - init(); - PIN_StartProgram(); + PIN_AddThreadStartFunction(ThreadStart, 0); + PIN_AddThreadFiniFunction(ThreadFini, 0); + PIN_AddFiniFunction(Fini, 0); - return 0; + init(); + PIN_StartProgram(); + + return 0; }