2. 如何对变参函数进行打桩
例如 uint32_t sql_exec_insert(char * format,char* a,...)
在该函数中有可能又要调用真实函数。
2.1 用实际的参数直接填写到真实的函数
int32_t stub_sql_exec_insert (char* funcname, char * format,char* a,...) { static int call_count= 0;
if(0 == g_stub_clear_flag) { call_count = 0; g_stub_clear_flag g = 1; }
call_count++;
if(g_stub_list_flag & (1<< call_count-1)) { return 1;//失败 } else { if(0==strcmp(funcname, "func_aaa")) return sql_exec_insert (format, a,XX,YY,ZZ); else return sql_exec_insert (format, a,XX,YY);
} } |
这时XX,YY,ZZ可以直接使用外面的用例驱动中定义的真实情况数值。
2.2 可变变参函数使用
int32_t stub_sql_exec_insert (char * format,char* a,...) { static int call_count= 0; char arg_buf[1024]; va_list arg_ptr; int32_t ret; if(0 == g_stub_clear_flag) { call_count = 0; g_stub_clear_flag g = 1; }
call_count++;
if(g_stub_list_flag & (1<< call_count-1)) { return 1;//失败 } else { va_list arg_ptr; va_start(arg_ptr, format); ret = sql_exec_insert (format, arg_ptr); va_end(arg_ptr); return ret; } } |
2.3 汇编实现
原理:指定调用方式为调用者压参数,退参数,然后拷贝参数,调完后再退栈。
int32_t stub_sql_exec_insert (char * format,char* a,...) { static int call_count= 0; int32_t __CPTR_result; typedef uint32_t(*__CPTR_FuncPtr)(void); if(0 == g_stub_clear_flag) { call_count = 0; g_stub_clear_flag g = 1; }
call_count++;
if(g_stub_list_flag & (1<< call_count-1)) { return 1;//失败 } else { __CPTR_FuncPtr __CPTR_funcPtr = (__CPTR_FuncPtr)& sql_exec_insert; __asm__( "\t""pushl %esi""\n" "\t""pushl %edi""\n" "\t""pushl %ecx""\n" "\t""subl %128,%esp "\n" "\t""lea 8(%ebp),%esi "\n" "\t""lea (%esp),%edi "\n" "\t""movl %32,%ecx "\n" "\t""cld"\n" "\t""rep"\n" "\t""movsl"\n" }; __CPTR_result = __CPTR_funcPtr(); __asm__( "\t""addl %128,%esp "\n" "\t""pop %ecx""\n" "\t""pop %edi""\n" "\t""pop %esi""\n" }; return __CPTR_result;
} } |
不过,这是在x86机器上运行的汇编指令。