#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 )