As a driver developer WinDbg is one of my best friends.
Now starting with Windows 8, I installed the new WDK and wanted to use its new WinDbg. It has some nice features like remote debugging over the network.
But while using it, I became shocked when I realized that I can only activate 32 breakpoints. The following message is shown:
*******************************************************************************
* You have attempted to enable 33 KD breakpoints, which exceeds the *
* currently supported limit of 32 breakpoints for Windows kernel debugging. *
* Breakpoints exceeding this limit are ignored. *
* Please disable/clear breakpoints until you are within the supported limit. *
*******************************************************************************
This was not the case in earlier versions. Is there a way around this? A option I did not found yet, a registry key or maybe I can patch the executable?
Interesting. The warning messages are coming from dbgeng!AddBreakpoint and in stepping through the code it looks like the limit of 32 is hard coded:
cmp esi, 20h
jbe short loc_100A5721
push offset asc_10038758 ; "***************************************"...
call ?WarnOut##YAXPBGZZ
pop ecx
push esi
push offset aYouHaveAttempt ; "* You have attempted to enable %4u KD b"...
call ?WarnOut##YAXPBGZZ
push 20h
push offset aCurrentlySuppo ; "* currently supported limit of %4u brea"...
call ?WarnOut##YAXPBGZZ
push offset aBreakpointsExc ; "* Breakpoints exceeding this limit are "...
call ?WarnOut##YAXPBGZZ
I suspect that just patching this one check would NOT be sufficient, but I haven't looked any further to confirm that.
You can place int 3 (byte 0xCC) at any address by the following command: eb [address] cc
Make sure to restore the original byte when you hit int 3.
Related
I have a huge application (made in PowerBuilder) that crashes every once in a while so it is hard to reproduce this error. We have it set up so that when a crash like this occurs, we recieve a .dmp file.
I used WinDbg to analyze my .dmp file with the command !analyze -v. From this I can deduct that the error that occured was an Access Violation C0000005. Based on the [0] and [1] parameters, it attempted to dereference a null pointer.
WinDbg also showed me STACK_TEXT consisting of around 30 lines, but I am not sure how to read it. From what I have seen I need to use some sort of symbols.
First line of my STACK_TEXT is this:
00000000`00efca10 00000000`75d7fa46 : 00000000`10df1ae0 00000000`0dd62828 00000000`04970000 00000000`10e00388 : pbvm!ob_get_runtime_class+0xad
From this, my goal is to analyze this file to figure out where exactly in the program this error happened or which function it was in. Is this something I will be able to find after further analyzing the stack trace?
How can I pinpoint where in the program a crash happened using .dmp and WinDbg so I can fix my code?
If you analyze a crash dump with !analyze -v, the lines after STACK TEXT is the stack trace. The output is equivalent to kb, given you set the correct thread and context.
The output of kb is
Child EBP
Return address
First 4 values on the stack
Symbol
The backticks ` tell you that you are running in 64 bit and they split the 64 bit values in the middle.
On 32 bit, the first 4 parameters on the stack were often equivalent to the first 4 parameters to the function, depending on the calling convention.
On 64 bit, the stack is not so relevant any more, because with the 64 bit calling convention, parameters are passed via registers. Therefore you can probably ignore those values.
The interesting part is the symbol like pbvm!ob_get_runtime_class+0xad.
In front of ! is the module name, typically a DLL or EXE name. Look for something that you built. After the ! and before the + is a method name. After the + is the offset in bytes from the beginning of the function.
As long as you don't have functions with thousands of lines of code, that number should be small, like < 0x200. If the number is larger than that, it typically means that you don't have correct symbols. In that case, the method name is no longer reliable, since it's probably just the last known (the last exported) method name and a faaaar way from there, so don't trust it.
In case of pbvm!ob_get_runtime_class+0xad, pbvm is the DLL name, ob_get_runtime_class is the method name and +0xad is the offset within the method where the instruction pointer is.
To me (not knowing anything about PowerBuilder) PBVM sounds like the PowerBuilder DLL implementation for Virtual Memory. So that's not your code, it's the code compiled by Sybase. You'd need to look further down the call stack to find the culprit code in your DLL.
After reading Wikipedia, it seems that PowerBuilder does not necessarily compile to native code, but to intermediate P-Code instead. In this case you're probably out of luck, since your code is never really on the call stack and you need a special debugger or a WinDbg extension (which might not exist, like for Java). Run it with the -pbdebug command line switch or compile it to native code and let it crash again.
I was looking for a way to get the contents of the MXCSR register in WinDbg. Looking up the help for the r command I found a lot of options. I thought I had covered all registers with the command
0:000> rM 0xfe7f
However, the MXCSR register was still not included. So I did a full search in WinDbg help, which did not give me any results (sorry for the German screenshot):
So I continued my search in the Internet and finally found
0:000> r mxcsr
mxcsr=00001f80
I am now wondering whether there are other registers that will not be displayed by rM 0xfe7f but are available anyways. I am especially interested in user mode and x86 and AMD64 architecture.
I had a look at dbgeng.dll (version 10.0.20153.1000) and found a few more registers by trying some strings around offset 7DC340. Based on some of that information, I found the MSDN websites x64 registers and x86 registers.
In addition I found
brto, brfrom, exto, exfrom
The registers zmm0 through zmm15 can be used as zmm0h, possibly for the high half.
The registers xmm0/ymm0 through xmm15/ymm15 can be used as ymm0h and ymm0l, likely for the high and low half.
some more which didn't work either because of my CPU model or because I tried it in user mode instead of kernel mode.
For investigating managed heap corruption I would like to use ba (break on access) breakpoints. Can I use them in managed code? If yes, how can I set them programmatically?
UPDATE: It would also be okay so set them in WinDbg (-> set ba for every object of type XY)
Breakpoints set by 'ba' command are called processor or hardware breakpoints.
First the good news
It is easy to set hardware breakpoint. You will need to set one of the processor's debug registers (DR0, DR1, DR2 or DR3) with the address of the data and set debug control register DR7 with fields to set size of memory and type of access. The instruction (in x64 assembler) looks like:
MOV rax, DR0
Obviously you will have to somehow execute this assembler instruction from your language of choice, or use interop to C++ and inline assembly, but this is easier than for example setting software breakpoint.
Now the bad news
First of all, on SMP machines you will have to do this for all processors that can touch your code. This is probably solvable if you configure processor affinity for you process, or do debugging on single-proc machine. Second, there are only 4 debug processors on Intel architecture. If you try setting processor breakpoints with WinDbg, after 4th it will complain Too many data breakpoints for thread N after you hit g.
I assume the whole purpose you are asking about automation is because there are too many objects to set breakpoints by hand. Since you are limited to 4 ba breakpoints anyways, there is not much point in automating this.
Most modern operating systems run in the protected mode. Now is it possible for the user programs to enter the "ring 0" by directly setting the corresponding bits in some control registers. Or does it have to go through some syscall.
I believe to access the hardware we need to go through the operating system. But if we know the address of the hardware device can we just write some assembly language code with reference to the location of the device and access it. What happens when we give the address of some hardware device in the assembly language code.
Thanks.
To enter Ring 0, you must perform a system call, and by its nature, the system controls where you go, because for the call you simply give an index to the CPU, and the CPU looks inside a table to know what to call. You can't really get around the security aspect (obviously) to do something else, but maybe this link will help.
You can ask the operating system to map the memory of the hardware device into the memory space of your program. Once that's done, you can just read and write that memory from ring 3. Whether that's possible to do, or how to do that, depends on the operating system or the device.
; set PE bit
mov cr0, eax
or eax, 1
mov eax, cr0
; far jump (cs = selector of code segment)
jmp cs:#pm
#pm:
; Now we are in PM
Taken from Wikipedia.
Basic idea is to set (to 1) 0th bit in cr0 control register.
But if you are already in protected mode (i.e. you are in windows/linux), security restricts you to do it (you are in ring 3 - lowest trust).
So be the first one to get into protected mode.
I'm getting this error while doing a git svn rebase in cygwin
Out of memory during "large" request for 268439552 bytes, total sbrk() is 140652544 bytes at /usr/lib/perl5/site_perl/Git.pm line 898, <GEN1> line 3.
268439552 is 256MB. Cygwin's maxium memory size is set to 1024MB so I'm guessing that it has a different maximum memory size for perl?
How can I increase the maximum memory size that perl programs can use?
update:
This is where the error occurs (in Git.pm):
while (1) {
my $bytesLeft = $size - $bytesRead;
last unless $bytesLeft;
my $bytesToRead = $bytesLeft < 1024 ? $bytesLeft : 1024;
my $read = read($in, $blob, $bytesToRead, $bytesRead); //line 898
unless (defined($read)) {
$self->_close_cat_blob();
throw Error::Simple("in pipe went bad");
}
$bytesRead += $read;
}
I've added a print before line 898 to print out $bytesToRead and $bytesRead and the result was 1024 for $bytesToRead, and 134220800 for $bytesRead, so it's reading 1024 bytes at a time and it has already read 128MB. Perl's 'read' function must be out of memory and is trying to request for double it's memory size...is there a way to specify how much memory to request? or is that implementation dependent?
UPDATE2:
While testing memory allocation in cygwin:
This C program's output was 1536MB
int main() {
unsigned int bit=0x40000000, sum=0;
char *x;
while (bit > 4096) {
x = malloc(bit);
if (x)
sum += bit;
bit >>= 1;
}
printf("%08x bytes (%.1fMb)\n", sum, sum/1024.0/1024.0);
return 0;
}
While this perl program crashed if the file size is greater than 384MB (but succeeded if the file size was less).
open(F, "<400") or die("can't read\n");
$size = -s "400";
$read = read(F, $s, $size);
The error is similar
Out of memory during "large" request for 536875008 bytes, total sbrk() is 217088 bytes at mem.pl line 6.
This is a problem that has been solved in the latest version of msysgit by Gregor Uhlenheuer. There is a patch available. The problem is that in Git.pm, the file is read in one go. The solution is to read it in small chunks. I'm not sure if the fix has made it into any released versions, but the fix is easy to apply locally.
You need to change C:\Program Files\Git\lib\perl5\site_perl\Git.pm (about 8 lines change). Make sure you back it up first.
For the details of what to do, see Git.pm: Use stream-like writing in cat_blob().
The original discussion is Problems with larger files "Out of memory".
Have you tried increasing overall Cygwin's usable memory?
That message shows Perl was already up to 130 MiB (total sbrk()) and then tried to request a further 256MiB which failed.
From http://www.perlmonks.org/?node_id=541750
By default no Cygwin program can allocate more than 384 MB of memory
(program+data). You should not need to change this default in most
circumstances. However, if you need to use more real or virtual
memory in your machine you may add an entry in the either the
HKEY_LOCAL_MACHINE (to change the limit for all users) or
HKEY_CURRENT_USER (for just the current user) section of the registry.
Add the DWORD value heap_chunk_in_mb and set it to the desired
memory limit in decimal MB. It is preferred to do this in Cygwin
using the regtool program included in the Cygwin package. (For
more information about regtool or the other Cygwin utilities,
see the Section called Cygwin Utilities in Chapter 3 or use
each the --help option of each util.) You should always be
careful when using regtool since damaging your system registry
can result in an unusable system.
This is not a Perl-specific issue, but rather one related to cygwin. You can raise memory allocation with ulimit.
What version of git are you using? If you're not on the latest version, this might be an inefficiency that has been fixed with the latest version (e.g. looping through a very large file with foreach rather than while, as google suggests when I did a quick search.)
Solution with maximizing Cygwin memory actually does not work.
Currently there are two problems with Git on Windows:
Packs more than 2G are hardly
supported by either MsysGit and
Cygwin git
Cygwin default memory
amount is too small
32bit Git is problemistic
What have I done step by step:
I moved my git repo to Unix machine, set next configs:
[pack]
threads = 2
packSizeLimit = 2G
windowMemory = 512M
After that I made git gc and all packs were rebuilded to 2G ones.
Double checked that MsysGit is not installed on Windows machine, other way perl from MsysGit may be used.
Moved this repo back to windows machine and raised Cygwin memory limit:
regtool -i set /HKLM/Software/Cygwin/heap_chunk_in_mb 1536
It was important to set Cygwin memory higher than pack.windowMemoryĆpack.threads and not higher than 1.5G
So the first two problems are now solved. But the third is not.
Unfortunally it does not work on windows. During some repacks it sometimes crashes with out of memory. Even with threads = 1 and pack.windowMemory = 16M and max depth and delta set to 250.