让HotSpot生成固定的ReservedSpace地址可以更简单方便的调试汇编代码

ZHH2009 2014-07-30
HotSpot初始化阶段在src\share\vm\runtime\virtualspace.cpp的如下代码中生成ReservedSpace
ReservedSpace::ReservedSpace(size_t size, size_t alignment,
                             bool large,
                             bool executable) {
  initialize(size, alignment, large, NULL, 0, executable);
}

这种方式生成的地址是随机的,导致加上如下三个参数时
+PrintStubCode
+PrintAssembly
+PrintInterpreter

生成的汇编代码的地址也是随机的,不方便调试,
后来发现只要把前面的代码改成如下:
ReservedSpace::ReservedSpace(size_t size, size_t alignment,
                             bool large,
                             bool executable) {
  //0x01cd0000是requested_address
  initialize(size, alignment, large, (char *)0x01cd0000, 0, executable);
}

这样生成的汇编代码的地址每次都一样了,
比如StubRoutines::call_stub的汇编代码固定如下:
  //...
  ;; loop:
  0x01cd0425: mov    -0x4(%edx,%ecx,4),%eax
  0x01cd0429: mov    %eax,(%esp,%ebx,4)
  0x01cd042c: inc    %ebx
  0x01cd042d: dec    %ecx
  0x01cd042e: jne    0x01cd0425
  ;; parameters_done:
  0x01cd0430: mov    0x14(%ebp),%ebx
  0x01cd0433: mov    0x18(%ebp),%eax
  0x01cd0436: mov    %esp,%esi
  ;; call Java function
  0x01cd0438: call   *%eax
  //...
  ;; call_stub_return_address:


调试时,只要按地址打断点就能精确地到达你想要的那条汇编,
比如0x01cd0438对应的肯定是call   *%eax,从这里转到method entry point的汇编。

只不过有一点点缺陷,我用的是windows,
发现没有正确释放requested_address 对应的空间,
导致不是每次重启HotSpot时都成功,多试几次又好了。

requested_address从0x01cd0000换成0x7f00000成功次要多一些

我甚至在ReservedSpace::initialize中加了如下代码:
void initialize(size_t size, size_t alignment, bool large,
                  char* requested_address,
                  const size_t noaccess_prefix,
                  bool executable) {
  //...
    if (requested_address != 0) {
      unsigned int count = 10;

      while(count) {
        base = os::attempt_reserve_memory_at(size, requested_address);
        if (failed_to_reserve_as_requested(base, requested_address, size, false)) {
          // OS ignored requested address. Try different address.
          base = NULL;
          os::release_memory(requested_address, size);
          count--;
        } else {
          break;
        }
      }
    } else {
      base = os::reserve_memory(size, NULL, alignment);
    }

  //...
}
nijiaben 2014-07-30
不知道windows下是不是不一样,我在linux下没这个问题,产生的base地址都是一样的,还有你这么设置写死的话,这个构造函数被调用多次,也就第一次调用的时候能分配到那个地址吧

PS:我倒是觉得线程在刚start的时候会在栈空间上会随机分配一段内存,要想精准调试这个倒是可以控制一下,我的做法是将那随机分配的代码注释了
ZHH2009 2014-07-30
那个构造函数只调用一次,其他gc相关的不用这个构造函数,
如果不写死得到的各个stub的地址就不同了。

stub跟线程不相关吧,毕竟在生成stub时,都还没有java线程.
nijiaben 2014-07-30
恩,只有CodeCache会调用一下

我之前也碰到过类似的问题,也是希望调试汇编的时候,希望每次都能地址一致,我微薄之前有提到 http://weibo.com/p/1005051071312434/weibo?profile_ftype=1&key_word=randomize_va_space&is_search=1#_0
ZHH2009 2014-07-30
我没试过你的方法,因为我是用windows,不是用linux。

在linux下把内核参数randomize_va_space设为0对此贴中提到的问题有帮助吗?
有帮助的话,当然是只调内核参数好。
rink1969 2014-07-30
ZHH2009 写道


只不过有一点点缺陷,我用的是windows,
发现没有正确释放requested_address 对应的空间,
导致不是每次重启HotSpot时都成功,多试几次又好了。


这个应该不是没释放的问题
而是这段地址空间被动态库或者其他东西占用了。
可以在链接脚本里面把这段地址空间预留出来,就不会有这样的问题了。
nijiaben 2014-07-30
ZHH2009 写道
我没试过你的方法,因为我是用windows,不是用linux。

在linux下把内核参数randomize_va_space设为0对此贴中提到的问题有帮助吗?
有帮助的话,当然是只调内核参数好。

我在linux下没碰到你说的问题,返回的base地址都是一样的,那个内核参数没设置,我那么做当初主要是了解线程栈结构的时候做的,当时碰到的问题是帧结构里的数据的位置是变化的,最终发现原来在线程启动的时候在栈上随机取了一段,导致每次重启相同线程的相同帧的内存地址是不一样的
nijiaben 2014-07-30
rink1969 写道
ZHH2009 写道


只不过有一点点缺陷,我用的是windows,
发现没有正确释放requested_address 对应的空间,
导致不是每次重启HotSpot时都成功,多试几次又好了。


这个应该不是没释放的问题
而是这段地址空间被动态库或者其他东西占用了。
可以在链接脚本里面把这段地址空间预留出来,就不会有这样的问题了。

每个进程都是一套全新的完整的虚拟空间地址,应该不会因为没释放的问题,rink1969说的可能是原因,可以看看没有分配到你想要的地址的时候,预期的地址被哪个动态库占了
ZHH2009 2014-07-30
nijiaben 写道
rink1969 写道
ZHH2009 写道


只不过有一点点缺陷,我用的是windows,
发现没有正确释放requested_address 对应的空间,
导致不是每次重启HotSpot时都成功,多试几次又好了。


这个应该不是没释放的问题
而是这段地址空间被动态库或者其他东西占用了。
可以在链接脚本里面把这段地址空间预留出来,就不会有这样的问题了。

每个进程都是一套全新的完整的虚拟空间地址,应该不会因为没释放的问题,rink1969说的可能是原因,可以看看没有分配到你想要的地址的时候,预期的地址被哪个动态库占了


HotSpot本身就是一个DLL,如果第一次运行HotSpot成功了,第二次通常都失败,然后稍等片刻,运行第3或第4次又好了,在此期间并没有运行其他任何程序。

windows下是通过(char*)VirtualAlloc(addr, bytes, MEM_RESERVE, PAGE_READWRITE)来进行的,失败时,这个API就返回NULL。
ZHH2009 2014-07-30
ZHH2009 写道
ZHH2009 写道


只不过有一点点缺陷,我用的是windows,
发现没有正确释放requested_address 对应的空间,
导致不是每次重启HotSpot时都成功,多试几次又好了。



HotSpot本身就是一个DLL,如果第一次运行HotSpot成功了,第二次通常都失败,然后稍等片刻,运行第3或第4次又好了,在此期间并没有运行其他任何程序。

windows下是通过(char*)VirtualAlloc(addr, bytes, MEM_RESERVE, PAGE_READWRITE)来进行的,失败时,这个API就返回NULL。


当为NULL时,我用GetLastError得到的错误是 487 ERROR_INVALID_ADDRESS
Global site tag (gtag.js) - Google Analytics