Solved

Application base address?

Posted on 2001-06-09
13
505 Views
Last Modified: 2010-05-18
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
0
Comment
Question by:wipnav
[X]
Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people just like you are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
  • 5
  • 3
  • 2
  • +2
13 Comments
 
LVL 3

Expert Comment

by:f15iaf
ID: 6171277
addr(application);
0
 
LVL 3

Expert Comment

by:f15iaf
ID: 6171338
use getcurrentprocessid and openprocess and then
try to use readprocessmemory api function
0
 
LVL 20

Expert Comment

by:Madshi
ID: 6171368
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
0
Independent Software Vendors: We Want Your Opinion

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

 
LVL 14

Expert Comment

by:AvonWyss
ID: 6171370
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.
0
 
LVL 20

Expert Comment

by:Madshi
ID: 6171374
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...
0
 
LVL 14

Expert Comment

by:AvonWyss
ID: 6171376
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.
0
 
LVL 5

Expert Comment

by:Gwena
ID: 6171688
Listening :-)
0
 
LVL 1

Author Comment

by:wipnav
ID: 6177721
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.
0
 
LVL 14

Expert Comment

by:AvonWyss
ID: 6178690
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.
0
 
LVL 20

Accepted Solution

by:
Madshi earned 200 total points
ID: 6180052
You were asking about the application base address, it is in fact what I already told you. However, there are more addresses, e.g. the application code base address and the application data base address. For your problem you need the application code base address:

function GetCodeBase(module: dword) : pointer;
const CENEWHDR = $003C; // offset of new EXE header
      CEMAGIC  = $5A4D; // old EXE magic id:  'MZ'
      CPEMAGIC = $4550; // NT portable executable
var ih : PImageNtHeaders;
begin
  result := nil;
  try
    if word(pointer(module)^) = CEMAGIC then begin
      dword(ih) := module + word(pointer(module + CENEWHDR)^);
      if ih^.signature = CPEMAGIC then
        dword(result) := module + ih^.OptionalHeader.BaseOfCode;
    end;
  except end;
end;

Give in HInstance as the module handle of the current module, or (if you are in a dll and want to know the module handle of the exe) give in "GetModuleHandle(nil)".

Regards, Madshi.
0
 
LVL 20

Expert Comment

by:Madshi
ID: 6180056
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.
0
 
LVL 1

Author Comment

by:wipnav
ID: 6182481
Madshi,

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

Regards,

Bill
0
 
LVL 20

Expert Comment

by:Madshi
ID: 6182796
>> 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.
0

Featured Post

Free Tool: Subnet Calculator

The subnet calculator helps you design networks by taking an IP address and network mask and returning information such as network, broadcast address, and host range.

One of a set of tools we're offering as a way of saying thank you for being a part of the community.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Suggested Solutions

Title # Comments Views Activity
JAudiorecorder record freezing the app 29 93
Tvertscrollbox like a whatsapp layout 5 69
How to make Sign in, using Clientdataset? 1 43
Delphi android app hide keyboard 3 84
Hello everybody This Article will show you how to validate number with TEdit control, What's the TEdit control? TEdit is a standard Windows edit control on a form, it allows to user to write, read and copy/paste single line of text. Usua…
Introduction Raise your hands if you were as upset with FireMonkey as I was when I discovered that there was no TListview.  I use TListView in almost all of my applications I've written, and I was not going to compromise by resorting to TStringGrid…
Finds all prime numbers in a range requested and places them in a public primes() array. I've demostrated a template size of 30 (2 * 3 * 5) but larger templates can be built such 210  (2 * 3 * 5 * 7) or 2310  (2 * 3 * 5 * 7 * 11). The larger templa…
How to Install VMware Tools in Red Hat Enterprise Linux 6.4 (RHEL 6.4) Step-by-Step Tutorial

752 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question