Intel pin:如何检测重新分配的大小
Intel pin: how to detect realloc size
我有一个下面的 pin 工具,比如 trace.cpp
(与 pin 工具 manual 中的完全一样):
#include "pin.H"
#include <iostream>
#include <fstream>
/* ===================================================================== */
/* Names of malloc and free */
/* ===================================================================== */
#if defined(TARGET_MAC)
#define MALLOC "_malloc"
#define FREE "_free"
#else
#define MALLOC "malloc"
#define FREE "free"
#endif
/* ===================================================================== */
/* Global Variables */
/* ===================================================================== */
std::ofstream TraceFile;
/* ===================================================================== */
/* Commandline Switches */
/* ===================================================================== */
KNOB<string> KnobOutputFile(KNOB_MODE_WRITEONCE, "pintool",
"o", "malloctrace.out", "specify trace file name");
/* ===================================================================== */
/* ===================================================================== */
/* Analysis routines */
/* ===================================================================== */
VOID Arg1Before(CHAR * name, ADDRINT size)
{
std::cout << name << "(" << size << ")" << endl;
}
VOID MallocAfter(ADDRINT ret)
{
std::cout << " returns " << ret << endl;
}
/* ===================================================================== */
/* Instrumentation routines */
/* ===================================================================== */
VOID Image(IMG img, VOID *v)
{
// Instrument the malloc() and free() functions. Print the input argument
// of each malloc() or free(), and the return value of malloc().
//
// Find the malloc() function.
RTN mallocRtn = RTN_FindByName(img, MALLOC);
if (RTN_Valid(mallocRtn))
{
RTN_Open(mallocRtn);
// Instrument malloc() to print the input argument value and the return value.
RTN_InsertCall(mallocRtn, IPOINT_BEFORE, (AFUNPTR)Arg1Before,
IARG_ADDRINT, MALLOC,
IARG_FUNCARG_ENTRYPOINT_VALUE, 0,
IARG_END);
RTN_InsertCall(mallocRtn, IPOINT_AFTER, (AFUNPTR)MallocAfter,
IARG_FUNCRET_EXITPOINT_VALUE, IARG_END);
RTN_Close(mallocRtn);
}
// Find the free() function.
RTN freeRtn = RTN_FindByName(img, FREE);
if (RTN_Valid(freeRtn))
{
RTN_Open(freeRtn);
// Instrument free() to print the input argument value.
RTN_InsertCall(freeRtn, IPOINT_BEFORE, (AFUNPTR)Arg1Before,
IARG_ADDRINT, FREE,
IARG_FUNCARG_ENTRYPOINT_VALUE, 0,
IARG_END);
RTN_Close(freeRtn);
}
}
/* ===================================================================== */
VOID Fini(INT32 code, VOID *v)
{
TraceFile.close();
}
/* ===================================================================== */
/* Print Help Message */
/* ===================================================================== */
INT32 Usage()
{
cerr << "This tool produces a trace of calls to malloc." << endl;
cerr << endl << KNOB_BASE::StringKnobSummary() << endl;
return -1;
}
/* ===================================================================== */
/* Main */
/* ===================================================================== */
int main(int argc, char *argv[])
{
// Initialize pin & symbol manager
PIN_InitSymbols();
if( PIN_Init(argc,argv) )
{
return Usage();
}
// Write to a file since cout and cerr maybe closed by the application
TraceFile.open(KnobOutputFile.Value().c_str());
TraceFile << hex;
TraceFile.setf(ios::showbase);
// Register Image to be called to instrument functions.
IMG_AddInstrumentFunction(Image, 0);
PIN_AddFiniFunction(Fini, 0);
// Never returns
PIN_StartProgram();
return 0;
}
(唯一的变化是它打印而不是将其存储在输出文件中)
我有以下 C 代码示例 - example.c
:
#include <stdio.h>
#include <stdlib.h>
struct A {
int x[10];
int y[1];
};
int main()
{
struct A *ptr = calloc(1, sizeof(struct A));
ptr->x[10] = 4;
printf("%i\n", ptr->x[10]);
ptr = realloc(ptr, sizeof(int));
ptr->x[10] = 4;
printf("%i\n", ptr->x[10]);
free(ptr);
return 0;
}
当我使用图钉工具 运行 时,它会产生以下输出:
$ pin -t obj-intel64/trace.so -- ./example.o | tail
returns 139865991781744
malloc(272)
returns 139865991785984
malloc(44)
returns 33456736
malloc(4096)
returns 33456800
free(33456736)
4
4
注意两个 malloc
调用:
malloc(44)
malloc(4096)
它完美地检测到第一个(注意 c 代码中的 calloc 调用),但它检测到 4096 的 realloc(如果我在这里错了请纠正我)。但是,我相信它应该检测到 4 (sizeof int)。
我哪里错了?有什么方法可以检测到正确的尺寸(或者我在这里遗漏了什么)?
我对该工具进行了以下更改:
#include "pin.H"
#include <iostream>
#include <fstream>
/* ===================================================================== */
/* Names of malloc and free */
/* ===================================================================== */
#if defined(TARGET_MAC)
#define MALLOC "_malloc"
#define FREE "_free"
#else
#define MALLOC "malloc"
#define FREE "free"
#endif
/* ===================================================================== */
/* Global Variables */
/* ===================================================================== */
std::ofstream TraceFile;
/* ===================================================================== */
/* Commandline Switches */
/* ===================================================================== */
KNOB<string> KnobOutputFile(KNOB_MODE_WRITEONCE, "pintool",
"o", "malloctrace.out", "specify trace file name");
/* ===================================================================== */
/* ===================================================================== */
/* Analysis routines */
/* ===================================================================== */
VOID Arg1Before(CHAR * name, ADDRINT addr, ADDRINT size, ADDRINT return_ip)
{
std::cout << name << " : " << addr << "(" << size << ")" << " : " << return_ip << endl;
}
VOID MallocAfter(ADDRINT ret)
{
std::cout << " returns " << ret << endl;
}
/* ===================================================================== */
/* Instrumentation routines */
/* ===================================================================== */
VOID Image(IMG img, VOID *v)
{
// Instrument the malloc() and free() functions. Print the input argument
// of each malloc() or free(), and the return value of malloc().
//
// Find the malloc() function.
RTN mallocRtn = RTN_FindByName(img, "realloc");
if (RTN_Valid(mallocRtn))
{
RTN_Open(mallocRtn);
// Instrument malloc() to print the input argument value and the return value.
RTN_InsertCall(mallocRtn, IPOINT_BEFORE, (AFUNPTR)Arg1Before,
IARG_ADDRINT, "realloc",
IARG_FUNCARG_ENTRYPOINT_VALUE, 0,
IARG_FUNCARG_ENTRYPOINT_VALUE, 1,
IARG_END);
RTN_InsertCall(mallocRtn, IPOINT_AFTER, (AFUNPTR)MallocAfter,
IARG_FUNCRET_EXITPOINT_VALUE, IARG_END);
RTN_Close(mallocRtn);
}
// Find the free() function.
RTN freeRtn = RTN_FindByName(img, FREE);
if (RTN_Valid(freeRtn))
{
RTN_Open(freeRtn);
// Instrument free() to print the input argument value.
RTN_InsertCall(freeRtn, IPOINT_BEFORE, (AFUNPTR)Arg1Before,
IARG_ADDRINT, FREE,
IARG_FUNCARG_ENTRYPOINT_VALUE, 0,
IARG_END);
RTN_Close(freeRtn);
}
}
/* ===================================================================== */
VOID Fini(INT32 code, VOID *v)
{
TraceFile.close();
}
/* ===================================================================== */
/* Print Help Message */
/* ===================================================================== */
INT32 Usage()
{
cerr << "This tool produces a trace of calls to malloc." << endl;
cerr << endl << KNOB_BASE::StringKnobSummary() << endl;
return -1;
}
/* ===================================================================== */
/* Main */
/* ===================================================================== */
int main(int argc, char *argv[])
{
// Initialize pin & symbol manager
PIN_InitSymbols();
if( PIN_Init(argc,argv) )
{
return Usage();
}
// Write to a file since cout and cerr maybe closed by the application
TraceFile.open(KnobOutputFile.Value().c_str());
TraceFile << hex;
TraceFile.setf(ios::showbase);
// Register Image to be called to instrument functions.
IMG_AddInstrumentFunction(Image, 0);
PIN_AddFiniFunction(Fini, 0);
// Never returns
PIN_StartProgram();
return 0;
}
我通过“realloc”找到例程名称,而不是“malloc”,然后通过:
IARG_FUNCARG_ENTRYPOINT_VALUE, 0,
IARG_FUNCARG_ENTRYPOINT_VALUE, 1,
函数 Arg1Before
,检测 realloc
函数调用的两个参数。
然后在Arg1Before
函数中:
VOID Arg1Before(CHAR * name, ADDRINT addr, ADDRINT size, ADDRINT return_ip)
这里,size
是分配的内存大小,addr
是指针的地址,return_ip
是return指令指针的地址。
您正在使用跟踪工具跟踪对 malloc
和 free
的实际调用。您似乎没有跟踪对 calloc
和 realloc
的调用,大概是基于这些函数最终会调用 malloc
的假设。
但这不一定是真的。例如,如果 realloc
检测到现有的内存块已经足够大,可以满足请求,它可以 return 它的第一个参数而不做任何更多的事情,所以你不会看到对 malloc 的任何调用.这显然是您的示例中发生的情况,因为您的 realloc
调用请求的内存少于 calloc
分配的内存,并且我们可以看到它没有在此处执行此操作,因为 [=] 的地址18=] 当调用 free
时与 calloc
.
分配的块相同
如果现有分配比请求大得多,realloc
可能会选择将块复制到更小的分配中,可能使用 malloc
获得。 .但即使 realloc
确实决定减少已分配内存的大小,也不能保证它需要新的分配。在某些实现中,可以拆分现有块,将不需要的部分添加到空闲列表中。这不会涉及调用 free
或 malloc
.
那么,如果 malloc(4096)
不是来自 realloc
,那么它是从哪里来的呢?最有可能的答案是 malloc
是从标准库中调用的。例如,printf
可能已经注意到它需要为 stdout
分配一个输出缓冲区,因此它调用 malloc
来获取一些内存。
简而言之,您可能需要跟踪所有内存管理函数才能清楚地了解正在发生的事情。
我有一个下面的 pin 工具,比如 trace.cpp
(与 pin 工具 manual 中的完全一样):
#include "pin.H"
#include <iostream>
#include <fstream>
/* ===================================================================== */
/* Names of malloc and free */
/* ===================================================================== */
#if defined(TARGET_MAC)
#define MALLOC "_malloc"
#define FREE "_free"
#else
#define MALLOC "malloc"
#define FREE "free"
#endif
/* ===================================================================== */
/* Global Variables */
/* ===================================================================== */
std::ofstream TraceFile;
/* ===================================================================== */
/* Commandline Switches */
/* ===================================================================== */
KNOB<string> KnobOutputFile(KNOB_MODE_WRITEONCE, "pintool",
"o", "malloctrace.out", "specify trace file name");
/* ===================================================================== */
/* ===================================================================== */
/* Analysis routines */
/* ===================================================================== */
VOID Arg1Before(CHAR * name, ADDRINT size)
{
std::cout << name << "(" << size << ")" << endl;
}
VOID MallocAfter(ADDRINT ret)
{
std::cout << " returns " << ret << endl;
}
/* ===================================================================== */
/* Instrumentation routines */
/* ===================================================================== */
VOID Image(IMG img, VOID *v)
{
// Instrument the malloc() and free() functions. Print the input argument
// of each malloc() or free(), and the return value of malloc().
//
// Find the malloc() function.
RTN mallocRtn = RTN_FindByName(img, MALLOC);
if (RTN_Valid(mallocRtn))
{
RTN_Open(mallocRtn);
// Instrument malloc() to print the input argument value and the return value.
RTN_InsertCall(mallocRtn, IPOINT_BEFORE, (AFUNPTR)Arg1Before,
IARG_ADDRINT, MALLOC,
IARG_FUNCARG_ENTRYPOINT_VALUE, 0,
IARG_END);
RTN_InsertCall(mallocRtn, IPOINT_AFTER, (AFUNPTR)MallocAfter,
IARG_FUNCRET_EXITPOINT_VALUE, IARG_END);
RTN_Close(mallocRtn);
}
// Find the free() function.
RTN freeRtn = RTN_FindByName(img, FREE);
if (RTN_Valid(freeRtn))
{
RTN_Open(freeRtn);
// Instrument free() to print the input argument value.
RTN_InsertCall(freeRtn, IPOINT_BEFORE, (AFUNPTR)Arg1Before,
IARG_ADDRINT, FREE,
IARG_FUNCARG_ENTRYPOINT_VALUE, 0,
IARG_END);
RTN_Close(freeRtn);
}
}
/* ===================================================================== */
VOID Fini(INT32 code, VOID *v)
{
TraceFile.close();
}
/* ===================================================================== */
/* Print Help Message */
/* ===================================================================== */
INT32 Usage()
{
cerr << "This tool produces a trace of calls to malloc." << endl;
cerr << endl << KNOB_BASE::StringKnobSummary() << endl;
return -1;
}
/* ===================================================================== */
/* Main */
/* ===================================================================== */
int main(int argc, char *argv[])
{
// Initialize pin & symbol manager
PIN_InitSymbols();
if( PIN_Init(argc,argv) )
{
return Usage();
}
// Write to a file since cout and cerr maybe closed by the application
TraceFile.open(KnobOutputFile.Value().c_str());
TraceFile << hex;
TraceFile.setf(ios::showbase);
// Register Image to be called to instrument functions.
IMG_AddInstrumentFunction(Image, 0);
PIN_AddFiniFunction(Fini, 0);
// Never returns
PIN_StartProgram();
return 0;
}
(唯一的变化是它打印而不是将其存储在输出文件中)
我有以下 C 代码示例 - example.c
:
#include <stdio.h>
#include <stdlib.h>
struct A {
int x[10];
int y[1];
};
int main()
{
struct A *ptr = calloc(1, sizeof(struct A));
ptr->x[10] = 4;
printf("%i\n", ptr->x[10]);
ptr = realloc(ptr, sizeof(int));
ptr->x[10] = 4;
printf("%i\n", ptr->x[10]);
free(ptr);
return 0;
}
当我使用图钉工具 运行 时,它会产生以下输出:
$ pin -t obj-intel64/trace.so -- ./example.o | tail
returns 139865991781744
malloc(272)
returns 139865991785984
malloc(44)
returns 33456736
malloc(4096)
returns 33456800
free(33456736)
4
4
注意两个 malloc
调用:
malloc(44)
malloc(4096)
它完美地检测到第一个(注意 c 代码中的 calloc 调用),但它检测到 4096 的 realloc(如果我在这里错了请纠正我)。但是,我相信它应该检测到 4 (sizeof int)。
我哪里错了?有什么方法可以检测到正确的尺寸(或者我在这里遗漏了什么)?
我对该工具进行了以下更改:
#include "pin.H"
#include <iostream>
#include <fstream>
/* ===================================================================== */
/* Names of malloc and free */
/* ===================================================================== */
#if defined(TARGET_MAC)
#define MALLOC "_malloc"
#define FREE "_free"
#else
#define MALLOC "malloc"
#define FREE "free"
#endif
/* ===================================================================== */
/* Global Variables */
/* ===================================================================== */
std::ofstream TraceFile;
/* ===================================================================== */
/* Commandline Switches */
/* ===================================================================== */
KNOB<string> KnobOutputFile(KNOB_MODE_WRITEONCE, "pintool",
"o", "malloctrace.out", "specify trace file name");
/* ===================================================================== */
/* ===================================================================== */
/* Analysis routines */
/* ===================================================================== */
VOID Arg1Before(CHAR * name, ADDRINT addr, ADDRINT size, ADDRINT return_ip)
{
std::cout << name << " : " << addr << "(" << size << ")" << " : " << return_ip << endl;
}
VOID MallocAfter(ADDRINT ret)
{
std::cout << " returns " << ret << endl;
}
/* ===================================================================== */
/* Instrumentation routines */
/* ===================================================================== */
VOID Image(IMG img, VOID *v)
{
// Instrument the malloc() and free() functions. Print the input argument
// of each malloc() or free(), and the return value of malloc().
//
// Find the malloc() function.
RTN mallocRtn = RTN_FindByName(img, "realloc");
if (RTN_Valid(mallocRtn))
{
RTN_Open(mallocRtn);
// Instrument malloc() to print the input argument value and the return value.
RTN_InsertCall(mallocRtn, IPOINT_BEFORE, (AFUNPTR)Arg1Before,
IARG_ADDRINT, "realloc",
IARG_FUNCARG_ENTRYPOINT_VALUE, 0,
IARG_FUNCARG_ENTRYPOINT_VALUE, 1,
IARG_END);
RTN_InsertCall(mallocRtn, IPOINT_AFTER, (AFUNPTR)MallocAfter,
IARG_FUNCRET_EXITPOINT_VALUE, IARG_END);
RTN_Close(mallocRtn);
}
// Find the free() function.
RTN freeRtn = RTN_FindByName(img, FREE);
if (RTN_Valid(freeRtn))
{
RTN_Open(freeRtn);
// Instrument free() to print the input argument value.
RTN_InsertCall(freeRtn, IPOINT_BEFORE, (AFUNPTR)Arg1Before,
IARG_ADDRINT, FREE,
IARG_FUNCARG_ENTRYPOINT_VALUE, 0,
IARG_END);
RTN_Close(freeRtn);
}
}
/* ===================================================================== */
VOID Fini(INT32 code, VOID *v)
{
TraceFile.close();
}
/* ===================================================================== */
/* Print Help Message */
/* ===================================================================== */
INT32 Usage()
{
cerr << "This tool produces a trace of calls to malloc." << endl;
cerr << endl << KNOB_BASE::StringKnobSummary() << endl;
return -1;
}
/* ===================================================================== */
/* Main */
/* ===================================================================== */
int main(int argc, char *argv[])
{
// Initialize pin & symbol manager
PIN_InitSymbols();
if( PIN_Init(argc,argv) )
{
return Usage();
}
// Write to a file since cout and cerr maybe closed by the application
TraceFile.open(KnobOutputFile.Value().c_str());
TraceFile << hex;
TraceFile.setf(ios::showbase);
// Register Image to be called to instrument functions.
IMG_AddInstrumentFunction(Image, 0);
PIN_AddFiniFunction(Fini, 0);
// Never returns
PIN_StartProgram();
return 0;
}
我通过“realloc”找到例程名称,而不是“malloc”,然后通过:
IARG_FUNCARG_ENTRYPOINT_VALUE, 0,
IARG_FUNCARG_ENTRYPOINT_VALUE, 1,
函数 Arg1Before
,检测 realloc
函数调用的两个参数。
然后在Arg1Before
函数中:
VOID Arg1Before(CHAR * name, ADDRINT addr, ADDRINT size, ADDRINT return_ip)
这里,size
是分配的内存大小,addr
是指针的地址,return_ip
是return指令指针的地址。
您正在使用跟踪工具跟踪对 malloc
和 free
的实际调用。您似乎没有跟踪对 calloc
和 realloc
的调用,大概是基于这些函数最终会调用 malloc
的假设。
但这不一定是真的。例如,如果 realloc
检测到现有的内存块已经足够大,可以满足请求,它可以 return 它的第一个参数而不做任何更多的事情,所以你不会看到对 malloc 的任何调用.这显然是您的示例中发生的情况,因为您的 realloc
调用请求的内存少于 calloc
分配的内存,并且我们可以看到它没有在此处执行此操作,因为 [=] 的地址18=] 当调用 free
时与 calloc
.
如果现有分配比请求大得多,realloc
可能会选择将块复制到更小的分配中,可能使用 malloc
获得。 .但即使 realloc
确实决定减少已分配内存的大小,也不能保证它需要新的分配。在某些实现中,可以拆分现有块,将不需要的部分添加到空闲列表中。这不会涉及调用 free
或 malloc
.
那么,如果 malloc(4096)
不是来自 realloc
,那么它是从哪里来的呢?最有可能的答案是 malloc
是从标准库中调用的。例如,printf
可能已经注意到它需要为 stdout
分配一个输出缓冲区,因此它调用 malloc
来获取一些内存。
简而言之,您可能需要跟踪所有内存管理函数才能清楚地了解正在发生的事情。