Windbg — , недопустимое приведение, псевдоним как против aS

#casting #alias #windbg

#Кастинг #псевдоним #windbg

Вопрос:

Добрый день,

У меня есть скрипт Windbg, который выполняет итерации по фреймам стека с использованием .do цикла. Для каждого фрейма, который он использует, !for_each_local и $spat ("@#Local","foo") для сопоставления с вещами, на которые мне интересно получить первоначальный взгляд. Затем я использую dx @$t2 = для назначения и окончательной печати того, что меня интересует, т. Е. dx @$t2 = ((foobase*) this)->m_current->m_name — в основном это работает нормально.

Время от времени во фрейме будет this , который не может быть успешно приведен с помощью dx , так что это похоже на то, что barbase это было бы необходимо, а не foobase dx кажется, что все в порядке, потому что я обернул это в .foreach (output { dx @$t2 = ((foobase*) this)->m_current->m_name }) {} , так что в конечном итоге оно содержит что-то .catch , что вызывает завершение работы скрипта (это несмотря на попытку a в качестве — Stack Overflow).

Сначала я действительно не понимал, что происходит, но выполнение .printf "%man", @$t2 помогло мне определить содержимое, <HRESULT 0x80004002> которое, я думаю, подразумевает недопустимое приведение — что, если это так, имеет смысл. Моя строка скрипта используется, foobase когда это было бы необходимо barbase .

Если я прав, то я ищу способ проверить это, прежде чем углубляться в сценарий дальше и пытаться получить доступ к деталям, которые, как я знаю, приведут к завершению работы скрипта.

Кажется, я придумал сложный способ сделать это… но я хотел спросить, есть ли что-нибудь получше…

 .frame 0a     $$ a frame with barbase, not foobase
dx @$t2 = ((foobase*) this)->m_name
.printf "%man", @$t2     $$ prints <HRESULT 0x80004002>
as /c CastCheck .printf "%ma", @$t2
.if ($spat(@"${CastCheck}","<HRESULT 0x80004002>") = 1) { .printf "yes" } .else { .printf "no" }     $$ prints yes
  

Есть ли способ проверить, $t2 содержит ли индикатор недопустимого приведения, без использования псевдонима?

Я спрашиваю об этом, потому что использование псевдонима вызвало у меня много путаницы… в моем скрипте (чтобы он работал, и, похоже, он работает довольно хорошо) Мне пришлось использовать aS вместо as (я могу использовать as fine из окна командной строки, и я не совсем понимаю, почему мне нужно изменить на aS после чтения документации), и мне также нужно заканчивать строку точкой с запятой (в отличие от любой другой строки в моем скрипте), и мне нужно использовать ad /q CastCheck; непосредственно перед aS , а затем быстро после, иначе псевдоним, кажется, каким-то образом теряется… итак, вы можете сказать, что использование этого псевдонима вызвало у меня небольшие проблемы.

Итак, есть ли а) простой способ предварительно проверить, является ли то, на что я смотрю, foobase или barbase , или б) проверка после попытки приведения, $t2 содержит ли это <HRESULT 0x80004002> ? Если я делаю .printf "%d", @$t2 это показывает 5 5 тоже что-то представляет?

Или, действительно, любые другие идеи (или вопросы).

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

Я собираюсь попытаться и проиллюстрировать, что я имею в виду, двумя короткими прогонами кода, выполняемыми в окне командной строки… где кадр 00 содержит a, this который можно привести к foobase , а затем . printf работает хорошо, и где кадр 0a содержит this это barbase (но мой скрипт по-прежнему этого не ожидает, и я хочу иметь возможность его обслуживать)… dx все еще что-то вставляет в $t10 … Я хочу иметь возможность определять, что это мусор (или предварительно определять, что мне не следует даже пробовать dx , если this есть barbase , поскольку это бессмысленно, и меня это все равно не интересует).

 0:038> .frame 00
00 00000006`3e2bc930 00007ffe`926293a8 BlahBlahBlah 
0:038> dx @$t10 = ((foobase *) this)->m_name
@$t10 = ((foobase *) this)->m_name                 : 0x869c7b8 : "nice string" [Type: char *]
0:038> .printf "%man", @$t10
nice string
  

Вот где this это barbase , и даже не имеет m_name :

 0:038> .frame 0a
0a 00000006`3e2bd220 00007ffe`91ec7780 BlahBlahBlah 
0:038> dx @$t10 = ((foobase *) this)->m_name
@$t10 = ((foobase *) this)->m_name                 : 0x2265646f00000005 : "--- memory read error at address 0x2265646f`00000005 ---" [Type: char *]
0:038> .printf "%man", @$t10
<HRESULT 0x80004002>
  

