线程间的共享内存
The shared memory between threads
我使用 Intel 工具 Pin
来检测多线程进程并监控 Linux 上线程之间的共享内存访问,我在 Pin
中开发了一个工具来记录共享内存地址,Pin中检测代码如下:
VOID Instruction(INS ins, VOID *v)
{
UINT32 memOperands = INS_MemoryOperandCount(ins);
// Iterate over each memory operand of the instruction.
for (UINT32 memOp = 0; memOp < memOperands; memOp++)
{
if (INS_MemoryOperandIsRead(ins, memOp))
{
INS_InsertPredicatedCall(
ins, IPOINT_BEFORE, (AFUNPTR)RecordMemRead,
IARG_INST_PTR,
IARG_MEMORYOP_EA, memOp,
IARG_END);
}
// Note that in some architectures a single memory operand can be
// both read and written (for instance incl (%eax) on IA-32)
// In that case we instrument it once for read and once for write.
if (INS_MemoryOperandIsWritten(ins, memOp))
{
INS_InsertPredicatedCall(
ins, IPOINT_BEFORE, (AFUNPTR)RecordMemWrite,
IARG_INST_PTR,
IARG_MEMORYOP_EA, memOp,
IARG_END);
}
}
}
函数RecordMemRead
和RecordMemWrite
是用来记录线程的信息和读写内存时的内存地址,我在这个函数中使用了lock。
我想记录线程间共享的内存地址,比如全局变量或者堆内存。
但是当我使用一个简单的多线程程序来测试我的工具时。测试如下。在这个程序中,用户没有定义任何共享变量或共享内存:
#include <stdio.h>
#include <pthread.h>
#include <unistd.h>
#include <stdlib.h>
void * fun1(void *arg)
{
}
int main(int argc,char* argv[])
{
pthread_t npid1;
pthread_create(&npid1,NULL,fun1,NULL);
pthread_join(npid1,NULL);
return 0;
}
结果表示多线程访问过的内存,下一行输出内存访问指令的调试信息:
read addr: b775252c
line:0 col: 0 file:
write addr: b775252c
line:0 col: 0 file:
write addr: b775252c
line:0 col: 0 file:
write addr: b775252c
line:0 col: 0 file:
write addr: b775252c
line:0 col: 0 file:
write addr: b775252c
line:0 col: 0 file:
write addr: b775252c
line:0 col: 0 file:
read addr: b556ad64
line:0 col: 0 file:
read addr: b556abc4
line:0 col: 0 file:
write addr: b556abc4
line:0 col: 0 file:
结果表明两个线程都访问了一些内存,而read/write指令没有调试信息(我在编译时添加了-g选项),所以这些内存可能是由库访问的
Q1:哪些线程使用这些内存?
Q2:如果我只想监控用户定义的内存,没有在库中定义,如何区分?
- 显然,您需要有关这些地址中发生的事情的更多信息。我建议使用 pin 的 RTN_* 和 IMG API 来获取有关正在执行的例程的更多信息,然后在反汇编程序中检查相关图像。
- 您可以按代码源过滤访问,而不是按内存过滤。简单地避免检测作为系统库一部分的指令。
关于评论中的讨论,还应考虑您未检测库使用的同步机制的情况。
我使用 Intel 工具 Pin
来检测多线程进程并监控 Linux 上线程之间的共享内存访问,我在 Pin
中开发了一个工具来记录共享内存地址,Pin中检测代码如下:
VOID Instruction(INS ins, VOID *v)
{
UINT32 memOperands = INS_MemoryOperandCount(ins);
// Iterate over each memory operand of the instruction.
for (UINT32 memOp = 0; memOp < memOperands; memOp++)
{
if (INS_MemoryOperandIsRead(ins, memOp))
{
INS_InsertPredicatedCall(
ins, IPOINT_BEFORE, (AFUNPTR)RecordMemRead,
IARG_INST_PTR,
IARG_MEMORYOP_EA, memOp,
IARG_END);
}
// Note that in some architectures a single memory operand can be
// both read and written (for instance incl (%eax) on IA-32)
// In that case we instrument it once for read and once for write.
if (INS_MemoryOperandIsWritten(ins, memOp))
{
INS_InsertPredicatedCall(
ins, IPOINT_BEFORE, (AFUNPTR)RecordMemWrite,
IARG_INST_PTR,
IARG_MEMORYOP_EA, memOp,
IARG_END);
}
}
}
函数RecordMemRead
和RecordMemWrite
是用来记录线程的信息和读写内存时的内存地址,我在这个函数中使用了lock。
我想记录线程间共享的内存地址,比如全局变量或者堆内存。
但是当我使用一个简单的多线程程序来测试我的工具时。测试如下。在这个程序中,用户没有定义任何共享变量或共享内存:
#include <stdio.h>
#include <pthread.h>
#include <unistd.h>
#include <stdlib.h>
void * fun1(void *arg)
{
}
int main(int argc,char* argv[])
{
pthread_t npid1;
pthread_create(&npid1,NULL,fun1,NULL);
pthread_join(npid1,NULL);
return 0;
}
结果表示多线程访问过的内存,下一行输出内存访问指令的调试信息:
read addr: b775252c
line:0 col: 0 file:
write addr: b775252c
line:0 col: 0 file:
write addr: b775252c
line:0 col: 0 file:
write addr: b775252c
line:0 col: 0 file:
write addr: b775252c
line:0 col: 0 file:
write addr: b775252c
line:0 col: 0 file:
write addr: b775252c
line:0 col: 0 file:
read addr: b556ad64
line:0 col: 0 file:
read addr: b556abc4
line:0 col: 0 file:
write addr: b556abc4
line:0 col: 0 file:
结果表明两个线程都访问了一些内存,而read/write指令没有调试信息(我在编译时添加了-g选项),所以这些内存可能是由库访问的
Q1:哪些线程使用这些内存?
Q2:如果我只想监控用户定义的内存,没有在库中定义,如何区分?
- 显然,您需要有关这些地址中发生的事情的更多信息。我建议使用 pin 的 RTN_* 和 IMG API 来获取有关正在执行的例程的更多信息,然后在反汇编程序中检查相关图像。
- 您可以按代码源过滤访问,而不是按内存过滤。简单地避免检测作为系统库一部分的指令。
关于评论中的讨论,还应考虑您未检测库使用的同步机制的情况。