Lloyd Bond
Lloyd Bond

Reputation: 33

Windbg Type Casting

I would like to type cast an object of a child class to a parent class in WinDbg at the command window.

Example classes

class parent
{
public:
    int a;
    int b;
    parent(){ a = 10; b = 10; }
    parent(int c) : a(a){}
};

class child : public parent
{
public:
    int a;
    int b;
    child(){ a = 20; b = 20; }
    child(int d) : b(d){}
};

I am using Windbg and I was reading through the help file. It shows under C++ Numbers and Operators that I can do the following typecastings from the WinDbg command window:

dynamic_cast <type>(Value) 
static_cast <type>(Value) 
reinterpret_cast <type>(Value) 
const_cast <type>(Value)
(type) Value

So I would type in the Windbg command window:

?? (type) Value

What works is

?? (char)a
?? static_cast<char>(a)

where a is an int.

What doesn't work is

?? (parent)chld
?? static_cast<parent>(chld)
?? static_cast<mod!parent>(chld)

where chld is an object of class child and child inherits class parent.

object example:

child chld;

The error returned is

Type conflict error at '<EOL>'

If I do a x mod!* I get a giant list, in that list are

MOD!parent
MOD!child

If I do a ?? chld then the object gets dumped to the screen just fine.

Why I would want to do this? Well you can do

?? chld.childattr++ and so I would like to actually do ?? ((parent)chld).parentattr++

The windbg help says:

Symbols in C++ Expressions

In a C++ expression, each symbol is interpreted according to its type. Depending on what the symbol refers to, it might be interpreted as an integer, a data structure, a function pointer, or any other data type. If you use a symbol that does not correspond to a C++ data type (such as an unmodified module name) within a C++ expression, a syntax error occurs.

So I see no reason I shouldn't be able to type cast an object to a parent data type.

I did a lot of searching and nothing really came up for this, if someone could point me in the right direction so that I could read about why this should or shouldn't work or maybe what I need to do to be successful or even why this is not something I should expect from WinDbg.

Edited: To add code example.

Upvotes: 3

Views: 4694

Answers (1)

blabb
blabb

Reputation: 9007

code , snippet or anything that is reproducible to some extent in other machines can provide a more robust and clear answers instead of dry theoretical question

i interpret your question to be of the type can pe header be dumped as _eprocess structure

if so you can do some thing like this

lkd> ?? (char *)@$proc->ImageFileName
char * 0x866be194
 "windbg.exe"
lkd> lm m windbg
start    end        module name
01000000 01097000   windbg     (pdb symbols)          
lkd> db windbg l10
01000000  4d 5a 90 00 03 00 00 00-04 00 00 00 ff ff 00 00  MZ..............
lkd> da windbg+4e 
0100004e  "This program cannot be run in DO"
0100006e  "S mode....$"
lkd> ?? (char *)((nt!_EPROCESS *) @@masm(windbg - 174+4e) )->ImageFileName
char * 0x0100004e
 "This program cannot be run in DOS mode....$"

though still at loss this edit is in response to edited question

full source for walkthrough your parent class slightly modified to eliminate unreferenced parameter warning and output ambiguity and used inside function main

:\>type parchiltst.cpp
#include <stdio.h>
class parent
{
public:
    int a;
    int b;
    parent(){ a = 35; b = 28; }
    parent(int c) : a(c){}
};
class child : public parent
{
public:
    int a;
    int b;
    child(){ a = 20; b = 20; }
    child(int d) : b(d){}
};
int main (void) {
    parent par,papa,mama,gramp;
    child  chill,bigbro,lilsis,crybab;
    par.a=70;par.b=65;chill.a=4;chill.b=8;
    gramp=parent(par); papa=parent(); mama=parent(1234);
    bigbro=child(chill);lilsis=child();crybab=child(5678);
    printf("%d  %d  %d  %d  %d  %d  %d  %d  %d  %d  %d  %d  %d  %d\n",
        chill.a,chill.b,gramp.a,gramp.b,papa.a,papa.b,mama.a,mama.b,
        bigbro.a,bigbro.b,lilsis.a,lilsis.b,crybab.a,crybab.b);
    return 0;
}

compiled ,linked and executed to show output

:\>cl /Zi /nologo /W4 /analyze parchiltst.cpp /link /RELEASE
parchiltst.cpp

