Reputation: 400
I have a bunch of aliases for accessing global debug variables in my code, which look something like this:
aS _dbg_log_last "dx mymodule!g_dbg_variable_with_a_long_name->logger.log_buffer[mymodule!g_dbg_variable_with_a_long_name->logger.size - 1]"
I am obviously not a fan of the last one with the repetition, so I tried to refactor it to the following:
aS _dbg_log "mymodule!g_dbg_variable_with_a_long_name->logger"
aS _dbg_log_last "dx ${_dbg_log} .log_buffer[${_dbg_log}.size - 1]"
If I copy the contents of the _dbg_log_last
alias and run it manually, everything works. But if I actually try to invoke it, I am getting an error:
Error: unexpected token at {_dbg_log}...
So it look like it swallow the $
character when executing the alias. I have tried also unquoting either or both aliases, using as
instead of aS
, adding /f
and other flags to alias interpreter, escaping the $
with \$
or $$
, nothing works.
Minimal repro:
aS _foo "1"
aS _bar "dx ${_foo} ,x"
dx ${_foo} ,x
_bar
Expected:
1 ,x : 0x1
1 ,x : 0x1
Actual:
1 ,x : 0x1
Error: Unexpected token at '{_foo} ,x'
Upvotes: 0
Views: 35
Reputation: 9007
As Nietsa says mixing dx with as / aS may not be compatible
but unless you force execute with a .block{} the aliases are not going to be expanded
ill show an example with a public struct see if that helps you
delete prior aliases if any and list
0:000> ad *
0:000> al
No aliases
define new alaises and list
0:000> as foo ((ntdll!_PEB *)@$proc)->ProcessParameters
0:000> as bar ${foo}->DesktopInfo
0:000> al
Alias Value
------- -------
bar ${foo}->DesktopInfo
foo ((ntdll!_PEB *)@$proc)->ProcessParameters
check the simple alias
0:000> ?? ${foo}->WindowTitle
struct _UNICODE_STRING
"C:\Program Files (x86)\Windows Kits\10\Debuggers\x64\cdb.exe"
+0x000 Length : 0x78
+0x002 MaximumLength : 0x7a
+0x008 Buffer : 0x000002c3`30ca2e3a "C:\Program Files (x86)\Windows Kits\10\Debuggers\x64\cdb.exe"
check the compound alias without a surrounding .block{}
0:000> ?? ${bar}
Unexpected character in '${foo}->DesktopInfo'
surround it with a .block to force expansion first
0:000> .block { ?? ${bar} }
struct _UNICODE_STRING
"WinSta0\Default"
+0x000 Length : 0x1e
+0x002 MaximumLength : 0x20
+0x008 Buffer : 0x000002c3`30ca2eb4 "WinSta0\Default"
0:000>
supposedly if you have a script file that is based on foo and bar above as below
.block { ?? ${bar}.Buffer[0] }
.block { ?? ${bar}.Buffer[1] }
.block { ?? ${bar}.Buffer[2] }
.block { ?? ${bar}.Buffer[3] }
.block { ?? ${bar}.Buffer[4] }
.block { ?? ${bar}.Buffer[5] }
.block { ?? ${bar}.Buffer[6] == '1' }
.block { ?? ${bar}.Buffer[6] == '0' }
running the script should yield
0:000> $$>< d:\alias.wds
wchar_t 0x57 'W'
wchar_t 0x69 'i'
wchar_t 0x6e 'n'
wchar_t 0x53 'S'
wchar_t 0x74 't'
wchar_t 0x61 'a'
bool false
bool true
0:000>
Upvotes: 0
Reputation: 8176
I can't directly answer your question, and I surmise the problem lies in the fact that you're using the "old" alias scheme with the new dx
(object model expression).
It's easier to stick with only the new dx command. Here's a simple repro example:
#include <iostream>
typedef struct Logger
{
unsigned fooLogger;
unsigned barLogger;
unsigned size;
const char* log_buffer[1];
} Logger;
typedef struct MyStruct
{
unsigned foo;
unsigned bar;
Logger logger;
} MyStruct;
MyStruct* g_dbg_variable_with_a_long_name;
void DumpStruct()
{
std::printf("foo: 0x%08x\n", g_dbg_variable_with_a_long_name->foo);
std::printf("bar: 0x%08x\n", g_dbg_variable_with_a_long_name->bar);
std::printf("fooLogger: 0x%08x\n", g_dbg_variable_with_a_long_name->logger.fooLogger);
std::printf("barLogger: 0x%08x\n", g_dbg_variable_with_a_long_name->logger.barLogger);
std::printf("size: %d\n", g_dbg_variable_with_a_long_name->logger.size);
for (unsigned i = 0; i < g_dbg_variable_with_a_long_name->logger.size; i++)
{
std::printf("log_buffer[%d]: %s\n", i, g_dbg_variable_with_a_long_name->logger.log_buffer[i]);
}
}
int main(void)
{
MyStruct myStruct;
myStruct.foo = 0x12345678;
myStruct.bar = 0xdeadbeef;
myStruct.logger.fooLogger = 0x11111111;
myStruct.logger.barLogger = 0x22222222;
myStruct.logger.size = 2;
myStruct.logger.log_buffer[0] = "Hello";
myStruct.logger.log_buffer[1] = "World";
g_dbg_variable_with_a_long_name = &myStruct;
DumpStruct();
return 0;
}
Set a BP on DumpStruct
(the idea is to have a point where the struct is known to be initialized; yes, I know, it's a global initialized with a local...).
bp test!DumpStruct
Now, use dx
to assign what you want (instead of aliasing through sa
):
dx @$_dbg_log = test!g_dbg_variable_with_a_long_name->logger
dx @$_dbg_log_last = @$_dbg_log.log_buffer[@$_dbg_log.size - 1]
(side note: those assignements are technically made to debugger registers, you can get them with dx @$vars
; just don't forget they are prefixed with @$
which may be the source of confusion for the dx command in your case).
Output:
0:000> dx @$vars
@$vars
_dbg_log [Type: Logger]
_dbg_log_last : 0x7ff7af61aca8 : "World" [Type: char *]
0:000> dx @$_dbg_log
@$_dbg_log [Type: Logger]
[+0x000] fooLogger : 0x11111111 [Type: unsigned int]
[+0x004] barLogger : 0x22222222 [Type: unsigned int]
[+0x008] size : 0x2 [Type: unsigned int]
[+0x010] log_buffer [Type: char * [1]]
0:000> dx @$_dbg_log_last
@$_dbg_log_last : 0x7ff7af61aca8 : "World" [Type: char *]
87 'W' [Type: char]
$$ same as:
0:000> dx @$_dbg_log_last,s
@$_dbg_log_last,s : 0x7ff7af61aca8 : "World" [Type: char *]
87 'W' [Type: char]
You could also do a bit differently and do :
0:000> dx @$first = 0
@$first = 0 : 0
0:000> dx @$last = @$_dbg_log.size - 1
@$last = @$_dbg_log.size - 1 : 0x1
0:000> dx @$_dbg_log.log_buffer[@$first]
@$_dbg_log.log_buffer[@$first] : 0x7ff7af61aca0 : "Hello" [Type: char *]
72 'H' [Type: char]
0:000> dx @$_dbg_log.log_buffer[@$last]
@$_dbg_log.log_buffer[@$last] : 0x7ff7af61aca8 : "World" [Type: char *]
87 'W' [Type: char]
Or log all at once:
(note: since the buffer is declared with only one element, we need to tell windbg how much elements the table has; one of the few cases where you can't pass a variable... we need to pass a scalar here)
0:000> dx *(char* (*)[2])@$_dbg_log.log_buffer
*(char* (*)[2])@$_dbg_log.log_buffer [Type: char * [2]]
[0] : 0x7ff7af61aca0 : "Hello" [Type: char *]
[1] : 0x7ff7af61aca8 : "World" [Type: char *]
$$ !!! DOES NOT WORK !!! :(
0:000> dx *(char* (*)[@$_dbg_log.size])@$_dbg_log.log_buffer
Error: Unexpected token at '@$_dbg_log.size])@$_dbg_log.log_buffer'
Upvotes: 0