7

I'd like to do backtrace on MIPS. Then, I face one problem: how do I get the current PC register value, since it doesn't belong to 32 normal registers.. Thanks for your suggestion..

Grady Player
  • 14,399
  • 2
  • 48
  • 76
Randy
  • 97
  • 1
  • 8

3 Answers3

8

Make a subroutine that looks somewhat like:

.text 
.globl GetIP 

GetIP:
move $v0, $ra
jr $ra

And then call the routine; it'll give you the address of the first instruction after the call.

Zach Riggle
  • 2,975
  • 19
  • 26
3

after a jal call it will be copied to the ra register... so you could store ra, then jal to the next line, read ra, restore ra.

Grady Player
  • 14,399
  • 2
  • 48
  • 76
2

Although this question isn't tagged c, I figured it might be useful to share a solution utilizing inline assembly in gcc.

__attribute__((noinline)) static void *get_pc(void)
{
    void *pc;
    asm volatile ("move %0, $ra" : "=r"(pc));
    return pc;
}

Of course, the gist of the solution is the same as the currently accepted answer. Since the function is very small, it is a good candidate for inlining when optimization is turned on. However, if that function were inlined, its return value would be invalid : it would simply return some value of ra in the calling function, since a jal or jalr wouldn't be generated, and ra thus not set to the instruction following jal/jalr. This is why __attribute__((noinline)) is essential in this case.

Daniel Kamil Kozar
  • 18,476
  • 5
  • 50
  • 64
  • A more portable way would be to use GCC's builtins to retrieve the return address: `__builtin_extract_return_addr (__builtin_return_address (0))` instead of the inline assembly. – stefanct Dec 22 '22 at 20:34