namhyung / uftrace

Function graph tracer for C/C++/Rust/Python
https://uftrace.github.io/slide/
GNU General Public License v2.0
3.06k stars 473 forks source link

Add symbolic enum support #263

Closed namhyung closed 6 years ago

namhyung commented 6 years ago

I implemented basic support to show enum constant as symbol and pushed the code to review/enum-support-v1.

It's only used by --auto-args for now but may it can be extended to be specified in command line. Currently only a few of selected functions are affected: mmap, mprotect, open, lseek, dlopen, socket, accept4, gethostbyaddr, kill, signal, sigaction, sigaddset, sigdelset, sigismember, prctl.

$ uftrace --auto-args tests/t-mmap
# DURATION    TID     FUNCTION
            [14962] | main() {
            [14962] |   foo() {
   6.862 us [14962] |     open("/dev/zero", O_RDONLY) = 3;
   3.707 us [14962] |     mmap(0, 4096, PROT_READ, MAP_ANON|MAP_PRIVATE, 3, 0) = 0x7f0c84826000;
   3.380 us [14962] |     mprotect(0x7f0c84826000, 4096, PROT_NONE) = 0;
   4.753 us [14962] |     munmap(0x7f0c84826000, 4096) = 0;
   2.394 us [14962] |     close(3) = 0;
  29.476 us [14962] |   } /* foo */
  30.601 us [14962] | } /* main */
honggyukim commented 6 years ago

@namhyung I see that this is working fine in my tests. I hope this can be supported with dwarf in the future. Thanks a lot for doing this!

namhyung commented 6 years ago

Yep, I plan to add enum support for DWARF. :)

flavono123 commented 6 years ago

@namhyung I also test the same command and working fine too. 🙌 🎉

$ uftrace --auto-args tests/t-mmap
# DURATION    TID     FUNCTION
            [ 3615] | main() {
            [ 3615] |   foo() {
   6.608 us [ 3615] |     open("/dev/zero", O_RDONLY) = 3;
   2.472 us [ 3615] |     mmap(0, 4096, PROT_READ, MAP_ANON|MAP_PRIVATE, 3, 0) = 0x7f4e73b6b000;
   2.667 us [ 3615] |     mprotect(0x7f4e73b6b000, 4096, PROT_NONE) = 0;
   3.587 us [ 3615] |     munmap(0x7f4e73b6b000, 4096) = 0;
   1.841 us [ 3615] |     close(3) = 0;
  22.517 us [ 3615] |   } /* foo */
  23.248 us [ 3615] | } /* main */

A question❓; If new flags of API are added, supports those manually(hard-coded), right?

namhyung commented 6 years ago

Yes, it needs to be added to misc/prototypes.h.

flavono123 commented 6 years ago

@namhyung Also tested some flags for others:

dlopen(RTLD_LAZY)

# referencing the EXAMPLE section in `man dlopen`
$ cat dlopen.c
// ref: man dlopen
#include <stdio.h>
#include <stdlib.h>
#include <dlfcn.h>
#include <gnu/lib-names.h>  /* Defines LIBM_SO (which will be a
                              string such cas "libm.so.6") */
