Wednesday, April 11, 2007

 

memmove(), memcpy() and DTrace

I was trying to use DTrace to watch the flow of control within a specific function in an application, and I saw some weird behavior. Specifically, what I was seeing was this:
  4        -> memmove
  4        <- memmove
  4      <- memcpy
  4      -> memmove
  4      <- memmove
  4    <- memcpy

After this, the indenting was out of alignment, tending more towards the left side of the screen than it should. Very annoying, but I was curious to see why I always seems to be returning from both memmove() and memcpy() when I should only have been returning from memmove(). (I wasn't seeing any entry points to memcpy() to match the returns.)

I went looking through the code at opensolaris.org, and here's what I saw:
     85  ENTRY(memmove)  /* (void *s1, void *s2, size_t n) */
     86  cmpq %rsi,%rdi / if (source addr > dest addr)
     87  leaq -1(%rsi,%rdx),%r9
     88  jle .CopyRight /
     89  cmpq %r9,%rdi
     90  jle .CopyLeft
     91  jmp .CopyRight
     92 
     93  ENTRY(memcpy)                        /* (void *, const void*, size_t) */
     94 
     95 .CopyRight:
     96 LABEL(1try):
     97         cmp     $16, %rdx
     98         mov     %rdi, %rax
     99         jae     LABEL(1after)
    100 
    101         .p2align 4

Hmm, so the two functions share the same code, or at least part of it. (The CopyLeft and CopyRight functions are copy in different directions. memmove() has to handle overlapping segments differently so that it doesn't overwrite memory that it hasn't moved yet, thus CopyLeft. memcpy() doesn't have this restriction, so it uses the simpler CopyRight.)

Given that these two share the same code in this fashion, they must necessarily share the same exit points, at least for code paths going through CopyRight. And that's why I was seeing two return probes firing, one for memmove() and another for memcpy(). In specifying all function entry and exit points, I'm causing DTrace to instrument both memmove() and memcpy(), and DTrace is doing this in such a way that there are two probes at this same point. When the executing process hits that point, it fires both probes, and I see a return from two different functions.

For the curious, here's the DTrace script I was running.
#!/usr/sbin/dtrace -s

#pragma D option flowindent

pid$target:dataserver:tdsrecv_language:entry
{
        self->traceme = 1;
}

pid$target:::entry,
pid$target:::return
/self->traceme/
{
}

pid$target:dataserver:tdsrecv_language:return
{
        self->traceme = 0;
        exit(0);
}


Comments: Post a Comment



<< Home

This page is powered by Blogger. Isn't yours?