I would like to develop a strategy to deal with situations where
customers have experienced a difficult-to-replicate bug check and the
only information they can provide to me is the bug check code and the
four bug check parameters, specifically when one of these parameters is
the address of an instruction that caused a problem.
Let’s use bug check 0x1E KMODE_EXCEPTION_NOT_HANDLED as an example.
This bug check displays as the second parameter the address of the
instruction that caused the exception. Given this address, I would like
to be able to determine the line number in my driver’s source code that
caused the exception.
In order to accomplish this I have added the following statements to my
SOURCES file, instructing the linker to generate a MAP file which can
help me to map the address that caused the exception to the line in my
source code that produced the offending instruction:
!IF $(FREEBUILD)
LINKER_FLAGS=$(LINKER_FLAGS) -MAP:.\obj\i386$(TARGETNAME).map \
-MAPINFO:EXPORTS -MAPINFO:LINES -MAPINFO:FIXUPS
!ELSE
LINKER_FLAGS=$(LINKER_FLAGS) -MAP:.\obj\i386$(TARGETNAME).map \
-MAPINFO:EXPORTS -MAPINFO:LINES -MAPINFO:FIXUPS
!ENDIF
Now for my first question. In order for the MAP file to be useful, the
address of the instruction that caused the exception must fall between
the preferred load address and the last Rva+Base address listed in the
public function section of the MAP file. If I have not specified my own
preferred load address at link time then there is very little chance
that my driver will actually have loaded at 0x10000. This means that I
should really be passing a /BASE parameter to the linker with a
preferred base address that is unlikely to be used by any other images.
What are the suggested ranges of addresses for non-Microsoft developers
who wish to set the preferred base address of their drivers to something
other than 0x10000 ?
Also, even if I have rebased my driver to another base address, if a
virtual address space collision occurs for the module will the loader
always load my module on a 64K boundary? If so then I can still use my
map file, assuming that my driver’s size is < 64K.
Now, assuming that I’ve been able to detemine a preferred base address
that has little chance of conflicting with other drivers and that I’ve
linked my driver using this as the /BASE parameter, and assuming that
the exception address DOES fall within the range between this preferred
base address and the last address in the Rva+Base list, how do I perform
the calculation to go from exception address to source code line number?
I’ve actually tested the technique from John Robbin’s debugging book and
it hasn’t worked for my driver. He suggests using the following
formula:
(crash address) - (preferred load address) - 0x1000
The 0x1000 is there, as he explains, because the crash address is
actually an OFFSET from the beginning of the code section and the code
section isn’t the first part of the binary - it’s preceded by the PE
header of size 0x1000 bytes. So this header’s size must be subtracted
when calculating the address that will be looked up in the MAP file’s
lines section.
What I’m wondering is if there may indeed be more than the PE header
before the code segment. Looking at the first part of a MAP file for a
driver (MyDriver.sys) that I just built, I noticed that the code section
(the .text section) starts at 0x80. Does this mean that when
calculating the address for line lookup the formula would read:
(crash address) - (preferred load address) - 0x1000 - (start address of
.text section)
=================================
// Extract from top of MAP file for MyDriver.sys
Preferred load address is 00010000
Start Length Name Class
0001:00000000 00000080H .idata$5 CODE
0001:00000080 00000064H .rdata CODE
0001:000000f0 00005c06H .text CODE
0002:00000000 00000000H .data DATA
0002:00000000 00000470H .bss DATA
0003:00000000 00000028H .idata$2 CODE
0003:00000028 00000014H .idata$3 CODE
0003:0000003c 00000080H .idata$4 CODE
0003:000000bc 0000027eH .idata$6 CODE
=================================
Also, when reading the MAP file you often see addresses with the format
XXXX:YYYYYYYY. Forgive my ignorance, but what does the XXXX portion
stand for? Is it a section number?
On a somewhat related topic, I want to strip the .DBG symbols from my
final .SYS image. After stripping the .DBG symbols out of my .SYS
image, will the .PDB file that was generated with the original .SYS
image still match (in the debugger) the new stripped-down version of my
.SYS image?
Nate