Good day,
I have a Windbg script that iterates around the frames of a stack using a .do
loop. For each frame it uses !for_each_local
and $spat ("@#Local","foo")
to match for things I'm interested in getting an initial look at. I then use dx @$t2 =
to assign and finally print out what I'm interested in, i.e. dx @$t2 = ((foobase*) this)->m_current->m_name
- mostly this works fine.
Every now and again, there'll be a this
in a frame that can't be cast successfully with the dx
, so it's like barbase
it would need, not foobase
... the dx
seems OK because I've wrapped it in a .foreach (output { dx @$t2 = ((foobase*) this)->m_current->m_name }) {}
so it ends up containing something that causes the script to exit (that's despite trying a .catch
).
At first I didn't really realise what was going on, but doing a .printf "%ma\n", @$t2
helped me to ascertain the contents is <HRESULT 0x80004002>
which I think implies invalid cast - which, if so, makes perfect sense. My script line is using foobase
when it would need barbase
.
If I'm correct, what I'm looking for is a way to check that, before I delve into the script further and try to access details I know will cause the script to exit.
I seem to have come up with a convoluted way of doing it... but I wanted to ask if there was anything better...
.frame 0a $$ a frame with barbase, not foobase
dx @$t2 = ((foobase*) this)->m_name
.printf "%ma\n", @$t2 $$ prints <HRESULT 0x80004002>
as /c CastCheck .printf "%ma", @$t2
.if ($spat(@"${CastCheck}","<HRESULT 0x80004002>") = 1) { .printf "yes" } .else { .printf "no" } $$ prints yes
Is there a way to check if $t2
contains an indicator of invalid cast without using an alias?
I ask this because using the alias has caused me much confusion... in my script (for it to work, and it does seem to work quite well) I've had to use aS
instead of as
(I can use as
fine from the Command Window, and I don't really understand why I need to change to aS
from reading the documentation) and I also need to end the line with a semi-colon (unlike any other line in my script) and I need to use ad /q CastCheck;
immediately before the aS
, and then quickly afterwards, otherwise the alias seems to get lost, somehow... so you can tell the use of this alias has caused me a little trouble.
So, is there either a) an easy way to pre-check whether what I'm looking at is foobase
or barbase
, or b) post-check after the cast attempt whether $t2
contains this <HRESULT 0x80004002>
? If I do a .printf "%d", @$t2
it shows 5
... does 5
represent something too?
Or, indeed, any other ideas (or questions).
EDIT:
I'm going to try and illustrate what I mean with 2 short runs of code done in the Command Window... where frame 00 contains a this
that can be cast to foobase
and then the .printf
works nicely, and where frame 0a contains a this
that's a barbase
(but my script still doesn't expect it and I want to be able to cater for it)... the dx
still puts something in $t10
... I want to be able to detect that it's garbage (or pre-detect I shouldn't even try the dx
, if this
is barbase
, as it's pointless and I'm not interested in it anyway).
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 "%ma\n", @$t10
nice string
This is where the this
is a barbase
, and doesn't even have a 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 "%ma\n", @$t10
<HRESULT 0x80004002>
When put inside a loop I've found that the script will exit with a Memory access error
on frame 0a when I try to check the length of the string I believe to have been returned by dx
.
Basically, in the second block I want a way of either checking $t10
for something that is not a nice string (probably this <HRESULT 0x80004002>
?) or, even better, not doing the dx
and .printf
at all, because I was able to check before that this
was a barbase
, not a foobase
.
Is that making any more sense, or should I start again?
well you attempted but it is still vague
can you explain what is necessity to do .frame
and then dx this ??
you can cast any address to any type
for example in the first run I am casting the this to a proper type and enumerating all Frames
in the next run I am casting to a bogus type and enumerating
in both of this only one frame has a this pointer
when it is proper type it returns proper member
when it is bogus well it returns bogus stuff
0:000> !for_each_frame dx ((Student *) this)->Name
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
00 000000c5`d6f6f8c0 00007ff7`2818117c thisptr!Student::PrintStudent+0x9 [f:\src\thisptr\thisptr.cpp @ 20]
((Student *) this)->Name : 0x7ff7282153e0 : "dave" [Type: char *]
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
01 000000c5`d6f6f8f0 00007ff7`281b6c20 thisptr!main+0x2c [f:\src\thisptr\thisptr.cpp @ 33]
Error: Unable to bind name 'this'
it found a this but it cant find the Member Name
0:000> !for_each_frame dx ((ntdll!_EPROCESS *) this)->Name
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
00 000000c5`d6f6f8c0 00007ff7`2818117c thisptr!Student::PrintStudent+0x9 [f:\src\thisptr\thisptr.cpp @ 20]
Error: Unable to bind name 'Name' <<<<<<
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
01 000000c5`d6f6f8f0 00007ff7`281b6c20 thisptr!main+0x2c [f:\src\thisptr\thisptr.cpp @ 33]
Error: Unable to bind name 'this'
btw you know what type a this pointer is already so why are you casting it ??
you can find the type of this ptr with various commands some of which are shown below
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
adding another answer to emphasize the usage of javascript instead of parsing text
javascript script support was added to windbg quiet a long time back and it is being improved a lot
(to try the latest javascript additions use the windbg preview in latest windows 10 version)
x /v /t or dv /t provides the type of the this pointer
javascript provides a targetType property for these object
here is how to use it
create a .js file foo.js with the contents below
function typethis ( somevar )
{
host.diagnostics.debugLog( somevar.targetType , "\t" , JSON.stringify(somevar) , "\n" )
}
in windbg do
.load jsprovider
.scriptload x:\..\\..\foo.js
dx @$scriptcontents.functionname(argument) to run the script
and the results will be
0:000> .load jsprovider
0:000> .scriptload f:\wdscr\typthis.js
JavaScript script successfully loaded from 'f:\wdscr\typthis.js'
0:000> dx @$scriptContents.typethis( this )
Student * {"Roll":1,"Name":{},"Marks":72.3}
@$scriptContents.typethis( this )
User contributions licensed under CC BY-SA 3.0