访问C中保存C ++对象的void指针的内容

时间:2012-10-16 16:59:35

标签: c++ c instrumentation

我正在使用C ++程序上的C客户端使用DynamoRIO进行二进制检测尽管您可能不需要了解DynamoRIO来回答我的问题。目前我是包装具有签名的函数:

virtual void foo(Klass& s)

然后在wrap函数中,我可以将此函数调用的参数调用(Klass& s)转换为void指针(void *arg1)。我需要使用这个参数(即访问字段,调用方法),但我无法将其转换为适当的指针,因为Klass是一个C ++类,而我正在使用的客户端是纯C.

当我尝试打印void*的内容时,将其投放到size_t,例如:

printf("%zd\n", (size_t)arg1);

它给了我一个8位数字,例如25102856,我猜它是一个记忆地址。

我的问题是如何在程序中访问此对象?

请询问您需要的所有信息,我对所有想法持开放态度。

3 个答案:

答案 0 :(得分:3)

要使其正常工作 - 为getter和setter定义C样式包装器,如下例所示:

为您的班级

class Klass {
public:
  int getA() const;
  void setA(int);
  virtua int getB() const;
};

定义包装此类的C结构:

typedef int (*GetInt)(void*);
typedef void (*SetInt)(void*,int);
// and similar for other types


struct KlassCInterface {
  void* object;
  GetInt getA;
  SetInt setA;
  GetInt getB;
};

extern "C" int getA(void* obj)
{
    return static_cast<Klass*>(klassObj)->getA();
}
...
KlassCInterface* getCInterface(Klass* obj)
{
   // malloc just in case your client want to use free()
   KlassCInterface* retVal = (KlassCInterface*)malloc(sizeof(KlassCInterface));
   retVal->object = obj;
   retVal->getA = &getA;
   ...
   return retVal;     
}

传递void * data时,将其作为C接口结构传递:

Klass* obj = new Klass(...);
KlassCInterface* objC = getCInterface(obj);

registerData(objC);

在您的C代码中 - 使用此C接口:

void doSthWihtKlass(void* data)
{
   KlassCInterface* objC  = (KlassCInterface*)data;
   printf("%d\n", objC->getA(objC->object));
}

答案 1 :(得分:1)

这应该很难做到。您将不得不了解底层的C ++ ABI。 G ++实现了this

通常,C ++类的实现与C中的结构类似。粗略地说,基类对象首先按其声明的顺序排列。然后,该类的所有其他子对象按其声明的顺序进入下一个。此规则以递归方式应用于每个封闭对象。多态对象将具有不同的布局,因为必须存储更多信息;特别是,指向虚方法的指针或指向包含这些指针的结构的指针必须存储在对象旁边。

请注意,ISO 14882并未解决这个问题。弄乱这一点肯定会引发未定义的行为。

关于调用虚方法,您必须查找v-table。再一次,从编译器中研究ABI。

答案 2 :(得分:1)

您需要了解有关指针语义的更多信息(这就是我认为@Alek的意思)。

首先,您可以使用%p printf格式说明符直接打印指针。这通常会产生一些有用的值,例如指针指向的内存位置。

您可以将指针强制转换为char *并使用它直接从内存中读取字节。或者您可以使用unsigned char *将其强制转换为%x并执行“十六进制转储”。您可以将它转换为int *并读取由C实现表示的整数 - 例如,可能是8位字节上的4字节2的补码小端符号整数,例如没有未使用的位。

例如,

((unsigned long *)(((short *) ptr) + 7))[4]将跳过等于7个短路大小加上4个无符号长整数的字节数,并从内存位置读取无符号长整数。假设unsigned long的正确表示(如C实现所期望的那样)被写入该确切的内存位置,您将获得其值。

您不仅必须确切地确定ptr所指向的内存中所写的内容(这就是提到ABI的原因),而且生成的程序将不可移植并受制于突发奇想地改变/休息。

您可能还需要<inttypes.h>标题中指定的精确宽度整数类型。