При вводе в цикл я обнаружил, что скрипт завершится с Memory access error на кадре 0a, когда я попытаюсь проверить длину строки, которая, как я полагаю, была возвращена dx .

В принципе, во втором блоке мне нужен способ либо проверять $t10 на наличие чего-то, что не является хорошей строкой (возможно, этого <HRESULT 0x80004002> ?), либо, что еще лучше, вообще не выполнять dx и .printf , потому что я мог проверить до того, как это this было barbase , а не foobase a.

Это имеет какой-то смысл, или я должен начать снова?

Комментарии:

1. можете ли вы отредактировать что-нибудь, что можно воспроизвести, это упростило бы попытку ответить, а не бороться с расплывчатыми описаниями

2. Попытался это сделать! Прошу прощения, если это ухудшило ситуацию.

3. Вероятно, мне нужен способ сделать .if и $spat , чтобы различать их … 0:038> .frame 00 00 000000063e2bc930 00007ffe926293a8 BlahBlahBlah 0:038> dv /t this class foobase * this = 0x0000000008622c10 0:038> .frame 0a 0a 000000063e2bd220 00007ffe91ec7780 BlahBlahBlah 0:038> dv /t this class barbase * this = 0x00000000194dacf0 но как?

4. C не поддерживает информацию о типе для своих объектов. Таким образом, вы не можете отличить два блока памяти по 16 байт друг от друга. Вы можете привести все, но это может не сработать. В вашем случае это не работает. Почему вы, как программист, не знаете, есть ли у вас foobase или barbase внутри метода BlahBlahBlah?

5. Пара идей, которые можно добавить в микс!: 1). Может ли назначение с приведением быть выполнено через r? ? И если да, то 1.a) Работает ли это, как указано на странице справки: Causes the pseudo-register to acquire *typed* information ? 1.б) Помогает ли выполнение назначения в два этапа (сначала это, а затем участник)? 2). Сможете ли вы выяснить фактическое «это», изучив их v-таблицы? foobase и barbase будут иметь разные v-таблицы? 3) 5 , вероятно, смещено (?) от «m_name», и когда вы выполняете printf с %d , оно принимает 32-разрядный аргумент и записывает нижнюю часть 0x2265646f00000005 .

Ответ №1:

ну, вы пытались, но это все еще расплывчато

можете ли вы объяснить, что необходимо сделать .frame
, а затем dx это??

вы можете привести любой адрес к любому типу

например, при первом запуске я приведу this к правильному типу и перечислю все фреймы

в следующем запуске я приведу к фиктивному типу и перечислю

в обоих случаях только один фрейм имеет указатель this

когда это правильный тип, он возвращает правильный элемент

когда он поддельный, он возвращает поддельный материал

 0:000> !for_each_frame dx ((Student *) this)->Name
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
00 000000c5`d6f6f8c0 00007ff7`2818117c thisptr!Student::PrintStudent 0x9 [f:srcthisptrthisptr.cpp @ 20] 
((Student *) this)->Name                 : 0x7ff7282153e0 : "dave" [Type: char *]
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
01 000000c5`d6f6f8f0 00007ff7`281b6c20 thisptr!main 0x2c [f:srcthisptrthisptr.cpp @ 33] 
Error: Unable to bind name 'this'
  

он нашел это, но не может найти имя участника

 0:000> !for_each_frame dx ((ntdll!_EPROCESS *) this)->Name
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
00 000000c5`d6f6f8c0 00007ff7`2818117c thisptr!Student::PrintStudent 0x9 [f:srcthisptrthisptr.cpp @ 20] 
Error: Unable to bind name 'Name' <<<<<<
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
01 000000c5`d6f6f8f0 00007ff7`281b6c20 thisptr!main 0x2c [f:srcthisptrthisptr.cpp @ 33] 
Error: Unable to bind name 'this' 
  

кстати, вы уже знаете, к какому типу a относится этот указатель, так зачем вы его приводите??

вы можете определить тип этого ptr с помощью различных команд, некоторые из которых показаны ниже

 0:000> dx this
this                 : 0xc5d6f6f910 [Type: Student *] <<<
    [ 0x000] Roll             : 1 [Type: int]
    [ 0x008] Name             : 0x7ff7282153e0 : "dave" [Type: char *]
    [ 0x010] Marks            : 72.300000 [Type: double]


0:000> ?? this 
class Student * 0x000000c5`d6f6f910  <<<
    0x000 Roll             : 0n1
    0x008 Name             : 0x00007ff7`282153e0  "dave"
    0x010 Marks            : 72.299999999999997158 


