Getting call stack (like dbx where cmd)

A

Adrian

Is there a way (understandably non-portable) to get the
call stack from within a function? That is, assuming the
application has been compiled with symbols, get the list
of calling function names (similar to dbx "where" command").

I am working with IBM compiler and AIX but any other
OS/compiler solution would be interesting as well.

To answer the inevitable question why I want this,
I am writing a simple profiler for my library. However,
within the library I want to distinguish which part of
the application I was called from....

Thanks for any ideas or pointers,
Adrian
 
P

Paul Pluzhnikov

Adrian said:
Is there a way (understandably non-portable) to get the
call stack from within a function?

Sure: if dbx can do it, so can you.
To answer the inevitable question why I want this,
I am writing a simple profiler for my library. However,
within the library I want to distinguish which part of
the application I was called from....

Why not pass a parameter?
Thanks for any ideas or pointers,

Look for POWERPC parts here:
http://cvs.sourceforge.net/viewcvs.py/mpatrol/mpatrol/src/stack.c

This is off-topic in comp.lang.c (I think).
Followup-to comp.unix.aix

Cheers,
 
C

CBFalconer

Adrian said:
Is there a way (understandably non-portable) to get the
call stack from within a function? That is, assuming the
application has been compiled with symbols, get the list
of calling function names (similar to dbx "where" command").

I am working with IBM compiler and AIX but any other
OS/compiler solution would be interesting as well.

To answer the inevitable question why I want this,
I am writing a simple profiler for my library. However,
within the library I want to distinguish which part of
the application I was called from....

Since you know the CPU things are running on, it should not be hard
to write a couple of callable assembly language routines to return
those values. Something like:

void *getbp(void);
void *getsp(void);

They might even be implemented as inline, since they should be very
short, and that will avoid complications of digging into the
stack. getbp would probable resolve to "mov ax,bp".

Implementation is OT here, however how they should be integrated
into a C program is not.
 
S

Shaun Clowes

Adrian said:
I am working with IBM compiler and AIX but any other
OS/compiler solution would be interesting as well.

Well, since this completely OS/Architecture specific you'll generally have
to search newsgroups for solutions for the specific platforms you're looking
for. Anyways, for AIX it'll look something like this:

void FaultHandler(int iSignal, siginfo_t *ptSigInfo, void *pvSomething)
{
DumpCallStack(1, (ucontext_t *) pvSomething);
}

void DumpCallStack(int iFd, ucontext_t *ptContext)

void *pvInstructionPointer;
void **ppvStackFrame;
int iFrame = 0;

/* The standard stack layout for a process on the PowerPC architecture
(AIX ABI) when a() has called b() which called c() looks
like the following:

--------------------------------
-- | Saved Stack Pointer | <-- Stack pointer (%R1/SP)
| | Saved Control Register |
| | Saved Location Register | Not used until call out of
C()
| --------------------------------
| | |
| | Local Variables for c() |
| | |
| --------------------------------
-> | Saved Stack Pointer | --
| Saved Control Register | |
| Saved Location Register | | Saved by c() containing
location
-------------------------------- | or call from b()
| | |
| Local Variables for b() | |
| | |
-------------------------------- |
| Saved Stack Pointer | <-
| Saved Control Register |
| Saved Location Register | Saved by b() containing
location
-------------------------------- or call from a()
| |
| Local Variables for a() |
| |
--------------------------------

Refer to the PowerPC Compiler Writer's Guide or the AIX Assembly
Language
Reference for more information */
sprintf(sString, "Faulted while executing instruction at 0x%08x\n"
"\n"
"Traceback:\n",
ptContext->uc_mcontext.jmp_context.iar);
write(iFd, sString, strlen(sString));

/* Roll down the stack frames */
pvInstructionPointer = (void *) ptContext->uc_mcontext.jmp_context.iar;
ppvStackFrame = (void **) ptContext->uc_mcontext.jmp_context.gpr[1];
do
{
sprintf(sString, "(%2d) 0x%p\n", iFrame, pvInstructionPointer);
write(iFd, sString, strlen(sString));

/* Have we hit the bottom of the stack? */
if (!ppvStackFrame[0])
break;

/* Validate the stack frame before using any portion of it */
if (!ValidAddress((void *) ppvStackFrame) ||
!ValidAddress((void *) ppvStackFrame[0]) ||
!ValidAddress((void *) ((void **) ppvStackFrame[0] + 2)))
{
sprintf(sString, "Invalid frame at %p\n", (void *) ppvStackFrame);
write(iFd, sString, strlen(sString));
break;
}

ppvStackFrame = (void **) ppvStackFrame[0];
pvInstructionPointer = ppvStackFrame[2];
iFrame++;
} while(ppvStackFrame);

Cheers,
Shaun
 
T

T.R.Bennett

Shaun Clowes said:
Adrian said:
I am working with IBM compiler and AIX but any other
OS/compiler solution would be interesting as well.

Well, since this completely OS/Architecture specific you'll generally have
to search newsgroups for solutions for the specific platforms you're looking
for. Anyways, for AIX it'll look something like this:

void FaultHandler(int iSignal, siginfo_t *ptSigInfo, void *pvSomething)
{
DumpCallStack(1, (ucontext_t *) pvSomething);
}

void DumpCallStack(int iFd, ucontext_t *ptContext)

void *pvInstructionPointer;
void **ppvStackFrame;
int iFrame = 0;

/* The standard stack layout for a process on the PowerPC architecture
(AIX ABI) when a() has called b() which called c() looks
like the following:

--------------------------------
-- | Saved Stack Pointer | <-- Stack pointer (%R1/SP)
| | Saved Control Register |
| | Saved Location Register | Not used until call out of
C()
| --------------------------------
| | |
| | Local Variables for c() |
| | |
| --------------------------------
-> | Saved Stack Pointer | --
| Saved Control Register | |
| Saved Location Register | | Saved by c() containing
location
-------------------------------- | or call from b()
| | |
| Local Variables for b() | |
| | |
-------------------------------- |
| Saved Stack Pointer | <-
| Saved Control Register |
| Saved Location Register | Saved by b() containing
location
-------------------------------- or call from a()
| |
| Local Variables for a() |
| |
--------------------------------

Refer to the PowerPC Compiler Writer's Guide or the AIX Assembly
Language
Reference for more information */
sprintf(sString, "Faulted while executing instruction at 0x%08x\n"
"\n"
"Traceback:\n",
ptContext->uc_mcontext.jmp_context.iar);
write(iFd, sString, strlen(sString));

/* Roll down the stack frames */
pvInstructionPointer = (void *) ptContext->uc_mcontext.jmp_context.iar;
ppvStackFrame = (void **) ptContext->uc_mcontext.jmp_context.gpr[1];
do
{
sprintf(sString, "(%2d) 0x%p\n", iFrame, pvInstructionPointer);
write(iFd, sString, strlen(sString));

/* Have we hit the bottom of the stack? */
if (!ppvStackFrame[0])
break;

/* Validate the stack frame before using any portion of it */
if (!ValidAddress((void *) ppvStackFrame) ||
!ValidAddress((void *) ppvStackFrame[0]) ||
!ValidAddress((void *) ((void **) ppvStackFrame[0] + 2)))
{
sprintf(sString, "Invalid frame at %p\n", (void *) ppvStackFrame);
write(iFd, sString, strlen(sString));
break;
}

ppvStackFrame = (void **) ppvStackFrame[0];
pvInstructionPointer = ppvStackFrame[2];
iFrame++;
} while(ppvStackFrame);

Cheers,
Shaun


Thanks for the tips Shaun, however you didn't define the
function "ValidAddress()".

-tony
 
S

Shaun Clowes

T.R.Bennett said:
"Shaun Clowes" <[email protected]> wrote in message ....
Thanks for the tips Shaun, however you didn't define the
function "ValidAddress()".

True, here goes:

int ValidAddress(void *pvAddr)
{
int iRet = 1;

/* We could also use lchown() and probably a number of others,
* we just need a system call which takes in a userland pointer
* and doesn't change any important process context */
if (access((char *) pvAddr, F_OK) && (errno == EFAULT))
iRet = 0;

return(iRet);
}

Some people prefer mincore(2).

Cheers,
Shaun
 

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

Forum statistics

Threads
474,148
Messages
2,570,838
Members
47,385
Latest member
Joneswilliam01

Latest Threads

Top