Link to home
Start Free TrialLog in
Avatar of wipnav
wipnav

asked on

Application base address?

Hi,

I'm trying to track down some exceptions in a large Delphi 3 application. When I get an exception it gives me the memory address of the exception. In order to use my link map to find out where the problem is, I need to subtract the memory address that my program is loaded at. My question is, how do I find out the starting address that my program is currently loaded at in memory?

Regards,

Bill
Avatar of f15iaf
f15iaf

addr(application);
use getcurrentprocessid and openprocess and then
try to use readprocessmemory api function
GetModuleHandle(nil) gives you the handle of your process. You can simply convert this handle into a pointer, which is then the base address of your process.

var baseAddress : pointer;
begin
  baseAddress := pointer(GetModuleHandle(nil));

Usually for applications it's $400000.

Regards, Madshi.

P.S: Sad, that you're still using Delphi3, otherwise I would have pointed you to my exception handling package. But well, in case you're upgrading to D4/5/6 somewhen, here is the link:

http://help.madshi.net/Data/madExcept.htm
Since Win32 uses a flat memory model, the base address usually stays the same. You can define it in the project options, linker tab. Note that apparently some code in SysUtils already does some address math on exceptions.
P.P.S: Don't you know the "Find runtime error" function? Look in your Delphi menu. It works like this:

(1) Set a breakpoint to the first line of your project file.
(2) Start your exe inside of the IDE, until it stops at the breakpoint.
(3) Use the menu item "search/find" -> "runtime error", give in the exception address (with a leading "$").

Delphi will now show you the line where the exception occured. Well, in fact, Delphi shows you the line after the exception location...
Instead of setting a breakpoint on the first code line, you can also start the project with F7 - it's even shorter. But the goal is the same.

Strange enough, in Delphi 2 and older compilers (r.g. BP7 etc.), one could also search for an error address when the debugger was not running.
Listening :-)
Avatar of wipnav

ASKER

Thank you for your comments and suggestions.

First. I am not doing this from within the IDE. The exceptions have never been seen
in testing. There are about 1000 users of this application, and the exceptions are so
rare that no one even complains about them. The only way that I know about them is
the fact that my application creates an exception log file whenever an exception is
raised.

I have a menu item that I use to raise an exception at a specific line of code.
I use this feature to test if the exception log file contains the correct relative
address of the exception.

The only solution that I have been able to get to work is to raise an exception at a
know line in my program, and subtract the relative address of that line of code
(as listed in the link map). Then I store this as my base address. When I get an
actual exception, I subtract this base address and I get the correct relative address,
which I log. This works, but I have to hardcode in the address from the link map each
time that I rebuild my application. In addition, since I only save this base address
once, when the program starts, I can't handle the situation of when my application is
moved to another location in memory (which I assume can happen).

So, I am looking for a better solution.

To test the proposed solutions:

I raised an exception at line 3607 in unit main.pas. According to the link map this
statement is at the relative address of 154948 within my application. Once I take the
exception address returned by ExceptAddr, and subtract the application base
address, I except to get 154948.

Suggestion 1:

  "addr(application);"

  Im my exception handling method I placed the following code:

  var
    BaseOffset, ExceptionAddress: Integer;
  begin
    BaseOffset := Integer(Pointer(Addr(Application)));
    ExceptionAddress := Integer(ExceptAddr) - BaseOffset;

  Output:
    BaseOffset was 5756F8
    ExceptionAddress was FFFE0266

  This is not what I would except.

Suggestion 2:

  "use getcurrentprocessid and openprocess and then
  try to use readprocessmemory api function"

  Please provide a more specific code sample.

Suggestion 3:

  "GetModuleHandle(nil) gives you the handle of your process.
  You can simply convert this handle into a pointer, which is
  then the base address of your process.

  var baseAddress : pointer;
  begin
    baseAddress := pointer(GetModuleHandle(nil));"

  Im my exception handling method I placed the following code:

  var
    BaseOffset, ExceptionAddress: Integer;
  begin
    BaseOffset := Integer(Pointer(GetModuleHandle(nil)));
    ExceptionAddress := Integer(ExceptAddr) - BaseOffset;

  Output:
    BaseOffset was 400000
    ExceptionAddress was 15595E

  This is close, but I expect to get 154948.
For testing, you could try this (anywhere in your code):

        raise Exception.Create('Test') at nil;

and look at the exception address you get. If should obviouly be 0, if it isn't, something else is messing around in your address calculation.
ASKER CERTIFIED SOLUTION
Avatar of Madshi
Madshi

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
P.S: The exception address is not the beginning of the instruction where the exception was raised, it's the beginning of the next asm instruction.
Avatar of wipnav

ASKER

Madshi,

Thank you. I don't understand how it works, but it works, and that is all I need.

Regards,

Bill
>> I don't understand how it works

In 32bit Windows each process has a flat memory/address area from $00000000 - $7FFFFFFF. Each module (exe or dll) is simply mapped to a specific address inside this whole area (via file mapping, see CreateFileMapping). The address at which the module image is loaded is used as the module handle. So by using "pointer(moduleHandle)" you get the pointer to the complete module image (= file content) in the memory area of the current process. Each 32bit module has a PE header. The function posted above takes a module handle, converts it into a pointer (which will point to a valid PE header), then uses one element of the PE header structure, which tells us at which offset the code of this PE module begins. Usually for Delphi modules this is $1000. The map file address neither contains this code offset, nor does it contain the image base address (= module handle) of the module. Thus you have to sub both from your exception address to get a relative address, which fits to your map file.

If you didn't understand any part of this text, or if something is missing for you to understand, please feel free to ask...   :-)

Regards, Madshi.