Windbg scripting - echo the class type of a variable - class

In Windbg I have a script that iterates through the frames of a stack and does a good job of pulling back things of interest, echoing them to the Command Window (it just sniffs things out that could require further investigation).
In certain frames, there will be a this that I'm interested in some details of. I can certainly extract the details fine, but I'd like to get the actual class type from it too. I know that if I then do a dv /t I will see something like the following:
0:115> .frame 14
0:115> dv /t
class foo1 * this = 0x00000000e9ed0010
I would like a way of being able to pass just foo1 to a .printf command.
In frames that have more than simply this, I can restrict output by using the pattern dv /t this obviously, but is there a good way of having something like what follows in a frame and me being able to extract just foo1?
0:115> .frame 17
0:115> dv /t
class foo1 * this = 0x00000000f3e2f568
class foo2 * bar2 = 0x0000000000000001
bool _somebool = true
Doing what follows is very close to the limited output I'd like... but I just want to neaten it up.
0:115> .frame 17
0:115> dv /t this
class foo1 * this = 0x00000000f3e2f568
Following the example code from blabb:
0:000> dv /t
class Time * this = 0x001efb24
int h = 0n23
int m = 0n59
int s = 0n59
0:000> dv /t this
class Time * this = 0x001efb24
0:000> some command
Time
The third command is what I'm looking for.

What I understood is: you need a command that takes foo1 as a parameter and gives an output like dv /t but just for all foo1.
IMHO, it's hardly possible with builtin WinDbg functionality. You could fiddle around with .foreach inculding $spat and the like.
One possibility is .shell along with the command line tool findstr or Cygwin grep. But that's not convenient, because it always outputs Process started etc. You could again work around this using .foreach and skipping some tokens, but that's tedious.
There are grep implementations for WinDbg such as long123king's grep plugin and if I recall correctly, there's also a grep implementation in PDE.
Then there is pykd, which has the powers of Python and let's you do basically anything.

i am not sure i understand what you need
but have you given the new dx expression evaluator a try
for example
0:000> dv /t
class Time * this = 0x001efb24
int h = 0n23
int m = 0n59
int s = 0n59
0:000> dv /t this
class Time * this = 0x001efb24
0:000> dx #$curstack.Frames[0].LocalVariables
#$curstack.Frames[0].LocalVariables
this : 0x1efb24 [Type: Time *]
0:000> dx #$curstack.Frames[0].LocalVariables.this
#$curstack.Frames[0].LocalVariables.this : 0x1efb24 [Type: Time *]
[+0x000] hour : 23 [Type: int]
[+0x004] minute : 59 [Type: int]
[+0x008] second : 59 [Type: int]
you can enhance this with javascript to fine tune it to you needs
here is how you can enhance this with javascript
make a file whateverfoo.js with contents below
function log(logstr) {
return host.diagnostics.debugLog(logstr + "\n")
}
function locvartgttyp(frameno)
{
log( host.currentThread.Stack.Frames[frameno].LocalVariables.this.targetType.name)
}
and use it like
:\>echo %wdbg%
"c:\Program Files\Windows Kits\10\Debuggers\x86\cdb.exe"
:\>%wdbg% time.exe
Microsoft (R) Windows Debugger Version 10.0.17763.132 X86
0:000> g time!main
time!main:
01237a80 55 push ebp
0:000> tc;t
time!Time::Time:
01231140 55 push ebp
0:000> dv /t
class Time * this = 0x00000002
int h = 0n23
int m = 0n59
int s = 0n59
0:000> .load jsprovider
0:000> .scriptload c:\wdscr\locvar.js
JavaScript script successfully loaded from 'c:\wdscr\locvar.js'
0:000> dx #$scriptContents.locvartgttyp(0)
Time *
#$scriptContents.locvartgttyp(0)
0:000>

Related

How to set a data breakpoint on a variable address in CDB (WinDbg)

