checkpatch: validate signature styles and To: and Cc: lines
[linux-2.6.git] / scripts / recordmcount.c
index 37c5965..ee52cb8 100644 (file)
@@ -24,6 +24,7 @@
 #include <sys/types.h>
 #include <sys/mman.h>
 #include <sys/stat.h>
+#include <getopt.h>
 #include <elf.h>
 #include <fcntl.h>
 #include <setjmp.h>
@@ -39,6 +40,7 @@ static char gpfx;     /* prefix for global symbol name (sometimes '_') */
 static struct stat sb; /* Remember .st_size, etc. */
 static jmp_buf jmpenv; /* setjmp/longjmp per-file error escape */
 static const char *altmcount;  /* alternate mcount symbol name */
+static int warn_on_notrace_sect; /* warn when section has mcount not being recorded */
 
 /* setjmp() return values */
 enum {
@@ -118,6 +120,34 @@ umalloc(size_t size)
        return addr;
 }
 
+static unsigned char ideal_nop5_x86_64[5] = { 0x0f, 0x1f, 0x44, 0x00, 0x00 };
+static unsigned char ideal_nop5_x86_32[5] = { 0x3e, 0x8d, 0x74, 0x26, 0x00 };
+static unsigned char *ideal_nop;
+
+static char rel_type_nop;
+
+static int (*make_nop)(void *map, size_t const offset);
+
+static int make_nop_x86(void *map, size_t const offset)
+{
+       uint32_t *ptr;
+       unsigned char *op;
+
+       /* Confirm we have 0xe8 0x0 0x0 0x0 0x0 */
+       ptr = map + offset;
+       if (*ptr != 0)
+               return -1;
+
+       op = map + offset - 1;
+       if (*op != 0xe8)
+               return -1;
+
+       /* convert to nop */
+       ulseek(fd_map, offset - 1, SEEK_SET);
+       uwrite(fd_map, ideal_nop, 5);
+       return 0;
+}
+
 /*
  * Get the whole file as a programming convenience in order to avoid
  * malloc+lseek+read+free of many pieces.  If successful, then mmap
@@ -301,7 +331,12 @@ do_file(char const *const fname)
                        w2(ehdr->e_machine), fname);
                fail_file();
                break;
-       case EM_386:     reltype = R_386_32;                   break;
+       case EM_386:
+               reltype = R_386_32;
+               make_nop = make_nop_x86;
+               ideal_nop = ideal_nop5_x86_32;
+               mcount_adjust_32 = -1;
+               break;
        case EM_ARM:     reltype = R_ARM_ABS32;
                         altmcount = "__gnu_mcount_nc";
                         break;
@@ -312,7 +347,12 @@ do_file(char const *const fname)
        case EM_S390:    /* reltype: e_class    */ gpfx = '_'; break;
        case EM_SH:      reltype = R_SH_DIR32;                 break;
        case EM_SPARCV9: reltype = R_SPARC_64;     gpfx = '_'; break;
-       case EM_X86_64:  reltype = R_X86_64_64;                break;
+       case EM_X86_64:
+               make_nop = make_nop_x86;
+               ideal_nop = ideal_nop5_x86_64;
+               reltype = R_X86_64_64;
+               mcount_adjust_64 = -1;
+               break;
        }  /* end switch */
 
        switch (ehdr->e_ident[EI_CLASS]) {
@@ -328,8 +368,10 @@ do_file(char const *const fname)
                                "unrecognized ET_REL file: %s\n", fname);
                        fail_file();
                }
-               if (w2(ehdr->e_machine) == EM_S390)
+               if (w2(ehdr->e_machine) == EM_S390) {
                        reltype = R_390_32;
+                       mcount_adjust_32 = -4;
+               }
                if (w2(ehdr->e_machine) == EM_MIPS) {
                        reltype = R_MIPS_32;
                        is_fake_mcount32 = MIPS32_is_fake_mcount;
@@ -344,8 +386,10 @@ do_file(char const *const fname)
                                "unrecognized ET_REL file: %s\n", fname);
                        fail_file();
                }
-               if (w2(ghdr->e_machine) == EM_S390)
+               if (w2(ghdr->e_machine) == EM_S390) {
                        reltype = R_390_64;
+                       mcount_adjust_64 = -8;
+               }
                if (w2(ghdr->e_machine) == EM_MIPS) {
                        reltype = R_MIPS_64;
                        Elf64_r_sym = MIPS64_r_sym;
@@ -361,19 +405,33 @@ do_file(char const *const fname)
 }
 
 int
-main(int argc, char const *argv[])
+main(int argc, char *argv[])
 {
        const char ftrace[] = "/ftrace.o";
        int ftrace_size = sizeof(ftrace) - 1;
        int n_error = 0;  /* gcc-4.3.0 false positive complaint */
+       int c;
+       int i;
+
+       while ((c = getopt(argc, argv, "w")) >= 0) {
+               switch (c) {
+               case 'w':
+                       warn_on_notrace_sect = 1;
+                       break;
+               default:
+                       fprintf(stderr, "usage: recordmcount [-w] file.o...\n");
+                       return 0;
+               }
+       }
 
-       if (argc <= 1) {
-               fprintf(stderr, "usage: recordmcount file.o...\n");
+       if ((argc - optind) < 1) {
+               fprintf(stderr, "usage: recordmcount [-w] file.o...\n");
                return 0;
        }
 
        /* Process each file in turn, allowing deep failure. */
-       for (--argc, ++argv; argc > 0; --argc, ++argv) {
+       for (i = optind; i < argc; i++) {
+               char *file = argv[i];
                int const sjval = setjmp(jmpenv);
                int len;
 
@@ -382,14 +440,14 @@ main(int argc, char const *argv[])
                 * function but does not call it. Since ftrace.o should
                 * not be traced anyway, we just skip it.
                 */
-               len = strlen(argv[0]);
+               len = strlen(file);
                if (len >= ftrace_size &&
-                   strcmp(argv[0] + (len - ftrace_size), ftrace) == 0)
+                   strcmp(file + (len - ftrace_size), ftrace) == 0)
                        continue;
 
                switch (sjval) {
                default:
-                       fprintf(stderr, "internal error: %s\n", argv[0]);
+                       fprintf(stderr, "internal error: %s\n", file);
                        exit(1);
                        break;
                case SJ_SETJMP:    /* normal sequence */
@@ -397,7 +455,7 @@ main(int argc, char const *argv[])
                        fd_map = -1;
                        ehdr_curr = NULL;
                        mmap_failed = 1;
-                       do_file(argv[0]);
+                       do_file(file);
                        break;
                case SJ_FAIL:    /* error in do_file or below */
                        ++n_error;