Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

MachRegister::getReturnAddress not implemented on x86/x86_64 #40

Closed
pefoley2 opened this issue May 11, 2016 · 12 comments
Closed

MachRegister::getReturnAddress not implemented on x86/x86_64 #40

pefoley2 opened this issue May 11, 2016 · 12 comments
Labels

Comments

@pefoley2
Copy link
Contributor

I'm trying to manually create a Stackwalker::Frame object by passing in ra, sp and fp.
It appears that MachRegister::getReturnAddress is the best way to get the ra register, but it's not currently implemented on x86. Is there another way to get the necessary context to create a frame object?
For reference, I'm trying to get the parent function from within a snippet inserted at the entry point of the function I'm interested in. I tried using the Walker::walkStack api, but that doesn't seem to be able to properly walk back out of an snippet, so manually creating a Frame object based on BPatch_registerExpr values from the function the snippet is inserted into seems like the best approach.
https://github.com/dyninst/dyninst/blob/master/common/src/dyn_regs.C#L259

@wrwilliams
Copy link
Member

Is this in a rewritten binary? There's a stepper in Dyninst itself that will handle this, but it depends on the mutator knowing where it's put things. Alternately, you can force the rewriter (or Dyninst in create/attach mode, for that matter) to emit stack frames (there's a BPatch flag for that).

I should also note that the ARM-only interface there is deliberate. Unlike x86 (but like power) the ARM ABI has the RA living in a register after a call; unlike power, ARM will leave that register reserved until/unless it needs to spill it (e.g. for another call). What you want on x86 is to unwind in terms of stack pointer and frame pointer (if applicable).

What we want to do during rewriting is augment the binary's unwind information so that it's straightforward to walk through non-standard frames, but that's a big project.

@pefoley2
Copy link
Contributor Author

I'm trying to support both run-time rewriting and rewritten binaries.
So it looks like the issue was I needed to call setInstrStackFrame(), I'll take another look at my code.

@pefoley2
Copy link
Contributor Author

I'm now calling setInstrStackFrames(true), but I'm still not getting the function names for runtime rewriting, and the rewritten binary is crashing with:

Program received signal SIGSEGV, Segmentation fault.
__memcpy_sse2_unaligned () at ../sysdeps/x86_64/multiarch/memcpy-sse2-unaligned.S:168
168 ../sysdeps/x86_64/multiarch/memcpy-sse2-unaligned.S: No such file or directory.
(gdb) bt
#0 __memcpy_sse2_unaligned () at ../sysdeps/x86_64/multiarch/memcpy-sse2-unaligned.S:168
#1 0x00007ffff6901ba2 in memcpy (__len=, __src=, __dest=) at /usr/include/bits/string3.h:53
#2 Dyninst::Stackwalker::ProcSelf::readMem (this=, dest=, source=, size=) at /home/peter/dyninst/stackwalk/src/linuxbsd-swk.C:136
#3 0x00007ffff6910fc0 in Dyninst::Stackwalker::CallChecker::isPrevInstrACall (this=0x7c6960, addr=4679821817286441308, target=@0x7fffffffd998: 140737329946466) at /home/peter/dyninst/stackwalk/src/callchecker-IAPI.C:53
#4 0x00007ffff69084b6 in Dyninst::Stackwalker::StepperWandererImpl::getCallerFrame (this=0x7abd50, in=..., out=...) at /home/peter/dyninst/stackwalk/src/x86-wanderer.C:98
#5 0x00007ffff68e903e in Dyninst::Stackwalker::Walker::walkSingleFrame (this=this@entry=0x77c780, in=..., out=...) at /home/peter/dyninst/stackwalk/src/walker.C:514
#6 0x00007ffff68ea7ba in Dyninst::Stackwalker::Walker::walkStackFromFrame (this=this@entry=0x77c780, stackwalk=std::vector of length 2, capacity 2 = {...}, frame=...) at /home/peter/dyninst/stackwalk/src/walker.C:440
#7 0x00007ffff68eacde in Dyninst::Stackwalker::Walker::walkStack (this=0x77c780, stackwalk=std::vector of length 2, capacity 2 = {...}, thread=14556) at /home/peter/dyninst/stackwalk/src/walker.C:400
#8 0x00007ffff7db8dbd in __dynprof_get_parent() () from /home/peter/dynprof/libdynprof.so
#9 0x0000000000700641 in ?? ()
#10 0x40f21125e77b395c in ?? ()
#11 0x0000000000000000 in ?? ()

My code is at https://github.com/pefoley2/dynprof, fwiw.

@pefoley2
Copy link
Contributor Author

I got a stackwalker debug log and it looks like the addresses are somehow getting messed up. http://termbin.com/8beh
e.g. [walker.C:524] - Returning frame with RA 50001247, SP 7ffd595eebe0, FP 7ffd595eedf0

@pefoley2
Copy link
Contributor Author

Is there a way to get a valid RA on x86 so that i can lookup the function name?

@wrwilliams
Copy link
Member

That's one of the points of the Dyninst internal instrumentation stepper. We don't actually preserve how we've relocated code when we rewrite. There should be symbols corresponding to the relocated function, though. And that RA looks quite likely to be somewhere in .dyninstInst (at a guess, the section starts at 0x50000000?)

@pefoley2
Copy link
Contributor Author

Ah, that makes sense.
What I'm really trying to track is the relationships between functions by figuring out the name of the function which called foo(). Is there a good way to track this information? Unfortunately the various APIs I've looked at so far haven't worked.

@wrwilliams
Copy link
Member

Statically, build a call graph. Dynamically, do stackwalking, but ideally on as unperturbed an application as possible.

@pefoley2
Copy link
Contributor Author

I guess the problem is most likely that I'm inserting multiple snippets at both the entry and exit points of each function in the program I'm instrumenting. What I'd like to be able to do is distinguish between a()->b() and c->b(), but it doesn't seem like the existing APIs let you climb out of a snippet in the called function to figure out what the original caller function was.

@cuviper
Copy link
Contributor

cuviper commented May 11, 2016

If you only care about entry and exit, can you just instrument the call site?

@pefoley2
Copy link
Contributor Author

Yeah, I'm going to try that next.

@wrwilliams
Copy link
Member

Alternately (and faster), your entry/exit snippets can store the current context in (possibly per-thread) mutatee-side data structures and build your calling context trees that way.

Closing this as the discussion has gone far afield from the original issue, which I'm stamping "by design".

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

3 participants