0:000> x /t this
000000c5`d6f6f8f0 class Student * this = 0x000000c5`d6f6f910  <<<


0:000> x /v /t this
prv local  000000c5`d6f6f8f0    8 class Student * this = 0x000000c5`d6f6f910

0:000> dt this 
Local var @ 0xc5d6f6f8f0 Type Student*
0x000000c5`d6f6f910 
    0x000 Roll             : 0n1
    0x008 Name             : 0x00007ff7`282153e0  "dave"
    0x010 Marks            : 72.299999999999997158 


0:000> dt /v this 
Local var [AddrFlags 90  AddrOff 0000000000000030  Reg/Val rsp (7)] @ 0xc5d6f6f8f0 Type Student*
0x000000c5`d6f6f910 class Student, 5 elements, 0x18 bytes
    0x000 Roll             : 0n1
    0x008 Name             : 0x00007ff7`282153e0  "dave"
    0x010 Marks            : 72.299999999999997158 
   <function> Student     void (
    int, 
    char*, 
    double) 000000c5`d6f6f910
   <function> PrintStudent     void ( void ) 000000c5`d6f6f910

0:000> dt /v /t this 
Local var [AddrFlags 90  AddrOff 0000000000000030  Reg/Val rsp (7)] @ 0xc5d6f6f8f0 Type Student*
0x000000c5`d6f6f910 class Student, 5 elements, 0x18 bytes
    0x000 Roll             : 0n1
    0x008 Name             : 0x00007ff7`282153e0  "dave"
    0x010 Marks            : 72.299999999999997158 
   <function> Student     void (
    int, 
    char*, 
    double) 000000c5`d6f6f910
   <function> PrintStudent     void ( void ) 000000c5`d6f6f910
  

Комментарии:

1. Я думаю, вы лучше меня проиллюстрировали свой первый блок кода. Да, я могу нормально работать с кадром 00, а кадр 01 выдает unable to bind ошибку. То, что я искал — в цикле моего скрипта — было средством избежать того, чтобы это было выброшено, или выхода скрипта из более глубоких логических областей, избегая даже проверки фрейма, где, как я знал, не будет this->m_name Name в вашем примере, в этом случае вывод из моего скрипта приятный и чистый, без различных бессмысленных (? — возможно, неинтересные — лучшее слово) выдаются ошибки.

2. Спасибо за иллюстрацию различных способов получения типа… Я уже знал большинство из них, но не все — конечно, нет x /v /t this . В идеале, для чистоты вывода скрипта снова — без всей посторонней информации, я хотел способ получения только типа … и я думаю, что dv /t this это самый чистый на данный момент — то, что он возвращает, управляемо, но я все равно хотел бы иметь возможность проанализировать эту результирующую строку, чтобы удалить class с передней части и все, что за ее пределами * … опять же, это все для представления в скрипте.

3. как я уже говорил в вашем другом вопросе, сбросьте всю эту чушь для синтаксического анализа текста и используйте javascript, я добавлю еще один ответ ниже

4. Спасибо! Я не возражаю против использования тупых вещей … ванили… С каждым разом я узнаю немного больше. 😉 Возможно, я не так продуктивен, как мог бы использовать Javascript, возможно, но это очень нравится, когда вы в конечном итоге получаете то, что хотите, работая. Я всегда ценю ваш вклад в эти вопросы.

Ответ №2:

добавление другого ответа, чтобы подчеркнуть использование javascript вместо синтаксического анализа текста

поддержка скриптов javascript была добавлена в windbg quiet давным-давно, и она значительно улучшается

(чтобы попробовать последние дополнения javascript, используйте предварительный просмотр windbg в последней версии Windows 10)

x /v /t или dv /t предоставляет тип этого указателя

javascript предоставляет свойство TargetType для этих объектов

вот как это использовать

создайте файл .js foo.js с приведенным ниже содержанием

 function typethis ( somevar ) 
{
    host.diagnostics.debugLog( somevar.targetType ,  "t" , JSON.stringify(somevar) , "n"  )
}
  

в windbg сделать

 .load jsprovider
.scriptload x:..\..foo.js
dx @$scriptcontents.functionname(argument) to run the script
  

и результаты будут

 0:000> .load jsprovider
0:000> .scriptload f:wdscrtypthis.js
JavaScript script successfully loaded from 'f:wdscrtypthis.js'
0:000> dx @$scriptContents.typethis( this )
Student *   {"Roll":1,"Name":{},"Marks":72.3}
@$scriptContents.typethis( this )