int
main(void)
{
   void *handle;
   double (*cosine)(double);
   char *error;

   handle = dlopen(LIBM_SO, RTLD_LAZY);
   if (!handle) {
       fprintf(stderr, "%s\n", dlerror());
       exit(EXIT_FAILURE);
   }

   dlerror();    /* Clear any existing error */

   cosine = (double (*)(double)) dlsym(handle, "cos");

   error = dlerror();
   if (error != NULL) {
       fprintf(stderr, "%s\n", error);
       exit(EXIT_FAILURE);
   }

   printf("%f\n", (*cosine)(2.0));
   dlclose(handle);
   exit(EXIT_SUCCESS);
}
$ gcc -pg -g -o dlopen dlopen.c -ldl
$ uftrace --auto-arg dlopen
-0.416147
# DURATION    TID     FUNCTION
            [ 2980] | main() {
   9.603 us [ 2980] |   dlopen("libm.so.6", RTLD_LAZY) = 0x7f1de3402b50;
   0.445 us [ 2980] |   dlerror();
   1.172 us [ 2980] |   dlsym();
   0.098 us [ 2980] |   dlerror();
   5.910 us [ 2980] |   printf("%f\n") = 10;
   0.797 us [ 2980] |   dlclose();
            [ 2980] |   exit() {

uftrace stopped tracing with remaining functions
================================================
task: 2980
[1] exit
[0] main

sigaddset, sigdelset, sigismember

$ cat sigset.c
// ref: http://www.cs.fsu.edu/~xyuan/cop4610/examples/lect7/example2.c
#include <errno.h>
#include <signal.h>
#include <stdio.h>
#include <unistd.h>

void print_mask()
{
  sigset_t sigset;
  int errno_save;

  errno_save = errno;
  if (sigprocmask(0, NULL, &sigset) < 0)
    perror("Sigprocmask");
  printf("sigmask = ");
  if (sigismember(&sigset, SIGINT)) printf("SIGINT ");
  if (sigismember(&sigset, SIGQUIT)) printf("SIGQUIT ");
  if (sigismember(&sigset, SIGUSR1)) printf("SIGUSR1 ");
  if (sigismember(&sigset, SIGUSR2)) printf("SIGUSR2 ");
  if (sigismember(&sigset, SIGALRM)) printf("SIGALARM ");
  if (sigismember(&sigset, SIGABRT)) printf("SIGABRT ");
  if (sigismember(&sigset, SIGCHLD)) printf("SIGCHLD ");
  if (sigismember(&sigset, SIGHUP)) printf("SIGHUP ");
  if (sigismember(&sigset, SIGTERM)) printf("SIGTERM ");
  printf("\n");
  errno = errno_save;
}

int main() {
  sigset_t mask;
  sigset_t omask;

  sigemptyset(&mask);
  sigaddset(&mask, SIGINT);
  sigdelset(&mask, SIGUSR1);
  sigprocmask(SIG_BLOCK, &mask, &omask);
  print_mask();
}
$ gcc -pg -g -o sigset sigset.c
$ uftrace --auto-arg sigset
sigmask = SIGINT SIGUSR1 
# DURATION    TID     FUNCTION
            [ 2629] | main() {
   2.024 us [ 2629] |   sigemptyset(0x7ffd6f1d0430) = 0;
   0.884 us [ 2629] |   sigaddset(0x7ffd6f1d0430, SIGINT) = 0;
   0.141 us [ 2629] |   sigaddset(0x7ffd6f1d0430, SIGUSR1) = 0;
   0.835 us [ 2629] |   sigdelset(0x7ffd6f1d0430, SIGUSR2) = 0;
   1.948 us [ 2629] |   sigprocmask();
            [ 2629] |   print_mask() {
   0.680 us [ 2629] |     __errno_location();
   0.178 us [ 2629] |     sigprocmask();
   3.740 us [ 2629] |     printf("sigmask = ") = 10;
   0.792 us [ 2629] |     sigismember(0x7ffd6f1d0390, SIGINT) = 1;
   0.307 us [ 2629] |     printf("SIGINT ") = 7;
   0.123 us [ 2629] |     sigismember(0x7ffd6f1d0390, SIGQUIT) = 0;
   0.129 us [ 2629] |     sigismember(0x7ffd6f1d0390, SIGUSR1) = 1;
   0.185 us [ 2629] |     printf("SIGUSR1 ") = 8;
   0.099 us [ 2629] |     sigismember(0x7ffd6f1d0390, SIGUSR2) = 0;
   0.104 us [ 2629] |     sigismember(0x7ffd6f1d0390, SIGALRM) = 0;
   0.120 us [ 2629] |     sigismember(0x7ffd6f1d0390, SIGABRT) = 0;
   0.131 us [ 2629] |     sigismember(0x7ffd6f1d0390, SIGCHLD) = 0;
   0.130 us [ 2629] |     sigismember(0x7ffd6f1d0390, SIGHUP) = 0;
   0.109 us [ 2629] |     sigismember(0x7ffd6f1d0390, SIGTERM) = 0;
   0.554 us [ 2629] |     putchar('\x0a') = 10;
   0.100 us [ 2629] |     __errno_location();
  11.401 us [ 2629] |   } /* print_mask */
  22.423 us [ 2629] | } /* main */

lseek

$ cat lseek.c
// ref: http://codewiki.wikidot.com/c:system-calls:lseek
#include <unistd.h>
#include <fcntl.h>
#include <sys/types.h>
#include <stdio.h>

int main()
{
        int file=0;
        if((file=open("uftrace.txt",O_RDONLY)) < -1)
                return 1;

        char buffer[20];
    buffer[19] = '\0';
        if(read(file,buffer,19) != 19)  return 1;
        printf("%s\n",buffer);

        if(lseek(file,10,SEEK_SET) < 0) return 1;

        if(read(file,buffer,19) != 19)  return 1;
        printf("%s\n",buffer);

        return 0;
}
$ cat uftrace.txt
Function (graph) tracer for user-space
$ gcc -pg -g -o lseek lseek.c
$ uftrace --auto-arg lseek
Function (graph) tr
graph) tracer for u
# DURATION    TID     FUNCTION
            [ 3843] | main() {
   3.920 us [ 3843] |   open("uftrace.txt", O_RDONLY) = 3;
   4.089 us [ 3843] |   read(3, 0x7ffd44533a20, 19) = 19;
   3.336 us [ 3843] |   puts("Function (graph) tr") = 20;
   1.242 us [ 3843] |   lseek(3, 10, SEEK_SET) = 10;
   0.422 us [ 3843] |   read(3, 0x7ffd44533a20, 19) = 19;
   0.229 us [ 3843] |   puts("graph) tracer for u") = 20;
  17.316 us [ 3843] | } /* main */
Function (graph) tr
graph) tracer for u
# DURATION    TID     FUNCTION
            [ 3843] | main() {
   3.920 us [ 3843] |   open("uftrace.txt", O_RDONLY) = 3;
   4.089 us [ 3843] |   read(3, 0x7ffd44533a20, 19) = 19;
   3.336 us [ 3843] |   puts("Function (graph) tr") = 20;
   1.242 us [ 3843] |   lseek(3, 10, SEEK_SET) = 10;
   0.422 us [ 3843] |   read(3, 0x7ffd44533a20, 19) = 19;
   0.229 us [ 3843] |   puts("graph) tracer for u") = 20;
  17.316 us [ 3843] | } /* main */