home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
OS/2 Shareware BBS: 14 Text
/
14-Text.zip
/
os2dump.zip
/
DUMP1011.INF
(
.txt
)
next >
Wrap
OS/2 Help File
|
1995-08-26
|
103KB
|
2,680 lines
ΓòÉΓòÉΓòÉ 1. Introduction ΓòÉΓòÉΓòÉ
This document was written by
Gary Jarman,
P O Box 74202,
Turffontein,
2140,
South Africa.
Welcome to Dump Analysis 101. This document is intended to introduce you to the
world of 16 bit application dumps. If you use this document please send me a
postcard with your opinions. There is no catch involved, I would just like to
know if anyone out there has used this file, and if they have, what they
thought of it.
I am hoping that this will be a learning experience for both you and I. If you
see any errors, or can add to what I have written, please let me know.
In the meantime I am starting work on the 32 bit application dump document
(Dump Analysis 102), to be followed by a document dealing with system hangs and
application loops (Dump Analysis 103).
Enjoy your reading, Gary, 13 August 1995.
ΓòÉΓòÉΓòÉ 2. Changes between versions. ΓòÉΓòÉΓòÉ
Rev. 1
The main correction here is that in the original, I had the SP pointing to the
next available space on the stack. This is incorrect. The SP always points to
the last parameter pushed onto the stack. I have corrected all diagrams and all
the references that I could find.
ΓòÉΓòÉΓòÉ 3. The 'don't blame me' section. ΓòÉΓòÉΓòÉ
All opinions expressed in this document are mine and mine alone. They do not
necessarily reflect the views of my employers, my parents, or anyone alse that
I know, and even those people that I don't know.
In addition I accept no responsibility for any damage to anything in your, and
anyone elses, country/house/surroundings while you are reading, or following
the advice of, this document.
ΓòÉΓòÉΓòÉ 4. The aim of this document. ΓòÉΓòÉΓòÉ
I wrote this document because I enjoy looking at dumps and wanted to share some
of my knowledge with others. Dumps are not as complicated as many people
believe, and I hope that after reading through this file more people will
experiment with looking at dumps.
This document will provide you with one approach to looking at dumps. There are
others that differ slightly from mine and these will work just as well. All I
am doing here is explaining the method I use.
To help achieve this I am going to go through the method that I use, and at the
end I will give two sample dumps (only the relevant parts) and pointers on how
I went through them.
ΓòÉΓòÉΓòÉ 5. Limitations of examples in this document. ΓòÉΓòÉΓòÉ
The examples used in this document all have the following things in common:
1. They are all Trap Ds.
2. They are all application abends, ie. no hangs etc.
3. They all occurred on OS/2 2.11.
4. The applications were all 16 bit.
ΓòÉΓòÉΓòÉ 6. Equipment required for dump analysis. ΓòÉΓòÉΓòÉ
The most obvious thing that you'll require will be a dump analysis tool. The
tool that I use is PMDF (Presentation Manager Dump Formatter) from IBM. Contact
your local IBM representative for information on how to get a copy. I am not
going to discuss the installation of this product, and I am not going to
explain all of the commands available (the product comes with a .INF file that
explains all of the commands available to you).
There are a couple of other utilities that I use, refer to Getting additional
information for more information on these.
The only other things that you'll need is a pile of paper and lots of patience.
ΓòÉΓòÉΓòÉ 7. What can you achieve with a dump?. ΓòÉΓòÉΓòÉ
Dumps will not help you solve EVERY problem. There are those times when, after
looking at a dump you know the variable that caused the problem, why it caused
the problem and how to fix it. But on the other hand, there are also those
times when you will be left knowing why the trap occurred but not knowing where
the data corruption originally occurred.
ΓòÉΓòÉΓòÉ 8. Taking a dump. ΓòÉΓòÉΓòÉ
There are two ways to take a dump. The first method is to use the Alt+Ctrl+(2 x
(NumLock)) key sequence (manual), and the other way is to put TRAPDUMP=ON in
your config.sys(automatic). The manual method is useful when you have a system
hang or an application loop, you can NOT use it for application dumps (refer to
What happens when the system dumps to see why). The automatic method will
cause the system to prompt you to enter dump diskettes whenever a trap occurs,
you can limit the dump process to certain types of traps, and you can dump to
another partition instead of diskette. For more information on how to use the
TRAPDUMP command, refer to the OS/2 command reference
You might have to go into your system setup and set the interrupt level to 3 to
allow the dumping to take place. I had to do this before my pc would initiate
the dump process automatically.
ΓòÉΓòÉΓòÉ 9. What happens when the system dumps. ΓòÉΓòÉΓòÉ
When you get a trap, OS/2 takes a note of the register contents and other
information that it will use in the trap information screen. If the application
had an exitlist linked to it (this is done in the application using the
DosExitList command), OS/2 will go through the function specified by the
DosExitList call. Then OS/2 will clear up all memory that the application was
using, and only then will the trap information screen be displayed.
It is for this reason that it is pointless to initiate a manual dump when you
see the trap screen. All the dump will show you is the memory used by every
other thread still in the system, and there will be no trace of the application
that abended.
So, if you want to find out why an application is abending you have to have the
config.sys file set up so that the dump process is kicked off automatically.
If there is anyone out there who knows any more than this, please let me know.
ΓòÉΓòÉΓòÉ 10. Stacks ΓòÉΓòÉΓòÉ
The key to reading dumps is the ability to read stacks. Every slot displayed
in the dump (use .p to display all slots in your current dump) will have a
stack. Each slot corresponds to a thread that was running in the system at the
time the dump was taken. Stacks are used to store local variables and to pass
parameters when functions are called. They are also used by the system to save
information on where to return control to when a function is completed.
ΓòÉΓòÉΓòÉ 10.1. How is a stack allocated by OS/2?. ΓòÉΓòÉΓòÉ
Each thread that is created has a stack. The stack is created in a segment. It
is created as a sparse object. What this means is that the operating system
allocates the area of memory, but does not commit the entire area allocated.
Only the last page (OS/2 handles memory as pages, a page is 4KB in size) is
committed, while the page above that is committed as a guard page. OS/2 then
uses the guard page technique to allocate the memory as it is required. When an
operation occurs that will exceed the boundaries of the committed page and go
into the guard page, a guard page fault will occur. OS/2 has a default guard
page fault handler that will commit what was the guard page and make the next
available page the guard page. This technique helps prevent excessive swapping
as memory that is not actually being used (even though it has been allocated to
a process), is not committed and has thus not used up physical memory. This
method of allocating memory for a stack is used for all stacks except that of
the first thread created by the process.
The fact that OS/2 commits the LAST page in the segment (the one with the
highest addresses) first also explains why the earlier functions have higher
value addresses on the stack than the last accessed functions.
A segment can be a maximum of 64KB and that is the maximum size a stack may be.
This is the maximum that a 16 bit system can address (in the 32 bit system this
can be up to 4GB).
ΓòÉΓòÉΓòÉ 10.2. How is a stack populated?. ΓòÉΓòÉΓòÉ
As mentioned earlier stacks are used to store local variables as well as to
pass data between functions. This section attempts to explain how this is done.
The example will assume that the first function to be kicked off is
function_one, it performs some processing and then makes a call to
function_two, passing it two parameters. The example also shows how the space
for the local variables of function_two is reserved. For function_one I have
given the required lines of example C code and their corresponding assembler
instructions. For each instruction there is a diagram that represents the stack
after that instruction is executed.
The example assumes that when we enter function_one the SS:BP is 1F:E95E, the
SP would also be E95E.
Example C source code:
VOID function_one (MPARAM ....)
{ USHORT usVar1,
usVar2,
usVar3,
usVar4,
usVar5;
.
.
.
function_two(usVar2, usVar4);
.
.
.
}
Example assembler code :
bd0f:e318 .... enter a,0
bd0f:e320 ....
.
.
bd0f:e44c .... push word ptr [bp - 08]
bd0f:e44f .... push word ptr [bp - 04]
bd0f:e452 .... call bd36:0b5c
bd0f:e457 .... add sp,+04
.
.
.
To view the stack contents as we enter function_one refer to fig. 1
Function_one has 5 local variables, all of type USHORT, space on the stack must
be reserved for these variables as the system enters function_one. To do this
the first instruction is an ENTER instruction. This changes the SP value by the
value of its first parameter (in this case a (hex) 10) to give us an SP of E954
(E95E-(5*sizeof(USHORT))). The ENTER command is the equivalent of the following
instructions :
1. PUSH BP
2. MOVE BP,SP
3. SUB SP,nn.
Compare Fig. 1 to Fig 2 to see the changes after executing the enter
instruction. This is the same method used for entering all functions.
We have done some processing in function_one and now we want to call
function_two, we are going to pass two variables, also of type USHORT.
Refer to Fig. 3 to see stack contents after the first parameter is put on the
stack, and Fig. 4 for the second parameter being put on the stack.
Take note that in this example I have shown the assembler code as putting
parameter 2 on the stack and then parameter 1. This will depend on the stack
conventions used by the compiler the program was compiled with.
This example also assumes that the five variables were loaded to the stack in
the order that they were defined. This is not always the case, refer to
Example of compiler generated files.
The parameters are put onto the stack using the PUSH command, data is always
put onto a stack using the PUSH command (data is removed from the stack using
the POP command). The PUSH statement will first decrement the SP by two before
putting the data on the stack.
When the first push was executed the SP would change from E954 to E952. The
second USHORT would be pushed the same way and the SP would point to E950. The
next instruction would be a CALL instruction (since we are now going to go to
function_two). When the call instruction is handled by the hardware, the IP is
pushed onto the stack and, if it is a far call, the CS is also pushed onto the
stack. Note that at the stage the CS:IP are pushed onto the stack they are
pointing to the next instruction (in function_one) to be executed following the
call.
The fact that the address we are calling is displayed as both a selector and
offset indicates that we are making a far call. A far call occurs when control
is transferred to a piece of code contained in a selector different to that of
the calling code. If we were calling a piece of code that was contained in the
selector bd0f (ie. the selector we are currently running in) it would be
referred to as a near call. A near call would look as follows : bd0f:e457 ....
call e56a and the address of the entry point for that called function would
then be bd0f:e56a. Also with a near call, only the offset of the next
instruction would be loaded to the stack.
Refer to Fig. 5 to see the stack contents once we have left function_one but
have not yet executed any instructions in function_two.
The first instruction that we would encounter in function_two is an ENTER. What
this does is to push the BP onto the stack and then move the current value of
SP to BP. Before the ENTER is executed the SS:BP is 1F:E59E, the SP is E58C.
The enter command will put the value of BP (E59E) on the stack (in so doing the
value of SP would be decremented by two, giving E58A) and then subtract the
value of the first parameter (the length of the local variables) from the SP,
thus giving us E572.
Example assembler code (at entry of function two):
.
.
.
bd36:0b5c .... enter 16,0
.
.
.
Refer to Fig. 6 to see the stack contents when the enter command has been
executed.
ΓòÉΓòÉΓòÉ 10.3. Stack Registers ΓòÉΓòÉΓòÉ
From the above we can see that there are three registers used with the stack:
1. SS - stack selector, this points to the segment containing the stack.
2. (E)BP - Base Pointer, points to the current base of the stack.
3. (E)SP - Stack Pointer, this points to the current position on the stack
where data would be moved to in the event of a PUSH statement.
ΓòÉΓòÉΓòÉ 10.4. Stack frames. ΓòÉΓòÉΓòÉ
The stack is broken down into stack frames. A stack frame can be thought of as
a unit containing all of the data required by a function. A frame consists of
the parameters passed, the return CS:IP, the return BP and the local variables.
^
Γöé Γöé Γöé ^
Γöé Γöé Γöé Γöé
Γöé local data Γöé Γöé <ΓöÇΓöÇΓöÇΓöÇΓöÇ higher value Γöé
Γöé Γöé Γöé addresses Γöé
Γöé Γöé Γöé (eg. 1f:e206) Γöé
Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ Γöé Γöé
Γöé Γöé Γöé Γöé
Γöé parameters Γöé Γöé Γöé
Γöé Γöé Γöé Γöé
Γöé Γöé Γöé Γöé
Γöé Γöé Γöé Γöé
Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ Γöé Γöé
Γöé return IP Γöé Γöé Γöé
Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ Γöé Unwinding a Γöé
Γöé return CS Γöé Γöé stack takes Γöé
Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ Γöé you in this Γöé
ΓöîΓöÇΓöÇ>Γöé return BP ΓöéΓöÇΓöÇΓöÇΓöÿ direction. Γöé
Γöé Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ Γöé
Γöé Γöé Γöé Γöé
Γöé Γöé Γöé Γöé
Γöé Γöé Γöé Γöé
points Γöé Γöé Γöé
to Γöé Γöé local data Γöé Γöé
previousΓöé Γöé Γöé
stack Γöé Γöé Γöé
frame Γöé Γöé Γöé
Γöé Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ ΓöÇΓöÇΓöÇΓöÇΓöÉ Γöé
Γöé Γöé Γöé Γöé Γöé
Γöé Γöé parameters Γöé Γöé Γöé
Γöé Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ Γöé Γöé
Γöé Γöé return IP Γöé Γöé Γöé
Γöé Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ Γöé Γöé
Γöé Γöé return CS Γöé Γöé Γöé
Γöé Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ Γö£ΓöÇΓöÇ stack frame Γöé
ΓööΓöÇΓöÇΓöÇΓöé return BP Γöé Γöé Γöé
Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ Γöé Γöé
Γöé Γöé Γöé Γöé
Γöé Γöé Γöé Γöé
Γöé Γöé Γöé Γöé
Γöé Γöé Γöé Γöé
Γöé local data Γöé Γöé Γöé
Γöé Γöé Γöé Γöé
Γöé Γöé Γöé Γöé
Γöé Γöé Γöé Γöé
Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ ΓöÇΓöÇΓöÇΓöÇΓöÿ <ΓöÇΓöÇΓöÇ lower value Γöé
addresses
(eg. 1f:054a)
Be careful of how you picture the growth of a stack. As mentioned in How is a
stack created OS/2 starts allocating pages from the end of the segment
allocated for the stack. This means that the stack frame that was allocated
first, has the highest address (in terms of numerical value) while the last
allocated frame has the lowest numerical address but is at the top of the
stack.
From the illustration above there are a few things that can be used as
guidelines for dump analysis.
1. When unwinding a stack, the base pointers you are using should always get
higher in numerical value (ie. you are working from the lowest value to the
highest). If this trend is reversed, the chances are you have a corrupted
stack.
2. If an assembler instruction references BP - ??, 90% of the time it will be
referring to local variables of that function. BP + ?? will be referring to
parameters passed to that function.
ΓòÉΓòÉΓòÉ 10.5. Unwinding a stack. ΓòÉΓòÉΓòÉ
This is probably the most important thing you will need to know in order to
analyse a dump. The stack can tell you the route that the application took to
get to its sudden, unexpected death. If you have read the section How is a
stack used? and Stack frames then you should have a fairly good idea of the
structure of a stack. If you understand this then it is pretty simple to
understand how to unwind the stack.
When you first look at the dump, go to SS:BP. This will point you to the middle
of the stack frame that was active when you trapped. What it will point you to
is the BP that was used by the function that called the failing function. The 4
(or 2 depending on whether it was a far or near call (refer to Near and far
calls )) bytes after that BP will be address that the function would have
returned to, if only it had had the chance.
Note the current BP contents and the failing CS:IP. Get the BP, and CS:IP
pointed to by SS:BP and write those down. Use the BP that you have just got off
the stack and together with the SS it will point you to the middle of the next
frame, from where you can get the BP used by the function that called the
function that called the function that died (and so it carries on).
You have reached the bottom of the stack when the return BP is 0.
Why do you want to do this?. When you are looking at a dump, there are often
times that it was a parameter that was passed that caused the problem. So you
need to at least go back to the second last function to see what parameters it
passed. In some cases you'll have to go back further to get to work out how the
parameter you suspect actually got to contain the value it did.
Refer to Fig. 7 for an example of a stack and how the frames link together,
and Simplified look at unwinding the stack for more information.
When you are looking through a function other than the one that failed, always
specify a value rather than a register name. Using the register name will cause
PMDF to use the value in that register at the time of the abend. This is fine
for the SS which is the same for all functions, but the BP will change with
each function.
ΓòÉΓòÉΓòÉ 11. Approach to looking at dumps. ΓòÉΓòÉΓòÉ
There is no fixed approach to looking at a dump. Each dump has to be looked at
in its own way. There are however a few guidelines that I can give to help
track down the problem.
ΓòÉΓòÉΓòÉ 12. What PMDF gives us. ΓòÉΓòÉΓòÉ
When you first load a dump PMDF gives you a display showing the contents of all
the registers of the thread that was active at the time of the dump (in the
case of a trap D this will be the thread that abended). It also gives you the
assembler instruction that failed, and why it failed.
You can redisplay the register contents, and the assembler instruction using
the .r command. Refer to Initial display and output of .r.
Above the register information will be a line that will give you varous handles
associated with the thread and its process. On the far left hand side is the
slot number. If you were to do a .p, PMDF would display all the slots that were
running in the system at the time it trapped (a slot corresponds to a thread).
On the far right of the top line is a name, this is the name of the dll/exe
that was running the thread.
Make a note of the slot number, it could be used later on.
What have we learnt so far?
1. The name of the dll/exe that failed.
2. The assembler instruction that failed.
3. Why that assembler instruction failed.
ΓòÉΓòÉΓòÉ 13. Getting the failing dll/exe. ΓòÉΓòÉΓòÉ
The easiest way to do this is to do a .m CS:IP. This will give you some
information about the thread including the dll/exe that owns it. Refer to
Output of .m.
If you want the path as well as the dll/exe name then refer to Getting the path
and dll name the hard way.
ΓòÉΓòÉΓòÉ 14. Investigating why the data is corrupt. ΓòÉΓòÉΓòÉ
If you perform a u CS:IP - 20 you will display the assembler instructions just
before the failing address. Here you must be careful. Look at the instructions
you have just unassembled. Do they look right?. Does the instruction at the
failing address look like the one displayed when you loaded the dump?. Is there
an instruction at the address of the CS:IP?. This is important because
sometimes PMDF will start unassembling instructions from the offset that you
have given it, and the instructions it gives you are incorrect. If this is the
case then try - 30, or - 10. Basically experiment until you are getting a list
of instructions that looks correct. Refer to Output of u CS:IP - 20.
Look at the way that the data is handled. Look at where the data that caused
the problem comes from. If the data comes from BP - ?? then we are dealing with
a local variable, if it comes from BP + ?? we are dealing with a parameter
passed from another function (refer to Examples of compiler generated files for
an example of this.). At this stage you have to decide how to proceed. If you
are dealing with a local variable refer to Following a local variable. but if
you are dealing with a paramater that was passed then refer to Following a
parameter. .
ΓòÉΓòÉΓòÉ 15. Near and far calls. ΓòÉΓòÉΓòÉ
Code is loaded into segments. When a function calls another function or API, it
does so via a near or far call.
A near call is where the section of code being called is in the same segment as
the code currently in control. A near call does not have a selector in the
address. An example CALL 1F24, if we are currently at 10B7:562, would mean that
we were calling 10B7:1F24. The stack would contain the return BP and IP but not
the CS.
A far call is when the code being called is in a different segment to the
currently executing code. For example, if we were at 10B7:562 and wanted to
make a far call it would look like CALL 10BF:32A. The stack would have the
return BP, the return IP and the return CS.
How can you decide, from the data on the stack, if a far or near call was
executed. Look at where the return CS would be, do a dl return CS, the result
will tell you that the segment you are enquiring about contains either data,
code or is invalid. If it is either data or invalid then you know you are
dealing with a near call.
If it tells you that the segment contains code, you can perform one more check.
Do a u return CS:IP - 20 and see if there is a call statement just above the
return CS:return IP address thet you have used for the unpack. Look at that
call instruction, is it a far call ?.
This knowledge is needed when you get around to examining data on the stack,
refer to Following a parameter for more information on this.
ΓòÉΓòÉΓòÉ 16. Following a local variable. ΓòÉΓòÉΓòÉ
What this requires is that you go through the function, looking for all
references to the area of memory referred to in the failing instruction, taking
note of what data is moved into and out of that area. By the time you get to
the failing instruction you will be able to tell where the data came from and
how it was manipulated to arrive at the current value. There is a possibility
that the data originally moved into the local variable was moved in from one of
the paramaters passed and you might have to track down that variable (refer to
Following a parameter. for how this is done).
The easiest way to follow the progress of a local variable is to start at the
beginning of the function and work your way down until you get to the failing
instruction. To get to the start of the function can be done in one of two
ways.
The first method is to unpack back up the code, from the failing instruction,
until you get to the first ENTER instruction (ie. use the u CS:IP - 20
instruction). With this method you are starting at the failing instruction and
working back in blocks, it is not the best way to do things as it is messy and
doesn't give you a nice flow of code to go through.
The second method is to actually get the address of the start of the function
and then unpack from that point down. Do a dw SS:BP, this will get you to the
point on the stack where you have the BP of the function that called the
failing function, the IP that the failing function would have returned to and,
if it was a far call, the CS. Both the CS and IP mentioned previously are going
to be referred to as the return CS and return IP from now on.
Do a u return CS:return IP - 20 This will display the assembler instructions
before the address to which the failing function would have returned. Just
above the return CS:return IP will be a call statement. The address in the call
statement is the address of the entry point to the function that failed.
Take the address that was called and do a u called CS:called IP l200. This
will list the assembler instructions from the entry point onwards. The l200
parameter tells PMDF how many bytes to show (the value is used by PMDF as a hex
value). You can obviously change the value, if you leave it out the default
will be displayed (somewhere between 20 to 30 bytes).
If you do a u CS:IP then the instructions from that address are displayed. If
you then just enter a u then PMDF will display the assembler instructions
starting with the instruction following the last displayed instruction. The
same principle applies when displaying memory.
Refer to Output of u CS:IP - 20. for some examples to illustrate the above.
ΓòÉΓòÉΓòÉ 17. Following a parameter. ΓòÉΓòÉΓòÉ
Following the progress of a parameter requires the ability to unwind a stack as
well as the methods explained in Following a local variable.
The first thing that you have to do is to go to the function that called the
failing function. To do this do a dw SS:BP to get to the return BP, return IP
and, in the event of a far call, the return CS. Do a u return CS:return IP - 20
to get the instructions that preceded the address to which we would have
returned.
Typically we would have a CALL instruction directly above the return address,
and above that would be a number of PUSH statements. The PUSH statements can
safely be assumed to be parameters being pushed onto the stack.
You need to determine which parameter is the one you are interested in. Take
the value in the BP register (do a .r if necessary), add 4 to it if you know
you reached this location via a near call, or 6 if you arrived via a far call
and you are now pointing to the last parameter pushed onto the stack (ie. the
value at BP + (4 or 6) will always be the value that was pushed onto the stack
by the last PUSH statement that you find above the CALL). To carry this example
further, BP + 8 will be the second last PUSH instruction before the call
statement.
Since we are working with 16 bit, the values pushed onto the stack will always
be 2 bytes in length. The reason the first parameter location is at BP + 6 is
because, BP is pointing to the return BP, BP + 2 points to the return IP, BP +
4 will point to the return CS in a far call situation, and the first parameter
location in a near call situation.
ΓòÉΓòÉΓòÉ 18. Looking at the stack. ΓòÉΓòÉΓòÉ
I always unwind the stack for about 5 frames (sometimes you have to do a lot
more) as one of the first steps. This is not always necessary, which is why I
have left it until here.
Refer to Unwinding a stack and Simplified look at unwinding the stack for how
to unwind the stack. At each frame do a .m return CS:return IP to get the name
of the dll/exe that you were called from. I always write this down so that I
can tell the programmer how the application reached the function that it
abended in.
ΓòÉΓòÉΓòÉ 19. Summary of what we've got. ΓòÉΓòÉΓòÉ
By following the above steps, we are able to provide the following information
to the programmer:
1. The dll/exe path and name in which the abend occurred ( Getting the
dll/exe name.).
2. Why the trap happened ( What PMDF gives us.).
3. Was it a parameter or a local variable that was corrupted (or a mixture of
the two) ( Investigating why the data is corrupt.).
4. How the data got to be the way it was ( Following a local variable or
Following a parameter).
5. The exe/dlls that we have been through to get to the failing function (
Looking at the stack).
6. If it was a corrupt parameter, we can tell tem what number out of all the
parameters it was ( Following a parameter and How is a stack
populated?).
While this may seem impressive to the programmer, it doesn't really help much.
They will need a bit more information, like what is the function within the dll
that abended, what was the parameter that was corrupt (to name a few of the
things they would like).
The following sections explain how to get some extra information for the
programmer. From this stage on we are not as reliant on PMDF as we have been up
until now.
ΓòÉΓòÉΓòÉ 20. Getting additional information. ΓòÉΓòÉΓòÉ
The following couple of screens discuss other tools that I have used to help
get additional information to solve dumps.
ΓòÉΓòÉΓòÉ 20.1. Using the source code. ΓòÉΓòÉΓòÉ
If you have the source code available to you, you could recompile it with the
options set to create both a MAP file and an assembler file.
For the IBM C Set compiler the options are :
/Fa (in your compile step)- will give you an assembler listing.
/MAP (in the link step) - will give you a map file.
At the end of this you will have a .MAP file and a .ASM file. The .ASM file
will contain the assembler version of your source code (complete with line
numbers for you to be able to cross match to the source code).
And a .MAP file to give you a list of offsets into the dll/exe file and how
those offsets correspond to the line numbers of the source code. You could
combine the output of this and the .ASM file to provide you with useful
information.
For an example of the source code, map file contents and assembler file
contents refer to Example of the compiler generated files.
You could now get the IP of the failing instruction, look into the .MAP file,
find the nearest offset to the value of your IP, take the line number and look
into the .ASM file. By doing this you can get the exact line of code that
caused the problem.
The .MAP file may not always have the exact IP value that you have been given
by PMDF. This is because each line of source code may comprise more than one
line of assembler code. The value you have could, for example, point to the
third line of assembler code for that instruction, while the .MAP file will
have the value that points to the first assembler line for that instruction.
You can, if you are in doubt, unpack the code around the failing instruction
and compare it to that of the .ASM file. This will settle any doubts you may
have. Be careful when doing this, the .ASM file will have decimal values, while
the dump code will have hex values. Thus the dump would for example display BP
+ a, while the .ASM file will display BP + 10.
Always be aware of how values are being displayed in the various files that you
are using.
Because in Getting the dll/exe name you have been able to get the name of the
dll/exe of all of the functions you have been through, you can if you want,
recompile all of these to get their .MAP and .ASM files as well. In this way
you can get the lines of code that set up any parameters passed.
This method is the one that will give you the most information to give to the
programmer.
ΓòÉΓòÉΓòÉ 20.2. ExeInfo - getting a dll using CSLIM. ΓòÉΓòÉΓòÉ
There is a useful tool called exeinfo, that is available from Ngb Technologies.
If you pass this application the CSLIM and a directory to search in, it will
return you the name of all dll/exe files that meet the requirements.
To get the CSLIM all you have to do is a dl on the CS value. This will give you
the limit, and that limit is your CSLIM.
Let us suppose that from the following section of the stack, we want to know
who 5c5f belongs to.
# dw ss:bp
001f:0000e13e e414 2c1e 5c5f ffc5 5c4f 4a03 017f 5c57
001f:0000e14e e48b e44d 3300 61af 0000 0000 0000 ff00
001f:0000e15e ff0b 61ba 017f e168 001f 7fff 0001 9ec0
001f:0000e16e 32d0 000f 98cc 30b0 0000 28c0 b200 ef9a
001f:0000e17e fe00 00ff 0000 bd00 00ac 0000 6377 0000
001f:0000e18e 06d7 2947 bd0f 0001 000f 9ec0 32d0 0043
001f:0000e19e 98cc 30b0 bd7f 0000 0000 0000 000c bd7f
001f:0000e1ae e1c6 281f bd0f 0000 0001 000f 9ec0 4242
Do a dl on the CS (5c5f). The lim=???? is the CSLIM for that CS.
# dl 5c5f
5c5f Code Bas=0b8b0000 Lim=00002ff9 DPL=3 P RE A
Use the CSLIM as input into EXEINFO, and the path that you want searched.
exeinfo -f -l2ff9 f:\main\dll\*.*
The output will look as follows.
ExeInfo, New Exe File Format Info, v2.0f
(C) Copyright Ngb Technologies, 1991-1993, All rights reserved.
F:\MAIN\DLL\BDDAS601.DLL
50518bytes 95-08-09 20:52:06
001 02ffa CODE EXECUTEONLY
F:\MAIN\DLL\BDYAT003.DLL
41460bytes 95-08-09 16:10:32
001 02ffa CODE EXECUTEONLY
Unfortunately, this example returned two dll names to us. The easiest way to
determine which is the correct one is to do a .m 5c5f:2c1e, which will
eliminate one of them.
ΓòÉΓòÉΓòÉ 20.3. FINDSEG - getting a dll using CSLIM. ΓòÉΓòÉΓòÉ
Another tool to get the dll name from the CSLIM is called FINDSEG from IBM. If
you pass this application the CSLIM and a directory to search in, it will
return you the name of all dll/exe files that meet the requirements.
To get the CSLIM all you have to do is a dl on the CS value. This will give you
the limit, and that limit is your CSLIM.
Let us suppose that from the following section of the stack, we want to know
who 5c5f belongs to.
# dw ss:bp
001f:0000e13e e414 2c1e 5c5f ffc5 5c4f 4a03 017f 5c57
001f:0000e14e e48b e44d 3300 61af 0000 0000 0000 ff00
001f:0000e15e ff0b 61ba 017f e168 001f 7fff 0001 9ec0
001f:0000e16e 32d0 000f 98cc 30b0 0000 28c0 b200 ef9a
001f:0000e17e fe00 00ff 0000 bd00 00ac 0000 6377 0000
001f:0000e18e 06d7 2947 bd0f 0001 000f 9ec0 32d0 0043
001f:0000e19e 98cc 30b0 bd7f 0000 0000 0000 000c bd7f
001f:0000e1ae e1c6 281f bd0f 0000 0001 000f 9ec0 4242
Do a dl on the CS (5c5f). The lim=???? is the CSLIM for that CS.
# dl 5c5f
5c5f Code Bas=0b8b0000 Lim=00002ff9 DPL=3 P RE A
Use the CSLIM as input into FINDSEG, and the path that you want searched.
findseg -l0x2ff9 -B -s f:\main\dll
The output will look as follows.
FINDSEG.EXE VER. 1.33 1992/03/18
(C) Copyright IBM Corp, 1990,1991,1992.
Written by Takaaki Nonaka
Search path : F:\main\dll and its sub-directories
Search file : *.EXE *.COM *.DLL *.IFS *.DRV
Search range : 0x02FF8(12280)-Ox02FFA(12282) bytes
Access rights: not specified
F:\main\dll\BDDAS601.DLL
50518bytes 95-08-09 20:52:06
001 02FFA CODE FIXED NONSHARED LOADONCALL E/R RELOC PL3 NONDISCARDABLE
F:\main\dll\BDYAT003.DLL
41460bytes 95-08-09 16:10:32
001 02FFA CODE FIXED NONSHARED LOADONCALL E/R RELOC PL3 NONDISCARDABLE
2 segments in 2 files
Unfortunately, this example returned two dll names to us. The easiest way to
determine which is the correct one is to do a .m 5c5f:2c1e , which will
eliminate one of them.
ΓòÉΓòÉΓòÉ 20.4. QTRAP - getting a lot more using CS, IP, CSLIM and dll name. ΓòÉΓòÉΓòÉ
Using either EXEINFO or FINDSEG you can get the dll name, you have the CSLIM
either from the registers, or from doing a dl on the CS. From the stack, or the
registers, you will have the CS and IP. Therefore we have all the information
needed to use QTRAP. QTRAP is written by Adrian Bonsall (I don't know where he
works, but I got it in the same package as FINDSEG, so I am assuming (forgive
me Adrian if I am wrong) that he works for IBM).
Using this application will give you nearest entry point, nearest public
symbol, and nearest source line. It also gives you the object that has that
code, this is useful if you have one dll that has many objects linked in.
Let us suppose that from the following section of the stack, we want to know
what line of source code 5c5f%colon.2c1e belongs to. In the previous two
sections we have narrowed the choice down to two dlls. Using the .m 5c5f:2c1e I
have determined that the dll is BDDAS601.DLL, so I am now going to run QTRAP on
it.
# dw ss:bp
001f:0000e13e e414 2c1e 5c5f ffc5 5c4f 4a03 017f 5c57
001f:0000e14e e48b e44d 3300 61af 0000 0000 0000 ff00
001f:0000e15e ff0b 61ba 017f e168 001f 7fff 0001 9ec0
001f:0000e16e 32d0 000f 98cc 30b0 0000 28c0 b200 ef9a
001f:0000e17e fe00 00ff 0000 bd00 00ac 0000 6377 0000
001f:0000e18e 06d7 2947 bd0f 0001 000f 9ec0 32d0 0043
001f:0000e19e 98cc 30b0 bd7f 0000 0000 0000 000c bd7f
001f:0000e1ae e1c6 281f bd0f 0000 0001 000f 9ec0 4242
qtrap 5c5f:2c1e f:\main\dll\bddas601.dll /SIZE=2ffa
Take note that I have added one to the CSLIM of 2ff9 and have passed the new
value to QTRAP. This is because I discovered that when we switched to OS/2 2.11
the application would no longer find the information, unless we added one to
the CSLIM. If you look at the output from FINDSEG you will see that it defines
its search range as one below and one above the CSLIM that you give to it
(could it be that if that was not done, it would also not find the
information?). I have no idea why this is so but if you have any info that
could be of help, please let me know.
QTRAP v3.03 by Adrian Bonsall - Automated Trap Resolver
5C5F is Entry #2955 in the Local Descriptor Table with a ReqPrivLvl of 3.
Selector 5C5F is not assigned to any of the default segments of f:\main\dll\bddas601.dll
Checking imported modules for segment of size 2FFA:
Searching .... BDDAS601 .... Segment found.
Sel. Off. Seg.No. Length AllocSize Flags
5C5F 2C1E 0001 0x2FFA 0x2FFA CODE RELOC DPL3
Nearest Entry Point : 0001:1116 TPBDDAS601.
Nearest Public Symbol : 0001:1116 TPBDDAS601 (D:\SB\MAIN\OBJ\BDDAS601.OBJ)
Nearest Source Line : 0001:2BF7 line #1532 (D:\SB\MAIN\OBJ\BDDAS601.OBJ)
So now we have the nearest line of source a code in which function and what
.OBJ file in which dll. You can now refer to the source code if you have it,
and try to go further from here, or you could pass all of the information that
you have to the programmer and get him to look at it.
ΓòÉΓòÉΓòÉ 21. Dump examples. ΓòÉΓòÉΓòÉ
There are two examples contained here. The first is an application dump caused
by the application trying to access an invalid area of memory. The second is a
corrupted stack.
ΓòÉΓòÉΓòÉ 21.1. Application trap. ΓòÉΓòÉΓòÉ
These usually require that you determine how the data that caused the trap, got
there in the first place. The first step is to unwind the stack to get to the
function that called the failing function. Remember that the return CS:IP is
pointing to the instruction following the call instruction. Unassemble the
instructions just before the return address and in this way you'll get the
address that was called (ie. the entry point to the function that you have just
worked back from) as well as the parameters that were put on the stack.
If the data that caused the abend originated from BP + ??, then you are dealing
with one of the parameters passed. Your next step is to work out why that
parameter was bad. To do this you need to track the parameters as the functions
are called. Sometimes this requires that you go back two or three functions.
Try to see where the parameter was created and then work it out from there.
If the data causing the problem originated from BP - ??, then you are looking
at a local variable that is causing the trouble. In this case you must
concentrate on the function in which the trap occurred.
Refer to Fig. 9 - application dump stack. for my recommended approach.
ΓòÉΓòÉΓòÉ 21.2. Corrupted stacks. ΓòÉΓòÉΓòÉ
A corrupted stack is one where data has overwritten areas of the stack that it
shouldn't have.
There are two types of corruption that can occur. The first is that which
occurs when data overwites the return BP, CS and IP or when a null terminator
has corrupted a return BP. This type of corruption shows itself as a trap in
the return statement.
The other type is when data from one variable, overwrites the values of the
variable next to it thus giving the overwritten variable invalid data. This
will manifest itself as a trap d when the application tries to use that invalid
data.
Corrupted stacks require that you look carefully at the data on the stack, and
match what should be there with what is there. They are not impossible to fix,
and are in my opinion the most challenging dumps to get.
ΓòÉΓòÉΓòÉ 21.2.1. How do you know that you're dealing with a corrupt stack? ΓòÉΓòÉΓòÉ
There are a couple of indications that could point to this.
1. The CS:IP of the failing instruction does not look right, or the
instruction that was being executed doesn't look correct. This could be
because the data that has overwritten the return pointers did, by
coincidence, make up a valid pointer but is now pointing to the middle of
an instruction.
2. You have been unwinding the stack and suddenly the next return base pointer
takes you back up the stack. This is a sure sign that something is wrong.
3. The next base pointer that you get is pointing to an odd number. The
pointers used for return base pointers are always pointing to even offsets
(word or doubleword alignment).
4. Look at the data around where the return base pointer should be. The most
obvious would be if you displayed the stack at that area as bytes and
discovered that where the return BP should be was right in the middle of a
text field. Sometimes though, you aren't that lucky. Try see if the data
matches the kind of data you'd expect for the program abended.
Be careful that sometimes the point where you think the corruption has occurred
is not always the correct point. Sometimes the data that has overwritten your
return BP is valid in that it will refer you to somewhere else in the stack.
When you look at the return BP being pointed to you see it isn't valid, and
assume that that is where the stack has been corrupted. Unless you doublecheck,
this could lead you on a wild goose chase. For this reason I also keep an eye
on the return CS and IP, to ensure that they also look reasonably accurate.
ΓòÉΓòÉΓòÉ 21.2.2. How does a stack get corrupted ?. ΓòÉΓòÉΓòÉ
Because a stack is used for storing local variables, it does sometimes happen
that the programmer will try to move a string of 57 bytes into a field of 30
bytes. This will, obviously, overwrite the 27 bytes following the variable
concerned. Sometimes this will only affect other data fields, and this could
cause a problem if one of these variables is passed as a parameter to another
function. But in some cases it could overwrite the return BP, CS and IP. This
could cause a wild branch when the controlling function tries to hand control
back to its calling function.
There are times when the programmer has defined a variable for length 10 and
then tries to move a data of 10 bytes into that field. If the language used was
C you have to make allowance for a null terminator. The result of the previous
example is that the lower byte of the return BP is overwritten by a null.
ΓòÉΓòÉΓòÉ 21.2.3. Example of a corrupted stack. ΓòÉΓòÉΓòÉ
Refer to Corrupted stack example. for how I go about determining what caused a
stack to be corrupted.
ΓòÉΓòÉΓòÉ 22. Examples and diagrams. ΓòÉΓòÉΓòÉ
All of the diagrams displayed below are linked to from the various chapters
above.
ΓòÉΓòÉΓòÉ 22.1. Stack Conventions. ΓòÉΓòÉΓòÉ
Parameters are usually put onto the stack using PUSH and removed from the stack
using CALL. With the C convention, parameters are pushed onto the stack from
right to left, and they are removed from the stack by adding a constant to SP.
The pascal convention pushes parameters on from left to right and removes them
by specifying an operand for the RET which is added to SP after the return
address has been taken off the stack.
ΓòÉΓòÉΓòÉ 22.2. Fig 1 - stack before starting. ΓòÉΓòÉΓòÉ
The application has just entered function_one. The BP and SP are pointing
to the same place as no data has yet been moved to the stack.
ΓöîΓöÇΓöÇΓöÇ EBP : 0000E95E
Γöé ESP : 0000E95E ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÉ
Γöé SS : 001F Γöé
Γöé Γöé
ΓööΓöÇΓö¼ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÿ
Γöé
Γöé E92E 0000 0000 0000 0000 0000 0000 0000 0000
Γöé E93E 0000 0000 0000 0000 0000 0000 0000 0000
Γöé E94E 0000 0000 0000 0000 0000 0000 0000 0000
Γöé E95E 0000 0000 0000 0000 0000 0000 0000 0000
Γöé Γöé
ΓööΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÿ
ΓòÉΓòÉΓòÉ 22.3. Fig 2 - stack after the enter command is executed. ΓòÉΓòÉΓòÉ
The value in SP has been decremented by 10 to allow space for the
local variables. This is all that will be done by the enter command.
The variables are initialised by other instructions.
CS:IP BD0F:E320
ΓöîΓöÇΓöÇΓöÇ EBP : 0000E95E
Γöé ESP : 0000E954 ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÉ
Γöé SS : 001F Γöé
Γöé Γöé
ΓööΓöÇΓöÇΓöÉ Γöé
Γöé Γöé
Γöé E92E 0000 0000 0000 0000 0000 0000 0000 0000 Γöé
Γöé E93E 0000 0000 0000 0000 0000 0000 0000 0000 Γöé
Γöé E94E 0000 0000 0000 0000 0000 0000 0000 0000 Γöé
Γöé Γöé Γöé
Γöé ΓööΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÿ
Γöé E95E 0000 0000 0000 0000 0000 0000 0000 0000
Γöé Γöé
ΓööΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö┤
ΓòÉΓòÉΓòÉ 22.4. Fig. 3 - first parameter pushed onto the stack. ΓòÉΓòÉΓòÉ
The first parameter has been pushed onto the stack, the SP value
has been decremented by two to and now points to the last parameter
pushed onto the stack.
ΓöîΓöÇΓöÇΓöÇ EBP : 0000E95E
Γöé ESP : 0000E952 ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÉ
Γöé SS : 001F Γöé
Γöé Γöé
ΓööΓöÇΓöÇΓöÉ Γöé
Γöé Γöé
Γöé E92E 0000 0000 0000 0000 0000 0000 0000 0000 Γöé
Γöé E93E 0000 0000 0000 0000 0000 0000 0000 0000 Γöé
Γöé E94E 0000 0000 0001 001a 0001 e012 007c 0100 Γöé
Γöé Γöé Γöé
Γöé ΓööΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÿ
Γöé E95E 0000 0000 0000 0000 0000 0000 0000 0000
Γöé Γöé
ΓööΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÿ
ΓòÉΓòÉΓòÉ 22.5. Fig. 4 - second parameter pushed onto the stack. ΓòÉΓòÉΓòÉ
ΓöîΓöÇΓöÇΓöÇ EBP : 0000E95E
Γöé ESP : 0000E950 ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÉ
Γöé SS : 001F Γöé
Γöé Γöé
ΓööΓöÇΓöÇΓöÉ Γöé
Γöé Γöé
Γöé E92E 0000 0000 0000 0000 0000 0000 0000 0000 Γöé
Γöé E93E 0000 0000 0000 0000 0000 0000 0000 0000 Γöé
Γöé E94E 0000 007c 0001 001a 0001 e012 007c 0100 Γöé
Γöé Γöé Γöé
Γöé ΓööΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÿ
Γöé E95E 0000 0000 0000 0000 0000 0000 0000 0000
Γöé Γöé
ΓööΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÿ
ΓòÉΓòÉΓòÉ 22.6. Fig. 5 - just entered function_two. ΓòÉΓòÉΓòÉ
If we had executed a near call the SP would be E94C and the stack would not
contain the bd0f that it currently has.
CS:IP BD36:0B5C
ΓöîΓöÇΓöÇ EBP: 0000E95E
Γöé ESP: 0000E94C --ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÉ
Γöé SS: 001F Γöé
Γöé Γöé
Γöé E92E 0000 0000 0000 0000 0000 0000 0000 0000 Γöé
Γöé E93E 0000 0000 0000 0000 0000 0000 0000 e457 Γöé
Γöé Γöé Γöé
Γöé ΓööΓöÇΓöÇΓöÇΓöÇΓöÿ
Γöé E94E bd0f 007c 0001 001a 0001 e012 007c 0100
Γöé E95E 0000 0000 0000 0000 0000 0000 0000 0000
Γöé Γöé
ΓööΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÿ
ΓòÉΓòÉΓòÉ 22.7. Fig. 6 - stack after executing enter in function_two. ΓòÉΓòÉΓòÉ
CS:EIP: BD36:00000B5E
ΓöîΓöÇΓöÇ EBP: 0000E94A
Γöé ESP: 0000E924 -ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÉ
Γöé SS: 001F Γöé
Γöé Γöé
Γöé E92E 0000 0000 0000 0000 0000 0000 0000 0000 Γöé
Γöé Γöé Γöé
Γöé ΓööΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÿ
Γöé E93E 0000 0000 0000 0000 0000 0000 e95e e457
Γöé Γöé
ΓööΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÿ
E94E bdof 007c 0001 001a 0001 e012 007c 0100
E95E 0000 0000 0000 0000 0000 0000 0000 0000
ΓòÉΓòÉΓòÉ 22.8. Fig. 7 - unwinding a stack. ΓòÉΓòÉΓòÉ
The following example will take you through a couple of frames of a stack.
Notice how I start of by using the SS:BP to get to the first frame, and
thereafter I use the SS and the return BP, to get to the next frame. I have
also done a dl on the return CS. The fact that all of the return addresses in
this example have a return CS indicates that all of the calls that we did were
defined as far calls. The dl tells us that the segments are all code segments
(if they showed as data or invalid, then you would assume that you were dealing
with a near call, or a corrupt stack). I have also done a .m on all of the
return addresses to show you how you can get information on which dlls you have
gone through to get to where you abended.
The colors used are as follows:
1. return BP
2. return IP
3. return CS
(You should refer to Simplified look at unwinding the stack once you have
looked through this.)
# dw ss:bp
001f:0000e13e e414 2c1e 5c5fffc5 5c4f 4a03 017f 5c57
001f:0000e14e e48b e44d 3300 61af 0000 0000 0000 ff00
001f:0000e15e ff0b 61ba 017f e168 001f 7fff 0001 9ec0
001f:0000e16e 32d0 000f 98cc 30b0 0000 28c0 b200 ef9a
001f:0000e17e fe00 00ff 0000 bd00 00ac 0000 6377 0000
001f:0000e18e 06d7 2947 bd0f 0001 000f 9ec0 32d0 0043
001f:0000e19e 98cc 30b0 bd7f 0000 0000 0000 000c bd7f
001f:0000e1ae e1c6 281f bd0f 0000 0001 000f 9ec0 4242
# dl 5c5f
5c5f Code Bas=0b8b0000 Lim=00002ff9 DPL=3 P RE A
# .m 5c5f:2c1e
*har par cpg va flg next prev link hash hob hal
0e57 %fee32b84 00000010 %0b8b0000 3d9 0e56 0e58 0000 0b54 1405 0000 hco=020f4
hob har hobnxt flgs own hmte sown,cnt lt st xf
1405 0e57 0000 0838 1406 1406 0000 00 00 00 00 shared c:bddas601.dll
hco=20f4 pco=ffe6f4df hconext=00000 hptda=121b f=1d pid=004b c:bd.exe
# dw ss:e414
001f:0000e414 e48c 0ff3 5c5f e4e4 001f 0000 0000 0000
001f:0000e424 0000 0000 0000 0000 0000 0000 0000 0000
001f:0000e434 0000 0000 0000 0000 0000 0000 0000 0000
001f:0000e444 0000 0000 0000 0000 0000 001f e528 0068
001f:0000e454 0000 0000 0000 0000 0000 0000 0000 0000
001f:0000e464 0000 0000 0000 0000 0000 0000 0000 0000
001f:0000e474 0000 0000 0000 0000 0000 0000 0000 0000
001f:0000e484 0000 0000 0000 6100 e4a2 3204 000f e4e4
See how the last two frames above have the same return CS, so they have come
from the same segment but have done so via a far call.
# dw ss:e48c
001f:0000e48c e4a2 3204 000f e4e4 001f 619f e528 0068
001f:0000e49c 0000 48a9 017f e4fa 64aa 61a7 e4e4 001f
001f:0000e4ac 001f e528 ffff 0000 00b6 636f 0376 00b6
001f:0000e4bc 0035 0bff bd7f e4ea 0000 0000 636f e4ea
001f:0000e4cc e076 0068 000a b470 bd0f 9c04 32a0 bd7f
001f:0000e4dc 0000 e4f2 b44c bd0f 9c04 32a0 77e4 0020
001f:0000e4ec 0000 4856 017f e4e4 001f bd27 0068 e518
001f:0000e4fc e456 bd0f 0001 0001 77e4 0000 0020 9c04
# dl f
000f Code Bas=00010000 Lim=00004559 DPL=3 P RE A
# .m f:3204
*har par cpg va flg next prev link hash hob hal
0d4c %fee31492 00000010 %00010000 1d9 0d4d 0d4a 0000 0000 1223 0000 hptda=121b
hob har hobnxt flgs own hmte sown,cnt lt st xf
1223 0d4c 0000 0838 1228 1228 0000 00 00 00 00 shared c:bd.exe
# dw ss:e4a2
001f:0000e4a2 e4fa 64aa 61a7 e4e4 001f 001f e528 ffff
001f:0000e4b2 0000 00b6 636f 0376 00b6 0035 0bff bd7f
001f:0000e4c2 e4ea 0000 0000 636f e4ea e076 0068 000a
001f:0000e4d2 b470 bd0f 9c04 32a0 bd7f 0000 e4f2 b44c
001f:0000e4e2 bd0f 9c04 32a0 77e4 0020 0000 4856 017f
001f:0000e4f2 e4e4 001f bd27 0068 e518 e456 bd0f 0001
001f:0000e502 0001 77e4 0000 0020 9c04 32a0 0002 0000
001f:0000e512 9c04 32a0 bd7f e542 27e0 bd27 e528 001f
# dl 61a7
61a7 Code Bas=0c340000 Lim=00006d27 DPL=3 P RE A
# .m 61a7:64aa
*har par cpg va flg next prev link hash hob hal
0d86 %fee3198e 00000010 %0c340000 3d9 0d85 0d87 0000 0aab 1271 0000 hco=01e23
hob har hobnxt flgs own hmte sown,cnt lt st xf
1271 0d86 0000 0838 1272 1272 0000 00 00 00 00 shared c:ga1.dll
hco=1e23 pco=ffe6e6ca hconext=00000 hptda=121b f=1d pid=004b c:bd.exe
ΓòÉΓòÉΓòÉ 22.9. Fig. 8 - Corrupted stack example. ΓòÉΓòÉΓòÉ
This example contains a corrupted stack. The aim here is to show you how to try
and find out where it has been corrupted. Remember that as applications use the
stack and PUSH and POP data onto and off of it, the data remains there until it
is overwritten. A POP merely adjusts the SP value, it doesn't physically remove
the data from the stack. It is for this reason that you must NEVER assume that
a local variable will be empty the first time you enter a function. The only
time you can be sure that it has been cleared is if you have done it yourself.
>
IBM OS/2 System Dump Formatter for retail kernel
Formatter is --> Internal revision 6.514, 93/04/12
Dump file is --> Internal revision 6.661, 95/03/30
Current slot number: 00a3
Symbol (c:\os2\pdpsi\pmdf\ga21\os2krnlr.sym) linked
Symbol (c:\os2\pdpsi\pmdf\ga21\pmshl32.sym) linked
Symbol (c:\os2\pdpsi\pmdf\ga21\pmviop.sym) linked
Symbol (c:\os2\pdpsi\pmdf\ga21\pmctls.sym) linked
Symbol (c:\os2\pdpsi\pmdf\ga21\pmspl.sym) linked
Symbol (c:\os2\pdpsi\pmdf\ga21\pmshapi.sym) linked
Symbol (c:\os2\pdpsi\pmdf\ga21\pmgre.sym) linked
Symbol (c:\os2\pdpsi\pmdf\ga21\pmwin.sym) linked
Symbol (c:\os2\pdpsi\pmdf\ga21\pmwp.sym) linked
Symbol (c:\os2\pdpsi\pmdf\ga21\quecalls.sym) linked
Symbol (c:\os2\pdpsi\pmdf\ga21\sesmgr.sym) linked
Symbol (c:\os2\pdpsi\pmdf\ga21\os2char.sym) linked
Symbol (c:\os2\pdpsi\pmdf\ga21\doscall1.sym) linked
Slot Pid Ppid Csid Ord Sta Pri pTSD pPTDA pTCB Disp SG Name
*00a3# 010e 000c 010e 0001 ___ 1402 7bbfb000 7bc8be74 7bc6a9e0 0970 07 BDREMCMD
eax=00000230 ebx=00000884 ecx=0000000c edx=00000000 esi=00000442 edi=00008f76
eip=0000123b esp=00008a74 ebp=0000000a iopl=2 rf -- -- nv up ei ng nz na po nc
cs=000f ss=0027 ds=0027 es=0027 fs=150b gs=0000 cr2=00000000 cr3=001af000
000f:0000123b cb retf
#
Loading version data ... please wait
Loading structure info for OS/2 2.1 General Availability ... please wait....Done.
The data at the area pointed to by SS:BP is :
# dw ss:bp
0027:0000000a 5220 6e75 542d 6d69 2065 694c 7262 7261
0027:0000001a 2079 202d 6f43 7970 6972 6867 2074 6328
0027:0000002a 2029 3931 3838 202c 694d 7263 736f 666f
0027:0000003a 2074 6f43 7072 0011 4442 4552 434d 444d
0027:0000004a 3200 302e 0030 2e32 3030 4700 746f 7920
0027:0000005a 756f 2121 2021 6f59 2075 656e 6465 5620
0027:0000006a 7325 6f20 2066 4442 4552 4f4d 4554 2121
0027:0000007a 5920 756f 6820 7661 2065 2556 0a73 4300
The data at the area pointed to by SS:SP is :
# dw ss:sp
0027:00008a74 0230 000a 0027 0000 0000 2e32 3030 0002
0027:00008a84 8a9a 0000 0000 0023 0201 0002 0000 1328
0027:00008a94 000f 0001 8aa0 0027 8ac0 0027 8aa8 0027
0027:00008aa4 0000 0000 3a43 535c 5c42 5845 5c45 4442
0027:00008ab4 4552 434d 444d 452e 4558 0300 8b34 0027
0027:00008ac4 8b4c 0027 8b69 0027 8b82 0027 8ba2 0027
0027:00008ad4 8bb9 0027 8bd4 0027 8bf6 0027 8cc6 0027
0027:00008ae4 8d9f 0027 8dad 0027 8df6 0027 8e12 0027
The first indicator that we are dealing with a corrupt stack is the fact that
the instruction that has trapped is a far return. The next pointer is the
difference between the SP and the BP. The difference between the two should
NEVER be that great (It would be a truly bad programmer that had a local
variable of greater than 30000 bytes.). If we display the data at the BP, and
then do a dl on the CS that we should return to (because we are doing a retf we
know that the CS and the IP will be on the stack after the base pointer), we
get :
# DL 542D
542d Invalid Bas=00000000 Lim=00000000 DPL=0 NP
#
If we were not doing a retf and we wanted to make sure, then we could do a dl
on the segment that we are currently in (f) and then check that the IP we would
return to (according to the stack 6e75) was in the range of that CS.
# DL F
000f Code Bas=00010000 Lim=000043c9 DPL=3 P RE A
# DW F:6E75
Past end of segment: 000f:00006e75
#
Currently our SP points to 8a74, the BP points to a. We know that the bp is
obtained from the stack. When a return is executed, the BP is popped from the
stack and the SP is adjusted by two (because we are popping data the value is
decremented by two) therefore display the stack from some point above the
current SP. Currently, to give substance to the theory that the original return
was to 8a72 before the BP was adjusted, is the fact that at 8a72, there is a
value a. Now that you have listed the stack from SP - ??, search through it
looking for 8a72. You will find one at 8922, and the return address there is
f:1233. Do an unpack on f:123b (the address of the return instruction on which
we are crashing. You will get :
# U CS:IP - 20
000f:0000121b 051e00 add ax,001e
000f:0000121e 52 push dx
000f:0000121f 50 push ax
000f:00001220 90 nop
000f:00001221 0e push cs
000f:00001222 e80505 call 172a
000f:00001225 83c408 add sp,+08
000f:00001228 ff76c4 push word ptr [bp-3c]
000f:0000122b ff76c2 push word ptr [bp-3e]
000f:0000122e 90 nop
000f:0000122f 0e push cs
000f:00001230 e88502 call 14b8
# U
000f:00001233 83c404 add sp,+04
000f:00001236 8b46fe mov ax,word ptr [bp-02]
000f:00001239 1f pop ds
000f:0000123a c9 leave
000f:0000123b cb retf
000f:0000123c 680501 push 0105
000f:0000123f 8e065e0a mov es,word ptr [0a5e]
000f:00001243 26a11e01 mov ax,word ptr es:[011e]
000f:00001247 268b162001 mov dx,word ptr es:[0120]
000f:0000124c 051e00 add ax,001e
000f:0000124f 52 push dx
000f:00001250 50 push ax
#
The address 1233 does point to the next instruction after a call, therefore I
am now going to assume that that was the last correct frame. Now that we know
we were returning to 8a72, we have to look at the area in the BP - ?? to see if
we can find a string that has overwritten the return addresses at 8a72.
Stack displayed as bytes.
# db ss:sp - 500 l500
0027:00008574 00 01 08 86 27 00 12 18-1f a8 00 00 00 00 01 00 ....'....(......
0027:00008584 01 00 37 d0 0c 86 95 04-b5 01 b5 01 52 03 00 00 ..7P....5.5.R...
0027:00008594 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................
0027:000085a4 00 00 00 00 00 00 00 00-00 00 00 00 00 00 06 00 ................
0027:000085b4 00 00 06 00 01 00 00 00-b5 01 01 00 01 00 ea 85 ........5.....j.
0027:000085c4 f1 2a 02 00 00 01 08 86-27 00 12 18 1f a8 00 00 q*......'....(..
0027:000085d4 ea 85 95 04 0c 86 00 00-27 00 12 18 1f a8 37 d0 j.......'....(7P
0027:000085e4 fa 2a 1f a8 00 00 16 86-a4 27 67 a8 12 18 1f a8 z*.(....$'g(...(
0027:000085f4 08 86 27 00 00 01 1f a8-95 04 00 00 01 04 f4 df ..'....(......t_
0027:00008604 00 01 86 00 00 00 00 00-00 00 00 00 00 00 00 00 ................
0027:00008614 00 00 24 87 f9 2e 67 a8-1f a8 e4 1d 67 a8 1f a8 ..$.y.g(.(d.g(.(
0027:00008624 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................
0027:00008634 00 00 00 00 00 00 37 d0-00 00 6a 01 02 00 02 00 ......7P..j.....
0027:00008644 6b 06 37 d0 7a 86 8e 2e-8c 21 ef aa 00 01 ee 01 k.7Pz....!o*..n.
0027:00008654 6b 06 6c 01 6b 06 80 00-37 d0 ee 01 6b 06 6c 01 k.l.k...7Pn.k.l.
0027:00008664 6b 06 00 00 6b 06 02 00-6b 06 80 00 3a 00 6b 06 k...k...k...:.k.
0027:00008674 b5 01 ca 86 da 2c ce 86-da 2c 02 00 00 01 14 87 5.J.Z,N.Z,......
0027:00008684 e4 88 27 00 f1 00 de 86-27 00 06 00 f1 00 06 00 d.'.q.^.'...q...
0027:00008694 c2 86 cc 09 2f d0 e4 88-27 00 f1 00 de 86 18 0a B.L./Pd.'.q.^...
0027:000086a4 c2 86 f1 00 06 00 de 86-f1 00 06 00 27 00 3f d0 B.q...^.q...'.?P
0027:000086b4 18 0a 27 00 f7 00 cf 87-00 00 06 00 00 00 f0 88 ..'.w.O.......p.
0027:000086c4 c2 39 0f 00 e4 88 27 00-f1 00 de 86 27 00 06 00 B9..d.'.q.^.'...
0027:000086d4 8f 00 00 00 de 88 0a 79-7a 39 0d 0a 0d 0a 55 73 ....^..yz9....Us
0027:000086e4 65 72 69 64 3a 20 20 79-6f 75 21 21 21 20 59 6f erid: you!!! Yo
0027:000086f4 75 20 6e 65 65 64 20 56-32 2e 30 30 20 6f 66 20 u need V2.00 of
0027:00008704 42 44 52 45 4d 4f 54 45-21 21 20 59 6f 75 20 68 BDREMOTE!! You h
0027:00008714 61 76 65 20 56 32 2e 30-30 02 0d 0a 20 20 4d 61 ave V2.00... Ma
0027:00008724 63 68 69 6e 65 20 49 44-3a 20 59 6f 75 20 6e 65 chine ID: You ne
0027:00008734 65 64 20 56 32 2e 30 30-20 6f 66 20 42 44 52 45 ed V2.00 of BDRE
0027:00008744 4d 4f 54 45 21 21 20 59-6f 75 20 68 61 76 65 20 MOTE!! You have
0027:00008754 56 32 2e 30 30 02 0d 0a-20 20 44 61 74 65 3a 20 V2.00... Date:
0027:00008764 31 39 39 35 2d 30 37 2d-31 30 20 20 54 69 6d 65 1995-07-10 Time
0027:00008774 3a 20 31 34 3a 30 31 3a-32 38 3a 33 39 0d 0a 2d : 14:01:28:39..-
0027:00008784 2d 2d 2d 2d 2d 2d 2d 2d-2d 2d 2d 2d 2d 2d 2d 2d ----------------
0027:00008794 2d 2d 2d 2d 2d 2d 2d 2d-2d 2d 2d 2d 2d 2d 2d 2d ----------------
0027:000087a4 2d 2d 2d 2d 2d 2d 2d 2d-2d 2d 2d 2d 2d 2d 2d 2d ----------------
0027:000087b4 2d 2d 2d 2d 2d 2d 2d 2d-2d 2d 2d 2d 2d 2d 2d 2d ----------------
0027:000087c4 2d 2d 2d 2d 2d 2d 2d 2d-2d 0d 0a 00 3f d0 85 07 ---------...?P..
0027:000087d4 27 00 42 04 76 8f 00 00-8f 00 00 01 1e 88 17 00 '.B.v...........
0027:000087e4 30 07 0b 00 97 00 00 00-00 00 22 89 d3 10 0f 00 0.........".S...
0027:000087f4 00 00 00 00 01 00 00 00-00 00 c4 02 62 1f 27 00 ..........D.b.'.
0027:00008804 62 1f 30 07 57 a9 1e 88-27 00 00 01 57 a9 03 04 b.0.W)..'...W)..
0027:00008814 00 00 01 ac f4 df 00 01-ef ac 00 00 00 00 00 00 ...,t_..o,......
0027:00008824 00 00 00 00 00 00 00 00-46 88 0b 00 f7 cf 57 a9 ........F...wOW)
0027:00008834 58 88 27 00 4a 0c 2f a3-ea 51 8f a3 d1 03 2a 51 X.'.J./#jQ.#Q.*Q
0027:00008844 00 00 00 00 86 2e 9e 17-21 52 8f a3 ea 51 8f a3 ........!R.#jQ.#
0027:00008854 4a 0c 2f a3 d1 03 00 17-2c 00 9e 17 68 88 04 00 J./#Q...,...h...
0027:00008864 53 00 9e 17 00 00 00 00-3c 66 00 00 a0 88 04 00 S.......<f.. ...
0027:00008874 a3 2a 9e 17 3c 66 12 17-00 73 0e 17 2a 2b 9e 17 #*..<f...s..*+..
0027:00008884 3c 66 12 17 00 73 0e 17-48 88 04 00 09 00 00 00 <f...s..H.......
0027:00008894 9a 88 00 00 76 8f 00 00-b6 88 db 2c 0f 00 36 0c ....v...6.[,..6.
0027:000088a4 27 00 02 00 37 0c 34 0c-27 00 02 00 00 00 00 00 '...7.4.'.......
0027:000088b4 27 00 d4 88 ef 28 0f 00-00 00 42 04 76 8f 27 00 '.T.o(....B.v.'.
0027:000088c4 42 04 37 0c 27 00 00 00-13 0c 27 00 00 00 4c 00 B.7.'.....'...L.
0027:000088d4 00 00 88 08 e4 88 4a 39-0f 00 8f 00 00 00 76 8f ....d.J9......v.
0027:000088e4 f1 00 00 00 e0 88 27 00-06 00 f1 00 04 89 2d 23 q...`.'...q...-#
0027:000088f4 0f 00 06 00 0c 00 04 89-07 20 0f 00 0c 00 8f 00 ......... ......
0027:00008904 06 00 22 89 1d 15 0f 00-06 00 42 04 84 08 27 00 ..".......B...'.
0027:00008914 42 04 76 8f 4c 00 27 00-00 00 72 8a e5 11 72 8a B.v.L.'...r.e.r.
0027:00008924 33 12 0f 00 84 08 27 00-27 00 8f a3 ce 0b 1e 0c 3.....'.'..#N...
0027:00008934 68 89 04 00 01 00 00 00-1a 00 81 00 66 08 27 a3 h...........f.'#
0027:00008944 20 00 03 00 54 89 02 00-56 89 7f 7a 97 5f 00 00 ...T...V..z._..
0027:00008954 00 00 04 00 01 00 01 00-6c 9e 97 5f 66 08 27 a3 ........l.._f.'#
0027:00008964 20 00 00 00 00 00 82 16-76 89 7f 7a 97 5f 00 00 .......v..z._..
0027:00008974 00 00 00 00 00 00 82 16-82 89 0d 76 8f a3 00 00 ...........v.#..
0027:00008984 14 00 00 00 97 5f 38 00-37 00 a0 f1 df 9c 00 00 ....._8.7. q_...
0027:00008994 00 00 05 00 20 00 2f a3-a6 89 10 0c 8f a3 ce 0b .... ./#-....#N.
0027:000089a4 1e 0c 00 00 97 5f 00 f0-ff ef d2 16 ef 9c 00 00 ....._.p.oR.o...
0027:000089b4 00 00 06 00 24 00 2f a3-c6 89 10 0c 8f a3 ce 0b ....$./#F....#N.
0027:000089c4 1e 0c 00 00 16 01 1f 00-22 8a 27 00 08 00 27 00 ........".'...'.
0027:000089d4 d8 89 27 00 16 00 00 00-00 00 00 00 00 00 c2 c4 X.'...........BD
0027:000089e4 d9 c5 d4 c3 d4 c4 40 40-40 40 40 40 40 40 40 40 YETCTD@@@@@@@@@@
0027:000089f4 40 40 40 40 40 40 40 40-40 40 05 00 fb ff 05 00 @@@@@@@@@@..{...
0027:00008a04 24 8a cd a9 88 f1 df 9c-20 00 7f 8f f3 04 76 8f $.M).q_. ...s.v.
0027:00008a14 69 8a 00 00 27 00 88 00-00 00 00 00 00 00 00 00 i...'...........
0027:00008a24 26 8a 27 00 41 88 6a 8a-1f 00 76 8f 97 5f 00 00 -.'.A.j...v.._..
0027:00008a34 84 08 27 00 20 20 44 61-74 65 3a 20 31 39 39 35 ..'. Date: 1995
0027:00008a44 2d 30 37 2d 31 30 20 20-54 69 6d 65 3a 20 31 34 -07-10 Time: 14
0027:00008a54 3a 30 31 3a 32 38 3a 33-39 00 54 45 21 21 20 59 :01:28:39.TE!! Y
0027:00008a64 6f 75 20 68 61 76 65 20-56 32 2e 30 30 02 0a 00 ou have V2.00...
0027:00008a74 30 02 0a 00 27 00 00 00-00 00 32 2e 30 30 02 00 0...'.....2.00..
0027:00008a84 9a 8a 00 00 00 00 23 00-01 02 02 00 00 00 28 13 ......#.......(.
0027:00008a94 0f 00 01 00 a0 8a 27 00-c0 8a 27 00 a8 8a 27 00 .... .'.@.'.(.'.
0027:00008aa4 00 00 00 00 43 3a 5c 53-42 5c 45 58 45 5c 42 44 ....C:\SB\EXE\BD
0027:00008ab4 52 45 4d 43 4d 44 2e 45-58 45 00 03 34 8b 27 00 REMCMD.EXE..4.'.
0027:00008ac4 4c 8b 27 00 69 8b 27 00-82 8b 27 00 a2 8b 27 00 L.'.i.'...'.".'.
0027:00008ad4 b9 8b 27 00 d4 8b 27 00-f6 8b 27 00 c6 8c 27 00 9.'.T.'.v.'.F.'.
0027:00008ae4 9f 8d 27 00 ad 8d 27 00-f6 8d 27 00 12 8e 27 00 ..'.-.'.v.'...'.
0027:00008af4 20 8e 27 00 30 8e 27 00-4e 8e 27 00 56 8e 27 00 .'.0.'.N.'.V.'.
0027:00008b04 a1 8e 27 00 b6 8e 27 00-cc 8e 27 00 ea 8e 27 00 !.'.6.'.L.'.j.'.
0027:00008b14 08 8f 27 00 1b 8f 27 00-2a 8f 27 00 32 8f 27 00 ..'...'.*.'.2.'.
0027:00008b24 44 8f 27 00 54 8f 27 00-65 8f 27 00 00 00 00 00 D.'.T.'.e.'.....
0027:00008b34 55 53 45 52 5f 49 4e 49-3d 43 3a 5c 4f 53 32 5c USER_INI=C:\OS2\
0027:00008b44 4f 53 32 2e 49 4e 49 00-53 59 53 54 45 4d 5f 49 OS2.INI.SYSTEM_I
0027:00008b54 4e 49 3d 43 3a 5c 4f 53-32 5c 4f 53 32 53 59 53 NI=C:\OS2\OS2SYS
0027:00008b64 2e 49 4e 49 00 4f 53 32-5f 53 48 45 4c 4c 3d 43 .INI.OS2_SHELL=C
0027:00008b74 3a 5c 4f 53 32 5c 43 4d-44 2e 45 58 45 00 52 55 :\OS2\CMD.EXE.RU
0027:00008b84 4e 57 4f 52 4b 50 4c 41-43 45 3d 43 3a 5c 4f 53 NWORKPLACE=C:\OS
0027:00008b94 32 5c 50 4d 53 48 45 4c-4c 2e 45 58 45 00 43 4f 2\PMSHELL.EXE.CO
0027:00008ba4 4d 53 50 45 43 3d 43 3a-5c 4f 53 32 5c 43 4d 44 MSPEC=C:\OS2\CMD
0027:00008bb4 2e 45 58 45 00 41 55 54-4f 53 54 41 52 54 3d 54 .EXE.AUTOSTART=T
0027:00008bc4 41 53 4b 4c 49 53 54 2c-46 4f 4c 44 45 52 53 00 ASKLIST,FOLDERS.
0027:00008bd4 52 45 53 54 41 52 54 4f-42 4a 45 43 54 53 3d 53 RESTARTOBJECTS=S
0027:00008be4 54 41 52 54 55 50 46 4f-4c 44 45 52 53 4f 4e 4c TARTUPFOLDERSONL
Stack displayed as words.
# dw ss:sp - 500 l500
0027:00008574 0100 8608 0027 1812 a81f 0000 0000 0001
0027:00008584 0001 d037 860c 0495 01b5 01b5 0352 0000
0027:00008594 0000 0000 0000 0000 0000 0000 0000 0000
0027:000085a4 0000 0000 0000 0000 0000 0000 0000 0006
0027:000085b4 0000 0006 0001 0000 01b5 0001 0001 85ea
0027:000085c4 2af1 0002 0100 8608 0027 1812 a81f 0000
0027:000085d4 85ea 0495 860c 0000 0027 1812 a81f d037
0027:000085e4 2afa a81f 0000 8616 27a4 a867 1812 a81f
0027:000085f4 8608 0027 0100 a81f 0495 0000 0401 dff4
0027:00008604 0100 0086 0000 0000 0000 0000 0000 0000
0027:00008614 0000 8724 2ef9 a867 a81f 1de4 a867 a81f
0027:00008624 0000 0000 0000 0000 0000 0000 0000 0000
0027:00008634 0000 0000 0000 d037 0000 016a 0002 0002
0027:00008644 066b d037 867a 2e8e 218c aaef 0100 01ee
0027:00008654 066b 016c 066b 0080 d037 01ee 066b 016c
0027:00008664 066b 0000 066b 0002 066b 0080 003a 066b
0027:00008674 01b5 86ca 2cda 86ce 2cda 0002 0100 8714
0027:00008684 88e4 0027 00f1 86de 0027 0006 00f1 0006
0027:00008694 86c2 09cc d02f 88e4 0027 00f1 86de 0a18
0027:000086a4 86c2 00f1 0006 86de 00f1 0006 0027 d03f
0027:000086b4 0a18 0027 00f7 87cf 0000 0006 0000 88f0
0027:000086c4 39c2 000f 88e4 0027 00f1 86de 0027 0006
0027:000086d4 008f 0000 88de 790a 397a 0a0d 0a0d 7355
0027:000086e4 7265 6469 203a 7920 756f 2121 2021 6f59
0027:000086f4 2075 656e 6465 5620 2e32 3030 6f20 2066
0027:00008704 4442 4552 4f4d 4554 2121 5920 756f 6820
0027:00008714 7661 2065 3256 302e 0230 0a0d 2020 614d
0027:00008724 6863 6e69 2065 4449 203a 6f59 2075 656e
0027:00008734 6465 5620 2e32 3030 6f20 2066 4442 4552
0027:00008744 4f4d 4554 2121 5920 756f 6820 7661 2065
0027:00008754 3256 302e 0230 0a0d 2020 6144 6574 203a
0027:00008764 3931 3539 302d 2d37 3031 2020 6954 656d
0027:00008774 203a 3431 303a 3a31 3832 333a 0d39 2d0a
0027:00008784 2d2d 2d2d 2d2d 2d2d 2d2d 2d2d 2d2d 2d2d
0027:00008794 2d2d 2d2d 2d2d 2d2d 2d2d 2d2d 2d2d 2d2d
0027:000087a4 2d2d 2d2d 2d2d 2d2d 2d2d 2d2d 2d2d 2d2d
0027:000087b4 2d2d 2d2d 2d2d 2d2d 2d2d 2d2d 2d2d 2d2d
0027:000087c4 2d2d 2d2d 2d2d 2d2d 0d2d 000a d03f 0785
0027:000087d4 0027 0442 8f76 0000 008f 0100 881e 0017
0027:000087e4 0730 000b 0097 0000 0000 8922 10d3 000f
0027:000087f4 0000 0000 0001 0000 0000 02c4 1f62 0027
0027:00008804 1f62 0730 a957 881e 0027 0100 a957 0403
0027:00008814 0000 ac01 dff4 0100 acef 0000 0000 0000
0027:00008824 0000 0000 0000 0000 8846 000b cff7 a957
0027:00008834 8858 0027 0c4a a32f 51ea a38f 03d1 512a
0027:00008844 0000 0000 2e86 179e 5221 a38f 51ea a38f
0027:00008854 0c4a a32f 03d1 1700 002c 179e 8868 0004
0027:00008864 0053 179e 0000 0000 663c 0000 88a0 0004
0027:00008874 2aa3 179e 663c 1712 7300 170e 2b2a 179e
0027:00008884 663c 1712 7300 170e 8848 0004 0009 0000
0027:00008894 889a 0000 8f76 0000 88b6 2cdb 000f 0c36
0027:000088a4 0027 0002 0c37 0c34 0027 0002 0000 0000
0027:000088b4 0027 88d4 28ef 000f 0000 0442 8f76 0027
0027:000088c4 0442 0c37 0027 0000 0c13 0027 0000 004c
0027:000088d4 0000 0888 88e4 394a 000f 008f 0000 8f76
0027:000088e4 00f1 0000 88e0 0027 0006 00f1 8904 232d
0027:000088f4 000f 0006 000c 8904 2007 000f 000c 008f
0027:00008904 0006 8922 151d 000f 0006 0442 0884 0027
0027:00008914 0442 8f76 004c 0027 0000 8a72 11e5 8a72
0027:00008924 1233 000f 0884 0027 0027 a38f 0bce 0c1e
0027:00008934 8968 0004 0001 0000 001a 0081 0866 a327
0027:00008944 0020 0003 8954 0002 8956 7a7f 5f97 0000
0027:00008954 0000 0004 0001 0001 9e6c 5f97 0866 a327
0027:00008964 0020 0000 0000 1682 8976 7a7f 5f97 0000
0027:00008974 0000 0000 0000 1682 8982 760d a38f 0000
0027:00008984 0014 0000 5f97 0038 0037 f1a0 9cdf 0000
0027:00008994 0000 0005 0020 a32f 89a6 0c10 a38f 0bce
0027:000089a4 0c1e 0000 5f97 f000 efff 16d2 9cef 0000
0027:000089b4 0000 0006 0024 a32f 89c6 0c10 a38f 0bce
0027:000089c4 0c1e 0000 0116 001f 8a22 0027 0008 0027
0027:000089d4 89d8 0027 0016 0000 0000 0000 0000 c4c2
0027:000089e4 c5d9 c3d4 c4d4 4040 4040 4040 4040 4040
0027:000089f4 4040 4040 4040 4040 4040 0005 fffb 0005
0027:00008a04 8a24 a9cd f188 9cdf 0020 8f7f 04f3 8f76
0027:00008a14 8a69 0000 0027 0088 0000 0000 0000 0000
0027:00008a24 8a26 0027 8841 8a6a 001f 8f76 5f97 0000
0027:00008a34 0884 0027 2020 6144 6574 203a 3931 3539
0027:00008a44 302d 2d37 3031 2020 6954 656d 203a 3431
0027:00008a54 303a 3a31 3832 333a 0039 4554 2121 5920
0027:00008a64 756f 6820 7661 2065 3256 302e 0230 000a
0027:00008a74 0230 000a 0027 0000 0000 2e32 3030 0002
0027:00008a84 8a9a 0000 0000 0023 0201 0002 0000 1328
0027:00008a94 000f 0001 8aa0 0027 8ac0 0027 8aa8 0027
0027:00008aa4 0000 0000 3a43 535c 5c42 5845 5c45 4442
0027:00008ab4 4552 434d 444d 452e 4558 0300 8b34 0027
0027:00008ac4 8b4c 0027 8b69 0027 8b82 0027 8ba2 0027
0027:00008ad4 8bb9 0027 8bd4 0027 8bf6 0027 8cc6 0027
0027:00008ae4 8d9f 0027 8dad 0027 8df6 0027 8e12 0027
0027:00008af4 8e20 0027 8e30 0027 8e4e 0027 8e56 0027
0027:00008b04 8ea1 0027 8eb6 0027 8ecc 0027 8eea 0027
0027:00008b14 8f08 0027 8f1b 0027 8f2a 0027 8f32 0027
0027:00008b24 8f44 0027 8f54 0027 8f65 0027 0000 0000
0027:00008b34 5355 5245 495f 494e 433d 5c3a 534f 5c32
0027:00008b44 534f 2e32 4e49 0049 5953 5453 4d45 495f
0027:00008b54 494e 433d 5c3a 534f 5c32 534f 5332 5359
0027:00008b64 492e 494e 4f00 3253 535f 4548 4c4c 433d
0027:00008b74 5c3a 534f 5c32 4d43 2e44 5845 0045 5552
0027:00008b84 574e 524f 504b 414c 4543 433d 5c3a 534f
0027:00008b94 5c32 4d50 4853 4c45 2e4c 5845 0045 4f43
0027:00008ba4 534d 4550 3d43 3a43 4f5c 3253 435c 444d
0027:00008bb4 452e 4558 4100 5455 534f 4154 5452 543d
0027:00008bc4 5341 4c4b 5349 2c54 4f46 444c 5245 0053
0027:00008bd4 4552 5453 5241 4f54 4a42 4345 5354 533d
0027:00008be4 4154 5452 5055 4f46 444c 5245 4f53 4c4e
0027:00008bf4 0059 4150 4854 433d 5c3a 4253 455c 4558
0027:00008c04 433b 5c3a 4344 4641 3231 433b 5c3a 5153
0027:00008c14 4c4c 4249 433b 5c3a 4249 4c4d 4e41 4e5c
0027:00008c24 5445 5250 474f 433b 5c3a 554d 4c47 4249
0027:00008c34 433b 5c3a 534f 3b32 3a43 435c 4c4d 4249
0027:00008c44 433b 5c3a 534f 5c32 5953 5453 4d45 433b
0027:00008c54 5c3a 534f 5c32 444d 534f 575c 4e49 534f
0027:00008c64 3b32 3a43 4f5c 3253 495c 534e 4154 4c4c
0027:00008c74 433b 5c3a 433b 5c3a 534f 5c32 444d 534f
0027:00008c84 433b 5c3a 534f 5c32 5041 5350 433b 5c3a
0027:00008c94 444e 5c4d 4942 3b4e 3a43 4c5c 554d 3b32
0027:00008ca4 3a43 535c 5059 554c 3b53 3a43 545c 534d
0027:00008cb4 433b 5c3a 4f52 4f42 4153 4556 573b 5c3a
0027:00008cc4 003b 5044 5441 3d48 3a43 535c 5c42 4144
0027:00008cd4 4154 433b 5c3a 4253 435c 4746 433b 5c3a
0027:00008ce4 4344 4641 3231 433b 5c3a 5153 4c4c 4249
0027:00008cf4 433b 5c3a 4249 4c4d 4e41 4e5c 5445 5250
0027:00008d04 474f 433b 5c3a 4249 4c4d 4e41 433b 5c3a
0027:00008d14 554d 4c47 4249 433b 5c3a 4249 434d 4d4f
0027:00008d24 433b 5c3a 534f 3b32 3a43 435c 4c4d 4249
0027:00008d34 433b 5c3a 534f 5c32 5953 5453 4d45 433b
0027:00008d44 5c3a 534f 5c32 444d 534f 575c 4e49 534f
0027:00008d54 3b32 3a43 4f5c 3253 495c 534e 4154 4c4c
0027:00008d64 433b 5c3a 433b 5c3a 534f 5c32 4942 4d54
0027:00008d74 5041 433b 5c3a 534f 5c32 444d 534f 433b
0027:00008d84 5c3a 534f 5c32 5041 5350 433b 5c3a 444e
0027:00008d94 3b4d 3a43 4c5c 554d 3b32 5000 4f52 504d
0027:00008da4 3d54 6924 245b 5d70 4800 4c45 3d50 3a43
0027:00008db4 535c 4c51 494c 3b42 3a43 4f5c 3253 485c
0027:00008dc4 4c45 3b50 3a43 4f5c 3253 485c 4c45 5c50
0027:00008dd4 5554 4f54 4952 4c41 433b 5c3a 4d43 494c
0027:00008de4 3b42 3a43 4c5c 554d 3b32 3a43 4e5c 4d44
0027:00008df4 003b 4c47 534f 4153 5952 433d 5c3a 534f
0027:00008e04 5c32 4548 504c 475c 4f4c 5353 003b 5049
0027:00008e14 5f46 454b 5359 533d 4342 0053 414b 454c
0027:00008e24 444e 5245 433d 5c3a 4253 005c 4442 4844
0027:00008e34 4c45 3d50 3a43 535c 5c42 5049 5c46 4442
0027:00008e44 4844 4c45 2e50 4c48 0050 454b 5359 4f3d
0027:00008e54 004e 4f42 4b4f 4853 4c45 3d46 3a43 535c
0027:00008e64 4c51 494c 5c42 4f42 4b4f 433b 5c3a 4249
0027:00008e74 4c4d 4e41 425c 4f4f 3b4b 3a43 4f5c 3253
0027:00008e84 425c 4f4f 3b4b 3a43 435c 4c4d 4249 425c
0027:00008e94 4f4f 3b4b 3a43 4c5c 554d 3b32 4500 4d50
0027:00008ea4 4150 4854 433d 5c3a 534f 5c32 5041 5350
0027:00008eb4 003b 4956 4544 5f4f 4544 4956 4543 3d53
0027:00008ec4 4956 5f4f 4758 0041 4956 5f4f 4758 3d41
0027:00008ed4 4544 4956 4543 4228 4856 4756 2c41 5642
0027:00008ee4 5848 4147 0029 4956 5f4f 5653 4147 443d
0027:00008ef4 5645 4349 2845 5642 5648 4147 422c 4856
0027:00008f04 4758 0041 4e49 4c43 4455 3d45 3a43 535c
0027:00008f14 4c51 494c 3b42 4c00 4249 433d 5c3a 5153
0027:00008f24 4c4c 4249 003b 5251 4457 3d52 0043 5251
0027:00008f34 4957 534e 3d54 3a43 535c 4c51 494c 0042
0027:00008f44 4d43 4150 4854 433d 5c3a 4d43 494c 0042
0027:00008f54 4f42 4b4f 474d 3d52 3a43 4c5c 554d 3b32
0027:00008f64 4100 5050 5443 4e50 423d 5244 4d45 4d43
#
Looking at the stack we now find that there is a string that overwrites the
return addresses (see below). A good starting point now would be to look at
the last correct stack frame we could find and look at that program. You could
also try to see below the overwritten stack area to see if you can get another
correct frame. If you can then you will have two functions to work from.
Corrupted stacks require lots of investigation. As long as you understand how
stacks work and how data is stored on them, you should be able to sort it out.
0027:00008a54 3a 30 31 3a 32 38 3a 33-39 00 54 45 21 21 20 59 :01:28:39.TE!! Y
0027:00008a64 6f 75 20 68 61 76 65 20-56 32 2e 30 30 02 0a 00 ou have V2.00...
0027:00008a74 30 02 0a 00 27 00 00 00-00 00 32 2e 30 30 02 00 0...'.....2.00..
Another form of stack corruption that you will come across is when the one half
of the return BP has been overwritten. This is because a local variable has
been defined as a certain length, and the program has moved a value of exactly
that length into it and the null terminator has overwritten the one byte of the
BP. These are a bit easier to solve as you still have the return address to
work with.
ΓòÉΓòÉΓòÉ 22.10. Fig. 9 - application dump stack. ΓòÉΓòÉΓòÉ
#
OS/2 2.x Dump Formatter for retail kernel
Formatter is --> Internal revision 6.651, 94/10/19
Dump file is --> Internal revision 6.651, 94/10/19
Current slot number: 008f
Symbol (c:\os2\pdpsi\pmdf\std9501\os2krnlr.sym) linked
Slot Pid Ppid Csid Ord Sta Pri pTSD pPTDA pTCB Disp SG Name
*008f# 004b 000b 004b 0001 run 0500 7bbf7000 7bc9a608 7bc786e0 0f04 10 BD
eax=0000ffc5 ebx=0000e48b ecx=00000011 edx=50f8e44d esi=00004a03 edi=0000ffc5
eip=00001899 esp=0000e13c ebp=0000e13e iopl=2 rf -- -- nv up ei pl nz na po nc
cs=68e7 ss=001f ds=017f es=5c4f fs=150b gs=0000 cr2=00000000 cr3=00000000
68e7:00001899 a4 movsb es:ffc5=invalid ds:4a03=30
#
Loading version data ... please wait
Loading structure info for OS/2 2.11 as per 9501 version ... please wait..
# .
# .
#
# Done.
Now that we have loaded the dump we can see that the instruction that failed
was movsb and it failed because the value es:ffc5 was invalid. The ES is valid
but the ffc5 is not. If you investigated you would find that the movsb
instruction moves the value at ds:si to es:di. Lets look at what details we can
about the segment allocated to ES.
# dl 5c4f
5c4f Data Bas=0b890000 Lim=00000226 DPL=3 P RW A
We are trying to access offset ffc5 in a segment that has got a limit of 226.
Not surprising we trapped. The next question is where and why. Look at the dll
we are in.
# .M CS:IP
*har par cpg va flg next prev link hash hob hal
0bb6 %fee2f1ae 00000010 %0d1c0000 3d9 0bb5 0bb7 0000 09c3 0f03 0000 hco=017e9
hob har hobnxt flgs own hmte sown,cnt lt st xf
0f03 0bb6 0000 0838 0f02 0f02 0000 00 00 00 00 shared c:crtlib.dll
hco=17e9 pco=ffe6c7a8 hconext=018ad hptda=13b8 f=1c pid=006a c:loop.exe
We are in crtlib.dll. Since this dll is a system dll we can make an assumption
that it was a faulty parameter that was passed. I am not saying that system
dlls are perfect, but if you are dealing with an abend in one, then rather make
the assumption that it was a bad parameter first. If you prove all the
parameters were okay, then start looking at the system dll itself.
Now we have to look at the stack to see where crtlib was called from.
# dw ss:bp
001f:0000e13e e414 2c1e 5c5f ffc5 5c4f 4a03 017f 5c57
001f:0000e14e e48b e44d 3300 61af 0000 0000 0000 ff00
001f:0000e15e ff0b 61ba 017f e168 001f 7fff 0001 9ec0
001f:0000e16e 32d0 000f 98cc 30b0 0000 28c0 b200 ef9a
001f:0000e17e fe00 00ff 0000 bd00 00ac 0000 6377 0000
001f:0000e18e 06d7 2947 bd0f 0001 000f 9ec0 32d0 0043
001f:0000e19e 98cc 30b0 bd7f 0000 0000 0000 000c bd7f
001f:0000e1ae e1c6 281f bd0f 0000 0001 000f 9ec0 4242
The address that we were to return to is 5c5f:2c1e. What can we tell about the
segment?.
# dl 5c5f
5c5f Code Bas=0b8b0000 Lim=00002ff9 DPL=3 P RE A
PMDF is telling us that is a code segment running at descriptor privilege
level of 3. Who owns that segment ?.
# .m 5c5f:2c1e
*har par cpg va flg next prev link hash hob hal
0e57 %fee32b84 00000010 %0b8b0000 3d9 0e56 0e58 0000 0b54 1405 0000 hco=020f4
hob har hobnxt flgs own hmte sown,cnt lt st xf
1405 0e57 0000 0838 1406 1406 0000 00 00 00 00 shared c:bddas601.dll
hco=20f4 pco=ffe6f4df hconext=00000 hptda=121b f=1d pid=004b c:bd.exe
The segment is owned by BDDAS601.DLL. Refer to Getting the path and dll name
the hard way. and ExeInfo - getting a dll using CSLIM. or FINDSEG - getting a
dll using CSLIM. and QTRAP - getting a lot more using CS, IP, CSLIM and dll
name. for information on how to get the source code line number of that return
address.
Let us have a look at he parameters that were passed to crtlib.
# U 5C5F:2C1E - 30
5c5f:00002bee 50 push ax
5c5f:00002bef 9a7618e768 call 68e7:1876
5c5f:00002bf4 83c408 add sp,+08
5c5f:00002bf7 c45e06 les bx,dword ptr [bp+06]
5c5f:00002bfa 26c45f0a les bx,dword ptr es:[bx+0a]
5c5f:00002bfe 268b4710 mov ax,word ptr es:[bx+10]
5c5f:00002c02 268b5712 mov dx,word ptr es:[bx+12]
5c5f:00002c06 051100 add ax,0011
5c5f:00002c09 52 push dx
5c5f:00002c0a 50 push ax
5c5f:00002c0b 6b9ec6fe3d imul bx,word ptr [bp+fec6],3d ;'='
5c5f:00002c10 8d87c5ff lea ax,[bx+ffc5]
5c5f:00002c14 ba4f5c mov dx,5c4f
5c5f:00002c17 52 push dx
5c5f:00002c18 50 push ax
5c5f:00002c19 9a7618e768 call 68e7:1876 <--- call to crtlib
5c5f:00002c1e 83c408 add sp,+08 <--- address to return to
5c5f:00002c21 c45e06 les bx,dword ptr [bp+06]
5c5f:00002c24 26c45f0a les bx,dword ptr es:[bx+0a]
5c5f:00002c28 268b4710 mov ax,word ptr es:[bx+10]
5c5f:00002c2c 268b5712 mov dx,word ptr es:[bx+12]
5c5f:00002c30 052700 add ax,0027
5c5f:00002c33 52 push dx
5c5f:00002c34 50 push ax
#
At 5c5f:2c0b above PMDF has told us to add fec6 to the BP. Doing this would
give us an out of range address. Subtract that value from (hex)10000 and then
subtract the result from BP to get the correct pointer. I have no idea why this
sometimes happens.
# ?10000 - FEC6
013aH 314T 472Q 0000000100111010Y ':' TRUE
Test the parameters passed. From the above unassembled code we know that we
pushed 4 paramaters onto the stack. Therefore the last four values just before
the return CS will be the parameters passed.
# DW SS:BP - 10
001f:0000e12e e168 001f e408 001f 5c57 e48b e44d 5c57
001f:0000e13e e414 2c1e 5c5f ffc5 5c4f 4a03 017f 5c57
001f:0000e14e e48b e44d 3300 61af 0000 0000 0000 ff00
001f:0000e15e ff0b 61ba 017f e168 001f 7fff 0001 9ec0
001f:0000e16e 32d0 000f 98cc 30b0 0000 28c0 b200 ef9a
001f:0000e17e fe00 00ff 0000 bd00 00ac 0000 6377 0000
001f:0000e18e 06d7 2947 bd0f 0001 000f 9ec0 32d0 0043
001f:0000e19e 98cc 30b0 bd7f 0000 0000 0000 000c bd7f
# DW 17F:4A03
017f:00004a03 3030 3030 3130 3231 3030 3431 3036 3030
017f:00004a13 3000 3438 0035 3030 3130 3839 0032 0000
017f:00004a23 0000 1200 d100 7f48 0001 0005 0bff 01ff
017f:00004a33 0f06 43e0 bd5f 1200 0000 7f49 0001 0005
017f:00004a43 0bff 01ff 0f06 43e0 bd5f 2200 5e00 7f49
017f:00004a53 0001 0000 0000 0000 0000 7400 0061 0500
017f:00004a63 0500 0500 0601 540f 5f37 00bd 0000 2800
017f:00004a73 8d00 7f49 0001 0000 0000 0000 0000 0000
# DW 5C4F:FFC5
Past end of segment: 5c4f:0000ffc5
# .R
eax=0000ffc5 ebx=0000e48b ecx=00000011 edx=50f8e44d esi=00004a03 edi=0000ffc5
eip=00001899 esp=0000e13c ebp=0000e13e iopl=2 rf -- -- nv up ei pl nz na po nc
cs=68e7 ss=001f ds=017f es=5c4f fs=150b gs=0000 cr2=00000000 cr3=00000000
68e7:00001899 a4 movsb es:ffc5=invalid ds:4a03=30
Looking at the two parameters passed, and testing each of them we see that the
second parameter to be put on the stack (in C convention, the first parameter
to be passed) is invalid.
At this stage we go to the source code, because I know that am in BDDAS601.DLL
I don't have to run findseg. I get the CSLIM from the dl that I did earlier
(2ff9) and I have the CS:IP from the stack (5c5f:2c1e). So now I perform a
qtrap and get the following:
QTRAP v3.03 by Adrian Bonsall - Automated Trap Resolver
5C5F is Entry #2955 in the Local Descriptor Table with a ReqPrivLvl of 3.
Selector 5C5F is not assigned to any of the default segments of f:\main\dll\bddas601.dll
Checking imported modules for segment of size 2FFA:
Searching .... BDDAS601 .... Segment found.
Sel. Off. Seg.No. Length AllocSize Flags
5C5F 2C1E 0001 0x2FFA 0x2FFA CODE RELOC DPL3
Nearest Entry Point : 0001:1116 TPBDDAS601.
Nearest Public Symbol : 0001:1116 TPBDDAS601 (D:\SB\MAIN\OBJ\BDDAS601.OBJ)
Nearest Source Line : 0001:2BF7 line #1532 (D:\SB\MAIN\OBJ\BDDAS601.OBJ)
We can double check this by referring to the MAP file.
.
.
.
Line numbers for C:\SB\OBJ\BDDAS601.OBJ(F:\MAIN\SRC\REF\BDDAS601.C) segment BDDAS601_TEXT
.
.
.
1523 0001:2BB3 1526 0001:2BBE 1528 0001:2BD1 1530 0001:2BE4
1532 0001:2BF7 1534 0001:2C21 1536 0001:2C4B 1538 0001:2C65
.
.
.
Here we have a good example of where you have to look for the nearest number
matching the offset in map file, and not the exact offset, as discussed in
Using the source code.
.
.
; Line 1532
les bx,DWORD PTR [bp+6] ;pDlgDat
les bx,DWORD PTR es:[bx+10]
mov ax,WORD PTR es:[bx+16]
mov dx,WORD PTR es:[bx+18]
add ax,17
push dx
push ax
imul bx,WORD PTR [bp-314],61 ;sNamesdeleted
lea ax,WORD PTR _NamDetails[bx-61]
mov dx,SEG _NamDetails
push dx
push ax
call FAR PTR _strcpy
add sp,8 <-- pointed to by 5c5f:2c31
; Line 1533
.
.
Having got the line, I look at the source code for that line.
.
.
strcpy(DeleteDetails.szCardNumber,
CardDetails.szCardNumber);
strcpy(NamDetails[sNamesdeleted - 1].szNameNumber, <-- line 1532
BDDAS601REC(szNameNumber));
.
.
From looking at the unpacked assembler code in PMDF I know that parameter the
parameter passed as NamDetails[sNamesdeleted - 1].szNameNumber had an invalid
pointer of 5c4f:ffc5. At this stage it is up to the programmer to investigate
the logic of his code to see why this would be invalid. You can do some more
investigation at this stage. What is required is that you use the source code
and the assembler, and work through the function that called crtlib with an
invalid parameter. You might be able to determine why it was invalid. But that
is beyond the scope of this document.
As a matter of interest, the reason that this particular trap occurred was
because the sNamesdeleted was 0, therefore doing the -1 gave us garbage.
ΓòÉΓòÉΓòÉ 22.11. Initial display and output of .r. ΓòÉΓòÉΓòÉ
The display that you are presented with when you first load the dump.
OS/2 2.x Dump Formatter for retail kernel
Formatter is --> Internal revision 6.651, 94/10/19
Dump file is --> Internal revision 6.651, 94/10/19
Current slot number: 008f
Symbol (c:\os2\pdpsi\pmdf\std9501\os2krnlr.sym)
linked
Slot Pid Ppid Csid Ord Sta Pri pTSD pPTDA pTCB Disp SG Name
*008f# 004b 000b 004b 0001 run 0500 7bbf7000 7bc9a608 7bc786e0 0f04 10
BD
eax=0000ffc5 ebx=0000e48b ecx=00000011 edx=50f8e44d esi=00004a03 edi=0000ffc5
eip=00001899 esp=0000e13c ebp=0000e13e iopl=2 rf-- -- nv up ei pl nz na po nc
cs=68e7 ss=001f ds=017f es=5c4f fs=150b gs=0000 cr2=00000000 cr3=00000000
68e7:00001899 a4 movsb es:ffc5=invalid
ds:4a03=30
Loading version data ... please wait
Loading structure info for OS/2 2.11 as per 9501 version ... please wait..
# .
# .
#
# Done.
From this we have been given the name of the exe/dll that abended, the address
of the abending instruction (we could also get that from looking at the values
of the CS and IP registers). We were also given the actual instruction that
abended and we were even given the values that the instruction was using with
the invalid value pointed out to us.
You can easily get this information all over again by using .r which will cause
the following to be displayed :
# .r
eax=0000ffc5 ebx=0000e48b ecx=00000011 edx=50f8e44d esi=00004a03 edi=0000ffc5
eip=00001899 esp=0000e13c ebp=0000e13e iopl=2 rf-- -- nv up ei pl nz na po nc
cs=68e7 ss=001f ds=017f es=5c4f fs=150b gs=0000 cr2=00000000 cr3=00000000
68e7:00001899 a4 movsb es:ffc5=invalid
ds:4a03=30
ΓòÉΓòÉΓòÉ 22.12. Output of .m. ΓòÉΓòÉΓòÉ
Another way to get the name of the dll that you are working from. Do a .m on
the address that you want to enquire about. This will display the following
information :
# .M CS:IP
*har par cpg va flg next prev link hash hob hal
0bb6 %fee2f1ae 00000010 %0d1c0000 3d9 0bb5 0bb7 0000 09c3
0f03 0000 hco=017e9 hob har hobnxt flgs own hmte sown,cnt lt st xf
0f03 0bb6 0000 0838 0f02 0f02 0000 00 00 00 00 shared c:crtlib.dll
hco=17e9 pco=ffe6c7a8 hconext=018ad hptda=13b8 f=1c pid=006a c:loop.exe
# .m 5c5f:2c1e
*har par cpg va flg next prev link hash hob hal
0e57 %fee32b84 00000010 %0b8b0000 3d9 0e56 0e58 0000 0b54
1405 0000 hco=020f4 hob har hobnxt flgs own hmte sown,cnt lt st xf
1405 0e57 0000 0838 1406 1406 0000 00 00 00 00 shared
c:bddas601.dll
hco=20f4 pco=ffe6f4df hconext=00000 hptda=121b f=1d pid=004b c:bd.exe
The actual dll that we were in and the executable file that called it.
Be warned, just when things are going so well, you'll get a result that looks
like this. In a case like this I just try to work out what is the most likely
one that I will be dealing with.
# .m f:3204
*har par cpg va flg next prev link hash hob hal
0225 %fee21f38 00000010 %00010000 1d9 0224 0220 0000 0000 0270 0000 hptda=026b
hob har hobnxt flgs own hmte sown,cnt lt st xf
0270 0225 0000 0838 026f 026f 0000 00 00 00 00 shared c:eqnrckb.exe
*har par cpg va flg next prev link hash hob hal
0241 %fee221a0 00000010 %00010000 1d9 020f 0c96 0000 0000 13bd 0000 hptda=13b8
hob har hobnxt flgs own hmte sown,cnt lt st xf
13bd 0241 0000 0838 13be 13be 0000 00 00 00 00 shared c:loop.exe
*har par cpg va flg next prev link hash hob hal
024a %fee22266 00000010 %00010000 179 024b 0248 0000 0000 029e 0000 hptda=029a
hob har hobnxt flgs own hmte sown,cnt lt st xf
029e 024a 0000 002c 029a 029f 0000 00 00 00 00 priv 0006 c:lanmsgex.exe
*har par cpg va flg next prev link hash hob hal
0257 %fee22384 00000010 %00010000 1d9 0258 0255 0000 0000 02b0 0000 hptda=02ac
hob har hobnxt flgs own hmte sown,cnt lt st xf
02b0 0257 0000 0838 02b1 02b1 0000 00 00 00 00 shared c:landll.exe
*har par cpg va flg next prev link hash hob hal
0263 %fee2248c 00000010 %00010000 1d9 0265 0261 0000 0000 02c2 0000 hptda=02be
hob har hobnxt flgs own hmte sown,cnt lt st xf
02c2 0263 0000 0838 02c4 02c4 0000 00 00 00 00 shared c:lsdaemon.exe
*har par cpg va flg next prev link hash hob hal
026e %fee2257e 00000010 %00010000 1d9 026f 026c 0000 0000 02d0 0000 hptda=02cc
hob har hobnxt flgs own hmte sown,cnt lt st xf
02d0 026e 0000 0838 02d1 02d1 0000 00 00 00 00 shared c:logdaem.exe
*har par cpg va flg next prev link hash hob hal
0276 %fee2262e 00000010 %00010000 1d9 0277 0274 0000 0000 02dd 0000 hptda=02d9
hob har hobnxt flgs own hmte sown,cnt lt st xf
02dd 0276 0000 0838 02de 02de 0000 00 00 00 00 shared c:epwrout.exe
*har par cpg va flg next prev link hash hob hal
040a %fee248e6 00000010 %00010000 1c9 040b 0408 02b7 0000 032b 0000 hptda=04e3
02b7 %fee22bc4 00000010 %00010000 1d9 02b8 0090 0000 0000 032b 0000 hptda=0093
hob har hobnxt flgs own hmte sown,cnt lt st xf
032b 040a 0000 0838 032c 032c 0000 00 00 00 00 shared c:pmshell.exe
*har par cpg va flg next prev link hash hob hal
02fc %fee231b2 00000010 %00010000 179 02fd 02fa 0000 0000 0392 0000 hptda=038e
hob har hobnxt flgs own hmte sown,cnt lt st xf
0392 02fc 0000 002c 038e 0393 0000 00 00 00 00 priv 000c c:harderr.exe
*har par cpg va flg next prev link hash hob hal
0d3e %fee3135e 00000010 %00010000 1c9 0d3f 0d3c 031b 0000 03ae 0000 hptda=1205
031b %fee2345c 00000010 %00010000 1d9 031c 0319 0000 0000 03ae 0000 hptda=000e
hob har hobnxt flgs own hmte sown,cnt lt st xf
03ae 0d3e 0000 0838 03af 03af 0000 00 00 00 00 shared c:epwmux.exe
*har par cpg va flg next prev link hash hob hal
0377 %fee23c44 00000010 %00010000 1d9 0378 0375 0000 0000 0418 0000 hptda=0414
hob har hobnxt flgs own hmte sown,cnt lt st xf
0418 0377 0000 0838 0419 0419 0000 00 00 00 00 shared c:stoplan.exe
*har par cpg va flg next prev link hash hob hal
040a %fee248e6 00000010 %00010000 1c9 040b 0408 02b7 0000 032b 0000 hptda=04e3
02b7 %fee22bc4 00000010 %00010000 1d9 02b8 0090 0000 0000 032b 0000 hptda=0093
hob har hobnxt flgs own hmte sown,cnt lt st xf
032b 040a 0000 0838 032c 032c 0000 00 00 00 00 shared c:pmshell.exe
*har par cpg va flg next prev link hash hob hal
0446 %fee24e0e 00000010 %00010000 1d9 0447 0443 0000 0000 0585 0000 hptda=0581
hob har hobnxt flgs own hmte sown,cnt lt st xf
0585 0446 0000 0838 0586 0586 0000 00 00 00 00 shared c:muglrqst.exe
*har par cpg va flg next prev link hash hob hal
048a %fee253e6 00000010 %00010000 1d9 0465 048c 0000 0000 0565 0000 hptda=0535
hob har hobnxt flgs own hmte sown,cnt lt st xf
0565 048a 0000 0838 0601 0601 0000 00 00 00 00 shared c:cmstart.exe
*har par cpg va flg next prev link hash hob hal
04af %fee25714 00000010 %00010000 1d9 04b0 04ad 0000 0000 061e 0000 hptda=061a
hob har hobnxt flgs own hmte sown,cnt lt st xf
061e 04af 0000 0838 061f 061f 0000 00 00 00 00 shared c:wksta.exe
*har par cpg va flg next prev link hash hob hal
04c5 %fee258f8 00000010 %00010000 1d9 04c6 0490 0000 0000 0658 0000 hptda=05d4
hob har hobnxt flgs own hmte sown,cnt lt st xf
0658 04c5 0000 0838 0659 0659 0000 00 00 00 00 shared c:wkstahlp.exe
*har par cpg va flg next prev link hash hob hal
04e3 %fee25b8c 00000010 %00010000 1d9 04e4 04e1 0000 0000 069f 0000 hptda=069b
hob har hobnxt flgs own hmte sown,cnt lt st xf
069f 04e3 0000 0838 06a0 06a0 0000 00 00 00 00 shared c:lsclient.exe
*har par cpg va flg next prev link hash hob hal
04f0 %fee25caa 00000010 %00010000 1d9 04f1 04ee 0000 0000 06e6 0000 hptda=06cd
hob har hobnxt flgs own hmte sown,cnt lt st xf
06e6 04f0 0000 0838 06e7 06e7 0000 00 00 00 00 shared c:netpopup.exe
*har par cpg va flg next prev link hash hob hal
04f5 %fee25d18 00000010 %00010000 1d9 04f6 04aa 0000 0000 06f6 0000 hptda=064c
hob har hobnxt flgs own hmte sown,cnt lt st xf
06f6 04f5 0000 0838 06f7 06f7 0000 00 00 00 00 shared c:msrv.exe
*har par cpg va flg next prev link hash hob hal
055a %fee265c6 00000010 %00010000 1d9 055b 0558 0000 0000 0798 0000 hptda=0794
hob har hobnxt flgs own hmte sown,cnt lt st xf
0798 055a 0000 0838 0799 0799 0000 00 00 00 00 shared c:remmain.exe
*har par cpg va flg next prev link hash hob hal
057a %fee26886 00000010 %00010000 1d9 057b 0579 0000 0000 07d2 0000 hptda=07cf
hob har hobnxt flgs own hmte sown,cnt lt st xf
07d2 057a 0000 0838 07d3 07d3 0000 00 00 00 00 shared c:acsrasp.exe
*har par cpg va flg next prev link hash hob hal
05cc %fee26f92 00000010 %00010000 199 05cd 05ca 0000 0000 0893 0000 hptda=088f
hob har hobnxt flgs own hmte sown,cnt lt st xf
0893 05cc 0000 0830 0894 0894 0000 00 00 00 00 shared c:acs3eini.exe
*har par cpg va flg next prev link hash hob hal
06a7 %fee28264 00000020 %00010000 1c9 06a8 06a5 0000 0000 098f 0000 hptda=098b
hob har hobnxt flgs own hmte sown,cnt lt st xf
098f 06a7 0000 0838 0990 0990 0000 00 00 00 00 shared c:anxcmclc.exe
*har par cpg va flg next prev link hash hob hal
0e83 %fee32f4c 00000010 %00010000 1c9 0e85 0e80 0b91 0000 04d9 0000 hptda=1444
0b91 %fee2ee80 00000010 %00010000 1c9 0b92 0b8f 0b80 0000 04d9 0000 hptda=0ece
0b80 %fee2ed0a 00000010 %00010000 1c9 0b81 0b7e 0733 0000 04d9 0000 hptda=0eb0
0733 %fee28e6c 00000010 %00010000 1c9 0731 0732 06fa 0000 04d9 0000 hptda=0a1f
06fa %fee28986 00000010 %00010000 1c9 06fc 072a 0000 0000 04d9 0000 hptda=0976
hob har hobnxt flgs own hmte sown,cnt lt st xf
04d9 0e83 0000 0838 04da 04da 0000 00 00 00 00 shared c:cmd.exe
*har par cpg va flg next prev link hash hob hal
0e83 %fee32f4c 00000010 %00010000 1c9 0e85 0e80 0b91 0000 04d9 0000 hptda=1444
0b91 %fee2ee80 00000010 %00010000 1c9 0b92 0b8f 0b80 0000 04d9 0000 hptda=0ece
0b80 %fee2ed0a 00000010 %00010000 1c9 0b81 0b7e 0733 0000 04d9 0000 hptda=0eb0
0733 %fee28e6c 00000010 %00010000 1c9 0731 0732 06fa 0000 04d9 0000 hptda=0a1f
06fa %fee28986 00000010 %00010000 1c9 06fc 072a 0000 0000 04d9 0000 hptda=0976
hob har hobnxt flgs own hmte sown,cnt lt st xf
04d9 0e83 0000 0838 04da 04da 0000 00 00 00 00 shared c:cmd.exe
*har par cpg va flg next prev link hash hob hal
073f %fee28f74 00000010 %00010000 1d9 0740 073d 0000 0000 0a42 0000 hptda=0a3e
hob har hobnxt flgs own hmte sown,cnt lt st xf
0a42 073f 0000 0838 0a43 0a43 0000 00 00 00 00 shared c:sqlesta0.exe
*har par cpg va flg next prev link hash hob hal
0b73 %fee2ebec 00000010 %00010000 1d9 0b74 0b70 0000 0000 0eb2 0000 hptda=074a
hob har hobnxt flgs own hmte sown,cnt lt st xf
0eb2 0b73 0000 0838 0ea7 0ea7 0000 00 00 00 00 shared c:pmpc0.exe
*har par cpg va flg next prev link hash hob hal
0e83 %fee32f4c 00000010 %00010000 1c9 0e85 0e80 0b91 0000 04d9 0000 hptda=1444
0b91 %fee2ee80 00000010 %00010000 1c9 0b92 0b8f 0b80 0000 04d9 0000 hptda=0ece
0b80 %fee2ed0a 00000010 %00010000 1c9 0b81 0b7e 0733 0000 04d9 0000 hptda=0eb0
0733 %fee28e6c 00000010 %00010000 1c9 0731 0732 06fa 0000 04d9 0000 hptda=0a1f
06fa %fee28986 00000010 %00010000 1c9 06fc 072a 0000 0000 04d9 0000 hptda=0976
hob har hobnxt flgs own hmte sown,cnt lt st xf
04d9 0e83 0000 0838 04da 04da 0000 00 00 00 00 shared c:cmd.exe
*har par cpg va flg next prev link hash hob hal
0e83 %fee32f4c 00000010 %00010000 1c9 0e85 0e80 0b91 0000 04d9 0000 hptda=1444
0b91 %fee2ee80 00000010 %00010000 1c9 0b92 0b8f 0b80 0000 04d9 0000 hptda=0ece
0b80 %fee2ed0a 00000010 %00010000 1c9 0b81 0b7e 0733 0000 04d9 0000 hptda=0eb0
0733 %fee28e6c 00000010 %00010000 1c9 0731 0732 06fa 0000 04d9 0000 hptda=0a1f
06fa %fee28986 00000010 %00010000 1c9 06fc 072a 0000 0000 04d9 0000 hptda=0976
hob har hobnxt flgs own hmte sown,cnt lt st xf
04d9 0e83 0000 0838 04da 04da 0000 00 00 00 00 shared c:cmd.exe
*har par cpg va flg next prev link hash hob hal
0b9d %fee2ef88 00000010 %00010000 1d9 0b9e 0b9b 0000 0000 0ee3 0000 hptda=0edf
hob har hobnxt flgs own hmte sown,cnt lt st xf
0ee3 0b9d 0000 0838 0ee4 0ee4 0000 00 00 00 00 shared c:pc0.exe
*har par cpg va flg next prev link hash hob hal
0bd1 %fee2f400 00000010 %00010000 1d9 0bd2 0bcf 0000 0000 0f4d 0000 hptda=0f49
hob har hobnxt flgs own hmte sown,cnt lt st xf
0f4d 0bd1 0000 0838 0f4e 0f4e 0000 00 00 00 00 shared c:ulg.exe
*har par cpg va flg next prev link hash hob hal
0be1 %fee2f560 00000010 %00010000 1d9 0be2 0bdf 0000 0000 0f91 0000 hptda=0f8d
hob har hobnxt flgs own hmte sown,cnt lt st xf
0f91 0be1 0000 0838 0f92 0f92 0000 00 00 00 00 shared c:pc3.exe
*har par cpg va flg next prev link hash hob hal
0bf0 %fee2f6aa 00000010 %00010000 1d9 0c12 0c36 0000 0000 1038 0000 hptda=1056
hob har hobnxt flgs own hmte sown,cnt lt st xf
1038 0bf0 0000 0838 0525 0525 0000 00 00 00 00 shared c:pr.exe
*har par cpg va flg next prev link hash hob hal
0c3f %fee2fd74 00000010 %00010000 1d9 0c40 0c3b 0000 0000 106b 0000 hptda=1065
hob har hobnxt flgs own hmte sown,cnt lt st xf
106b 0c3f 0000 0838 106c 106c 0000 00 00 00 00 shared c:netprt.exe
*har par cpg va flg next prev link hash hob hal
0c62 %fee30076 00000010 %00010000 1d9 0c63 0c60 0000 0000 10c6 0000 hptda=10c2
hob har hobnxt flgs own hmte sown,cnt lt st xf
10c6 0c62 0000 0838 10c7 10c7 0000 00 00 00 00 shared c:eqntgui.exe
*har par cpg va flg next prev link hash hob hal
0d0f %fee30f54 00000010 %00010000 1d9 0d10 0d0d 0000 0000 11b7 0000 hptda=11b3
hob har hobnxt flgs own hmte sown,cnt lt st xf
11b7 0d0f 0000 0838 11b8 11b8 0000 00 00 00 00 shared c:epwmp.exe
*har par cpg va flg next prev link hash hob hal
0d1e %fee3109e 00000010 %00010000 1d9 0d1f 0d1b 0000 0000 11d9 0000 hptda=11d4
hob har hobnxt flgs own hmte sown,cnt lt st xf
11d9 0d1e 0000 0838 11da 11da 0000 00 00 00 00 shared c:epwpsi.exe
*har par cpg va flg next prev link hash hob hal
0d3e %fee3135e 00000010 %00010000 1c9 0d3f 0d3c 031b 0000 03ae 0000 hptda=1205
031b %fee2345c 00000010 %00010000 1d9 031c 0319 0000 0000 03ae 0000 hptda=000e
hob har hobnxt flgs own hmte sown,cnt lt st xf
03ae 0d3e 0000 0838 03af 03af 0000 00 00 00 00 shared c:epwmux.exe
*har par cpg va flg next prev link hash hob hal
0d4c %fee31492 00000010 %00010000 1d9 0d4d 0d4a 0000 0000 1223 0000 hptda=121b
hob har hobnxt flgs own hmte sown,cnt lt st xf
1223 0d4c 0000 0838 1228 1228 0000 00 00 00 00 shared c:bd.exe
*har par cpg va flg next prev link hash hob hal
0e83 %fee32f4c 00000010 %00010000 1c9 0e85 0e80 0b91 0000 04d9 0000 hptda=1444
0b91 %fee2ee80 00000010 %00010000 1c9 0b92 0b8f 0b80 0000 04d9 0000 hptda=0ece
0b80 %fee2ed0a 00000010 %00010000 1c9 0b81 0b7e 0733 0000 04d9 0000 hptda=0eb0
0733 %fee28e6c 00000010 %00010000 1c9 0731 0732 06fa 0000 04d9 0000 hptda=0a1f
06fa %fee28986 00000010 %00010000 1c9 06fc 072a 0000 0000 04d9 0000 hptda=0976
hob har hobnxt flgs own hmte sown,cnt lt st xf
04d9 0e83 0000 0838 04da 04da 0000 00 00 00 00 shared c:cmd.exe
ΓòÉΓòÉΓòÉ 22.13. Getting the path and dll name the hard way. ΓòÉΓòÉΓòÉ
Load the dump.
OS/2 2.x Dump Formatter for retail kernel
Formatter is --> Internal revision 6.651, 94/10/19
Dump file is --> Internal revision 6.651, 94/10/19
Current slot number: 008f
Symbol (c:\os2\pdpsi\pmdf\std9501\os2krnlr.sym) linked
Slot Pid Ppid Csid Ord Sta Pri pTSD pPTDA pTCB Disp SG Name
*008f# 004b 000b 004b 0001 run 0500 7bbf7000 7bc9a608 7bc786e0 0f04 10 BD
eax=0000ffc5 ebx=0000e48b ecx=00000011 edx=50f8e44d esi=00004a03 edi=0000ffc5
eip=00001899 esp=0000e13c ebp=0000e13e iopl=2 rf -- -- nv up ei pl nz na po nc
cs=68e7 ss=001f ds=017f es=5c4f fs=150b gs=0000 cr2=00000000 cr3=00000000
68e7:00001899 a4 movsb es:ffc5=invalid ds:4a03=30
#
Loading version data ... please wait
Loading structure info for OS/2 2.11 as per 9501 version ... please wait..
# .
# .
#
# Done.
Do a .m on the CS:IP.
# .m cs:ip
*har par cpg va flg next prev link hash hob hal
0bb6 %fee2f1ae 00000010 %0d1c0000 3d9 0bb5 0bb7 0000 09c3 0f03 0000 hco=017e9
hob har hobnxt flgs own hmte sown,cnt lt st xf
0f03 0bb6 0000 0838 0f02 0f02 0000 00 00 00 00 shared c:crtlib.dll
hco=17e9 pco=ffe6c7a8 hconext=018ad hptda=13b8 f=1c pid=006a c:loop.exe
Do a .mo on the handle to the MTE.
# .mo f02
hob va flgs own hmte sown,cnt lt st xf
0f02 %fdea2bf0 8000 ffa6 0000 0000 00 00 00 00 mte c:crtlib.dll
Display the memory (as double word) at the address pointed to by the va. Use
the % when using 32 bit addresses to tell the dump formatter that you are
passing it a 32 bit linear address.
# dd %fdea2bf0
%fdea2bf0 0f020001 fca85c98 fdea2c1c fdea2cec
%fdea2c00 0508b18a 00000004 000000ef fde3af6c
%fdea2c10 fde33f24 fde33d84 fde29f44 54524306
%fdea2c20 fd42494c ff9e0048 00000201 00000000
%fdea2c30 00000000 72a80000 00000420 02010000
%fdea2c40 00000000 00000000 00000000 0000078d
%fdea2c50 3a430012 5c42535c 5c4c4c44 5f505450
%fdea2c60 504d4f43 4c4c442e fdea2000 ff9e0048
Display the memory pointed to at offset 4 in the data that you displayed in the
above step.
# dd %fca85c98
%fca85c98 00000000 00000000 00000000 00000000
%fca85ca8 00000000 00000000 00001706 fca85d2f
%fca85cb8 00000007 00000000 00000000 fca85d9f
%fca85cc8 00000000 fca85d9f fca86e9e fca85c98
%fca85cd8 00000000 fca86e76 fca86e7e 00000000
%fca85ce8 000016f7 00000036 00000007 00000000
%fca85cf8 00000000 00000000 fca85d1a 00000000
%fca85d08 00000000 00000000 00000009 00010014
Display the memory at offset (hex)68 in the information you displayed in the
above step. This time you must display it in byte format. Look at the ASCII
translation on the left and you will have the path and file name.
# db %fca85d1a
%fca85d1a 43 3a 5c 53 42 5c 44 4c-4c 5c 43 52 54 4c 49 42 C:\SB\DLL\CRTLIB
%fca85d2a 2e 44 4c 4c 00 0c 00 06-00 20 28 06 00 01 0f ee .DLL..... (....n
%fca85d3a 68 00 00 00 00 0d 00 dd-fd 20 2d dd fd 03 0f e7 h......]} -]}..g
%fca85d4a 68 a0 d3 a8 fc 8d 00 4b-24 20 2d 4b 24 04 0f df h S(|..K$ -K$.._
%fca85d5a 68 b8 78 a8 fc 00 00 00-00 01 0c 34 08 00 00 d7 h8x(|......4...W
%fca85d6a 68 00 00 00 00 a0 00 14-00 01 0c 99 02 00 00 cf h.... .........O
%fca85d7a 68 00 00 00 00 00 00 00-00 01 0c 00 02 00 00 c7 h..............G
%fca85d8a 68 00 00 00 00 a1 00 c8-2e 01 0d 40 38 00 00 bf h....!.H...@8..?
#
ΓòÉΓòÉΓòÉ 22.14. Output of u CS:IP - 20. ΓòÉΓòÉΓòÉ
I have included the .r output so that you can see the values of CS and IP. You
can enter your own address and your own value that you want to go back by.
# .r
eax=0000ffc5 ebx=0000e48b ecx=00000011 edx=50f8e44d esi=00004a03 edi=0000ffc5
eip=00001899 esp=0000e13c ebp=0000e13e iopl=2 rf -- -- nv up ei pl nz na po nc
cs=68e7 ss=001f ds=017f es=5c4f fs=150b gs=0000 cr2=00000000 cr3=00000000
68e7:00001899 a4 movsb es:ffc5=invalid ds:4a03=30
# u cs:ip - 20
68e7:00001879 8bd7 mov dx,di
68e7:0000187b 8bde mov bx,si
68e7:0000187d 1e push ds
68e7:0000187e c5760a lds si,dword ptr [bp+0a]
68e7:00001881 8bfe mov di,si
68e7:00001883 8cd8 mov ax,ds
68e7:00001885 8ec0 mov es,ax
68e7:00001887 33c0 xor ax,ax
68e7:00001889 b9ffff mov cx,ffff
68e7:0000188c f2ae repne scasb
68e7:0000188e f7d1 not cx
68e7:00001890 c47e06 les di,dword ptr [bp+06]
See how if you just do a u now, PMDF will display the unassembled instructions
starting at the next instruction following the last one that was displayed.
# u
68e7:00001893 8bc7 mov ax,di
68e7:00001895 a801 test al,01
68e7:00001897 7402 jz 189b
68e7:00001899 a4 movsb
68e7:0000189a 49 dec cx
68e7:0000189b d1e9 shr cx,1
68e7:0000189d f3a5 repe movsw
68e7:0000189f 13c9 adc cx,cx
68e7:000018a1 f3a4 repe movsb
68e7:000018a3 8bf3 mov si,bx
68e7:000018a5 8bfa mov di,dx
68e7:000018a7 1f pop ds
ΓòÉΓòÉΓòÉ 22.15. Example of compiler generated files. ΓòÉΓòÉΓòÉ
Things to note in the following examples:
1. Notice how the assembler code has dealt with the variables of
PFAvoidDuplic. The local variables are all defined as - ??? and the two
paramaters are + ???. The - and + are relative to the BP for that function.
2. The variables are not positioned according to the way that they were
defined in the source code.
3. The assembler code for the call instruction starts at ????:0cf7 ( look at
the map file for line 816) but there are 7 lines of assembler code for that
line of source code. So if we were, for example, to abend in the
lea ax,WORD PTR [bp-52] ;szUserID
instruction the IP would be somewhere between 0cf7 abd 0d0a. Remember this
when you are looking for the IP in the MAP file and you can't find it. Just
look the nearest number that is lower than the IP you are looking for.
4. You can ignore the CS in the MAP file. To the best of my knowledge this
refers to the segment that the code will be loaded into if the entire code
is going to be loaded into more than one segment.
5. Using these files you can match any selector:offset to the actual line in
the source code file.
6. Remember to ensure that the version of code you re-compiled is the same as
that which is in the dump. Otherwise you could lead yourself on a wild
goose chase.
Source code (line 816) :
sProceed = PFAvoidDuplic(pDlgDat, /* ensure they are not adding */
szUserID); /* a duplicate. */
Source code (line 1133) :
_SHORT EXPENTRY PFAvoidDuplic
(
PDIAM pDlgDat,
PCHAR szUserid
)
{
UCHAR uchAccess; /* database access mode */
_SHORT sReturn; /* return to caller */
_CHAR szTest[10]; /* test recovery field */
PDBFIELD pDfi; /* number of cols from db2 */
_CHAR szCommand[400]; /* sql command line buffer */
_LONG lDbRet; /* return from sql cmd */
_CHAR szQueryHandle[4]; /* */
uchAccess = LOCAL; /* access local database */
sReturn = 0; /* set return to zero */
Assembler code :
; Line 816
push WORD PTR [bp+8]
push WORD PTR [bp+6] ;pDlgDat
lea ax,WORD PTR [bp-52] ;szUserID
push ss
push ax
call FAR PTR PFAVOIDDUPLIC
mov WORD PTR [bp-8],ax ;sProceed
; Line 1133
PUBLIC PFAVOIDDUPLIC
PFAVOIDDUPLIC PROC FAR
enter WORD PTR 426,0
push di
push si
push ds
mov ax,DGROUP
mov ds,ax
ASSUME DS: DGROUP
; pDlgDat = 10
; szUserid = 6
; uchAccess = -2
; sReturn = -8
; szTest = -422
; pDfi = -6
; szCommand = -408
; lDbRet = -412
; szQueryHandle = -426
; Line 1134
; Line 1136
; Line 1137
; Line 1139
; Line 1140
; Line 1141
; Line 1142
; Line 1144
mov BYTE PTR [bp-2],1 ;uchAccess
; Line 1145
mov WORD PTR [bp-8],0 ;sReturn
Example of the map file output :
BDYAA001
Start Length Name Class
0001:0000 0243AH BDDAA001_TEXT CODE
0002:0000 00954H _DATA DATA
0002:0954 00000H CONST CONST
0002:0954 00000H _BSS BSS
0002:0960 00000H c_common BSS
0003:0000 00005H FAR_BSS FAR_BSS
Origin Group
0002:0 DGROUP
Address Export Alias
0001:00B1 CPBDDAA001 CPBDDAA001
0001:034A EPBDDAA001 EPBDDAA001
0001:0000 IPBDDAA001 IPBDDAA001
0001:040C TPBDDAA001 TPBDDAA001
Address Publics by Name
.
.
.
.
0000:0000 Imp _itoa (CRTLIB._itoa)
0000:0000 Imp _ltoa (CRTLIB._ltoa)
Address Publics by Value
.
.
.
.
0000:0000 Imp _strlen (CRTLIB._strlen)
0000:0000 Imp DISABITEM (GA2.DISABITEM)
0000:0000 Imp DDFREEDBF (DDDM.DDFREEDBF)
0001:0000 IPBDDAA001
0001:00B1 CPBDDAA001
0001:034A EPBDDAA001
0001:040C TPBDDAA001
0001:0425 PFINITIALISESCREEN
0001:09EE PFVALIDATEDATA
0001:0B75 PFSAVEBPDRDATA
0001:0FFC PFLOADCHECKPOPUP
0001:108D PFCHECKLEVEL
0001:1223 PFVALIDATECHANGE
0001:12AC PFAVOIDDUPLIC
0001:13F6 PFALLOWEXIT
0001:178E PFCONTROLUNSUSPEND
0001:182D PFPROMPTFORPASSWORD
0001:18BE PFAMENDSTAFF
0001:1B98 PFHOSTFLOW
0001:239D PFCHECKSTRING
0003:0000 _dummy
Line numbers for C:\SB\OBJ\BDDAA001.OBJ(F:\MAIN\SRC\REF\BDDAA001.C) segment
BDDAA001_TEXT
.
.
.
813 0001:0CE5 816 0001:0CF7 818 0001:0D0A 819 0001:0D13
826 0001:0D40 831 0001:0D51 834 0001:0D66 836 0001:0D7D
.
.
.
1133 0001:12AC 1144 0001:12B8 1145 0001:12BC 1147 0001:12C1
1154 0001:12CE 1157 0001:12E9 1160 0001:12FB 1165 0001:130E
.
.
ΓòÉΓòÉΓòÉ 22.16. Simplified look at unwinding the stack. ΓòÉΓòÉΓòÉ
EXAMPLE FUNCTIONS EXAMPLE STACK
ΓöîΓöÇMAINΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÉ
Γöé Γöé
Γöé 1007:0010 CALL 1007:0340 Γöé
Γöé Γöé
Γöé Γöé
Γöé Γöé
ΓööΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÿ
ΓöîΓöÇFUNCTION AΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÉ
Γöé Γöé
Γöé 1007:0340 ENTER.... Γöé Γöé Γöé
Γöé Γöé 1f:a73e Γöé0000 Γöé
Γöé Γöé Γöé Γöé
Γöé Γöé Γöé Γöé
Γöé Γöé Γöé Γöé
Γöé Γöé Γöé Γöé
Γöé 1007:0356 CALL 1207:12d4 Γöé Γöé Γöé
Γöé 1007:035c ...... Γöé Γöé Γöé
Γöé Γöé Γöé Γöé
Γöé Γöé Γöé Γöé
Γöé Γöé 1f:a6bc Γöéa73e 035c 1007 Γöé
Γöé Γöé Γöé Γöé
Γöé Γöé Γöé Γöé
Γöé 1007:0402 RETF Γöé Γöé Γöé
ΓööΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÿ Γöé Γöé
Γöé Γöé
ΓöîΓöÇFUNCTION BΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÉ Γöé Γöé
Γöé Γöé Γöé Γöé
Γöé 1207:12d4 ENTER.... Γöé Γöé Γöé
Γöé Γöé Γöé Γöé
Γöé Γöé Γöé Γöé
Γöé Γöé Γöé Γöé
Γöé Γöé Γöé Γöé
Γöé Γöé Γöé Γöé
Γöé 1207:12e0 CALL 120f:01da Γöé Γöé Γöé
Γöé 1207:12e8 ....... Γöé Γöé Γöé
Γöé Γöé Γöé Γöé
Γöé Γöé Γöé Γöé
Γöé Γöé Γöé Γöé
Γöé Γöé Γöé Γöé
Γöé Γöé Γöé Γöé
Γöé 1207:1312 RETF Γöé Γöé Γöé
Γöé Γöé Γöé Γöé
ΓööΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÿ Γöé Γöé
Γöé Γöé
ΓöîΓöÇFUNCTION CΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÉ Γöé Γöé
Γöé Γöé Γöé Γöé
Γöé 120f:01da ENTER.... Γöé 1f:a69c Γöéa6bc 12e8 1207 Γöé
Γöé Γöé Γöé Γöé
Γöé Γöé Γöé Γöé
Γöé Γöé Γöé Γöé
Γöé Γöé Γöé Γöé
Γöé Γöé Γöé Γöé
Γöé 120f:02d0 CALL 120f:10da Γöé Γöé Γöé
Γöé 120f:02da ....... Γöé Γöé Γöé
Γöé Γöé Γöé Γöé
Γöé Γöé Γöé Γöé
Γöé Γöé Γöé Γöé
Γöé Γöé Γöé Γöé
Γöé Γöé Γöé Γöé
Γöé Γöé Γöé Γöé
Γöé 120f:02fc RETF Γöé Γöé Γöé
Γöé Γöé Γöé Γöé
ΓööΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÿ Γöé Γöé
Γöé Γöé
ΓöîΓöÇFUNCTION DΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÉ Γöé Γöé
Γöé Γöé 1f:a640 Γöéa69c 02da 120f Γöé
Γöé 120f:10da ENTER..... Γöé Γöé Γöé
Γöé Γöé Γöé Γöé
Γöé Γöé REGISTERS Γöé Γöé
Γöé Γöé BP - a640 Γöé Γöé
Γöé Γöé SS - 1f Γöé Γöé
Γöé Γöé CS - 120f Γöé Γöé
Γöé 120f:11a0 crash Γöé IP - 11a0 Γöé Γöé
Γöé Γöé
Γöé This function has no values Γöé
Γöé on the stack. Its values are Γöé
Γöé still on the registers. Γöé
Γöé Γöé
Γöé Γöé
Γöé Γöé
Γöé Γöé
Γöé Γöé
Γöé Γöé
Γöé Γöé
Γöé Γöé
Γöé 120f:120d RETF Γöé
ΓööΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÿ
Note how the BP always points to the BP that points to the next BP etc..This is
how the stack frames are linked. Next to each BP you have a return CS and IP.
These are your entry point into the the calling function. Use the three values
as a group.
Suppose you are trying to follow the values in a variable in FUNCTION A. The BP
you would use would be a73e, for FUNCTION B it would be a6bc. Remember that
when the CS and IP are put onto the stack, the BP active at that time is also
saved.
From this example you can also see how to get the start address of a function.
Suppose you want to debug FUNCTION D from its entry point to the failing
instruction. Go to the frame pointed to by SS:BP, take the return address and
unpack from that address back 20 bytes. IE. you go to 1f:a640 and do a u
120f:2da - 20. In the unpacked code, just above 120f:2da you will get the CALL
120f:10da. In this way you have got the start address of FUNCTION D.