I have a crash dump and I suspect GDI leaks to be a cause of the crash
From the full crash dump is there anyway to find out the number of GDI handles used by my process when it crashed?
I have created a Windbg script to dump all GDI Handles from the GDI Handle table. See https://aloiskraus.wordpress.com/2016/06/25/show-gdi-handles-by-type-in-windbg/
When you dump it e.g. two times you can see what has changed there:
0:013> $$>a<"D:\GdiDump\DumpGdi.txt"
GDI Handle Table 00000000013e0000 0000000001561000
GDI Handle Count 14
DeviceContexts: 4
Regions: 2
Bitmaps: 2
Palettes: 0
Fonts: 3
Brushes: 3
Pens: 0
Uncategorized: 0
0:013> g
0:014> $$>a<"D:\GdiDump\DumpGdi.txt"
GDI Handle Table 00000000013e0000 0000000001561000
GDI Handle Count 1021
DeviceContexts: 8
Regions: 3
Bitmaps: 1003
Palettes: 0
Fonts: 3
Brushes: 4
Pens: 0
Uncategorized: 0
Here is the script
$$ Run as: $$>a<DumpGdi.txt
$$ Written by Alois Kraus 2016
$$ uses pseudo registers r0-5 and r8-r14
r #$t1=0
r #$t8=0
r #$t9=0
r #$t10=0
r #$t11=0
r #$t12=0
r #$t13=0
r #$t14=0
$$ Increment count is 1 byte until we find a matching field with the current pid
r #$t4=1
r #$t0=$peb
$$ Get address of GDI handle table into t5
.foreach /pS 3 /ps 1 ( #$GdiSharedHandleTable { dt ntdll!_PEB GdiSharedHandleTable #$t0 } ) { r #$t5 = #$GdiSharedHandleTable }
$$ On first call !address produces more output. Do a warmup
.foreach /pS 50 ( #$myStartAddress {!address #$t5} ) { }
$$ Get start address of file mapping into t2
.foreach /pS 4 /ps 40 ( #$myStartAddress {!address #$t5} ) { r #$t2 = #$myStartAddress }
$$ Get end address of file mapping into t3
.foreach /pS 7 /ps 40 ( #$myEndAddress {!address #$t5} ) { r #$t3 = #$myEndAddress }
.printf "GDI Handle Table %p %p", #$t2, #$t3
.for(; #$t2 < #$t3; r #$t2 = #$t2 + #$t4)
{
$$ since we walk bytewise through potentially invalid memory we need first to check if it points to valid memory
.if($vvalid(#$t2,4) == 1 )
{
$$ Check if pid matches
.if (wo(#$t2) == #$tpid )
{
$$ increase handle count stored in $t1 and increase step size by 0x18 because we know the cell structure GDICell has a size of 0x18 bytes.
r #$t1 = #$t1+1
r #$t4 = 0x18
$$ Access wType of GDICELL and increment per GDI handle type
.if (by(#$t2+6) == 0x1 ) { r #$t8 = #$t8+1 }
.if (by(#$t2+6) == 0x4 ) { r #$t9 = #$t9+1 }
.if (by(#$t2+6) == 0x5 ) { r #$t10 = #$t10+1 }
.if (by(#$t2+6) == 0x8 ) { r #$t11 = #$t11+1 }
.if (by(#$t2+6) == 0xa ) { r #$t12 = #$t12+1 }
.if (by(#$t2+6) == 0x10 ) { r #$t13 = #$t13+1 }
.if (by(#$t2+6) == 0x30 ) { r #$t14 = #$t14+1 }
}
}
}
.printf "\nGDI Handle Count %d", #$t1
.printf "\n\tDeviceContexts: %d", #$t8
.printf "\n\tRegions: %d", #$t9
.printf "\n\tBitmaps: %d", #$t10
.printf "\n\tPalettes: %d", #$t11
.printf "\n\tFonts: %d", #$t12
.printf "\n\tBrushes: %d", #$t13
.printf "\n\tPens: %d", #$t14
.printf "\n\tUncategorized: %d\n", #$t1-(#$t14+#$t13+#$t12+#$t11+#$t10+#$t9+#$t8)
It is unlikely since the only debugger extension gdikdx.dll tailored at gdi tasks is not actively maintained since the w2k version and i believe they stopped shipping it since not that many folks are into hacking into gdi internals - according to someone's statement i stumbled upon in a newsgroup - therefore it is no longer invested into.
You're left with only a few options all of which are unfortunately about runtime troubleshooting.
You could start with a tool like nirsoft's GDIView to monitor the use of GDI resources from your app and then progress to any of the runtime instrumentation options:
gdi leaks detector tool described on msdn
bug browser
leaktrap
P.S. could you be more specific on the actual reason of your particular crash?
Tess talks about a similar situation, perhaps this will give you a lead...
http://blogs.msdn.com/tess/archive/2009/02/03/net-memory-leak-to-dispose-or-not-to-dispose-that-s-the-1-gb-question.aspx
Here is an alternative script that dumps the gdi handles from GdiSharedHandleTable it can be used in live usermode / live kernelmode / dump mode
it can also be used in !for_each_process command string to dump gdi handles from all running process in a kernel mode debugging
it uses a .catch block to print the summary
in kd some times the GdiSharedhandleTable page will be paged out / truncated to less than its allocation size The peb header paged out etc problems arise
so this script tries to read as much as it is possible and when a memory access violation happens leaves the catch block and prints a summary of
what it was able to salvage
btw this script is for 32 bit for 64 bit the Pseudo registers need to be adjusted as needed
r $t19=0;r $t18=0;r $t17=0;r $t16=0;r $t15=0;r $t14=0;r $t13=0;r $t12=0;
r $t0 = ##c++(#$Peb->GdiSharedHandleTable)
r $t1 = (##c++(#$Peb->GdiSharedHandleTable) + 0xffffff )
r $t2 = 0
.catch {
.printf /D "<b>gdioffs Kaddr Pid Count Handle Type Tname
IsLive UAddr </b>\n";
.while(#$t0 < #$t1) {
.while( wo(#$t0+4) != #$tpid) {
r $t0 = #$t0+0x10 ; r $t2 = #$t2+1
}
.printf "%08x " , #$t0 ; .printf "%08x " , dwo(#$t0)
.printf "%08x " , wo(#$t0+4) ;.printf "%08x " , wo(#$t0+6)
.printf "%08x " , (wo(#$t0+8)<<0x10)+#$t2 ; .printf "%08x " , by(#$t0+a)
.if( by(#$t0+a) == 1 ) {r $t19=#$t19+1;.printf "DC "}
.elsif( by(#$t0+a) == 4 ) {r $t18=#$t18+1;.printf "Region "}
.elsif( by(#$t0+a) == 5 ) {r $t17=#$t17+1;.printf "Bitmap "}
.elsif( by(#$t0+a) == 8 ) {r $t16=#$t16+1;.printf "Pallete "}
.elsif( by(#$t0+a) == a ) {r $t15=#$t15+1;.printf "Font "}
.elsif( by(#$t0+a) == 10) {r $t14=#$t14+1;.printf "Brush "}
.elsif( by(#$t0+a) == 30) {r $t13=#$t13+1;.printf "Pen "}
.else {r $t12=#$t12+1;.printf "Unknown "}
.printf "%08x " , by(#$t0+b)
.printf "%08x\n" , dwo(#$t0+c)
r $t0 = #$t0+0x10
r $t2 = #$t2+1
}
}
r? #$t11 = ##c++(#$peb->ProcessParameters->ImagePathName.Buffer)
.printf /D "<b>Gdi Handles for %mu</b>\n", #$t11
.printf "Total Gdi Handles = %d\n", (#$t19+#$t18+#$t17+#$t16+#$t15+#$t14+#$t13+#$t12)
.printf "DC = %d\n" , #$t19 ; .printf "Font = %d\n" , #$t18
.printf "Region = %d\n" , #$t17 ; .printf "Brush = %d\n" , #$t16
.printf "Bitmap = %d\n" , #$t15 ; .printf "Pen = %d\n" , #$t14
.printf "Pallete = %d\n" , #$t13 ; .printf "Unknpown = %d\n" , #$t12
result of execution
0:000> $$>a< c:\wdscr\dumpgdi.txt
gdioffs Kaddr Pid Count Handle Type Tname ;IsLive UAddr
00472b30 fe6b5728 00000ca4 00000000 0d0102b3 00000001 DC 00000040 000e0cb0
00472be0 fdf73da8 00000ca4 00000000 420502be 00000005 Bitmap 00000040 00000000
004737b0 fddac108 00000ca4 00000000 9605037b 00000005 Bitmap 00000040 00000000
00474030 fe76eda8 00000ca4 00000000 eb050403 00000005 Bitmap 00000040 00000000
00474c90 fddde008 00000ca4 00000000 d70a04c9 0000000a Font 00000040 001fb1e8
0047ab80 fddab008 00000ca4 00000000 ba050ab8 00000005 Bitmap 00000040 00000000
0047f270 fddbcda8 00000ca4 00000000 16050f27 00000005 Bitmap 00000040 00000000
0047fef0 fdee4da8 00000ca4 00000000 cd050fef 00000005 Bitmap 00000040 00000000
004809f0 fe72eda8 00000ca4 00000000 3405109f 00000005 Bitmap 00000040 00000000
00480e50 fdda5aa8 00000ca4 00000000 0e0510e5 00000005 Bitmap 00000040 00000000
00481cf0 ffb0fda8 00000ca4 00000000 df0511cf 00000005 Bitmap 00000040 00000000
00481d70 fddb0da8 00000ca4 00000000 930511d7 00000005 Bitmap 00000040 00000000
00482020 ff4a1da8 00000ca4 00000000 d4051202 00000005 Bitmap 00000040 00000000
00482060 fddd4008 00000ca4 00000000 39051206 00000005 Bitmap 00000040 00000000
00482170 fddb6008 00000ca4 00000000 20051217 00000005 Bitmap 00000040 00000000
00483140 ff4a0008 00000ca4 00000000 4e051314 00000005 Bitmap 00000040 00000000
00483870 ff427980 00000ca4 00000000 6d051387 00000005 Bitmap 00000040 00000000
00483d80 fe7d04b0 00000ca4 00000000 bd0513d8 00000005 Bitmap 00000040 00000000
00484620 ff437eb8 00000ca4 00000000 0d101462 00000010 Brush 00000040 000f0fd8
004846a0 fddc2da8 00000ca4 00000000 d305146a 00000005 Bitmap 00000040 00000000
00484b80 fdf1a728 00000ca4 00000000 530114b8 00000001 DC 00000040 000e0ae0
Memory access error at ') != #$tpid) <-------- jumps out of catch block here
Gdi Handles for C:\Windows\system32\calc.exe
Total Gdi Handles = 21
DC = 2
Font = 0
Region = 17
Brush = 0
Bitmap = 1
Pen = 1
Pallete = 0
Unknpown = 0
Related
I want to do something like break at Process!Function+0x66 but only if [RDX + 0x01c] == 1.
What would the syntax of breakpoint like this be?
evaluate with ? Process!Function+0x66
copy the result for using in breakpoint 0x12345678`90abcdef
bp 0x12345678`90abcdef ".if ( poi(#rdx+0x1c) != 1) {gc}"
a sample flow
0:000> ? msvcrt!memcpy+0x40
Evaluate expression: 140735863146304 = 00007fff`9f214740
0:000> u msvcrt!memcpy+0x40 l1
msvcrt!memcpy+0x40:
00007fff`9f214740 8a0411 mov al,byte ptr [rcx+rdx]
0:000> bp 00007fff`9f214740 " .if( poi(#rcx+#rdx) != 0x20) {gc}"
0:000> bl 0 e 00007fff`9f214740 0001 (0001) msvcrt!memcpy+0x40 ".if( poi(#rcx+#rdx) != 0x20) {gc}"
0:000> g
Microsoft (R) Windows Debugger Version 10.0.17763.132 AMD64
msvcrt!memcpy+0x40:
00007fff`9f214740 8a0411 mov al,byte ptr [rcx+rdx] ds:000001d6`1ebc6ac1=20
0:000> .lastevent
Last event: 724.1718: Hit breakpoint 0
debugger time: Wed Jun 16 00:25:26.965 2021
0:000> g
msvcrt!memcpy+0x40:
00007fff`9f214740 8a0411 mov al,byte ptr [rcx+rdx] ds:000001d6`20407c4a=20
0:000> .lastevent
Last event: 724.1718: Hit breakpoint 0
debugger time: Wed Jun 16 00:25:45.283 2021
0:000>
Answer: Thanks to Jerry Jeremiah I have the solution the end result is this:
grep -E '^\S{8} \S' test.lst | awk -F';' '{print substr($1,1,35)gensub("[[:space:]]+"," ","g",substr($1,36));}'
It requires having gawk installed
Original Question:
I have a file which i want to sanitise the output and then diff however i'm having problems coming up with working regex to do what i want
Basically i want to ignore the first 36 characters then after that start with the first non white space character and replace all multiple white spaces with a single space and strip and line comment off the end which starts with a ; and remove any trailing whitespace
I just cant figure out how to get a pattern that works while ignoring those first 36 characters, any time i use a capture group like (\S*([^\s]\s+))* it will only ever return the last match
This is an example of the code i'm grepping into sed:
00000000 =00A00000 z80_ram: equ $A00000 ; start of Z80 RAM
00000000 =00A000EA z80_dac3_pitch: equ $A000EA
00000000 =00A01FFD z80_dac_status: equ $A01FFD
00000000 =00A01FFF z80_dac_sample: equ $A01FFF
00000000 =00A02000 z80_ram_end: equ $A02000 ; end of non-reserved Z80 RAM
00000000 =00A10001 z80_version: equ $A10001
00000000 =00A10002 z80_port_1_data: equ $A10002
00000000 =00A10008 z80_port_1_control: equ $A10008
00000000 =00A1000A z80_port_2_control: equ $A1000A
00000000 =00A1000C z80_expansion_control: equ $A1000C
00000000 =00A11100 z80_bus_request: equ $A11100
00000000 =00A11200 z80_reset: equ $A11200
00000000 =00A04000 ym2612_a0: equ $A04000
00000000 =00A04001 ym2612_d0: equ $A04001
00000000 =00A04002 ym2612_a1: equ $A04002
00000000 =00A04003 ym2612_d1: equ $A04003
00000000 =00A14000 security_addr: equ $A14000
00000214 6600 bne.s SkipSetup ; Skip the VDP and Z80 setup code if port A, B or C is ok...?
00000216 4BFA 0000 lea SetupValues(pc),a5 ; Load setup values array address.
0000021A 4C9D 00E0 movem.w (a5)+,d5-d7
0000021E 4CDD 1F00 movem.l (a5)+,a0-a4
00000222 1029 EF01 move.b -$10FF(a1),d0 ; get hardware version (from $A10001)
00000226 0200 000F andi.b #$F,d0
0000022A 6700 beq.s SkipSecurity ; If the console has no TMSS, skip the security stuff.
0000022C 237C 5345 4741 2F00 move.l #'SEGA',$2F00(a1) ; move "SEGA" to TMSS register ($A14000)
The output I want is this:
00000000 =00A00000 z80_ram: equ $A00000
00000000 =00A000EA z80_dac3_pitch: equ $A000EA
00000000 =00A01FFD z80_dac_status: equ $A01FFD
00000000 =00A01FFF z80_dac_sample: equ $A01FFF
00000000 =00A02000 z80_ram_end: equ $A02000
00000000 =00A10001 z80_version: equ $A10001
00000000 =00A10002 z80_port_1_data: equ $A10002
00000000 =00A10008 z80_port_1_control: equ $A10008
00000000 =00A1000A z80_port_2_control: equ $A1000A
00000000 =00A1000C z80_expansion_control: equ $A1000C
00000000 =00A11100 z80_bus_request: equ $A11100
00000000 =00A11200 z80_reset: equ $A11200
00000000 =00A04000 ym2612_a0: equ $A04000
00000000 =00A04001 ym2612_d0: equ $A04001
00000000 =00A04002 ym2612_a1: equ $A04002
00000000 =00A04003 ym2612_d1: equ $A04003
00000000 =00A14000 security_addr: equ $A14000
00000214 6600 bne.s SkipSetup
00000216 4BFA 0000 lea SetupValues(pc),a5
0000021A 4C9D 00E0 movem.w (a5)+,d5-d7
0000021E 4CDD 1F00 movem.l (a5)+,a0-a4
00000222 1029 EF01 move.b -$10FF(a1),d0
00000226 0200 000F andi.b #$F,d0
0000022A 6700 beq.s SkipSecurity
0000022C 237C 5345 4741 2F00 move.l #'SEGA',$2F00(a1)
sed '
# Hold the line
h
# Remove 36 characters
s/.\{36\}//
# Remove comments
s/;.*//
# Remove leading spaces
s/[ ]*//
# Squeeze spaces after first word
s/\([^ ]*\) */\1 /
# Shuffle the output with holded line
G
s/\(.*\)\n\(.\{36\}\).*/\2\1/
'
Tested on repl when applied to input generates expected output.
how to get a pattern that works while ignoring those first 36 characters
First hold the line or relevant parts of the line you want to save. Then remove the parts you do not want to apply regex on, apply the regex. Then join the line with holded data and reorder them for the output.
You may use awk like:
awk -F';' '{a=substr($1,1,35); b=substr($1,36); gsub("[[:space:]]+"," ",b);print a b;}' file > outfile
See an online awk demo
Details
-F';' - field separator set to ;
a=substr($1,1,35) - set an a variable equal to a (1,35) char substring of Field 1
b=substr($1,36) - set a b variable equal to a (36,) char substring of Field 1
gsub("[[:space:]]+"," ",b) - replace all chunks of 1 or more whitespace chars with a single regular space char in the b variable only
print a b - print concatenated a and b variable values.
I am using the following windbg script to break when a certain value is encountered in the buffer when reading a file
bp ReadFile
.while(1)
{
g
$$ Get parameters of ReadFile()
r $t0 = dwo(esp+4)
r $t1 = dwo(esp+8)
r $t2 = dwo(esp+0x0c)
$$ Execute until return is reached
pt
$$ Read magic value in the buffer
$$ CHANGE position in buffer here
r $t5 = dwo(#$t1+0x00)
$$ Check if magic value matches
$$ CHANGE constant here
.if(#$t5 == 0x70170000)
{
$$db #$t1
$$ break
.break
}
}
$$ Clear BP for ReadFile (assume it is the 0th one)
bc 0
I get the following memory access violation when I run this script.
Memory access error at ');; $$ Check if magic value matches; $$ CHANGE constant here; .if(#$t5 == 0x70170000); {; $$db #$t1;; $$ break; .break; };'
Why is this the case?
If you need to read the buffer contents at kernel32!ReadFile you need to save the buffer address and step out of the function using gu (goup or step out)
when broken on ReadFile esp+8 points to the buffer so save it and step out
r $t1 = poi(#esp+8);gu
the first Dword of the buffer is poi(#$t1) compare it with the required Dword
and take necessary action with .if .else
.if( poi(#$t1) != 636c6163 ) {gc} .else {db #$t1 l10;gc}
putting this all together in one line the script shoule be
bp k*32!ReadFile "r $t1 =poi(#esp+8);gu;.if((poi(#$t1))!=636c6163){gc}.else{db #$t1 l10;gc}"
here 636c6163 is 'clac' (calc reversed ) use the dword you want instead of this
a sample run on calc.exe xp sp3 32 bits
bl
bp k*32!ReadFile "r $t1=poi(#esp+8);gu;.if((poi(#$t1))!=636c6163){gc}.else{db #$t1 l10;gc}"
.bpcmds
bp0 0x7c801812 "r $t1 = poi(#esp+8);gu;.if( (poi(#$t1))!=636c6163){gc}.else{db #$t1 l10;gc}"
0:002> g
00b865b0 63 61 6c 63 5f 77 68 61-74 69 73 5f 69 6e 74 72 calc_whatis_intr
00374df0 63 61 6c 63 00 ab ab ab-ab ab ab ab ab fe ee fe calc............
My application get access violation sometimes.
I runned application through windbg, and it stopped in the following function .
also tried _vscprintf instead of vsnprintf, and the result was same.
I 'm newbie about windbg.
Any help will be appreciated.
int tsk_sprintf_2(char** str, const char* format, va_list* ap)
{
int len = 0;
va_list ap2;
ap2 = *ap;
len = vsnprintf(0, 0, format, *ap); /*-> access violation in this point! */
*str = (char*)calloc(1, len+1);
vsnprintf(*str, len, format, ap2);
va_end(ap2);
return len;
}
==> the following are the result from windbg
MANAGED_STACK: !dumpstack -EE
OS Thread Id: 0x5b8 (22)
Current frame:
ChildEBP RetAddr Caller, Callee
PRIMARY_PROBLEM_CLASS: WRONG_SYMBOLS
BUGCHECK_STR: APPLICATION_FAULT_WRONG_SYMBOLS
LAST_CONTROL_TRANSFER: from 1026d3d8 to 102e14cf
STACK_TEXT:
WARNING: Stack unwind information not available. Following frames may be wrong.
1d3cde7c 1026d3d8 1d3cdea8 0898eeeb 00000000 MSVCR100D!vcwprintf_s_l+0x52ef
1d3cded0 1026d46c 00000000 00000000 0898ee88 MSVCR100D!vsnprintf_l+0x158
1d3cdeec 0834d927 00000000 00000000 0898ee88 MSVCR100D!vsnprintf+0x1c
1d3cdfe8 1002891e 1d3ce0d0 0898ee88 1d3ce1e4 tinySAK!tsk_sprintf_2+0x57
1d3ce0f0 10028b77 09a16fe8 0898ee88 00000000 tinyWRAP!debug_xxx_cb+0x6e
1d3ce1ec 088b697b 09a16fe8 0898ee88 00000444 tinyWRAP!DDebugCallback::debug_info_cb+0x37
1d3cffb4 7c80b713 1cd10f90 1d2cfb44 7c947d9a tinyNET!tnet_transport_mainthread+0x1adb
1d3cffec 00000000 088a2aff 1cd10f90 00000000 KERNEL32!GetModuleFileNameA+0x1b4
SYMBOL_STACK_INDEX: 0
SYMBOL_NAME: msvcr100d!vcwprintf_s_l+52ef
FOLLOWUP_NAME: MachineOwner
MODULE_NAME: MSVCR100D
IMAGE_NAME: MSVCR100D.dll
STACK_COMMAND: ~22s ; kb
BUCKET_ID: WRONG_SYMBOLS
FAILURE_BUCKET_ID: WRONG_SYMBOLS_c0000005_MSVCR100D.dll!vcwprintf_s_l
WATSON_STAGEONE_URL:
Followup: MachineOwner
---------
route.
You're attempting to print into a NULL pointer: len = vsnprintf(0, 0, format, *ap);; of course, it will crash. Send a valid address of output buffer as the first parameter and valid length as second.
I'm trying to get TCP open port list in iphone by using sysctlbyname().
sysctlbyname(const char *name, void *oldp, size_t *oldlenp, void *newp,
size_t newlen);
.
#include <sys/sysctl.h>
size_t len = 0;
if (sysctlbyname("net.inet.tcp.pcblist", 0, &len, 0, 0) < 0) {
perror("sysctlbyname");
} else {
char *buf = malloc(len);
//printf("%d",sizeof(buf));
sysctlbyname("net.inet.tcp.pcblist", buf, &len, 0, 0);
NSData *data = [NSData dataWithBytesNoCopy:buf length:len];
NSLog(#"data = %#", data);
//printf("%d",sizeof(buf));
//printf("%s",buf);
}
The information is copied into the buffer specified by oldp.
OUTPUT::
data = <18000000 34000000 d8160000 00000000 7d760000 00000000 0c020000 00000000 00000000 00000000 00000000 0050c598 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 c2160000 00000000 40008000 00000000 01400000
Buffer is filled with data here.but I'm unable to print the data in readable format.converting this data into NSString won't help as internally buffer has its own structure.
Anyone knows how to obtain TCP open port list as output from this data?
Thanks.
copy netstat code from BSD source.
see the printproto() function in main.c
This will explore all related to this buffer and how to get TCP port list.
Thanks.