111
113
umalloc(size_t size)
113
115
void *const addr = malloc(size);
115
117
fprintf(stderr, "malloc failed: %zu bytes\n", size);
123
static unsigned char ideal_nop5_x86_64[5] = { 0x0f, 0x1f, 0x44, 0x00, 0x00 };
124
static unsigned char ideal_nop5_x86_32[5] = { 0x3e, 0x8d, 0x74, 0x26, 0x00 };
125
static unsigned char *ideal_nop;
127
static char rel_type_nop;
129
static int (*make_nop)(void *map, size_t const offset);
131
static int make_nop_x86(void *map, size_t const offset)
136
/* Confirm we have 0xe8 0x0 0x0 0x0 0x0 */
141
op = map + offset - 1;
146
ulseek(fd_map, offset - 1, SEEK_SET);
147
uwrite(fd_map, ideal_nop, 5);
122
152
* Get the whole file as a programming convenience in order to avoid
123
153
* malloc+lseek+read+free of many pieces. If successful, then mmap
207
237
is_mcounted_section_name(char const *const txtname)
209
return 0 == strcmp(".text", txtname) ||
210
0 == strcmp(".ref.text", txtname) ||
211
0 == strcmp(".sched.text", txtname) ||
212
0 == strcmp(".spinlock.text", txtname) ||
213
0 == strcmp(".irqentry.text", txtname) ||
214
0 == strcmp(".text.unlikely", txtname);
239
return strcmp(".text", txtname) == 0 ||
240
strcmp(".ref.text", txtname) == 0 ||
241
strcmp(".sched.text", txtname) == 0 ||
242
strcmp(".spinlock.text", txtname) == 0 ||
243
strcmp(".irqentry.text", txtname) == 0 ||
244
strcmp(".kprobes.text", txtname) == 0 ||
245
strcmp(".text.unlikely", txtname) == 0;
217
248
/* 32 bit and 64 bit are very similar */
265
296
switch (ehdr->e_ident[EI_DATA]) {
266
297
static unsigned int const endian = 1;
268
299
fprintf(stderr, "unrecognized ELF data encoding %d: %s\n",
269
300
ehdr->e_ident[EI_DATA], fname);
273
if (1 != *(unsigned char const *)&endian) {
304
if (*(unsigned char const *)&endian != 1) {
274
305
/* main() is big endian, file.o is little endian. */
281
if (0 != *(unsigned char const *)&endian) {
312
if (*(unsigned char const *)&endian != 0) {
282
313
/* main() is little endian, file.o is big endian. */
288
319
} /* end switch */
289
if (0 != memcmp(ELFMAG, ehdr->e_ident, SELFMAG)
290
|| ET_REL != w2(ehdr->e_type)
291
|| EV_CURRENT != ehdr->e_ident[EI_VERSION]) {
320
if (memcmp(ELFMAG, ehdr->e_ident, SELFMAG) != 0
321
|| w2(ehdr->e_type) != ET_REL
322
|| ehdr->e_ident[EI_VERSION] != EV_CURRENT) {
292
323
fprintf(stderr, "unrecognized ET_REL file %s\n", fname);
297
328
switch (w2(ehdr->e_machine)) {
299
330
fprintf(stderr, "unrecognized e_machine %d %s\n",
300
331
w2(ehdr->e_machine), fname);
303
case EM_386: reltype = R_386_32; break;
336
make_nop = make_nop_x86;
337
ideal_nop = ideal_nop5_x86_32;
338
mcount_adjust_32 = -1;
304
340
case EM_ARM: reltype = R_ARM_ABS32;
305
341
altmcount = "__gnu_mcount_nc";
311
347
case EM_S390: /* reltype: e_class */ gpfx = '_'; break;
312
348
case EM_SH: reltype = R_SH_DIR32; break;
313
349
case EM_SPARCV9: reltype = R_SPARC_64; gpfx = '_'; break;
314
case EM_X86_64: reltype = R_X86_64_64; break;
351
make_nop = make_nop_x86;
352
ideal_nop = ideal_nop5_x86_64;
353
reltype = R_X86_64_64;
354
mcount_adjust_64 = -1;
315
356
} /* end switch */
317
358
switch (ehdr->e_ident[EI_CLASS]) {
319
360
fprintf(stderr, "unrecognized ELF class %d %s\n",
320
361
ehdr->e_ident[EI_CLASS], fname);
324
if (sizeof(Elf32_Ehdr) != w2(ehdr->e_ehsize)
325
|| sizeof(Elf32_Shdr) != w2(ehdr->e_shentsize)) {
365
if (w2(ehdr->e_ehsize) != sizeof(Elf32_Ehdr)
366
|| w2(ehdr->e_shentsize) != sizeof(Elf32_Shdr)) {
327
368
"unrecognized ET_REL file: %s\n", fname);
330
if (EM_S390 == w2(ehdr->e_machine))
371
if (w2(ehdr->e_machine) == EM_S390) {
331
372
reltype = R_390_32;
332
if (EM_MIPS == w2(ehdr->e_machine)) {
373
mcount_adjust_32 = -4;
375
if (w2(ehdr->e_machine) == EM_MIPS) {
333
376
reltype = R_MIPS_32;
334
377
is_fake_mcount32 = MIPS32_is_fake_mcount;
336
379
do32(ehdr, fname, reltype);
338
381
case ELFCLASS64: {
339
382
Elf64_Ehdr *const ghdr = (Elf64_Ehdr *)ehdr;
340
if (sizeof(Elf64_Ehdr) != w2(ghdr->e_ehsize)
341
|| sizeof(Elf64_Shdr) != w2(ghdr->e_shentsize)) {
383
if (w2(ghdr->e_ehsize) != sizeof(Elf64_Ehdr)
384
|| w2(ghdr->e_shentsize) != sizeof(Elf64_Shdr)) {
343
386
"unrecognized ET_REL file: %s\n", fname);
346
if (EM_S390 == w2(ghdr->e_machine))
389
if (w2(ghdr->e_machine) == EM_S390) {
347
390
reltype = R_390_64;
348
if (EM_MIPS == w2(ghdr->e_machine)) {
391
mcount_adjust_64 = -8;
393
if (w2(ghdr->e_machine) == EM_MIPS) {
349
394
reltype = R_MIPS_64;
350
395
Elf64_r_sym = MIPS64_r_sym;
351
396
Elf64_r_info = MIPS64_r_info;
352
397
is_fake_mcount64 = MIPS64_is_fake_mcount;
354
399
do64(ghdr, fname, reltype);
356
402
} /* end switch */
362
main(int argc, char const *argv[])
408
main(int argc, char *argv[])
364
410
const char ftrace[] = "/ftrace.o";
365
411
int ftrace_size = sizeof(ftrace) - 1;
366
412
int n_error = 0; /* gcc-4.3.0 false positive complaint */
369
fprintf(stderr, "usage: recordmcount file.o...\n");
416
while ((c = getopt(argc, argv, "w")) >= 0) {
419
warn_on_notrace_sect = 1;
422
fprintf(stderr, "usage: recordmcount [-w] file.o...\n");
427
if ((argc - optind) < 1) {
428
fprintf(stderr, "usage: recordmcount [-w] file.o...\n");
373
432
/* Process each file in turn, allowing deep failure. */
374
for (--argc, ++argv; 0 < argc; --argc, ++argv) {
433
for (i = optind; i < argc; i++) {
434
char *file = argv[i];
375
435
int const sjval = setjmp(jmpenv);
380
440
* function but does not call it. Since ftrace.o should
381
441
* not be traced anyway, we just skip it.
383
len = strlen(argv[0]);
384
444
if (len >= ftrace_size &&
385
strcmp(argv[0] + (len - ftrace_size), ftrace) == 0)
445
strcmp(file + (len - ftrace_size), ftrace) == 0)
390
fprintf(stderr, "internal error: %s\n", argv[0]);
450
fprintf(stderr, "internal error: %s\n", file);
393
case SJ_SETJMP: { /* normal sequence */
453
case SJ_SETJMP: /* normal sequence */
394
454
/* Avoid problems if early cleanup() */
396
456
ehdr_curr = NULL;
400
case SJ_FAIL: { /* error in do_file or below */
460
case SJ_FAIL: /* error in do_file or below */
403
case SJ_SUCCEED: { /* premature success */
463
case SJ_SUCCEED: /* premature success */
406
466
} /* end switch */
408
468
return !!n_error;