class Test
{
public:
Test()
{
std::cout << "ctor" << std::endl;
ptr = new int(5);
*(ptr + 1) = 42;
};
~Test() { std::cout << "dtor" << std::endl; };
int* ptr;
};
void foo()
{
Test test;
}
int main()
{
foo();
return 0;
}
In the above example I want to set a data breakpoint at the address pointed to by ptr plus an offset (4 bytes in this case), to detect the heap corruption.
After I break inside the Test constructor, I have tried using the following to set the breakpoint but have failed:
0:000> ba w 4 (ptr + 4)
Bp expression '(ptr + 4)' could not be resolved, adding deferred bp
*** Bp expression '(ptr + 4)' contains symbols not qualified with module name
If I put the address manually then it obviously works. But I don't want to hard code the address in the command because I am doing this as part of a script and the address inside ptr can change every time.
What is the correct syntax for adding the data breakpoint without hardcoding the address?
You need ##c++() or .expr /s c++:
0:000> bp MemoryBreak!Test::Test
0:000> g
Breakpoint 2 hit
MemoryBreak!Test::Test:
[...]
0:000> l+t
Source options are 1:
1/t - Step/trace by source line
0:000> p
MemoryBreak!Test::Test+0x42:
0:000> ? ##c++(ptr)
Evaluate expression: 2790386541360 = 00000289`afffa330
0:000> ba w 4 ##c++(ptr)+4
0:000> bl
1 e Disable Clear 00007ff7`5fac2720 [C:\....cpp # 23] 0001 (0001) 0:**** MemoryBreak!main
2 e Disable Clear 00007ff7`5fac1fa0 [C:\....cpp # 6] 0001 (0001) 0:**** MemoryBreak!Test::Test
3 e Disable Clear 00000289`afffa334 w 4 0001 (0001) 0:****
0:000> g
Breakpoint 3 hit
MemoryBreak!Test::Test+0xa7:

Save job output from SDSF into a PDS and using ISPF functions in REXX

We periodically runs jobs and we need to save the output into a PDS and then parse the output to extract parts of it to save into another member. It needs to be done by issuing a REXX command using the percent sign and the REXX member name as an SDSF command line. I've attempted to code a REXX to do this, but it is getting an error when trying to invoke an ISPF service, saying the ISPF environment has not been established. But, this is SDSF running under ISPF.
My code has this in it (copied from several sources and modified):
parse arg PSDSFPARMS "(" PUSERPARMS
parse var PSDSFPARMS PCURRPNL PPRIMPNL PROWTOKEN PPRIMCMD .
PRIMCMD=x2c(PPRIMCMD)
RC = isfquery()
if RC <> 0 then
do
Say "** SDSF environment does not exist, exec ending."
exit 20
end
RC = isfcalls("ON")
Address SDSF "ISFGET" PPRIMPNL "TOKEN('"PROWTOKEN"')" ,
" (" VERBOSE ")"
LRC = RC
if LRC > 0 then
call msgrtn "ISFGET"
if LRC <> 0 then
Exit 20
JOBNAME = value(JNAME.1)
JOBNBR = value(JOBID.1)
SMPDSN = "SMPE.*.OUTPUT.LISTINGS"
LISTC. = ''
SMPODSNS. = ''
SMPODSNS.0 = 0
$ = outtrap('LISTC.')
MSGVAL = msg('ON')
address TSO "LISTC LVL('"SMPDSN"') ALL"
MSGVAL = msg(MSGVAL)
$ = outtrap('OFF')
do LISTCi = 1 to LISTC.0
if word(LISTC.LISTCi,1) = 'NONVSAM' then
do
parse var LISTC.LISTCi . . DSN
SMPODSNS.0 = SMPODSNS.0 + 1
i = SMPODSNS.0
SMPODSNS.i = DSN
end
IX = pos('ENTRY',LISTC.LISTCi)
if IX <> 0 then
do
IX = pos('NOT FOUND',LISTC.LISTCi,IX + 8)
if IX <> 0 then
do
address ISPEXEC "SETMSG MSG(IPLL403E)"
EXITRC = 16
leave
end
end
end
LISTC. = ''
if EXITRC = 16 then
exit 0
address ISPEXEC "TBCREATE SMPDSNS NOWRITE" ,
"NAMES(TSEL TSMPDSN)"
I execute this code by typing %SMPSAVE next to the spool output line on the "H" SDSF panel and it runs fine until it gets to this point in the REXX:
114 *-* address ISPEXEC "TBCREATE SMPDSNS NOWRITE" ,
"NAMES(TSEL TSMPDSN)"
>>> "TBCREATE SMPDSNS NOWRITE NAMES(TSEL TSMPDSN)"
ISPS118S SERVICE NOT INVOKED. A VALID ISPF ENVIRONMENT DOES NOT EXIST.
+++ RC(20) +++
Does anyone know why it says I don't have a valid ISPF environment and how I can get around this?
I've done quite a bit in the past with REXX, including writing REXX code to handle line commands, but this is the first time I've tried to use ISPEXEC commands within this code.
Thank you,
Alan

conditional breakpoint does not work in windbg

I have following c++ code
int myvar=1;
void test1( int j)
{
int b=j+1;
}
void main()
{
myvar=2;
test1(50);
myvar=3;
test1(100);
myvar=6;
test1(200);
}
I'm trying to set a breakpoint that stops if myvar is greater than 4 when running function test1.
Here is my breakpoint:
bp test!test1 ".if ( poi(myvar)>0n4) {} .else {gc} "
however, it stops every time test1 is executed...
The executable file is called test.exe, a 64 bit application.
Any suggestion would be appreciated.
A little bit of debugging in the breakpoint reveals what is happening:
0 e Disable Clear 00007ff6`77e11410 [f:\projects\windbg_help\main.cpp # 4] 0001 (0001) 0:**** windbg_help!test1 "?? myvar; r $t1=myvar; ?? #$t1; r $t2=poi(myvar); ?? #$t2; .if (dwo(myvar) > 0n4) {.echo yes; gc} .else {.echo no; gc} "
I set the t1 temp register to myvar, and t2 temp register to the contents of myvar, then display them:
0:000> g
int 0n2
unsigned int64 0x00007ff6`77e1c000
unsigned int64 0xffffffff`00000002
no
int 0n3
unsigned int64 0x00007ff6`77e1c000
unsigned int64 0xffffffff`00000003
no
int 0n6
unsigned int64 0x00007ff6`77e1c000
unsigned int64 0xffffffff`00000006
yes
ModLoad: 00007ff9`c8520000 00007ff9`c8531000 C:\WINDOWS\System32\kernel.appcore.dll
ModLoad: 00007ff9`c9da0000 00007ff9`c9e3e000 C:\WINDOWS\System32\msvcrt.dll
ModLoad: 00007ff9`c9aa0000 00007ff9`c9bc2000 C:\WINDOWS\System32\RPCRT4.dll
ntdll!NtTerminateProcess+0x14:
00007ff9`cc5cfcd4 c3 ret
Notice how poi(myvar) is returning a 64bit value, and the upper 32bits are set. You poi(myvar) > 0n4 comparison is saying:
if (0xffffffff0000000? > 4) then { always true }
use dwo(myvar) instead to read only the 32bit contents

robotic arm not working with pyserial and gcode

I am working on a robotic arm.
M106 is turn on the fan
M17 is stepper on
M18 is stepper off
G1 X... Y.. X.. is the coordinates of movement
the port is correct, the terminal prints the hello hi there...
However the robotic arm is not moving, I totally have no clue why is this happening.
Is it there is some problem with my code?
import serial
import struct
def gcode_encode(gcode):
gcode += '\r\n'
return struct.pack(f'<{len(gcode)}s', gcode.encode(encoding='utf-8'))
print("hello")
# ser = serial.Serial('COM7', 9600, timeout=0, parity=serial.PARITY_EVEN, rtscts=1)
ser = serial.Serial()
ser.port = 'COM7'
ser.baudrate = 9600
ser.timeout = 0
ser.open()
g = gcode_encode('M106')
ser.write(b'g')
g = gcode_encode('M17')
ser.write(b'g')
g = gcode_encode('M18')
ser.write(b'g')
g = gcode_encode('G1 X0 Y120 Z120')
ser.write(b'g')
g = gcode_encode('G1 X50 Y120 Z60')
ser.write(b'g')
ser.close()
print("hi")
You are writing only the character 'g' to the port. If you want to write bytes of a variable g, you need to use bytes(g). The same is with f'<{len(gcode)}s', the characters in single or double quotes are not a command here, but just a string. Also you don't need packing of the string, just encoding.
Also add some pauses between commands using time.sleep().

kdb: guid encoding in c results in invalid serialization

I'm trying to manipulate guid from C++. Whenever I attempt to serialize a guid, I get a null pointer.
U g={0};
auto k = ku(g);
auto p = ::b9(2, k);
First two lines are straight from the manual for creating a null guid. This will result in p == 0.
Really what I was attempting to do was creating a list of guid and then serializing:
k = ktn(UU, 3)
kU(k)[0] = <an instance of U with the g bytes initialized>
kU(k)[1] = <an instance of U with the g bytes initialized>
kU(k)[2] = <an instance of U with the g bytes initialized>
That did not work when attempting to serialize.
I believe you should be using 3 as the first argument to b9. For example:
jmcmurray#homer ~/c $ more test.c
#include"k.h"
K f(K x)
{
K k = ktn(UU,3);I j=0;
for(j=0;j<3;j++){
U g={0};I i=0;
for(i=j;i<j+16;i++){
g.g[i] = (unsigned char)i;
}
kU(k)[0] = g;
}
return b9(3,k);
}
jmcmurray#homer ~/c $ gcc -shared -fPIC -DKXVER=3 test.c -o test.so
jmcmurray#homer ~/c $ q
KDB+ 3.5 2017.11.30 Copyright (C) 1993-2017 Kx Systems
l64/ 8()core 16048MB jmcmurray homer.aquaq.co.uk 192.168.1.57 EXPIRE 2019.06.30 AquaQ #52428
q)f:`:./test 2:(`f;1)
q)f[]
0x010000003e000000020003000000000002030405060708090a0b0c0d0e0f00ae67af727f000..
q)-9!f[]
00000203-0405-0607-0809-0a0b0c0d0e0f 001868af-727f-0000-6062-67af727f0000 a0a..
q)
Here I am able to return a serialised list of GUIDs from my shared object & deserialize on the q side. When I tried with 2 as in your example I got a 'type error when running the function in q.
According to https://code.kx.com/q/interfaces/capiref/#b9-serialize 3 means
unenumerate, compress, allow serialization of timespan and timestamp
2 is the same without "compress". So I guess you must compress GUIDs?