* 'perf-core-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/linux-2.6-tip: (163 commits) tracing: Fix compile issue for trace_sched_wakeup.c [S390] hardirq: remove pointless header file includes [IA64] Move local_softirq_pending() definition perf, powerpc: Fix power_pmu_event_init to not use event->ctx ftrace: Remove recursion between recordmcount and scripts/mod/empty jump_label: Add COND_STMT(), reducer wrappery perf: Optimize sw events perf: Use jump_labels to optimize the scheduler hooks jump_label: Add atomic_t interface jump_label: Use more consistent naming perf, hw_breakpoint: Fix crash in hw_breakpoint creation perf: Find task before event alloc perf: Fix task refcount bugs perf: Fix group moving irq_work: Add generic hardirq context callbacks perf_events: Fix transaction recovery in group_sched_in() perf_events: Fix bogus AMD64 generic TLB events perf_events: Fix bogus context time tracking tracing: Remove parent recording in latency tracer graph options tracing: Use one prologue for the preempt irqs off tracer function tracers ...
Showing the changes to scripts (8 of 158 files). Show all
Unified · Split
| @@ -11,6 +11,7 @@ hostprogs-$(CONFIG_KALLSYMS) += kallsyms · 10 unmodified lines | ||
| 11 | 11 | hostprogs-$(CONFIG_LOGO) += pnmtologo |
| 12 | 12 | hostprogs-$(CONFIG_VT) += conmakehash |
| 13 | 13 | hostprogs-$(CONFIG_IKCONFIG) += bin2c |
| 14 | +hostprogs-$(BUILD_C_RECORDMCOUNT) += recordmcount | |
| 14 | 15 | |
| 15 | 16 | always := $(hostprogs-y) $(hostprogs-m) |
| 16 | 17 | |
| @@ -209,12 +209,22 @@ cmd_modversions = \ · 208 unmodified lines | ||
| 209 | 209 | endif |
| 210 | 210 | |
| 211 | 211 | ifdef CONFIG_FTRACE_MCOUNT_RECORD |
| 212 | +ifdef BUILD_C_RECORDMCOUNT | |
| 213 | +# Due to recursion, we must skip empty.o. | |
| 214 | +# The empty.o file is created in the make process in order to determine | |
| 215 | +# the target endianness and word size. It is made before all other C | |
| 216 | +# files, including recordmcount. | |
| 217 | +cmd_record_mcount = if [ $(@) != "scripts/mod/empty.o" ]; then \ | |
| 218 | + $(objtree)/scripts/recordmcount "$(@)"; \ | |
| 219 | + fi; | |
| 220 | +else | |
| 212 | 221 | cmd_record_mcount = set -e ; perl $(srctree)/scripts/recordmcount.pl "$(ARCH)" \ |
| 213 | 222 | "$(if $(CONFIG_CPU_BIG_ENDIAN),big,little)" \ |
| 214 | 223 | "$(if $(CONFIG_64BIT),64,32)" \ |
| 215 | 224 | "$(OBJDUMP)" "$(OBJCOPY)" "$(CC)" "$(LD)" "$(NM)" "$(RM)" "$(MV)" \ |
| 216 | 225 | "$(if $(part-of-module),1,0)" "$(@)"; |
| 217 | 226 | endif |
| 227 | +endif | |
| 218 | 228 | |
| 219 | 229 | define rule_cc_o_c |
| 220 | 230 | $(call echo-cmd,checksrc) $(cmd_checksrc) \ |
| @@ -101,14 +101,6 @@ basename_flags = -D"KBUILD_BASENAME=KBUILD_STR($(call name-fix,$(basetarget)))" · 100 unmodified lines | ||
| 101 | 101 | modname_flags = $(if $(filter 1,$(words $(modname))),\ |
| 102 | 102 | -D"KBUILD_MODNAME=KBUILD_STR($(call name-fix,$(modname)))") |
| 103 | 103 | |
| 104 | −#hash values | |
| 105 | −ifdef CONFIG_DYNAMIC_DEBUG | |
| 106 | −debug_flags = -D"DEBUG_HASH=$(shell ./scripts/basic/hash djb2 $(@D)$(modname))"\ | |
| 107 | − -D"DEBUG_HASH2=$(shell ./scripts/basic/hash r5 $(@D)$(modname))" | |
| 108 | −else | |
| 109 | −debug_flags = | |
| 110 | −endif | |
| 111 | − | |
| 112 | 104 | orig_c_flags = $(KBUILD_CPPFLAGS) $(KBUILD_CFLAGS) $(KBUILD_SUBDIR_CCFLAGS) \ |
| 113 | 105 | $(ccflags-y) $(CFLAGS_$(basetarget).o) |
| 114 | 106 | _c_flags = $(filter-out $(CFLAGS_REMOVE_$(basetarget).o), $(orig_c_flags)) |
| @@ -152,8 +144,7 @@ endif · 37 unmodified lines | ||
| 152 | 144 | |
| 153 | 145 | c_flags = -Wp,-MD,$(depfile) $(NOSTDINC_FLAGS) $(LINUXINCLUDE) \ |
| 154 | 146 | $(__c_flags) $(modkern_cflags) \ |
| 155 | − -D"KBUILD_STR(s)=\#s" $(basename_flags) $(modname_flags) \ | |
| 156 | − $(debug_flags) | |
| 147 | + -D"KBUILD_STR(s)=\#s" $(basename_flags) $(modname_flags) | |
| 157 | 148 | |
| 158 | 149 | a_flags = -Wp,-MD,$(depfile) $(NOSTDINC_FLAGS) $(LINUXINCLUDE) \ |
| 159 | 150 | $(__a_flags) $(modkern_aflags) |
| @@ -9,7 +9,7 @@ · 8 unmodified lines | ||
| 9 | 9 | # fixdep: Used to generate dependency information during build process |
| 10 | 10 | # docproc: Used in Documentation/DocBook |
| 11 | 11 | |
| 12 | −hostprogs-y := fixdep docproc hash | |
| 12 | +hostprogs-y := fixdep docproc | |
| 13 | 13 | always := $(hostprogs-y) |
| 14 | 14 | |
| 15 | 15 | # fixdep is needed to compile other host programs |
| @@ -1,64 +0,0 @@ | ||
| 1 | −/* | |
| 2 | − * Copyright (C) 2008 Red Hat, Inc., Jason Baron <jbaron@redhat.com> | |
| 3 | − * | |
| 4 | − */ | |
| 5 | − | |
| 6 | −#include <stdio.h> | |
| 7 | −#include <stdlib.h> | |
| 8 | −#include <string.h> | |
| 9 | − | |
| 10 | −#define DYNAMIC_DEBUG_HASH_BITS 6 | |
| 11 | − | |
| 12 | −static const char *program; | |
| 13 | − | |
| 14 | −static void usage(void) | |
| 15 | −{ | |
| 16 | − printf("Usage: %s <djb2|r5> <modname>\n", program); | |
| 17 | − exit(1); | |
| 18 | −} | |
| 19 | − | |
| 20 | −/* djb2 hashing algorithm by Dan Bernstein. From: | |
| 21 | − * http://www.cse.yorku.ca/~oz/hash.html | |
| 22 | − */ | |
| 23 | − | |
| 24 | −static unsigned int djb2_hash(char *str) | |
| 25 | −{ | |
| 26 | − unsigned long hash = 5381; | |
| 27 | − int c; | |
| 28 | − | |
| 29 | − c = *str; | |
| 30 | − while (c) { | |
| 31 | − hash = ((hash << 5) + hash) + c; | |
| 32 | − c = *++str; | |
| 33 | − } | |
| 34 | − return (unsigned int)(hash & ((1 << DYNAMIC_DEBUG_HASH_BITS) - 1)); | |
| 35 | −} | |
| 36 | − | |
| 37 | −static unsigned int r5_hash(char *str) | |
| 38 | −{ | |
| 39 | − unsigned long hash = 0; | |
| 40 | − int c; | |
| 41 | − | |
| 42 | − c = *str; | |
| 43 | − while (c) { | |
| 44 | − hash = (hash + (c << 4) + (c >> 4)) * 11; | |
| 45 | − c = *++str; | |
| 46 | − } | |
| 47 | − return (unsigned int)(hash & ((1 << DYNAMIC_DEBUG_HASH_BITS) - 1)); | |
| 48 | −} | |
| 49 | − | |
| 50 | −int main(int argc, char *argv[]) | |
| 51 | −{ | |
| 52 | − program = argv[0]; | |
| 53 | − | |
| 54 | − if (argc != 3) | |
| 55 | − usage(); | |
| 56 | − if (!strcmp(argv[1], "djb2")) | |
| 57 | − printf("%d\n", djb2_hash(argv[2])); | |
| 58 | − else if (!strcmp(argv[1], "r5")) | |
| 59 | − printf("%d\n", r5_hash(argv[2])); | |
| 60 | − else | |
| 61 | − usage(); | |
| 62 | − exit(0); | |
| 63 | −} | |
| 64 | − | |
| @@ -0,0 +1,5 @@ | ||
| 1 | +#!/bin/sh | |
| 2 | +# Test for gcc 'asm goto' suport | |
| 3 | +# Copyright (C) 2010, Jason Baron <jbaron@redhat.com> | |
| 4 | + | |
| 5 | +echo "int main(void) { entry: asm goto (\"\"::::entry); return 0; }" | $@ -x c - -c -o /dev/null >/dev/null 2>&1 && echo "y" | |
| @@ -0,0 +1,363 @@ | ||
| 1 | +/* | |
| 2 | + * recordmcount.c: construct a table of the locations of calls to 'mcount' | |
| 3 | + * so that ftrace can find them quickly. | |
| 4 | + * Copyright 2009 John F. Reiser <jreiser@BitWagon.com>. All rights reserved. | |
| 5 | + * Licensed under the GNU General Public License, version 2 (GPLv2). | |
| 6 | + * | |
| 7 | + * Restructured to fit Linux format, as well as other updates: | |
| 8 | + * Copyright 2010 Steven Rostedt <srostedt@redhat.com>, Red Hat Inc. | |
| 9 | + */ | |
| 10 | + | |
| 11 | +/* | |
| 12 | + * Strategy: alter the .o file in-place. | |
| 13 | + * | |
| 14 | + * Append a new STRTAB that has the new section names, followed by a new array | |
| 15 | + * ElfXX_Shdr[] that has the new section headers, followed by the section | |
| 16 | + * contents for __mcount_loc and its relocations. The old shstrtab strings, | |
| 17 | + * and the old ElfXX_Shdr[] array, remain as "garbage" (commonly, a couple | |
| 18 | + * kilobytes.) Subsequent processing by /bin/ld (or the kernel module loader) | |
| 19 | + * will ignore the garbage regions, because they are not designated by the | |
| 20 | + * new .e_shoff nor the new ElfXX_Shdr[]. [In order to remove the garbage, | |
| 21 | + * then use "ld -r" to create a new file that omits the garbage.] | |
| 22 | + */ | |
| 23 | + | |
| 24 | +#include <sys/types.h> | |
| 25 | +#include <sys/mman.h> | |
| 26 | +#include <sys/stat.h> | |
| 27 | +#include <elf.h> | |
| 28 | +#include <fcntl.h> | |
| 29 | +#include <setjmp.h> | |
| 30 | +#include <stdio.h> | |
| 31 | +#include <stdlib.h> | |
| 32 | +#include <string.h> | |
| 33 | +#include <unistd.h> | |
| 34 | + | |
| 35 | +static int fd_map; /* File descriptor for file being modified. */ | |
| 36 | +static int mmap_failed; /* Boolean flag. */ | |
| 37 | +static void *ehdr_curr; /* current ElfXX_Ehdr * for resource cleanup */ | |
| 38 | +static char gpfx; /* prefix for global symbol name (sometimes '_') */ | |
| 39 | +static struct stat sb; /* Remember .st_size, etc. */ | |
| 40 | +static jmp_buf jmpenv; /* setjmp/longjmp per-file error escape */ | |
| 41 | + | |
| 42 | +/* setjmp() return values */ | |
| 43 | +enum { | |
| 44 | + SJ_SETJMP = 0, /* hardwired first return */ | |
| 45 | + SJ_FAIL, | |
| 46 | + SJ_SUCCEED | |
| 47 | +}; | |
| 48 | + | |
| 49 | +/* Per-file resource cleanup when multiple files. */ | |
| 50 | +static void | |
| 51 | +cleanup(void) | |
| 52 | +{ | |
| 53 | + if (!mmap_failed) | |
| 54 | + munmap(ehdr_curr, sb.st_size); | |
| 55 | + else | |
| 56 | + free(ehdr_curr); | |
| 57 | + close(fd_map); | |
| 58 | +} | |
| 59 | + | |
| 60 | +static void __attribute__((noreturn)) | |
| 61 | +fail_file(void) | |
| 62 | +{ | |
| 63 | + cleanup(); | |
| 64 | + longjmp(jmpenv, SJ_FAIL); | |
| 65 | +} | |
| 66 | + | |
| 67 | +static void __attribute__((noreturn)) | |
| 68 | +succeed_file(void) | |
| 69 | +{ | |
| 70 | + cleanup(); | |
| 71 | + longjmp(jmpenv, SJ_SUCCEED); | |
| 72 | +} | |
| 73 | + | |
| 74 | +/* ulseek, uread, ...: Check return value for errors. */ | |
| 75 | + | |
| 76 | +static off_t | |
| 77 | +ulseek(int const fd, off_t const offset, int const whence) | |
| 78 | +{ | |
| 79 | + off_t const w = lseek(fd, offset, whence); | |
| 80 | + if ((off_t)-1 == w) { | |
| 81 | + perror("lseek"); | |
| 82 | + fail_file(); | |
| 83 | + } | |
| 84 | + return w; | |
| 85 | +} | |
| 86 | + | |
| 87 | +static size_t | |
| 88 | +uread(int const fd, void *const buf, size_t const count) | |
| 89 | +{ | |
| 90 | + size_t const n = read(fd, buf, count); | |
| 91 | + if (n != count) { | |
| 92 | + perror("read"); | |
| 93 | + fail_file(); | |
| 94 | + } | |
| 95 | + return n; | |
| 96 | +} | |
| 97 | + | |
| 98 | +static size_t | |
| 99 | +uwrite(int const fd, void const *const buf, size_t const count) | |
| 100 | +{ | |
| 101 | + size_t const n = write(fd, buf, count); | |
| 102 | + if (n != count) { | |
| 103 | + perror("write"); | |
| 104 | + fail_file(); | |
| 105 | + } | |
| 106 | + return n; | |
| 107 | +} | |
| 108 | + | |
| 109 | +static void * | |
| 110 | +umalloc(size_t size) | |
| 111 | +{ | |
| 112 | + void *const addr = malloc(size); | |
| 113 | + if (0 == addr) { | |
| 114 | + fprintf(stderr, "malloc failed: %zu bytes\n", size); | |
| 115 | + fail_file(); | |
| 116 | + } | |
| 117 | + return addr; | |
| 118 | +} | |
| 119 | + | |
| 120 | +/* | |
| 121 | + * Get the whole file as a programming convenience in order to avoid | |
| 122 | + * malloc+lseek+read+free of many pieces. If successful, then mmap | |
| 123 | + * avoids copying unused pieces; else just read the whole file. | |
| 124 | + * Open for both read and write; new info will be appended to the file. | |
| 125 | + * Use MAP_PRIVATE so that a few changes to the in-memory ElfXX_Ehdr | |
| 126 | + * do not propagate to the file until an explicit overwrite at the last. | |
| 127 | + * This preserves most aspects of consistency (all except .st_size) | |
| 128 | + * for simultaneous readers of the file while we are appending to it. | |
| 129 | + * However, multiple writers still are bad. We choose not to use | |
| 130 | + * locking because it is expensive and the use case of kernel build | |
| 131 | + * makes multiple writers unlikely. | |
| 132 | + */ | |
| 133 | +static void *mmap_file(char const *fname) | |
| 134 | +{ | |
| 135 | + void *addr; | |
| 136 | + | |
| 137 | + fd_map = open(fname, O_RDWR); | |
| 138 | + if (0 > fd_map || 0 > fstat(fd_map, &sb)) { | |
| 139 | + perror(fname); | |
| 140 | + fail_file(); | |
| 141 | + } | |
| 142 | + if (!S_ISREG(sb.st_mode)) { | |
| 143 | + fprintf(stderr, "not a regular file: %s\n", fname); | |
| 144 | + fail_file(); | |
| 145 | + } | |
| 146 | + addr = mmap(0, sb.st_size, PROT_READ|PROT_WRITE, MAP_PRIVATE, | |
| 147 | + fd_map, 0); | |
| 148 | + mmap_failed = 0; | |
| 149 | + if (MAP_FAILED == addr) { | |
| 150 | + mmap_failed = 1; | |
| 151 | + addr = umalloc(sb.st_size); | |
| 152 | + uread(fd_map, addr, sb.st_size); | |
| 153 | + } | |
| 154 | + return addr; | |
| 155 | +} | |
| 156 | + | |
| 157 | +/* w8rev, w8nat, ...: Handle endianness. */ | |
| 158 | + | |
| 159 | +static uint64_t w8rev(uint64_t const x) | |
| 160 | +{ | |
| 161 | + return ((0xff & (x >> (0 * 8))) << (7 * 8)) | |
| 162 | + | ((0xff & (x >> (1 * 8))) << (6 * 8)) | |
| 163 | + | ((0xff & (x >> (2 * 8))) << (5 * 8)) | |
| 164 | + | ((0xff & (x >> (3 * 8))) << (4 * 8)) | |
| 165 | + | ((0xff & (x >> (4 * 8))) << (3 * 8)) | |
| 166 | + | ((0xff & (x >> (5 * 8))) << (2 * 8)) | |
| 167 | + | ((0xff & (x >> (6 * 8))) << (1 * 8)) | |
| 168 | + | ((0xff & (x >> (7 * 8))) << (0 * 8)); | |
| 169 | +} | |
| 170 | + | |
| 171 | +static uint32_t w4rev(uint32_t const x) | |
| 172 | +{ | |
| 173 | + return ((0xff & (x >> (0 * 8))) << (3 * 8)) | |
| 174 | + | ((0xff & (x >> (1 * 8))) << (2 * 8)) | |
| 175 | + | ((0xff & (x >> (2 * 8))) << (1 * 8)) | |
| 176 | + | ((0xff & (x >> (3 * 8))) << (0 * 8)); | |
| 177 | +} | |
| 178 | + | |
| 179 | +static uint32_t w2rev(uint16_t const x) | |
| 180 | +{ | |
| 181 | + return ((0xff & (x >> (0 * 8))) << (1 * 8)) | |
| 182 | + | ((0xff & (x >> (1 * 8))) << (0 * 8)); | |
| 183 | +} | |
| 184 | + | |
| 185 | +static uint64_t w8nat(uint64_t const x) | |
| 186 | +{ | |
| 187 | + return x; | |
| 188 | +} | |
| 189 | + | |
| 190 | +static uint32_t w4nat(uint32_t const x) | |
| 191 | +{ | |
| 192 | + return x; | |
| 193 | +} | |
| 194 | + | |
| 195 | +static uint32_t w2nat(uint16_t const x) | |
| 196 | +{ | |
| 197 | + return x; | |
| 198 | +} | |
| 199 | + | |
| 200 | +static uint64_t (*w8)(uint64_t); | |
| 201 | +static uint32_t (*w)(uint32_t); | |
| 202 | +static uint32_t (*w2)(uint16_t); | |
| 203 | + | |
| 204 | +/* Names of the sections that could contain calls to mcount. */ | |
| 205 | +static int | |
| 206 | +is_mcounted_section_name(char const *const txtname) | |
| 207 | +{ | |
| 208 | + return 0 == strcmp(".text", txtname) || | |
| 209 | + 0 == strcmp(".sched.text", txtname) || | |
| 210 | + 0 == strcmp(".spinlock.text", txtname) || | |
| 211 | + 0 == strcmp(".irqentry.text", txtname) || | |
| 212 | + 0 == strcmp(".text.unlikely", txtname); | |
| 213 | +} | |
| 214 | + | |
| 215 | +/* 32 bit and 64 bit are very similar */ | |
| 216 | +#include "recordmcount.h" | |
| 217 | +#define RECORD_MCOUNT_64 | |
| 218 | +#include "recordmcount.h" | |
| 219 | + | |
| 220 | +static void | |
| 221 | +do_file(char const *const fname) | |
| 222 | +{ | |
| 223 | + Elf32_Ehdr *const ehdr = mmap_file(fname); | |
| 224 | + unsigned int reltype = 0; | |
| 225 | + | |
| 226 | + ehdr_curr = ehdr; | |
| 227 | + w = w4nat; | |
| 228 | + w2 = w2nat; | |
| 229 | + w8 = w8nat; | |
| 230 | + switch (ehdr->e_ident[EI_DATA]) { | |
| 231 | + static unsigned int const endian = 1; | |
| 232 | + default: { | |
| 233 | + fprintf(stderr, "unrecognized ELF data encoding %d: %s\n", | |
| 234 | + ehdr->e_ident[EI_DATA], fname); | |
| 235 | + fail_file(); | |
| 236 | + } break; | |
| 237 | + case ELFDATA2LSB: { | |
| 238 | + if (1 != *(unsigned char const *)&endian) { | |
| 239 | + /* main() is big endian, file.o is little endian. */ | |
| 240 | + w = w4rev; | |
| 241 | + w2 = w2rev; | |
| 242 | + w8 = w8rev; | |
| 243 | + } | |
| 244 | + } break; | |
| 245 | + case ELFDATA2MSB: { | |
| 246 | + if (0 != *(unsigned char const *)&endian) { | |
| 247 | + /* main() is little endian, file.o is big endian. */ | |
| 248 | + w = w4rev; | |
| 249 | + w2 = w2rev; | |
| 250 | + w8 = w8rev; | |
| 251 | + } | |
| 252 | + } break; | |
| 253 | + } /* end switch */ | |
| 254 | + if (0 != memcmp(ELFMAG, ehdr->e_ident, SELFMAG) | |
| 255 | + || ET_REL != w2(ehdr->e_type) | |
| 256 | + || EV_CURRENT != ehdr->e_ident[EI_VERSION]) { | |
| 257 | + fprintf(stderr, "unrecognized ET_REL file %s\n", fname); | |
| 258 | + fail_file(); | |
| 259 | + } | |
| 260 | + | |
| 261 | + gpfx = 0; | |
| 262 | + switch (w2(ehdr->e_machine)) { | |
| 263 | + default: { | |
| 264 | + fprintf(stderr, "unrecognized e_machine %d %s\n", | |
| 265 | + w2(ehdr->e_machine), fname); | |
| 266 | + fail_file(); | |
| 267 | + } break; | |
| 268 | + case EM_386: reltype = R_386_32; break; | |
| 269 | + case EM_ARM: reltype = R_ARM_ABS32; break; | |
| 270 | + case EM_IA_64: reltype = R_IA64_IMM64; gpfx = '_'; break; | |
| 271 | + case EM_PPC: reltype = R_PPC_ADDR32; gpfx = '_'; break; | |
| 272 | + case EM_PPC64: reltype = R_PPC64_ADDR64; gpfx = '_'; break; | |
| 273 | + case EM_S390: /* reltype: e_class */ gpfx = '_'; break; | |
| 274 | + case EM_SH: reltype = R_SH_DIR32; break; | |
| 275 | + case EM_SPARCV9: reltype = R_SPARC_64; gpfx = '_'; break; | |
| 276 | + case EM_X86_64: reltype = R_X86_64_64; break; | |
| 277 | + } /* end switch */ | |
| 278 | + | |
| 279 | + switch (ehdr->e_ident[EI_CLASS]) { | |
| 280 | + default: { | |
| 281 | + fprintf(stderr, "unrecognized ELF class %d %s\n", | |
| 282 | + ehdr->e_ident[EI_CLASS], fname); | |
| 283 | + fail_file(); | |
| 284 | + } break; | |
| 285 | + case ELFCLASS32: { | |
| 286 | + if (sizeof(Elf32_Ehdr) != w2(ehdr->e_ehsize) | |
| 287 | + || sizeof(Elf32_Shdr) != w2(ehdr->e_shentsize)) { | |
| 288 | + fprintf(stderr, | |
| 289 | + "unrecognized ET_REL file: %s\n", fname); | |
| 290 | + fail_file(); | |
| 291 | + } | |
| 292 | + if (EM_S390 == w2(ehdr->e_machine)) | |
| 293 | + reltype = R_390_32; | |
| 294 | + do32(ehdr, fname, reltype); | |
| 295 | + } break; | |
| 296 | + case ELFCLASS64: { | |
| 297 | + Elf64_Ehdr *const ghdr = (Elf64_Ehdr *)ehdr; | |
| 298 | + if (sizeof(Elf64_Ehdr) != w2(ghdr->e_ehsize) | |
| 299 | + || sizeof(Elf64_Shdr) != w2(ghdr->e_shentsize)) { | |
| 300 | + fprintf(stderr, | |
| 301 | + "unrecognized ET_REL file: %s\n", fname); | |
| 302 | + fail_file(); | |
| 303 | + } | |
| 304 | + if (EM_S390 == w2(ghdr->e_machine)) | |
| 305 | + reltype = R_390_64; | |
| 306 | + do64(ghdr, fname, reltype); | |
| 307 | + } break; | |
| 308 | + } /* end switch */ | |
| 309 | + | |
| 310 | + cleanup(); | |
| 311 | +} | |
| 312 | + | |
| 313 | +int | |
| 314 | +main(int argc, char const *argv[]) | |
| 315 | +{ | |
| 316 | + const char ftrace[] = "kernel/trace/ftrace.o"; | |
| 317 | + int ftrace_size = sizeof(ftrace) - 1; | |
| 318 | + int n_error = 0; /* gcc-4.3.0 false positive complaint */ | |
| 319 | + | |
| 320 | + if (argc <= 1) { | |
| 321 | + fprintf(stderr, "usage: recordmcount file.o...\n"); | |
| 322 | + return 0; | |
| 323 | + } | |
| 324 | + | |
| 325 | + /* Process each file in turn, allowing deep failure. */ | |
| 326 | + for (--argc, ++argv; 0 < argc; --argc, ++argv) { | |
| 327 | + int const sjval = setjmp(jmpenv); | |
| 328 | + int len; | |
| 329 | + | |
| 330 | + /* | |
| 331 | + * The file kernel/trace/ftrace.o references the mcount | |
| 332 | + * function but does not call it. Since ftrace.o should | |
| 333 | + * not be traced anyway, we just skip it. | |
| 334 | + */ | |
| 335 | + len = strlen(argv[0]); | |
| 336 | + if (len >= ftrace_size && | |
| 337 | + strcmp(argv[0] + (len - ftrace_size), ftrace) == 0) | |
| 338 | + continue; | |
| 339 | + | |
| 340 | + switch (sjval) { | |
| 341 | + default: { | |
| 342 | + fprintf(stderr, "internal error: %s\n", argv[0]); | |
| 343 | + exit(1); | |
| 344 | + } break; | |
| 345 | + case SJ_SETJMP: { /* normal sequence */ | |
| 346 | + /* Avoid problems if early cleanup() */ | |
| 347 | + fd_map = -1; | |
| 348 | + ehdr_curr = NULL; | |
| 349 | + mmap_failed = 1; | |
| 350 | + do_file(argv[0]); | |
| 351 | + } break; | |
| 352 | + case SJ_FAIL: { /* error in do_file or below */ | |
| 353 | + ++n_error; | |
| 354 | + } break; | |
| 355 | + case SJ_SUCCEED: { /* premature success */ | |
| 356 | + /* do nothing */ | |
| 357 | + } break; | |
| 358 | + } /* end switch */ | |
| 359 | + } | |
| 360 | + return !!n_error; | |
| 361 | +} | |
| 362 | + | |
| 363 | + | |
| @@ -0,0 +1,366 @@ | ||
| 1 | +/* | |
| 2 | + * recordmcount.h | |
| 3 | + * | |
| 4 | + * This code was taken out of recordmcount.c written by | |
| 5 | + * Copyright 2009 John F. Reiser <jreiser@BitWagon.com>. All rights reserved. | |
| 6 | + * | |
| 7 | + * The original code had the same algorithms for both 32bit | |
| 8 | + * and 64bit ELF files, but the code was duplicated to support | |
| 9 | + * the difference in structures that were used. This | |
| 10 | + * file creates a macro of everything that is different between | |
| 11 | + * the 64 and 32 bit code, such that by including this header | |
| 12 | + * twice we can create both sets of functions by including this | |
| 13 | + * header once with RECORD_MCOUNT_64 undefined, and again with | |
| 14 | + * it defined. | |
| 15 | + * | |
| 16 | + * This conversion to macros was done by: | |
| 17 | + * Copyright 2010 Steven Rostedt <srostedt@redhat.com>, Red Hat Inc. | |
| 18 | + * | |
| 19 | + * Licensed under the GNU General Public License, version 2 (GPLv2). | |
| 20 | + */ | |
| 21 | +#undef append_func | |
| 22 | +#undef sift_rel_mcount | |
| 23 | +#undef find_secsym_ndx | |
| 24 | +#undef __has_rel_mcount | |
| 25 | +#undef has_rel_mcount | |
| 26 | +#undef tot_relsize | |
| 27 | +#undef do_func | |
| 28 | +#undef Elf_Ehdr | |
| 29 | +#undef Elf_Shdr | |
| 30 | +#undef Elf_Rel | |
| 31 | +#undef Elf_Rela | |
| 32 | +#undef Elf_Sym | |
| 33 | +#undef ELF_R_SYM | |
| 34 | +#undef ELF_R_INFO | |
| 35 | +#undef ELF_ST_BIND | |
| 36 | +#undef uint_t | |
| 37 | +#undef _w | |
| 38 | +#undef _align | |
| 39 | +#undef _size | |
| 40 | + | |
| 41 | +#ifdef RECORD_MCOUNT_64 | |
| 42 | +# define append_func append64 | |
| 43 | +# define sift_rel_mcount sift64_rel_mcount | |
| 44 | +# define find_secsym_ndx find64_secsym_ndx | |
| 45 | +# define __has_rel_mcount __has64_rel_mcount | |
| 46 | +# define has_rel_mcount has64_rel_mcount | |
| 47 | +# define tot_relsize tot64_relsize | |
| 48 | +# define do_func do64 | |
| 49 | +# define Elf_Ehdr Elf64_Ehdr | |
| 50 | +# define Elf_Shdr Elf64_Shdr | |
| 51 | +# define Elf_Rel Elf64_Rel | |
| 52 | +# define Elf_Rela Elf64_Rela | |
| 53 | +# define Elf_Sym Elf64_Sym | |
| 54 | +# define ELF_R_SYM ELF64_R_SYM | |
| 55 | +# define ELF_R_INFO ELF64_R_INFO | |
| 56 | +# define ELF_ST_BIND ELF64_ST_BIND | |
| 57 | +# define uint_t uint64_t | |
| 58 | +# define _w w8 | |
| 59 | +# define _align 7u | |
| 60 | +# define _size 8 | |
| 61 | +#else | |
| 62 | +# define append_func append32 | |
| 63 | +# define sift_rel_mcount sift32_rel_mcount | |
| 64 | +# define find_secsym_ndx find32_secsym_ndx | |
| 65 | +# define __has_rel_mcount __has32_rel_mcount | |
| 66 | +# define has_rel_mcount has32_rel_mcount | |
| 67 | +# define tot_relsize tot32_relsize | |
| 68 | +# define do_func do32 | |
| 69 | +# define Elf_Ehdr Elf32_Ehdr | |
| 70 | +# define Elf_Shdr Elf32_Shdr | |
| 71 | +# define Elf_Rel Elf32_Rel | |
| 72 | +# define Elf_Rela Elf32_Rela | |
| 73 | +# define Elf_Sym Elf32_Sym | |
| 74 | +# define ELF_R_SYM ELF32_R_SYM | |
| 75 | +# define ELF_R_INFO ELF32_R_INFO | |
| 76 | +# define ELF_ST_BIND ELF32_ST_BIND | |
| 77 | +# define uint_t uint32_t | |
| 78 | +# define _w w | |
| 79 | +# define _align 3u | |
| 80 | +# define _size 4 | |
| 81 | +#endif | |
| 82 | + | |
| 83 | +/* Append the new shstrtab, Elf_Shdr[], __mcount_loc and its relocations. */ | |
| 84 | +static void append_func(Elf_Ehdr *const ehdr, | |
| 85 | + Elf_Shdr *const shstr, | |
| 86 | + uint_t const *const mloc0, | |
| 87 | + uint_t const *const mlocp, | |
| 88 | + Elf_Rel const *const mrel0, | |
| 89 | + Elf_Rel const *const mrelp, | |
| 90 | + unsigned int const rel_entsize, | |
| 91 | + unsigned int const symsec_sh_link) | |
| 92 | +{ | |
| 93 | + /* Begin constructing output file */ | |
| 94 | + Elf_Shdr mcsec; | |
| 95 | + char const *mc_name = (sizeof(Elf_Rela) == rel_entsize) | |
| 96 | + ? ".rela__mcount_loc" | |
| 97 | + : ".rel__mcount_loc"; | |
| 98 | + unsigned const old_shnum = w2(ehdr->e_shnum); | |
| 99 | + uint_t const old_shoff = _w(ehdr->e_shoff); | |
| 100 | + uint_t const old_shstr_sh_size = _w(shstr->sh_size); | |
| 101 | + uint_t const old_shstr_sh_offset = _w(shstr->sh_offset); | |
| 102 | + uint_t t = 1 + strlen(mc_name) + _w(shstr->sh_size); | |
| 103 | + uint_t new_e_shoff; | |
| 104 | + | |
| 105 | + shstr->sh_size = _w(t); | |
| 106 | + shstr->sh_offset = _w(sb.st_size); | |
| 107 | + t += sb.st_size; | |
| 108 | + t += (_align & -t); /* word-byte align */ | |
| 109 | + new_e_shoff = t; | |
| 110 | + | |
| 111 | + /* body for new shstrtab */ | |
| 112 | + ulseek(fd_map, sb.st_size, SEEK_SET); | |
| 113 | + uwrite(fd_map, old_shstr_sh_offset + (void *)ehdr, old_shstr_sh_size); | |
| 114 | + uwrite(fd_map, mc_name, 1 + strlen(mc_name)); | |
| 115 | + | |
| 116 | + /* old(modified) Elf_Shdr table, word-byte aligned */ | |
| 117 | + ulseek(fd_map, t, SEEK_SET); | |
| 118 | + t += sizeof(Elf_Shdr) * old_shnum; | |
| 119 | + uwrite(fd_map, old_shoff + (void *)ehdr, | |
| 120 | + sizeof(Elf_Shdr) * old_shnum); | |
| 121 | + | |
| 122 | + /* new sections __mcount_loc and .rel__mcount_loc */ | |
| 123 | + t += 2*sizeof(mcsec); | |
| 124 | + mcsec.sh_name = w((sizeof(Elf_Rela) == rel_entsize) + strlen(".rel") | |
| 125 | + + old_shstr_sh_size); | |
| 126 | + mcsec.sh_type = w(SHT_PROGBITS); | |
| 127 | + mcsec.sh_flags = _w(SHF_ALLOC); | |
| 128 | + mcsec.sh_addr = 0; | |
| 129 | + mcsec.sh_offset = _w(t); | |
| 130 | + mcsec.sh_size = _w((void *)mlocp - (void *)mloc0); | |
| 131 | + mcsec.sh_link = 0; | |
| 132 | + mcsec.sh_info = 0; | |
| 133 | + mcsec.sh_addralign = _w(_size); | |
| 134 | + mcsec.sh_entsize = _w(_size); | |
| 135 | + uwrite(fd_map, &mcsec, sizeof(mcsec)); | |
| 136 | + | |
| 137 | + mcsec.sh_name = w(old_shstr_sh_size); | |
| 138 | + mcsec.sh_type = (sizeof(Elf_Rela) == rel_entsize) | |
| 139 | + ? w(SHT_RELA) | |
| 140 | + : w(SHT_REL); | |
| 141 | + mcsec.sh_flags = 0; | |
| 142 | + mcsec.sh_addr = 0; | |
| 143 | + mcsec.sh_offset = _w((void *)mlocp - (void *)mloc0 + t); | |
| 144 | + mcsec.sh_size = _w((void *)mrelp - (void *)mrel0); | |
| 145 | + mcsec.sh_link = w(symsec_sh_link); | |
| 146 | + mcsec.sh_info = w(old_shnum); | |
| 147 | + mcsec.sh_addralign = _w(_size); | |
| 148 | + mcsec.sh_entsize = _w(rel_entsize); | |
| 149 | + uwrite(fd_map, &mcsec, sizeof(mcsec)); | |
| 150 | + | |
| 151 | + uwrite(fd_map, mloc0, (void *)mlocp - (void *)mloc0); | |
| 152 | + uwrite(fd_map, mrel0, (void *)mrelp - (void *)mrel0); | |
| 153 | + | |
| 154 | + ehdr->e_shoff = _w(new_e_shoff); | |
| 155 | + ehdr->e_shnum = w2(2 + w2(ehdr->e_shnum)); /* {.rel,}__mcount_loc */ | |
| 156 | + ulseek(fd_map, 0, SEEK_SET); | |
| 157 | + uwrite(fd_map, ehdr, sizeof(*ehdr)); | |
| 158 | +} | |
| 159 | + | |
| 160 | + | |
| 161 | +/* | |
| 162 | + * Look at the relocations in order to find the calls to mcount. | |
| 163 | + * Accumulate the section offsets that are found, and their relocation info, | |
| 164 | + * onto the end of the existing arrays. | |
| 165 | + */ | |
| 166 | +static uint_t *sift_rel_mcount(uint_t *mlocp, | |
| 167 | + unsigned const offbase, | |
| 168 | + Elf_Rel **const mrelpp, | |
| 169 | + Elf_Shdr const *const relhdr, | |
| 170 | + Elf_Ehdr const *const ehdr, | |
| 171 | + unsigned const recsym, | |
| 172 | + uint_t const recval, | |
| 173 | + unsigned const reltype) | |
| 174 | +{ | |
| 175 | + uint_t *const mloc0 = mlocp; | |
| 176 | + Elf_Rel *mrelp = *mrelpp; | |
| 177 | + Elf_Shdr *const shdr0 = (Elf_Shdr *)(_w(ehdr->e_shoff) | |
| 178 | + + (void *)ehdr); | |
| 179 | + unsigned const symsec_sh_link = w(relhdr->sh_link); | |
| 180 | + Elf_Shdr const *const symsec = &shdr0[symsec_sh_link]; | |
| 181 | + Elf_Sym const *const sym0 = (Elf_Sym const *)(_w(symsec->sh_offset) | |
| 182 | + + (void *)ehdr); | |
| 183 | + | |
| 184 | + Elf_Shdr const *const strsec = &shdr0[w(symsec->sh_link)]; | |
| 185 | + char const *const str0 = (char const *)(_w(strsec->sh_offset) | |
| 186 | + + (void *)ehdr); | |
| 187 | + | |
| 188 | + Elf_Rel const *const rel0 = (Elf_Rel const *)(_w(relhdr->sh_offset) | |
| 189 | + + (void *)ehdr); | |
| 190 | + unsigned rel_entsize = _w(relhdr->sh_entsize); | |
| 191 | + unsigned const nrel = _w(relhdr->sh_size) / rel_entsize; | |
| 192 | + Elf_Rel const *relp = rel0; | |
| 193 | + | |
| 194 | + unsigned mcountsym = 0; | |
| 195 | + unsigned t; | |
| 196 | + | |
| 197 | + for (t = nrel; t; --t) { | |
| 198 | + if (!mcountsym) { | |
| 199 | + Elf_Sym const *const symp = | |
| 200 | + &sym0[ELF_R_SYM(_w(relp->r_info))]; | |
| 201 | + char const *symname = &str0[w(symp->st_name)]; | |
| 202 | + | |
| 203 | + if ('.' == symname[0]) | |
| 204 | + ++symname; /* ppc64 hack */ | |
| 205 | + if (0 == strcmp((('_' == gpfx) ? "_mcount" : "mcount"), | |
| 206 | + symname)) | |
| 207 | + mcountsym = ELF_R_SYM(_w(relp->r_info)); | |
| 208 | + } | |
| 209 | + | |
| 210 | + if (mcountsym == ELF_R_SYM(_w(relp->r_info))) { | |
| 211 | + uint_t const addend = _w(_w(relp->r_offset) - recval); | |
| 212 | + | |
| 213 | + mrelp->r_offset = _w(offbase | |
| 214 | + + ((void *)mlocp - (void *)mloc0)); | |
| 215 | + mrelp->r_info = _w(ELF_R_INFO(recsym, reltype)); | |
| 216 | + if (sizeof(Elf_Rela) == rel_entsize) { | |
| 217 | + ((Elf_Rela *)mrelp)->r_addend = addend; | |
| 218 | + *mlocp++ = 0; | |
| 219 | + } else | |
| 220 | + *mlocp++ = addend; | |
| 221 | + | |
| 222 | + mrelp = (Elf_Rel *)(rel_entsize + (void *)mrelp); | |
| 223 | + } | |
| 224 | + relp = (Elf_Rel const *)(rel_entsize + (void *)relp); | |
| 225 | + } | |
| 226 | + *mrelpp = mrelp; | |
| 227 | + return mlocp; | |
| 228 | +} | |
| 229 | + | |
| 230 | + | |
| 231 | +/* | |
| 232 | + * Find a symbol in the given section, to be used as the base for relocating | |
| 233 | + * the table of offsets of calls to mcount. A local or global symbol suffices, | |
| 234 | + * but avoid a Weak symbol because it may be overridden; the change in value | |
| 235 | + * would invalidate the relocations of the offsets of the calls to mcount. | |
| 236 | + * Often the found symbol will be the unnamed local symbol generated by | |
| 237 | + * GNU 'as' for the start of each section. For example: | |
| 238 | + * Num: Value Size Type Bind Vis Ndx Name | |
| 239 | + * 2: 00000000 0 SECTION LOCAL DEFAULT 1 | |
| 240 | + */ | |
| 241 | +static unsigned find_secsym_ndx(unsigned const txtndx, | |
| 242 | + char const *const txtname, | |
| 243 | + uint_t *const recvalp, | |
| 244 | + Elf_Shdr const *const symhdr, | |
| 245 | + Elf_Ehdr const *const ehdr) | |
| 246 | +{ | |
| 247 | + Elf_Sym const *const sym0 = (Elf_Sym const *)(_w(symhdr->sh_offset) | |
| 248 | + + (void *)ehdr); | |
| 249 | + unsigned const nsym = _w(symhdr->sh_size) / _w(symhdr->sh_entsize); | |
| 250 | + Elf_Sym const *symp; | |
| 251 | + unsigned t; | |
| 252 | + | |
| 253 | + for (symp = sym0, t = nsym; t; --t, ++symp) { | |
| 254 | + unsigned int const st_bind = ELF_ST_BIND(symp->st_info); | |
| 255 | + | |
| 256 | + if (txtndx == w2(symp->st_shndx) | |
| 257 | + /* avoid STB_WEAK */ | |
| 258 | + && (STB_LOCAL == st_bind || STB_GLOBAL == st_bind)) { | |
| 259 | + *recvalp = _w(symp->st_value); | |
| 260 | + return symp - sym0; | |
| 261 | + } | |
| 262 | + } | |
| 263 | + fprintf(stderr, "Cannot find symbol for section %d: %s.\n", | |
| 264 | + txtndx, txtname); | |
| 265 | + fail_file(); | |
| 266 | +} | |
| 267 | + | |
| 268 | + | |
| 269 | +/* Evade ISO C restriction: no declaration after statement in has_rel_mcount. */ | |
| 270 | +static char const * | |
| 271 | +__has_rel_mcount(Elf_Shdr const *const relhdr, /* is SHT_REL or SHT_RELA */ | |
| 272 | + Elf_Shdr const *const shdr0, | |
| 273 | + char const *const shstrtab, | |
| 274 | + char const *const fname) | |
| 275 | +{ | |
| 276 | + /* .sh_info depends on .sh_type == SHT_REL[,A] */ | |
| 277 | + Elf_Shdr const *const txthdr = &shdr0[w(relhdr->sh_info)]; | |
| 278 | + char const *const txtname = &shstrtab[w(txthdr->sh_name)]; | |
| 279 | + | |
| 280 | + if (0 == strcmp("__mcount_loc", txtname)) { | |
| 281 | + fprintf(stderr, "warning: __mcount_loc already exists: %s\n", | |
| 282 | + fname); | |
| 283 | + succeed_file(); | |
| 284 | + } | |
| 285 | + if (SHT_PROGBITS != w(txthdr->sh_type) || | |
| 286 | + !is_mcounted_section_name(txtname)) | |
| 287 | + return NULL; | |
| 288 | + return txtname; | |
| 289 | +} | |
| 290 | + | |
| 291 | +static char const *has_rel_mcount(Elf_Shdr const *const relhdr, | |
| 292 | + Elf_Shdr const *const shdr0, | |
| 293 | + char const *const shstrtab, | |
| 294 | + char const *const fname) | |
| 295 | +{ | |
| 296 | + if (SHT_REL != w(relhdr->sh_type) && SHT_RELA != w(relhdr->sh_type)) | |
| 297 | + return NULL; | |
| 298 | + return __has_rel_mcount(relhdr, shdr0, shstrtab, fname); | |
| 299 | +} | |
| 300 | + | |
| 301 | + | |
| 302 | +static unsigned tot_relsize(Elf_Shdr const *const shdr0, | |
| 303 | + unsigned nhdr, | |
| 304 | + const char *const shstrtab, | |
| 305 | + const char *const fname) | |
| 306 | +{ | |
| 307 | + unsigned totrelsz = 0; | |
| 308 | + Elf_Shdr const *shdrp = shdr0; | |
| 309 | + | |
| 310 | + for (; nhdr; --nhdr, ++shdrp) { | |
| 311 | + if (has_rel_mcount(shdrp, shdr0, shstrtab, fname)) | |
| 312 | + totrelsz += _w(shdrp->sh_size); | |
| 313 | + } | |
| 314 | + return totrelsz; | |
| 315 | +} | |
| 316 | + | |
| 317 | + | |
| 318 | +/* Overall supervision for Elf32 ET_REL file. */ | |
| 319 | +static void | |
| 320 | +do_func(Elf_Ehdr *const ehdr, char const *const fname, unsigned const reltype) | |
| 321 | +{ | |
| 322 | + Elf_Shdr *const shdr0 = (Elf_Shdr *)(_w(ehdr->e_shoff) | |
| 323 | + + (void *)ehdr); | |
| 324 | + unsigned const nhdr = w2(ehdr->e_shnum); | |
| 325 | + Elf_Shdr *const shstr = &shdr0[w2(ehdr->e_shstrndx)]; | |
| 326 | + char const *const shstrtab = (char const *)(_w(shstr->sh_offset) | |
| 327 | + + (void *)ehdr); | |
| 328 | + | |
| 329 | + Elf_Shdr const *relhdr; | |
| 330 | + unsigned k; | |
| 331 | + | |
| 332 | + /* Upper bound on space: assume all relevant relocs are for mcount. */ | |
| 333 | + unsigned const totrelsz = tot_relsize(shdr0, nhdr, shstrtab, fname); | |
| 334 | + Elf_Rel *const mrel0 = umalloc(totrelsz); | |
| 335 | + Elf_Rel * mrelp = mrel0; | |
| 336 | + | |
| 337 | + /* 2*sizeof(address) <= sizeof(Elf_Rel) */ | |
| 338 | + uint_t *const mloc0 = umalloc(totrelsz>>1); | |
| 339 | + uint_t * mlocp = mloc0; | |
| 340 | + | |
| 341 | + unsigned rel_entsize = 0; | |
| 342 | + unsigned symsec_sh_link = 0; | |
| 343 | + | |
| 344 | + for (relhdr = shdr0, k = nhdr; k; --k, ++relhdr) { | |
| 345 | + char const *const txtname = has_rel_mcount(relhdr, shdr0, | |
| 346 | + shstrtab, fname); | |
| 347 | + if (txtname) { | |
| 348 | + uint_t recval = 0; | |
| 349 | + unsigned const recsym = find_secsym_ndx( | |
| 350 | + w(relhdr->sh_info), txtname, &recval, | |
| 351 | + &shdr0[symsec_sh_link = w(relhdr->sh_link)], | |
| 352 | + ehdr); | |
| 353 | + | |
| 354 | + rel_entsize = _w(relhdr->sh_entsize); | |
| 355 | + mlocp = sift_rel_mcount(mlocp, | |
| 356 | + (void *)mlocp - (void *)mloc0, &mrelp, | |
| 357 | + relhdr, ehdr, recsym, recval, reltype); | |
| 358 | + } | |
| 359 | + } | |
| 360 | + if (mloc0 != mlocp) { | |
| 361 | + append_func(ehdr, shstr, mloc0, mlocp, mrel0, mrelp, | |
| 362 | + rel_entsize, symsec_sh_link); | |
| 363 | + } | |
| 364 | + free(mrel0); | |
| 365 | + free(mloc0); | |
| 366 | +} | |