[Ltrace-devel] Some MIPS backend work

Petr Machata pmachata at redhat.com
Wed Jan 29 21:05:59 UTC 2014


This e-mail went out over a week ago.  I noticed just now that I forgot
to CC: the ltrace devel list, so I'm resending it.  I haven't had a
chance to work on the MIPS backend since I wrote this.

------

Hi there,

I had a chance to look into MIPS tracing on Sunday.  For the PLT-ful
case we can just reuse what core does, so that's not a problem.

In PLT-disabled binaries, the calls are done through addresses fetched
from GOT.

00400660 <main>:
  [...]
  400670:	3c1c0042 	lui	gp,0x42
  400674:	279c8900 	addiu	gp,gp,-30464 <-- gp = some global pointer?
  [...]
  40068c:	8f828034 	lw	v0,-32716(gp) <-- address from GOT
  400690:	00200825 	move	at,at
  400694:	0040c821 	move	t9,v0
  400698:	0320f809 	jalr	t9    <-- jump to it
  40069c:	00200825 	move	at,at

GOT initially contains addresses that point to .MIPS.stubs section,
where the jump leads:

  400820:	8f998010 	lw	t9,-32752(gp) <-- t9 = GOT[0]
  400824:	03e07821 	move	t7,ra         <-- t7 = caller's return addr
  400828:	0320f809 	jalr	t9
  40082c:	24180009 	li	t8,9          <-- t8 = .dynsym index

After the first call, GOT entry is resolved and contains address of the
resolved symbol.  So .MIPS.stubs is avoided except on first call, and
possibly even then, if the binary has been prelinked (but I haven't had
a chance to check that, my qemu image isn't prelinked).

So we have to do the same relatively complicated thing that PPC backend
does: the first time a stub breakpoint is hit, we single-step through
dynamic linker, looking for when the corresponding GOT entry is updated.
When it is, we rewrite it back, but remember the resolved address.  When
this stub breakpoint is hit the second time, we just move PC over to
that resolved address that we remembered (and update $t9 as well).

This is now partly implemented on pmachata/mips.  It doesn't handle
prelinked binaries yet, and I didn't try to run the test suite yet
eihter.  But it's a good start, and already it could give reasonable
traces for ls, pwd, and a couple test binaries.

The original code placed the breakpoint at the resolved address, and
knew to update it after the function returns.  Unfortunately that
creates a window between when the call is resolved, and when it returns,
where any calls (like those from other threads, or recursive calls done
through PLT) would be missed.  That's why I ported the fairly
complicated PPC approach.

Originally I wanted to leave out an optimization that PPC backend does,
whereby you remember the address of the instruction which resolved a GOT
entry, and put a breakpoint there.  Next time, instead of
single-stepping through dynamic linker, you just let the traced process
hit this breakpoint.  Now MIPS doesn't allow PTRACE_SINGLESTEP, and we
must do it in software, so single-stepping is super expensive.  In my
qemu, the first instance of each library call took like half a second to
resolve, and I'm afraid that on the often low-power MIPS boxes, this
could be similarly bad.  So eventually I put the optimization in.

Thanks,
PM



More information about the Ltrace-devel mailing list