From 782c8558a6da514148c35ccbbe30390b32577cd4 Mon Sep 17 00:00:00 2001 From: "Sasha Nicolas (zeroah)" Date: Tue, 15 Jun 2021 11:02:33 -0500 Subject: [PATCH] Fix checkStack() to perform the necessary checks. Fix test_stack_* expected stacks. --- src/dyninst/dyninst_comp.C | 203 ++++++++++++++++++------------------- src/dyninst/dyninst_comp.h | 2 - src/dyninst/test_stack_1.C | 17 ++-- src/dyninst/test_stack_2.C | 23 ++--- src/dyninst/test_stack_3.C | 23 ++--- src/dyninst/test_stack_4.C | 25 ++--- 6 files changed, 134 insertions(+), 159 deletions(-) diff --git a/src/dyninst/dyninst_comp.C b/src/dyninst/dyninst_comp.C index 5d157633e..59ce20dbf 100644 --- a/src/dyninst/dyninst_comp.C +++ b/src/dyninst/dyninst_comp.C @@ -1426,123 +1426,116 @@ const char *fixUnderscores(const char *str) return buf; } -bool checkStack(BPatch_thread *appThread, - const frameInfo_t correct_frame_info[], - unsigned num_correct_names, - int test_num, const char *test_name) +// Check is for each call in expected stack, the same amount of call is in +// the collected stack. This prevents wrong recursion frames. +bool hasSameAmountOfCalls(vector & stack, + vector expected_stack) { - unsigned i, j; + // count occurances of functions in expected_stack + unordered_map expected_count; + for(const frameInfo_t frame : expected_stack) + expected_count[frame.function_name]++; - const int name_max = 256; - bool failed = false; + // go through stack frames and decrement count of expected + for(auto& frame: stack) + { + BPatch_function *func = frame.findFunction(); + string name = func ? func->getName() : ""; + if(expected_count.find(name)==expected_count.end()) continue; + expected_count[name]--; + } - BPatch_Vector stack; - appThread->getCallStack(stack); + // count if all are zero + for(const frameInfo_t frame : expected_stack) + if(expected_count[frame.function_name]!=0) return false; - if (1) { - dprintf("Stack in test %d (%s):\n", test_num, test_name); - for( unsigned i = 0; i < stack.size(); i++) { - char name[name_max]; - BPatch_function *func = stack[i].findFunction(); - if (func == NULL) - strcpy(name, "[UNKNOWN]"); - else - func->getName(name, name_max); - dprintf(" %10p: %s, fp = %p, type %s\n", - stack[i].getPC(), - name, - stack[i].getFP(), - frameTypeString(stack[i].getFrameType())); + return true; +} - } - dprintf("End of stack dump.\n"); - } +// Makes sure the expected stack is subsequence of collected stack +bool isSubsequenceStack(vector & stack, unsigned size, + const frameInfo_t expected_stack[], unsigned expected_size) +{ + if(size==0) return false; + if(expected_size==0) return true; - if (stack.size() < num_correct_names) { - logerror("**Failed** test %d (%s)\n", test_num, test_name); - logerror(" Stack trace should contain more frames.\n"); - failed = true; - } + BPatch_function *func = stack[size-1].findFunction(); + string name = func ? func->getName() : ""; + + if(name==expected_stack[expected_size-1].function_name || + (expected_stack[expected_size-1].type==BPatch_frameTrampoline && + stack[size-1].getFrameType()==BPatch_frameTrampoline) || + (expected_stack[expected_size-1].type==BPatch_frameSignal && + stack[size-1].getFrameType()==BPatch_frameSignal)) + { + return isSubsequenceStack(stack, size-1, expected_stack, expected_size-1); + } + + return isSubsequenceStack(stack, size-1, expected_stack, expected_size); +} + +bool checkStack(BPatch_thread *appThread, + const frameInfo_t correct_frame_info[], + unsigned num_correct_names, + int test_num, const char *test_name) +{ + bool failed = false; + + BPatch_Vector stack; + appThread->getCallStack(stack); + + // Print out stack to "-verbose" log + dprintf("Stack in test %d (%s):\n", test_num, test_name); + for( unsigned i = 0; i < stack.size(); i++) { + BPatch_function *func = stack[i].findFunction(); + string name = func ? func->getName() : "[UNKNOWN]"; + dprintf(" %10p: %s, fp = %p, type %s\n", + stack[i].getPC(), + name.c_str(), + stack[i].getFP(), + frameTypeString(stack[i].getFrameType())); + + } + dprintf("End of stack dump.\n"); + + // check if stack is at least same size of correct_frame_info + if (stack.size() < num_correct_names) { + logerror("**Failed** test %d (%s)\n", test_num, test_name); + logerror(" Stack trace should contain more frames.\n"); + failed = true; + } - for (i = 0, j = 0; i < num_correct_names; i++, j++) { #if !defined(i386_unknown_nt4_0_test) - if (stack.size() && j < stack.size()-1 && stack[j].getFP() == 0) { - logerror("**Failed** test %d (%s)\n", test_num, test_name); - logerror(" A stack frame other than the lowest has a null FP.\n"); - failed = true; - break; - } + // check if any if the frames, except the last one, has FP!=0 + for (unsigned j = 0; j < num_correct_names; j++) + { + if (stack.size() && j < stack.size()-1 && stack[j].getFP() == 0) { + logerror("**Failed** test %d (%s)\n", test_num, test_name); + logerror(" A stack frame other than the lowest has a null FP.\n"); + failed = true; + break; + } + } // for #endif - if (stack.size() >= j) - break; - if (correct_frame_info[i].valid) { - char name[name_max], name2[name_max]; - - BPatch_function *func = stack[j].findFunction(); - if (func != NULL) - func->getName(name, name_max); - - BPatch_function *func2 = - appThread->getProcess()->findFunctionByEntry(reinterpret_cast(stack[j].getPC())); - if (func2 != NULL) - func2->getName(name2, name_max); - - if ((func == NULL && func2 != NULL) || - (func != NULL && func2 == NULL)) { - logerror("**Failed** test %d (%s)\n", test_num, test_name); - logerror(" frame->findFunction() disagrees with thread->findFunctionByEntry()\n"); - logerror(" frame->findFunction() returns %s\n", - name); - logerror(" thread->findFunctionByEntry() return %s\n", - name2); - failed = true; - break; - } else if (func!=NULL && func2!=NULL && strcmp(name, name2)!=0) { - logerror("**Failed** test %d (%s)\n", test_num, test_name); - logerror(" BPatch_frame::findFunction disagrees with BPatch_thread::findFunctionByEntry\n"); - failed = true; - break; - } - - if (correct_frame_info[i].type != stack[j].getFrameType()) { - logerror("**Failed** test %d (%s)\n", test_num, test_name); - logerror(" Stack frame #%d has wrong type, is %s, should be %s\n", i+1, frameTypeString(stack[i].getFrameType()), frameTypeString(correct_frame_info[i].type)); - logerror(" Stack frame 0x%lx, 0x%lx\n", stack[i].getPC(), stack[i].getFP() ); - failed = true; - break; - } + // check if stack follows sequence in correct_frame_info + if(!isSubsequenceStack(stack, stack.size(), correct_frame_info, num_correct_names)) + { + logerror("**Failed** test %d (%s)\n", test_num, test_name); + logerror(" Collected stack does not contain expected stack.\n"); + failed = true; + } - if (stack[j].getFrameType() == BPatch_frameSignal || - stack[j].getFrameType() == BPatch_frameTrampoline) { - // No further checking for these types right now - } else { - if (func == NULL) { - logerror("**Failed** test %d (%s)\n", - test_num, test_name); - logerror(" Stack frame #%d refers to an unknown function, should refer to %s\n", j+1, correct_frame_info[i].function_name); - failed = true; - break; - } else { /* func != NULL */ - if (!hasExtraUnderscores(correct_frame_info[i].function_name)) - strncpy(name, fixUnderscores(name), name_max); - - if (strcmp(name, correct_frame_info[i].function_name) != 0) { - if (correct_frame_info[i].optional) { - j--; - continue; - } - logerror("**Failed** test %d (%s)\n", test_num, test_name); - logerror(" Stack frame #%d refers to function %s, should be %s\n", j+1, name, correct_frame_info[i].function_name); - failed = true; - break; - } - } - } - } - } + // check if each call in correct_frame_info has the same amount of calls in stack + vector expected_stack(correct_frame_info, correct_frame_info+num_correct_names); + if(!hasSameAmountOfCalls(stack, expected_stack)) + { + logerror("**Failed** test %d (%s)\n", test_num, test_name); + logerror(" Possibly duplicate (case of wrong recursion) in collected stack. "); + failed = true; + } - return !failed; + return !failed; } /* End Test8 Specific */ diff --git a/src/dyninst/dyninst_comp.h b/src/dyninst/dyninst_comp.h index 664bdbea5..9921f4ac6 100644 --- a/src/dyninst/dyninst_comp.h +++ b/src/dyninst/dyninst_comp.h @@ -166,8 +166,6 @@ COMPLIB_DLL_EXPORT int instByteCnt(BPatch_addressSpace* as, const char* fname, COMPLIB_DLL_EXPORT int pointerSize(BPatch_image *img); typedef struct { - bool valid; - bool optional; BPatch_frameType type; const char *function_name; } frameInfo_t; diff --git a/src/dyninst/test_stack_1.C b/src/dyninst/test_stack_1.C index 8980b44ba..d22b0091b 100644 --- a/src/dyninst/test_stack_1.C +++ b/src/dyninst/test_stack_1.C @@ -61,20 +61,17 @@ extern "C" DLLEXPORT TestMutator *test_stack_1_factory() { test_results_t test_stack_1_Mutator::executeTest() { appProc->continueExecution(); static const frameInfo_t correct_frame_info[] = { -#if defined( os_linux_test ) && (defined( arch_x86_test ) || defined( arch_x86_64_test )) - { true, true, BPatch_frameNormal, "_dl_sysinfo_int80" }, -#endif #if !defined(rs6000_ibm_aix4_1_test) - { false, false, BPatch_frameNormal, NULL }, + { BPatch_frameNormal, "" }, #endif #if !defined(i386_unknown_nt4_0_test) - { true, false, BPatch_frameNormal, "stop_process_" }, + { BPatch_frameNormal, "stop_process_" }, #endif - { true, false, BPatch_frameNormal, "test_stack_1_func3" }, - { true, false, BPatch_frameNormal, "test_stack_1_func2" }, - { true, false, BPatch_frameNormal, "test_stack_1_func1" }, - { true, false, BPatch_frameNormal, "test_stack_1_mutateeTest" }, - { true, false, BPatch_frameNormal, "main" }, + { BPatch_frameNormal, "test_stack_1_func3" }, + { BPatch_frameNormal, "test_stack_1_func2" }, + { BPatch_frameNormal, "test_stack_1_func1" }, + { BPatch_frameNormal, "test_stack_1_mutatee" }, + { BPatch_frameNormal, "main" }, }; if (waitUntilStopped(bpatch, appProc, 1, "getCallStack") < 0) { diff --git a/src/dyninst/test_stack_2.C b/src/dyninst/test_stack_2.C index 00c313829..1cb6fb0fe 100644 --- a/src/dyninst/test_stack_2.C +++ b/src/dyninst/test_stack_2.C @@ -63,21 +63,18 @@ test_results_t test_stack_2_Mutator::executeTest() { static const frameInfo_t correct_frame_info[] = { -#if defined( os_linux_test ) && (defined( arch_x86_test ) || defined( arch_x86_64_test )) - { true, true, BPatch_frameNormal, "_dl_sysinfo_int80" }, -#endif #if !defined(rs6000_ibm_aix4_1_test) - { false, false, BPatch_frameNormal, NULL }, + { BPatch_frameNormal, "" }, #endif - { true, false, BPatch_frameNormal, "stop_process_" }, - { true, false, BPatch_frameNormal, "test_stack_2_func4" }, - { true, false, BPatch_frameNormal, "sigalrm_handler" }, - { true, false, BPatch_frameSignal, NULL }, - { true, false, BPatch_frameNormal, "test_stack_2_func3" }, - { true, false, BPatch_frameNormal, "test_stack_2_func2" }, - { true, false, BPatch_frameNormal, "test_stack_2_func1" }, - { true, false, BPatch_frameNormal, "test_stack_2_mutateeTest" }, - { true, false, BPatch_frameNormal, "main" } + { BPatch_frameNormal, "stop_process_" }, + { BPatch_frameNormal, "test_stack_2_func4" }, + { BPatch_frameNormal, "sigalrm_handler" }, + { BPatch_frameSignal, "" }, + { BPatch_frameNormal, "test_stack_2_func3" }, + { BPatch_frameNormal, "test_stack_2_func2" }, + { BPatch_frameNormal, "test_stack_2_func1" }, + { BPatch_frameNormal, "test_stack_2_mutatee" }, + { BPatch_frameNormal, "main" } }; if (waitUntilStopped(bpatch, appProc, 2, "getCallStack in signal handler") < 0) { diff --git a/src/dyninst/test_stack_3.C b/src/dyninst/test_stack_3.C index 2615fa0e5..8fe8a4c15 100644 --- a/src/dyninst/test_stack_3.C +++ b/src/dyninst/test_stack_3.C @@ -69,9 +69,6 @@ test_results_t test_stack_3_Mutator::executeTest() { appProc->continueExecution(); static const frameInfo_t correct_frame_info[] = { -#if defined( os_linux_test ) && (defined( arch_x86_test ) || defined( arch_x86_64_test )) - { true, true, BPatch_frameNormal, "_dl_sysinfo_int80" }, -#endif #if defined( os_aix_test ) && defined( arch_power_test ) /* AIX uses kill(), but the PC of a process in a syscall can not be correctly determined, and appears to be the address @@ -79,25 +76,23 @@ test_results_t test_stack_3_Mutator::executeTest() { #elif defined( os_windows_test ) && (defined( arch_x86 ) || defined( arch_x86_64_test )) /* Windows/x86 does not use kill(), so its lowermost frame will be something unidentifiable in a system DLL. */ - { false, false, BPatch_frameNormal, NULL }, #else - { true, false, BPatch_frameNormal, "kill" }, + { BPatch_frameNormal, "kill" }, #endif #if ! defined( os_windows_test ) /* Windows/x86's stop_process_() calls DebugBreak(); it's apparently normal to lose this frame. */ - { true, false, BPatch_frameNormal, "stop_process_" }, + { BPatch_frameNormal, "stop_process_" }, #endif - { true, false, BPatch_frameNormal, "test_stack_3_func3" }, - { true, false, BPatch_frameTrampoline, NULL }, + { BPatch_frameNormal, "test_stack_3_func3" }, + { BPatch_frameTrampoline, "" }, /* On AIX and x86 (and others), if our instrumentation fires before frame construction or after frame destruction, it's - acceptable to not report the function (since, after all, it - doesn't have a frame on the stack. */ - { true, true, BPatch_frameNormal, "test_stack_3_func2" }, - { true, false, BPatch_frameNormal, "test_stack_3_func1" }, - { true, false, BPatch_frameNormal, "test_stack_3_mutateeTest" }, - { true, false, BPatch_frameNormal, "main" } + acceptable to not report the function "test_stack_3_func2" + (since, after all, it doesn't have a frame on the stack. */ + { BPatch_frameNormal, "test_stack_3_func1" }, + { BPatch_frameNormal, "test_stack_3_mutatee" }, + { BPatch_frameNormal, "main" } }; /* Wait for the mutatee to stop in test_stack_3_func1(). */ diff --git a/src/dyninst/test_stack_4.C b/src/dyninst/test_stack_4.C index a77f99228..dd83939e3 100644 --- a/src/dyninst/test_stack_4.C +++ b/src/dyninst/test_stack_4.C @@ -67,21 +67,16 @@ test_results_t test_stack_4_Mutator::executeTest() { BPatch::bpatch->setInstrStackFrames(true); appProc->continueExecution(); - static const frameInfo_t correct_frame_info[] = { - -#if defined( os_linux_test ) && (defined( arch_x86_test ) || defined( arch_x86_64_test )) - { true, true, BPatch_frameNormal, "_dl_sysinfo_int80" }, -#endif - { true, false, BPatch_frameNormal, "kill" }, - { true, false, BPatch_frameNormal, "test_stack_4_func4" }, - { true, false, BPatch_frameTrampoline, NULL }, - { true, false, BPatch_frameNormal, "test_stack_4_sigalrm_handler" }, - { true, false, BPatch_frameSignal, NULL }, - { true, true, BPatch_frameNormal, "test_stack_4_func3" }, - { true, true, BPatch_frameNormal, "test_stack_4_func2" }, - { true, false, BPatch_frameNormal, "test_stack_4_func1" }, - { true, false, BPatch_frameNormal, "test_stack_4_mutateeTest" }, - { true, false, BPatch_frameNormal, "main" } + static const frameInfo_t correct_frame_info[] = + { + { BPatch_frameNormal, "kill" }, + { BPatch_frameNormal, "test_stack_4_func4" }, + { BPatch_frameTrampoline, ""}, + { BPatch_frameNormal, "test_stack_4_sigalrm_handler" }, + { BPatch_frameSignal, ""}, + { BPatch_frameNormal, "test_stack_4_func1" }, + { BPatch_frameNormal, "test_stack_4_mutatee" }, + { BPatch_frameNormal, "main" } }; /* Wait for the mutatee to stop in test_stack_4_func1(). */