:\>parchiltst.exe
4  8  70  65  35  28  1234  0  4  8  20  20  196608  5678 `

loading it under windbg and stepping upto printf so that all locals are properly initialised

:\>cdb parchiltst.exe

0:000> g main
parchiltst!main:
00401000 55              push    ebp
0:000> dv -V -t -i
prv local  0013ff18 @ebp-0x60 class child lilsis = class child
prv local  0013ff28 @ebp-0x50 class parent par = class parent
prv local  0013ff30 @ebp-0x48 class parent gramp = class parent
prv local  0013ff38 @ebp-0x40 class parent papa = class parent
prv local  0013ff40 @ebp-0x38 class parent mama = class parent
prv local  0013ff48 @ebp-0x30 class child chill = class child
prv local  0013ff58 @ebp-0x20 class child bigbro = class child
prv local  0013ff68 @ebp-0x10 class child crybab = class child
0:000> .lines
Line number information will be loaded
0:000> l+*
0:000> p
>   19:     parent par,papa,mama,gramp;
0:000>
>   20:     child  chill,bigbro,lilsis,crybab;
0:000>
>   21:     par.a=70;par.b=65;chill.a=4;chill.b=8;
0:000>
>   22:     gramp=parent(par); papa=parent(); mama=parent(1234);
0:000>
>   23:     bigbro=child(chill);lilsis=child();crybab=child(5678);
0:000>
>   26:         bigbro.a,bigbro.b,lilsis.a,lilsis.b,crybab.a,crybab.b);

evaluating all locals with c++ exp evaluator

0:000> !for_each_local "?? @#Local"
class child
   +0x000 a                : 0n35
   +0x004 b                : 0n28
   +0x008 a                : 0n4
   +0x00c b                : 0n8
class child
   +0x000 a                : 0n35
   +0x004 b                : 0n28
   +0x008 a                : 0n4
   +0x00c b                : 0n8
class child
   +0x000 a                : 0n35
   +0x004 b                : 0n28
   +0x008 a                : 0n2090270496
   +0x00c b                : 0n5678
class parent
   +0x000 a                : 0n70
   +0x004 b                : 0n65
class child
   +0x000 a                : 0n35
   +0x004 b                : 0n28
   +0x008 a                : 0n20
   +0x00c b                : 0n20
class parent
   +0x000 a                : 0n1234
   +0x004 b                : 0n0
class parent
   +0x000 a                : 0n35
   +0x004 b                : 0n28
class parent
   +0x000 a                : 0n70
   +0x004 b                : 0n65

checking individually

0:000> ?? ((child *) @@masm(mama))->a
int 0n35
0:000> ?? ((parent *) @@masm(mama))->a
int 0n1234
0:000> ?? ((parent *) @@masm(papa))->a
int 0n35
0:000> ?? ((child *) @@masm(papa))->a
int 0n1234
0:000> ?? ((child *) @@masm(lilsis))->a
int 0n20
0:000> ?? ((parent *) @@masm(lilsis))->a
int 0n35
0:000> ?? ((parent *) @@masm(lilsis))
class parent * 0x0013ff18
   +0x000 a                : 0n35
   +0x004 b                : 0n28
0:000> ?? ((child *) @@masm(lilsis))
class child * 0x0013ff18
   +0x000 a                : 0n35
   +0x004 b                : 0n28
   +0x008 a                : 0n20
   +0x00c b                : 0n20
0:000> ?? ((child *) @@masm(mama))
class child * 0x0013ff40
   +0x000 a                : 0n1234
   +0x004 b                : 0n0
   +0x008 a                : 0n35
   +0x00c b                : 0n28
0:000> ?? ((parent *) @@masm(mama))
class parent * 0x0013ff40
   +0x000 a                : 0n1234
   +0x004 b                : 0n0
0:000>

a trail of questions and answers that may lead to solutions

what do we want to display ?

a pointer to a class

what is the type of class

somefoo

so to display a pointer to somefoo in c++ expression evaluator

?? (somefoo *) should be used

a pointer needs an address or an expression that evaluates to an address

lilsis, papa , somefoo etc are expressions that can be interpreted in both masm and c++ evaluators

so to avoid ambiguity we need to explicitly state that lilsis etc needs to be evaluated as masm expression not as c++ expression because ?? tries to interpret lilsis , somefoo as c++ expression
so the full expression will be ?? (somefoo *) @@(someotherfoo)

notice @@ only is sufficient to indicate a masm expression but to further avoid ambiguity it is a good habit to specify expression evaluators explicitly like @@masm( , @@c++( and so forth

see below a single ? on class pointer returns an address and a ?? return the type

0:000> ? mama
Evaluate expression: 1310528 = 0013ff40
0:000> ?? mama
class parent
   +0x000 a                : 0n1234
   +0x004 b                : 0n0
0:000> ?? lilsis
class child
   +0x000 a                : 0n35
   +0x004 b                : 0n28
   +0x008 a                : 0n20
   +0x00c b                : 0n20
0:000> ? lilsis
Evaluate expression: 1310488 = 0013ff18
0:000> ?? @@(mama)
unsigned int64 0x13ff40
0:000> ?? @@masm(mama)
unsigned int64 0x13ff40
0:000> ?? @@c++(mama)
class parent
   +0x000 a                : 0n1234
   +0x004 b                : 0n0
0:000> ?? @@c++(crybab)
class child
   +0x000 a                : 0n35
   +0x004 b                : 0n28
   +0x008 a                : 0n2090270496
   +0x00c b                : 0n5678
0:000>

this applies not just to class but also to types displayed with dt

nt!_eprocess is manipulated below for different scenerios as an example

lkd> ?? ((nt!_EPROCESS) @$proc)->ImageFileName

Type conflict error at ')->ImageFileName'

lkd> ?? ((nt!_EPROCESS *) @$proc)->ImageFileName

unsigned char [16] 0x86305f14
0x6b 'k'

lkd> ?? (char *)((nt!_EPROCESS *) @$proc)->ImageFileName

char * 0x86305f14
 "kd.exe"

lkd> ?? (char *)((nt!_EPROCESS *) nt)->ImageFileName

Couldn't resolve error at 'nt)->ImageFileName'

lkd> ?? (char *)((nt!_EPROCESS *) @@(nt))->ImageFileName

char * 0x804d7174
 ""

?? #FIELD_OFFSET(nt!_EPROCESS , ImageFileName)

long 0n372

lkd> ? 0n372

Evaluate expression: 372 = 00000174

lkd> ? @@c++(#FIELD_OFFSET(nt!_EPROCESS , ImageFileName)) + nt

Evaluate expression: -2142408332 = 804d7174

lkd> ?? @@c++(#FIELD_OFFSET(nt!_EPROCESS , ImageFileName)) + nt

Couldn't resolve error at 'nt'

lkd> ?? @@c++(#FIELD_OFFSET(nt!_EPROCESS , ImageFileName)) + @@(nt)

unsigned int64 0xffffffff`804d7174
lkd> 

Upvotes: 5

Related Questions