На первый взгляд неверный указатель инструкций, сообщаемый VS2017 - PullRequest
3 голосов
/ 10 мая 2019

Редактировать:

Я исследовал больше, и описанная ниже проблема, кажется, возникает только тогда, когда я использую Visual Studio 2017, чтобы приостановить процесс.Также кажется, что когда rip указывает на неверное местоположение, это всегда смещение на +1 байт от правильного начала инструкции.

Кроме того, для контекста это большой проект C ++ с большим количеством dll, некоторые скомпилированыс MSVC 2015, остальное с ICC (Intel Compiler 2017).Это выполняется в процессе Python с использованием улучшенных привязок C ++ / python.

Исходное сообщение:

Я произвольно приостанавливаю свою программу, чтобы посмотреть, что мои потоки делают во время некоторых тяжелых вычислений.Обратите внимание, что я не отлаживаю сбой, возобновляя работу программы.

Однако отладчик VS иногда не может разобрать машинный код.Например, в одном потоке, где rip = 000007FE8B048EE2, он показывает это:

000007FE8B048EDE  ?? ?? 
000007FE8B048EDF  ?? ?? 
000007FE8B048EE0  ?? ?? 
000007FE8B048EE1  ?? ?? 
                    }

                    if (params.derandomize) {
000007FE8B048EE2  adc         ebp,eax  
                        GetRNG().Seed(id);
000007FE8B048EE4  pop         rax  
000007FE8B048EE5  wait  
000007FE8B048EE6  adc         byte ptr [rax],al  
000007FE8B048EE8  mov         rcx,rax  

Декодированные инструкции x86 также кажутся неправильными (adc, pop, wait, adc ??), поэтому я попытался присоединить WinDBG какхорошо (неинвазивный режим):

0:019> u rip
somedll!<lambda239>::operator()+0x132:
000007fe`8b048ee2 13e8            adc     ebp,eax
000007fe`8b048ee4 58              pop     rax
000007fe`8b048ee5 9b              wait
000007fe`8b048ee6 1000            adc     byte ptr [rax],al
000007fe`8b048ee8 4889c1          mov     rcx,rax
000007fe`8b048eeb 8b9570080000    mov     edx,dword ptr [rbp+870h]
000007fe`8b048ef1 e8fa911000      call    somedll!bla::bla::blabla::blabla::Seed (000007fe`8b1520f0)
000007fe`8b048ef6 4c8ba5b0080000  mov     r12,qword ptr [rbp+8B0h]

Хорошо, это тот же мусор ... Но потом я попытался разобрать с адреса чуть выше рипа:

0:019> u rip-30
somedll!<lambda239>::operator()+0x102:
000007fe`8b048eb2 00488b          add     byte ptr [rax-75h],cl
000007fe`8b048eb5 084863          or      byte ptr [rax+63h],cl
000007fe`8b048eb8 81d003000048    adc     eax,48000003h
000007fe`8b048ebe 83f8ff          cmp     eax,0FFFFFFFFh
000007fe`8b048ec1 740a            je      somedll!<lambda239>::operator()+0x11d (000007fe`8b048ecd)
000007fe`8b048ec3 4889c2          mov     rdx,rax
000007fe`8b048ec6 48899570080000  mov     qword ptr [rbp+870h],rdx
000007fe`8b048ecd 486381e0030000  movsxd  rax,dword ptr [rcx+3E0h]
0:019> u
somedll!<lambda239>::operator()+0x124:
000007fe`8b048ed4 483bd0          cmp     rdx,rax
000007fe`8b048ed7 7501            jne     somedll!<lambda239>::operator()+0x12a (000007fe`8b048eda)
000007fe`8b048ed9 cc              int     3
000007fe`8b048eda 80b96303000000  cmp     byte ptr [rcx+363h],0
000007fe`8b048ee1 7413            je      somedll!<lambda239>::operator()+0x146 (000007fe`8b048ef6)
000007fe`8b048ee3 e8589b1000      call    somedll!bla::bla::blabla::GetRNG (000007fe`8b152a40)
000007fe`8b048ee8 4889c1          mov     rcx,rax
000007fe`8b048eeb 8b9570080000    mov     edx,dword ptr [rbp+870h]
0:019> u
somedll!<lambda239>::operator()+0x141:
000007fe`8b048ef1 e8fa911000      call    somedll!bla::bla::blabla::blabla::Seed (000007fe`8b1520f0)
000007fe`8b048ef6 4c8ba5b0080000  mov     r12,qword ptr [rbp+8B0h]
000007fe`8b048efd 488d95f0070000  lea     rdx,[rbp+7F0h]
000007fe`8b048f04 488d8dc0070000  lea     rcx,[rbp+7C0h]
000007fe`8b048f0b 498b0424        mov     rax,qword ptr [r12]
000007fe`8b048f0f 4c8da570080000  lea     r12,[rbp+870h]
000007fe`8b048f16 488942d0        mov     qword ptr [rdx-30h],rax
000007fe`8b048f1a 4c8962d8        mov     qword ptr [rdx-28h],r12

первые инструкции"add byte ptr" и "or byte ptr" в 000007fe`8b048eb2 не имеют смысла, потому что rip-30, вероятно, попадает в середину инструкции, но после того, как он, кажется, выполняет повторную синхронизацию, потому что он соответствует исходному коду:

if (id == params.dbgbreak_id) {
    __debugbreak();
}

if (params.derandomize) {
    GetRNG().Seed(id);
}

000007fe`8b048ecd 486381e0030000  movsxd  rax,dword ptr [rcx+3E0h]
000007fe`8b048ed4 483bd0          cmp     rdx,rax                  // if (id == params.dbgbreak_id) {
000007fe`8b048ed7 7501            jne     somedll!<lambda239>::operator()+0x12a (000007fe`8b048eda)
000007fe`8b048ed9 cc              int     3                        // __debugbreak(); }
000007fe`8b048eda 80b96303000000  cmp     byte ptr [rcx+363h],0    // if (params.derandomize)
000007fe`8b048ee1 7413            je      somedll!<lambda239>::operator()+0x146 (000007fe`8b048ef6)
000007fe`8b048ee3 e8589b1000      call    somedll!bla::bla::blabla::GetRNG (000007fe`8b152a40)
000007fe`8b048ee8 4889c1          mov     rcx,rax
000007fe`8b048eeb 8b9570080000    mov     edx,dword ptr [rbp+870h]
000007fe`8b048ef1 e8fa911000      call    somedll!bla::bla::blabla::blabla::Seed (000007fe`8b1520f0)

ясно, что в 000007fe8b048ee2 нет инструкции, начинающейся!На 000007fe8b048ee1 есть je, а на 000007fe8b048ee3

звонят. Итак ... Я подумал, хм, в отладчике есть ошибка ... давайте проверим регистры:

0:019> r
rax=ffffffffffffffff rbx=000000000021d420 rcx=000000000021d5d0
rdx=0000000002696568 rsi=0000000000005d38 rdi=0000000056eefc40
rip=000007fe8b048ee2 rsp=0000000056eef5b0 rbp=0000000056eef5e0
 r8=0000000000000006  r9=000000000021d0b8 r10=0000000006456570
r11=0000000000000006 r12=0000000056eefe50 r13=00000000069a8820
r14=000000000021d1a8 r15=0000000056eefe60
iopl=0         nv up ei pl zr na po nc
cs=0033  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00000246

Что ??rip = 000007fe8b048ee2 ??Как это возможно?

Это объясняет, почему отладчик показывает мусор: он пытается разобрать, начиная с rip, но rip указывает на середину инструкции.Но почему заявленный разрыв неправильный?Виновник ОС?Я что-то упустил?

...