Determining a functions calling address

J

johny smith

I am trying to figure out a way to print the address of what called a
certain function once inside the function.

I am assuming that this information is on the stack somewhere. But can
someone give me some
advice? I don't know where to go to look this information up.

Do I need to access the stack, and hence do some kind of inline assembly
code to get the calling address?


For example:

int main()
{

myFunction(); // I need the address of this location or the next
line to be printed in the myFunction function.
 
D

David Hilsee

[snip]
void myFunction()
{
// print out the calling functions address in main or the address of
the location that made this function call.
// basically, I am trying to figure out who called this function based
on the address. This is used in debugging
// so I can track down who (what location) made the call if I get an
error in this function.


}

There is no portable way to do what you want to do. I would recommend
sprinkling your code with informative output/log statements. For example:

log("In main(), calling myFunction() the first time.");
myFunction();

log("In main(), calling myFunction() the second time.");
myFunction();

That approach would probably make your logs more readable, and the code
would be more portable.
 
S

Stephen Tyndall

johny smith said:
I am trying to figure out a way to print the address of what called a
certain function once inside the function.

Couldn't you just pass the address of the caller to the function? For
example, the following shows two versions: a template version and a normal
function version. Hope this helps.

#include <iostream>

using std::cout;

void doThatStuff(void* vp);

template<class T>

void doThisStuff(T* ptr) {

cout << "Error. doStuff(T* ptr) called from address " << ptr << "\n";

}

int main() {

doThisStuff(&main);

doThatStuff(&main);

return 0;

}

void doThatStuff(void* vp) {

cout << "Error. doStuff(void* vp) called from address " << vp << "\n";

}

//mike tyndall
 
S

Stephen Tyndall

Stephen Tyndall said:
Couldn't you just pass the address of the caller to the function? For
example, the following shows two versions: a template version and a normal
function version. Hope this helps.

#include <iostream>

using std::cout;

void doThatStuff(void* vp);

template<class T>

void doThisStuff(T* ptr) {

cout << "Error. doStuff(T* ptr) called from address " << ptr << "\n";

}

int main() {

doThisStuff(&main);

doThatStuff(&main);

return 0;

}

void doThatStuff(void* vp) {

cout << "Error. doStuff(void* vp) called from address " << vp << "\n";

}

//mike tyndall

BTW, I realize this is totally impractical for any large-scale project, but
maybe it'll help somehow. Maybe you could put #ifdef DEBUG directives in
the code, where extra function arguments are added if DEBUG is defined.
Good luck!
 
J

Jack Klein

Couldn't you just pass the address of the caller to the function? For
example, the following shows two versions: a template version and a normal
function version. Hope this helps.

#include <iostream>

using std::cout;

void doThatStuff(void* vp);

template<class T>

void doThisStuff(T* ptr) {

cout << "Error. doStuff(T* ptr) called from address " << ptr << "\n";

}

int main() {

doThisStuff(&main);

doThatStuff(&main);

There are two problems with this. One is that there is no need to
apply the & operator to the name of a free-standing function to take
its address. The second is more important. There is no defined
conversion between pointer to any type of function and pointer to
void, or indeed pointer to any other object type. The code above will
not compile.
 
S

Stephen Tyndall

Jack Klein said:
There are two problems with this. One is that there is no need to
apply the & operator to the name of a free-standing function to take
its address. The second is more important. There is no defined
conversion between pointer to any type of function and pointer to
void, or indeed pointer to any other object type. The code above will
not compile.

It compiles; I wrote it in VC++.NET and it works with no problems. BTW, I
know that the & wasn't necessary, but there's nothing wrong with making it
obvious that an address is being passed.
 
J

Jack Klein

Now that I think of it, taking the address of main() in a C++ program
is illegal no matter what you do with the address.
It compiles; I wrote it in VC++.NET and it works with no problems. BTW, I
know that the & wasn't necessary, but there's nothing wrong with making it
obvious that an address is being passed.

Apparently you are not using a real C++ compiler, or you are not using
the one you have in a standard conforming mode.

First you should have received diagnostics along these lines:

========
Borland C++ 5.6.4 for Win32 Copyright (c) 1993, 2002 Borland
simple.cpp:
"simple.cpp": E2012 Cannot take address of 'main' in function main()
at line 16
"simple.cpp": E2012 Cannot take address of 'main' in function main()
at line 17
*** 2 errors in Compile ***
BCC32 exited with error code: 1
Build cancelled due to errors
========

Interestingly enough when I modify your source code to remove the
illegality of taking the address of main, like this:
========
#include <iostream>

using std::cout;

void doThatStuff(void* vp);

template<class T>

void doThisStuff(T* ptr)
{
cout << "Error. doStuff(T* ptr) called from address " << ptr <<
"\n";
}

void my_main()
{
doThisStuff(my_main);
doThatStuff(my_main);
}

int main()
{
my_main();
return 0;
}

void doThatStuff(void* vp)
{
cout << "Error. doStuff(void* vp) called from address " << vp <<
"\n";
}
========

Borland's C++ Builder X accepts it without complaint, as does
Microsoft's Visual C++ 2005 Express Beta. The MINGW 3.2 included with
C++ Builder X generates a proper diagnostic:

========
C:\prog\CBuilderX\mingw\bin\g++ -c -o
C:\prog\CBuilderX\projects\simple2\windows\Debug_Build\simple2.cpp.obj
-g2 -O0 -MD -BC:\prog\CBuilderX\MinGW\bin
-IC:\prog\CBuilderX\mingw\include
-IC:\prog\CBuilderX\mingw\include\c++\3.2
windows\Debug_Build\simple2.cpp.cpp
windows/Debug_Build/simple2.cpp.cpp: In function `void my_main()':
"simple2.cpp.cpp": windows/Debug_Build/simple2.cpp.cpp invalid
conversion from `void (*)()' to at line 17
`void*'
Build cancelled due to errors
========

Testing it online with Comeau Computing's EDG front-end, arguably the
most standard conforming implementation readily accessible, also
results in a correct, and better presented, diagnostic:

========
Your Comeau C/C++ test results are as follows:

Comeau C/C++ 4.3.3 (Aug 6 2003 15:13:37) for ONLINE_EVALUATION_BETA1
Copyright 1988-2003 Comeau Computing. All rights reserved.
MODE:strict errors C++
"ComeauTest.c", line 17: error: argument of type "void (*)()" is
incompatible with
parameter of type "void *"
doThatStuff(my_main);
^
1 error detected in the compilation of "ComeauTest.c".
========

Note that ISO/IEC 14882 determines what is and is not legal C++, not
just what some compilers happen to accept. In particular, Windows
based compilers (Microsoft and Borland) seem to let a lot slip by,
such as an implicit conversion from "pointer to function returning
void and accepting no arguments" to "pointer to void".

The fact that compiler accepted it without issuing a diagnostic only
means that there is a serious error in your compiler. The fact that
it allowed you to take the address of main() in a C++ program is
another serious error. Microsoft's C++ compilers prior to 7.1 did not
put a great deal of emphasis on C++ standard conformance.

Regardless of what you think, the sample code you posted had two
serious errors.
 
S

Stephen Tyndall

Jack Klein said:
Now that I think of it, taking the address of main() in a C++ program
is illegal no matter what you do with the address.


Apparently you are not using a real C++ compiler, or you are not using
the one you have in a standard conforming mode.

I'm using VC++.NET 2003, and I haven't fiddled with any options.
First you should have received diagnostics along these lines:

======== [error listing snipped]
========

Interestingly enough when I modify your source code to remove the
illegality of taking the address of main, like this:
========
#include <iostream>

using std::cout;

void doThatStuff(void* vp);

template<class T>

void doThisStuff(T* ptr)
{
cout << "Error. doStuff(T* ptr) called from address " << ptr <<
"\n";
}

void my_main()
{
doThisStuff(my_main);
doThatStuff(my_main);
}

int main()
{
my_main();
return 0;
}

void doThatStuff(void* vp)
{
cout << "Error. doStuff(void* vp) called from address " << vp <<
"\n";
}
========

Borland's C++ Builder X accepts it without complaint, as does
Microsoft's Visual C++ 2005 Express Beta. The MINGW 3.2 included with
C++ Builder X generates a proper diagnostic:

======== [error listing snipped]
========

Testing it online with Comeau Computing's EDG front-end, arguably the
most standard conforming implementation readily accessible, also
results in a correct, and better presented, diagnostic:

======== [error listing snipped]
========

You went to a lot of effort. I couldn't have checked these, as I don't have
those compilers and I don't know where to get them.
Note that ISO/IEC 14882 determines what is and is not legal C++, not
just what some compilers happen to accept. In particular, Windows
based compilers (Microsoft and Borland) seem to let a lot slip by,
such as an implicit conversion from "pointer to function returning
void and accepting no arguments" to "pointer to void".

The fact that compiler accepted it without issuing a diagnostic only
means that there is a serious error in your compiler. The fact that
it allowed you to take the address of main() in a C++ program is
another serious error. Microsoft's C++ compilers prior to 7.1 did not
put a great deal of emphasis on C++ standard conformance.

I had no way of knowing this. I can't afford a copy of the C++ Standard;
all I do is compile and check for errors. Other than that, I learn what I
can from the newsgroups and books.
Regardless of what you think, the sample code you posted had two
serious errors.

Regardless of what you think, I wasn't trying to argue with you. All I said
was that it compiled with VC++.NET.

//mike tyndall
 
D

Denis Perelyubskiy

johny said:
I am trying to figure out a way to print the address of what called a
certain function once inside the function.

I am assuming that this information is on the stack somewhere. But can
someone give me some
advice? I don't know where to go to look this information up.

Do I need to access the stack, and hence do some kind of inline assembly
code to get the calling address?

As far as I know, there is no standard/portable way of doing this. There
may be some extension in the compiler you are using (I don't know of any
that do this, but who knows).

If you don't need your code to be portable but need to get this working,
google for subroutine calling convention for your hardware architecture,
or, perhaps, for stack layout. This should give you a clue of how to get
this sort of information.

Another thing you might try, is ask folks in some newsgroup, which deals
with your architecture (perhaps assembly, or something like that)

-d
 
P

Peter van Merkerk

johny said:
I am trying to figure out a way to print the address of what called a
certain function once inside the function.

I am assuming that this information is on the stack somewhere. But can
someone give me some
advice? I don't know where to go to look this information up.

Do I need to access the stack, and hence do some kind of inline assembly
code to get the calling address?


For example:

int main()
{

myFunction(); // I need the address of this location or the next
line to be printed in the myFunction function.
.
.

}

void myFunction()
{
// print out the calling functions address in main or the address of
the location that made this function call.
// basically, I am trying to figure out who called this function based
on the address. This is used in debugging
// so I can track down who (what location) made the call if I get an
error in this function.


}

There is no standard or portable way to do this. But if you are using a
debugger you could just take a peek at the call stack (I would be
surprised if the debugger you are using doesn't support this).

If you use Windows you might find this article interesting:
http://www.codeguru.com/Cpp/V-S/debug/tracing/article.php/c4429/
 
R

Ralph D. Ungermann

johny said:
I am trying to figure out a way to print the address of what called a
certain function once inside the function.

Please think twice, before you try such evil things!
I'm using C++ as a /high/ level language, and I'm happy with /not/
taking care of the stack contents and caller's addresses. I prefer
objects and methods.

I am assuming that this information is on the stack somewhere.

Probably -- if there *is* a stack. IIRC, it was the IBM/360, where the
return address was usually stored to R14; 2nd level subroutines used
R13, a.s.o. (the CPU had no stack pointer).

Do I need to access the stack, and hence do some kind of inline assembly
code to get the calling address?

In C/C++, this address is normally anywhere behind the function's
argument list.
Now have a look at stdarg.h: you can find some macros there to access
arguments from within a function declared with an ellipsis.
Older compilers implemented these with tricky pointer arithmetics, but
modern ones detect them and generate highly compiler specific
instructions here. No trivial task!

When you traverse past the last argument, you are probably close to the
return address. But details will change, if you compile with debugging
or profiling support, if you add a try-catch block, or if the optimizer
decides to pass some arguments on the FPU stack.

Unfortunately, there is no std::return_address, and to write your own,
you'll need full support from the people who wrote your compiler.



Now back to the original question: I don't want to insult you, but could
it be, that you simply need to debug or profile your code? There are
tons of software for this purposes out there. No need to spoil your code
with stack fiddling!
(Sorry, if my answer is too stupid -- you didn't say, that you're going
to write another debugger ;)

Otherwise, if you merely want your function behave different, depending
on who called it: sounds very familar to me. Actually, this one reminds
me to the question: "How can I tell, if my ostream& is a file or a
terminal?" (from inside an operator<<).

C++ has some neat features for elegant solutions of weird problems
(though not all are obvious). I suppose, that your design problem is
welcome in c.l.c++. So feel free to tell us more about your primary
intention.


Ralph
 
J

Jack Klein

[snip]
Borland's C++ Builder X accepts it without complaint, as does
Microsoft's Visual C++ 2005 Express Beta. The MINGW 3.2 included with
C++ Builder X generates a proper diagnostic:
[snip]


You went to a lot of effort. I couldn't have checked these, as I don't have
those compilers and I don't know where to get them.

Both are available for free download for personal use, although you do
have to register and provide certain information on their respective
web sites.

http://www.borland.com/products/downloads/download_cbuilderx.html
The IDE includes two compilers, Borland's and MINGW 3.2 port of GCC
for Windows. Very large download (327 MB), hope you have a fast
broadband connection.

http://lab.msdn.microsoft.com/express/visualc/default.aspx
Includes the beta version of Microsoft's Visual C++ 8.0 compiler, much
more standard C++ conforming than most earlier versions.

[snip]
I had no way of knowing this. I can't afford a copy of the C++ Standard;
all I do is compile and check for errors. Other than that, I learn what I
can from the newsgroups and books.

The latest, up-to-date version of the C++ standard can be purchased
and downloaded as a PDF file for $18.00US from ANSI's web site:

http://webstore.ansi.org/ansidocstore/product.asp?sku=INCITS/ISO/IEC+23270-2003
//mike tyndall

Are you Mike or Steve?

[posted and mailed]
 
S

Stephen Tyndall

Jack Klein said:
[snip]
Borland's C++ Builder X accepts it without complaint, as does
Microsoft's Visual C++ 2005 Express Beta. The MINGW 3.2 included with
C++ Builder X generates a proper diagnostic:
[snip]

You went to a lot of effort. I couldn't have checked these, as I don't have
those compilers and I don't know where to get them.

Both are available for free download for personal use, although you do
have to register and provide certain information on their respective
web sites.

http://www.borland.com/products/downloads/download_cbuilderx.html
The IDE includes two compilers, Borland's and MINGW 3.2 port of GCC
for Windows. Very large download (327 MB), hope you have a fast
broadband connection.

http://lab.msdn.microsoft.com/express/visualc/default.aspx
Includes the beta version of Microsoft's Visual C++ 8.0 compiler, much
more standard C++ conforming than most earlier versions.

Thanks for the links (and I do have a broadband connection).
[snip]
I had no way of knowing this. I can't afford a copy of the C++ Standard;
all I do is compile and check for errors. Other than that, I learn what I
can from the newsgroups and books.

The latest, up-to-date version of the C++ standard can be purchased
and downloaded as a PDF file for $18.00US from ANSI's web site:
http://webstore.ansi.org/ansidocstore/product.asp?sku=INCITS/ISO/IEC+23270-2003

Hmm...I don't really care for eBooks, but $18 is always better than $65.
I'll probably get that sometime soon.
Are you Mike or Steve?

Technically both; Steve's my first name, Mike my second. I go by Mike
because my dad's name is Steve and I'm using his e-mail account. Confusing,
I know : )

Maybe I should change my signature to:

//mike tyndall (not steve)

BTW, I'm grateful for the info about the errors in that program. I didn't
mean to come off as confrontational.

When I posted it, I was a little suspicious about taking the address of main
(because I found out in another post that you can't have recursive calls to
main), but it compiled and I was attempting to use it as an example. I
didn't think about the void pointer, though; I was under the impression that
a void pointer can point to any type (but is dangerous because it goes
around C++'s type-checking).

Here's a different version of the code. Can you tell me if there's anything
wrong with it (other than being a little unwieldy)? It compiles with
VC++.NET, but I'm not completely sure what that means now...
#define DEBUG

#include <iostream>

using std::cout;

#include <string>

using std::string;

//template function declaration

template<class T>

void doThisStuff(T& ptr) {

cout << "Error. Function called from address " << ptr << "\n";

}

//function declarations

void nonMainFunction();

void doThatStuff(

#ifdef DEBUG

string caller

#endif

);

//global variable declaration/definition

bool somethingIsWrong = true;

int main() {

doThatStuff(

#ifdef DEBUG

"main()"

#endif

);

nonMainFunction();

return 0;

}

void nonMainFunction() {

doThisStuff(nonMainFunction);

}

void doThatStuff(

#ifdef DEBUG

string caller

#endif

) {

//.....

#ifdef DEBUG

if:):somethingIsWrong) {

cout << "Error. doThatStuff() called by " << caller << "\n";

}

#endif

}

//mike tyndall
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
474,173
Messages
2,570,938
Members
47,481
Latest member
ElviraDoug

Latest Threads

Top