2019-06-12 04:55:44

by Matt Helsley

[permalink] [raw]
Subject: [PATCH v2 00/13] Cleanup recordmcount and begin objtool conversion

This series cleans up recordmcount and then makes it into
an objtool subcommand.

The series starts with 8 cleanup patches which make recordmcount
easier to review and integrate with objtool. The final 5 patches
show the beginning steps of converting recordmcount to use objtool's
ELF code rather than its own open-coded methods of accessing ELF
files.

---

v2:
Fix whitespace before line continuation

Add ftrace/mcount/record.h to objtool_dep

Rename the Makefile variable BUILD_C_RECORDMCOUNT to
better reflect its purpose

Similar: rename recordmcount_source => recordmcount_dep
When using objtool we can just depend on the
binary rather than the source the binary is
built from. This should address Josh's feedback and
make the Makefile code a bit clearer

Add a comment to make reading the Makefile a little
easier

Rebased to latest mainline -rc

Collected some build time measurements

Build times measurements -- median of multiple runs in a VM measured
with "time":

mainline (5.2.0-rc4) build times (median of 3 runs):
real 2m58.379s
user 2m29.621s
sys 1m35.116s

Post recordmcount-cleanup build times (median of 5 runs):
real 2m51.973s
user 2m29.094s
sys 1m33.688s

objtool mcount build times (median of 7 runs):
real 2m57.92s
user 2m33.73s
sys 1m37.06s

Note: I saw some significant variation especially in the "real" time
measurements probably because it was in a VM on a machine with
various "idle" GUI tasks running. This is why I took the median
rather than the mean. Though I haven't run the statistics, my
sense is the numbers don't support concluding that things really
got any faster or slower.

I'm working on a separate, follow-on RFC set which implements the
pseudo-pipe idea.

Matt Helsley (13):
recordmcount: Remove redundant strcmp
recordmcount: Remove uread()
recordmcount: Remove unused fd from uwrite() and ulseek()
recordmcount: Rewrite error/success handling
recordmcount: Kernel style function signature formatting
recordmcount: Kernel style formatting
recordmcount: Remove redundant cleanup() calls
recordmcount: Clarify what cleanup() does
objtool: Prepare to merge recordmcount
objtool: Make recordmcount into an objtool subcmd
objtool: recordmcount: Start using objtool's elf wrapper
objtool: recordmcount: Search for __mcount_loc before walking the
sections
objtool: recordmcount: Convert do_func() relhdrs

Makefile | 6 +-
scripts/.gitignore | 1 -
scripts/Makefile | 1 -
scripts/Makefile.build | 27 +-
tools/objtool/.gitignore | 1 +
tools/objtool/Build | 1 +
tools/objtool/Makefile | 1 +
tools/objtool/builtin-mcount.c | 72 +++++
tools/objtool/builtin-mcount.h | 23 ++
tools/objtool/builtin.h | 1 +
tools/objtool/objtool.c | 1 +
{scripts => tools/objtool}/recordmcount.c | 350 ++++++++++-----------
{scripts => tools/objtool}/recordmcount.h | 197 +++++++-----
{scripts => tools/objtool}/recordmcount.pl | 0
14 files changed, 407 insertions(+), 275 deletions(-)
create mode 100644 tools/objtool/builtin-mcount.c
create mode 100644 tools/objtool/builtin-mcount.h
rename {scripts => tools/objtool}/recordmcount.c (78%)
rename {scripts => tools/objtool}/recordmcount.h (78%)
rename {scripts => tools/objtool}/recordmcount.pl (100%)

--
2.20.1


2019-06-12 04:57:01

by Matt Helsley

[permalink] [raw]
Subject: [PATCH v2 04/13] recordmcount: Rewrite error/success handling

Recordmcount uses setjmp/longjmp to manage control flow as
it reads and then writes the ELF file. This unusual control
flow is hard to follow and check in addition to being unlike
kernel coding style.

So we rewrite these paths to use regular return values to
indicate error/success. When an error or previously-completed object
file is found we return an error code following kernel
coding conventions -- negative error values and 0 for success when
we're not returning a pointer. We return NULL for those that fail
and return non-NULL pointers otherwise.

One oddity is already_has_rel_mcount -- there we use pointer comparison
rather than string comparison to differentiate between
previously-processed object files and returning the name of a text
section.

Signed-off-by: Matt Helsley <[email protected]>
---
scripts/recordmcount.c | 160 +++++++++++++++++++++--------------------
scripts/recordmcount.h | 134 +++++++++++++++++++++++++---------
2 files changed, 182 insertions(+), 112 deletions(-)

diff --git a/scripts/recordmcount.c b/scripts/recordmcount.c
index 1fe5fba99959..584dcbf3f320 100644
--- a/scripts/recordmcount.c
+++ b/scripts/recordmcount.c
@@ -27,7 +27,6 @@
#include <getopt.h>
#include <elf.h>
#include <fcntl.h>
-#include <setjmp.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@@ -43,7 +42,6 @@ static int fd_map; /* File descriptor for file being modified. */
static int mmap_failed; /* Boolean flag. */
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 */
static void *file_map; /* pointer of the mapped file */
@@ -53,13 +51,6 @@ static void *file_ptr; /* current file pointer location */
static void *file_append; /* added to the end of the file */
static size_t file_append_size; /* how much is added to end of file */

-/* setjmp() return values */
-enum {
- SJ_SETJMP = 0, /* hardwired first return */
- SJ_FAIL,
- SJ_SUCCEED
-};
-
/* Per-file resource cleanup when multiple files. */
static void
cleanup(void)
@@ -75,20 +66,6 @@ cleanup(void)
file_updated = 0;
}

-static void __attribute__((noreturn))
-fail_file(void)
-{
- cleanup();
- longjmp(jmpenv, SJ_FAIL);
-}
-
-static void __attribute__((noreturn))
-succeed_file(void)
-{
- cleanup();
- longjmp(jmpenv, SJ_SUCCEED);
-}
-
/* ulseek, uwrite, ...: Check return value for errors. */

static off_t
@@ -107,12 +84,12 @@ ulseek(off_t const offset, int const whence)
}
if (file_ptr < file_map) {
fprintf(stderr, "lseek: seek before file\n");
- fail_file();
+ return -1;
}
return file_ptr - file_map;
}

-static size_t
+static ssize_t
uwrite(void const *const buf, size_t const count)
{
size_t cnt = count;
@@ -129,7 +106,8 @@ uwrite(void const *const buf, size_t const count)
}
if (!file_append) {
perror("write");
- fail_file();
+ cleanup();
+ return -1;
}
if (file_ptr < file_end) {
cnt = file_end - file_ptr;
@@ -155,7 +133,8 @@ umalloc(size_t size)
void *const addr = malloc(size);
if (addr == 0) {
fprintf(stderr, "malloc failed: %zu bytes\n", size);
- fail_file();
+ cleanup();
+ return NULL;
}
return addr;
}
@@ -183,8 +162,10 @@ static int make_nop_x86(void *map, size_t const offset)
return -1;

/* convert to nop */
- ulseek(offset - 1, SEEK_SET);
- uwrite(ideal_nop, 5);
+ if (ulseek(offset - 1, SEEK_SET) < 0)
+ return -1;
+ if (uwrite(ideal_nop, 5) < 0)
+ return -1;
return 0;
}

@@ -232,10 +213,12 @@ static int make_nop_arm(void *map, size_t const offset)
return -1;

/* Convert to nop */
- ulseek(off, SEEK_SET);
+ if (ulseek(off, SEEK_SET) < 0)
+ return -1;

do {
- uwrite(ideal_nop, nop_size);
+ if (uwrite(ideal_nop, nop_size) < 0)
+ return -1;
} while (--cnt > 0);

return 0;
@@ -252,8 +235,10 @@ static int make_nop_arm64(void *map, size_t const offset)
return -1;

/* Convert to nop */
- ulseek(offset, SEEK_SET);
- uwrite(ideal_nop, 4);
+ if (ulseek(offset, SEEK_SET) < 0)
+ return -1;
+ if (uwrite(ideal_nop, 4) < 0)
+ return -1;
return 0;
}

@@ -272,14 +257,23 @@ static int make_nop_arm64(void *map, size_t const offset)
*/
static void *mmap_file(char const *fname)
{
+ file_map = NULL;
+ sb.st_size = 0;
fd_map = open(fname, O_RDONLY);
- if (fd_map < 0 || fstat(fd_map, &sb) < 0) {
+ if (fd_map < 0) {
perror(fname);
- fail_file();
+ cleanup();
+ return NULL;
+ }
+ if (fstat(fd_map, &sb) < 0) {
+ perror(fname);
+ cleanup();
+ goto out;
}
if (!S_ISREG(sb.st_mode)) {
fprintf(stderr, "not a regular file: %s\n", fname);
- fail_file();
+ cleanup();
+ goto out;
}
file_map = mmap(0, sb.st_size, PROT_READ|PROT_WRITE, MAP_PRIVATE,
fd_map, 0);
@@ -287,11 +281,18 @@ static void *mmap_file(char const *fname)
if (file_map == MAP_FAILED) {
mmap_failed = 1;
file_map = umalloc(sb.st_size);
+ if (!file_map) {
+ perror(fname);
+ goto out;
+ }
if (read(fd_map, file_map, sb.st_size) != sb.st_size) {
perror(fname);
- fail_file();
+ free(file_map);
+ file_map = NULL;
+ goto out;
}
}
+out:
close(fd_map);

file_end = file_map + sb.st_size;
@@ -299,13 +300,13 @@ static void *mmap_file(char const *fname)
return file_map;
}

-static void write_file(const char *fname)
+static int write_file(const char *fname)
{
char tmp_file[strlen(fname) + 4];
size_t n;

if (!file_updated)
- return;
+ return 0;

sprintf(tmp_file, "%s.rc", fname);

@@ -317,25 +318,32 @@ static void write_file(const char *fname)
fd_map = open(tmp_file, O_WRONLY | O_TRUNC | O_CREAT, sb.st_mode);
if (fd_map < 0) {
perror(fname);
- fail_file();
+ cleanup();
+ return -1;
}
n = write(fd_map, file_map, sb.st_size);
if (n != sb.st_size) {
perror("write");
- fail_file();
+ cleanup();
+ close(fd_map);
+ return -1;
}
if (file_append_size) {
n = write(fd_map, file_append, file_append_size);
if (n != file_append_size) {
perror("write");
- fail_file();
+ cleanup();
+ close(fd_map);
+ return -1;
}
}
close(fd_map);
if (rename(tmp_file, fname) < 0) {
perror(fname);
- fail_file();
+ cleanup();
+ return -1;
}
+ return 0;
}

/* w8rev, w8nat, ...: Handle endianness. */
@@ -438,11 +446,15 @@ static void MIPS64_r_info(Elf64_Rel *const rp, unsigned sym, unsigned type)
}).r_info;
}

-static void
+static int
do_file(char const *const fname)
{
Elf32_Ehdr *const ehdr = mmap_file(fname);
unsigned int reltype = 0;
+ int rc = -1;
+
+ if (!ehdr)
+ goto out;

w = w4nat;
w2 = w2nat;
@@ -452,8 +464,8 @@ do_file(char const *const fname)
default:
fprintf(stderr, "unrecognized ELF data encoding %d: %s\n",
ehdr->e_ident[EI_DATA], fname);
- fail_file();
- break;
+ cleanup();
+ goto out;
case ELFDATA2LSB:
if (*(unsigned char const *)&endian != 1) {
/* main() is big endian, file.o is little endian. */
@@ -485,7 +497,8 @@ do_file(char const *const fname)
|| w2(ehdr->e_type) != ET_REL
|| ehdr->e_ident[EI_VERSION] != EV_CURRENT) {
fprintf(stderr, "unrecognized ET_REL file %s\n", fname);
- fail_file();
+ cleanup();
+ goto out;
}

gpfx = 0;
@@ -493,8 +506,8 @@ do_file(char const *const fname)
default:
fprintf(stderr, "unrecognized e_machine %u %s\n",
w2(ehdr->e_machine), fname);
- fail_file();
- break;
+ cleanup();
+ goto out;
case EM_386:
reltype = R_386_32;
rel_type_nop = R_386_NONE;
@@ -534,20 +547,22 @@ do_file(char const *const fname)
default:
fprintf(stderr, "unrecognized ELF class %d %s\n",
ehdr->e_ident[EI_CLASS], fname);
- fail_file();
- break;
+ cleanup();
+ goto out;
case ELFCLASS32:
if (w2(ehdr->e_ehsize) != sizeof(Elf32_Ehdr)
|| w2(ehdr->e_shentsize) != sizeof(Elf32_Shdr)) {
fprintf(stderr,
"unrecognized ET_REL file: %s\n", fname);
- fail_file();
+ cleanup();
+ goto out;
}
if (w2(ehdr->e_machine) == EM_MIPS) {
reltype = R_MIPS_32;
is_fake_mcount32 = MIPS32_is_fake_mcount;
}
- do32(ehdr, fname, reltype);
+ if (do32(ehdr, fname, reltype) < 0)
+ goto out;
break;
case ELFCLASS64: {
Elf64_Ehdr *const ghdr = (Elf64_Ehdr *)ehdr;
@@ -555,7 +570,8 @@ do_file(char const *const fname)
|| w2(ghdr->e_shentsize) != sizeof(Elf64_Shdr)) {
fprintf(stderr,
"unrecognized ET_REL file: %s\n", fname);
- fail_file();
+ cleanup();
+ goto out;
}
if (w2(ghdr->e_machine) == EM_S390) {
reltype = R_390_64;
@@ -567,13 +583,16 @@ do_file(char const *const fname)
Elf64_r_info = MIPS64_r_info;
is_fake_mcount64 = MIPS64_is_fake_mcount;
}
- do64(ghdr, fname, reltype);
+ if (do64(ghdr, fname, reltype) < 0)
+ goto out;
break;
}
} /* end switch */

- write_file(fname);
+ rc = write_file(fname);
+out:
cleanup();
+ return rc;
}

int
@@ -604,7 +623,6 @@ main(int argc, char *argv[])
/* Process each file in turn, allowing deep failure. */
for (i = optind; i < argc; i++) {
char *file = argv[i];
- int const sjval = setjmp(jmpenv);
int len;

/*
@@ -617,28 +635,16 @@ main(int argc, char *argv[])
strcmp(file + (len - ftrace_size), ftrace) == 0)
continue;

- switch (sjval) {
- default:
- fprintf(stderr, "internal error: %s\n", file);
- exit(1);
- break;
- case SJ_SETJMP: /* normal sequence */
- /* Avoid problems if early cleanup() */
- fd_map = -1;
- mmap_failed = 1;
- file_map = NULL;
- file_ptr = NULL;
- file_updated = 0;
- do_file(file);
- break;
- case SJ_FAIL: /* error in do_file or below */
+ /* Avoid problems if early cleanup() */
+ fd_map = -1;
+ mmap_failed = 1;
+ file_map = NULL;
+ file_ptr = NULL;
+ file_updated = 0;
+ if (do_file(file)) {
fprintf(stderr, "%s: failed\n", file);
++n_error;
- break;
- case SJ_SUCCEED: /* premature success */
- /* do nothing */
- break;
- } /* end switch */
+ }
}
return !!n_error;
}
diff --git a/scripts/recordmcount.h b/scripts/recordmcount.h
index 690fa86ded59..f863d6fce066 100644
--- a/scripts/recordmcount.h
+++ b/scripts/recordmcount.h
@@ -24,7 +24,9 @@
#undef mcount_adjust
#undef sift_rel_mcount
#undef nop_mcount
+#undef missing_sym
#undef find_secsym_ndx
+#undef already_has_rel_mcount
#undef __has_rel_mcount
#undef has_rel_mcount
#undef tot_relsize
@@ -54,7 +56,9 @@
# define append_func append64
# define sift_rel_mcount sift64_rel_mcount
# define nop_mcount nop_mcount_64
+# define missing_sym missing_sym_64
# define find_secsym_ndx find64_secsym_ndx
+# define already_has_rel_mcount already_has_rel_mcount_64
# define __has_rel_mcount __has64_rel_mcount
# define has_rel_mcount has64_rel_mcount
# define tot_relsize tot64_relsize
@@ -87,7 +91,9 @@
# define append_func append32
# define sift_rel_mcount sift32_rel_mcount
# define nop_mcount nop_mcount_32
+# define missing_sym missing_sym_32
# define find_secsym_ndx find32_secsym_ndx
+# define already_has_rel_mcount already_has_rel_mcount_32
# define __has_rel_mcount __has32_rel_mcount
# define has_rel_mcount has32_rel_mcount
# define tot_relsize tot32_relsize
@@ -174,7 +180,7 @@ static int MIPS_is_fake_mcount(Elf_Rel const *rp)
}

/* Append the new shstrtab, Elf_Shdr[], __mcount_loc and its relocations. */
-static void append_func(Elf_Ehdr *const ehdr,
+static int append_func(Elf_Ehdr *const ehdr,
Elf_Shdr *const shstr,
uint_t const *const mloc0,
uint_t const *const mlocp,
@@ -202,15 +208,20 @@ static void append_func(Elf_Ehdr *const ehdr,
new_e_shoff = t;

/* body for new shstrtab */
- ulseek(sb.st_size, SEEK_SET);
- uwrite(old_shstr_sh_offset + (void *)ehdr, old_shstr_sh_size);
- uwrite(mc_name, 1 + strlen(mc_name));
+ if (ulseek(sb.st_size, SEEK_SET) < 0)
+ return -1;
+ if (uwrite(old_shstr_sh_offset + (void *)ehdr, old_shstr_sh_size) < 0)
+ return -1;
+ if (uwrite(mc_name, 1 + strlen(mc_name)) < 0)
+ return -1;

/* old(modified) Elf_Shdr table, word-byte aligned */
- ulseek(t, SEEK_SET);
+ if (ulseek(t, SEEK_SET) < 0)
+ return -1;
t += sizeof(Elf_Shdr) * old_shnum;
- uwrite(old_shoff + (void *)ehdr,
- sizeof(Elf_Shdr) * old_shnum);
+ if (uwrite(old_shoff + (void *)ehdr,
+ sizeof(Elf_Shdr) * old_shnum) < 0)
+ return -1;

/* new sections __mcount_loc and .rel__mcount_loc */
t += 2*sizeof(mcsec);
@@ -225,7 +236,8 @@ static void append_func(Elf_Ehdr *const ehdr,
mcsec.sh_info = 0;
mcsec.sh_addralign = _w(_size);
mcsec.sh_entsize = _w(_size);
- uwrite(&mcsec, sizeof(mcsec));
+ if (uwrite(&mcsec, sizeof(mcsec)) < 0)
+ return -1;

mcsec.sh_name = w(old_shstr_sh_size);
mcsec.sh_type = (sizeof(Elf_Rela) == rel_entsize)
@@ -239,15 +251,22 @@ static void append_func(Elf_Ehdr *const ehdr,
mcsec.sh_info = w(old_shnum);
mcsec.sh_addralign = _w(_size);
mcsec.sh_entsize = _w(rel_entsize);
- uwrite(&mcsec, sizeof(mcsec));

- uwrite(mloc0, (void *)mlocp - (void *)mloc0);
- uwrite(mrel0, (void *)mrelp - (void *)mrel0);
+ if (uwrite(&mcsec, sizeof(mcsec)) < 0)
+ return -1;
+
+ if (uwrite(mloc0, (void *)mlocp - (void *)mloc0) < 0)
+ return -1;
+ if (uwrite(mrel0, (void *)mrelp - (void *)mrel0) < 0)
+ return -1;

ehdr->e_shoff = _w(new_e_shoff);
ehdr->e_shnum = w2(2 + w2(ehdr->e_shnum)); /* {.rel,}__mcount_loc */
- ulseek(0, SEEK_SET);
- uwrite(ehdr, sizeof(*ehdr));
+ if (ulseek(0, SEEK_SET) < 0)
+ return -1;
+ if (uwrite(ehdr, sizeof(*ehdr)) < 0)
+ return -1;
+ return 0;
}

static unsigned get_mcountsym(Elf_Sym const *const sym0,
@@ -350,9 +369,9 @@ static uint_t *sift_rel_mcount(uint_t *mlocp,
* that are not going to be traced. The mcount calls here will be converted
* into nops.
*/
-static void nop_mcount(Elf_Shdr const *const relhdr,
- Elf_Ehdr const *const ehdr,
- const char *const txtname)
+static int nop_mcount(Elf_Shdr const *const relhdr,
+ Elf_Ehdr const *const ehdr,
+ const char *const txtname)
{
Elf_Shdr *const shdr0 = (Elf_Shdr *)(_w(ehdr->e_shoff)
+ (void *)ehdr);
@@ -375,15 +394,18 @@ static void nop_mcount(Elf_Shdr const *const relhdr,
mcountsym = get_mcountsym(sym0, relp, str0);

if (mcountsym == Elf_r_sym(relp) && !is_fake_mcount(relp)) {
- if (make_nop)
+ if (make_nop) {
ret = make_nop((void *)ehdr, _w(shdr->sh_offset) + _w(relp->r_offset));
+ if (ret < 0)
+ return -1;
+ }
if (warn_on_notrace_sect && !once) {
printf("Section %s has mcount callers being ignored\n",
txtname);
once = 1;
/* just warn? */
if (!make_nop)
- return;
+ return 0;
}
}

@@ -395,13 +417,17 @@ static void nop_mcount(Elf_Shdr const *const relhdr,
Elf_Rel rel;
rel = *(Elf_Rel *)relp;
Elf_r_info(&rel, Elf_r_sym(relp), rel_type_nop);
- ulseek((void *)relp - (void *)ehdr, SEEK_SET);
- uwrite(&rel, sizeof(rel));
+ if (ulseek((void *)relp - (void *)ehdr, SEEK_SET) < 0)
+ return -1;
+ if (uwrite(&rel, sizeof(rel)) < 0)
+ return -1;
}
relp = (Elf_Rel const *)(rel_entsize + (void *)relp);
}
+ return 0;
}

+static const unsigned int missing_sym = (unsigned int)-1;

/*
* Find a symbol in the given section, to be used as the base for relocating
@@ -442,9 +468,11 @@ static unsigned find_secsym_ndx(unsigned const txtndx,
}
fprintf(stderr, "Cannot find symbol for section %u: %s.\n",
txtndx, txtname);
- fail_file();
+ cleanup();
+ return missing_sym;
}

+char const *already_has_rel_mcount = "success"; /* our work here is done! */

/* Evade ISO C restriction: no declaration after statement in has_rel_mcount. */
static char const *
@@ -460,7 +488,8 @@ __has_rel_mcount(Elf_Shdr const *const relhdr, /* is SHT_REL or SHT_RELA */
if (strcmp("__mcount_loc", txtname) == 0) {
fprintf(stderr, "warning: __mcount_loc already exists: %s\n",
fname);
- succeed_file();
+ cleanup();
+ return already_has_rel_mcount;
}
if (w(txthdr->sh_type) != SHT_PROGBITS ||
!(_w(txthdr->sh_flags) & SHF_EXECINSTR))
@@ -490,6 +519,10 @@ static unsigned tot_relsize(Elf_Shdr const *const shdr0,

for (; nhdr; --nhdr, ++shdrp) {
txtname = has_rel_mcount(shdrp, shdr0, shstrtab, fname);
+ if (txtname == already_has_rel_mcount) {
+ totrelsz = 0;
+ break;
+ }
if (txtname && is_mcounted_section_name(txtname))
totrelsz += _w(shdrp->sh_size);
}
@@ -498,7 +531,7 @@ static unsigned tot_relsize(Elf_Shdr const *const shdr0,


/* Overall supervision for Elf32 ET_REL file. */
-static void
+static int
do_func(Elf_Ehdr *const ehdr, char const *const fname, unsigned const reltype)
{
Elf_Shdr *const shdr0 = (Elf_Shdr *)(_w(ehdr->e_shoff)
@@ -512,26 +545,53 @@ do_func(Elf_Ehdr *const ehdr, char const *const fname, unsigned const reltype)
unsigned k;

/* Upper bound on space: assume all relevant relocs are for mcount. */
- unsigned const totrelsz = tot_relsize(shdr0, nhdr, shstrtab, fname);
- Elf_Rel *const mrel0 = umalloc(totrelsz);
- Elf_Rel * mrelp = mrel0;
+ unsigned totrelsz;

- /* 2*sizeof(address) <= sizeof(Elf_Rel) */
- uint_t *const mloc0 = umalloc(totrelsz>>1);
- uint_t * mlocp = mloc0;
+ Elf_Rel * mrel0;
+ Elf_Rel * mrelp;
+
+ uint_t * mloc0;
+ uint_t * mlocp;

unsigned rel_entsize = 0;
unsigned symsec_sh_link = 0;

+ int result = 0;
+
+ totrelsz = tot_relsize(shdr0, nhdr, shstrtab, fname);
+ if (totrelsz == 0)
+ return 0;
+ mrel0 = umalloc(totrelsz);
+ mrelp = mrel0;
+ if (!mrel0)
+ return -1;
+
+ /* 2*sizeof(address) <= sizeof(Elf_Rel) */
+ mloc0 = umalloc(totrelsz>>1);
+ mlocp = mloc0;
+ if (!mloc0) {
+ free(mrel0);
+ return -1;
+ }
+
for (relhdr = shdr0, k = nhdr; k; --k, ++relhdr) {
char const *const txtname = has_rel_mcount(relhdr, shdr0,
shstrtab, fname);
+ if (txtname == already_has_rel_mcount) {
+ result = 0;
+ file_updated = 0;
+ goto out; /* Nothing to be done; don't append! */
+ }
if (txtname && is_mcounted_section_name(txtname)) {
uint_t recval = 0;
- unsigned const recsym = find_secsym_ndx(
+ unsigned const int recsym = find_secsym_ndx(
w(relhdr->sh_info), txtname, &recval,
&shdr0[symsec_sh_link = w(relhdr->sh_link)],
ehdr);
+ if (recsym == missing_sym) {
+ result = -1;
+ goto out;
+ }

rel_entsize = _w(relhdr->sh_entsize);
mlocp = sift_rel_mcount(mlocp,
@@ -542,13 +602,17 @@ do_func(Elf_Ehdr *const ehdr, char const *const fname, unsigned const reltype)
* This section is ignored by ftrace, but still
* has mcount calls. Convert them to nops now.
*/
- nop_mcount(relhdr, ehdr, txtname);
+ if (nop_mcount(relhdr, ehdr, txtname) < 0) {
+ result = -1;
+ goto out;
+ }
}
}
- if (mloc0 != mlocp) {
- append_func(ehdr, shstr, mloc0, mlocp, mrel0, mrelp,
- rel_entsize, symsec_sh_link);
- }
+ if (!result && mloc0 != mlocp)
+ result = append_func(ehdr, shstr, mloc0, mlocp, mrel0, mrelp,
+ rel_entsize, symsec_sh_link);
+out:
free(mrel0);
free(mloc0);
+ return result;
}
--
2.20.1

2019-06-12 04:57:14

by Matt Helsley

[permalink] [raw]
Subject: [PATCH v2 05/13] recordmcount: Kernel style function signature formatting

The uwrite() and ulseek() functions are formatted inconsistently
with the rest of the file and the kernel overall. While we're
making other changes here let's fix this.

Signed-off-by: Matt Helsley <[email protected]>
---
scripts/recordmcount.c | 21 +++++++--------------
scripts/recordmcount.h | 13 ++++++-------
2 files changed, 13 insertions(+), 21 deletions(-)

diff --git a/scripts/recordmcount.c b/scripts/recordmcount.c
index 584dcbf3f320..1c3599f07f9b 100644
--- a/scripts/recordmcount.c
+++ b/scripts/recordmcount.c
@@ -52,8 +52,7 @@ static void *file_append; /* added to the end of the file */
static size_t file_append_size; /* how much is added to end of file */

/* Per-file resource cleanup when multiple files. */
-static void
-cleanup(void)
+static void cleanup(void)
{
if (!mmap_failed)
munmap(file_map, sb.st_size);
@@ -68,8 +67,7 @@ cleanup(void)

/* ulseek, uwrite, ...: Check return value for errors. */

-static off_t
-ulseek(off_t const offset, int const whence)
+static off_t ulseek(off_t const offset, int const whence)
{
switch (whence) {
case SEEK_SET:
@@ -89,8 +87,7 @@ ulseek(off_t const offset, int const whence)
return file_ptr - file_map;
}

-static ssize_t
-uwrite(void const *const buf, size_t const count)
+static ssize_t uwrite(void const *const buf, size_t const count)
{
size_t cnt = count;
off_t idx = 0;
@@ -127,8 +124,7 @@ uwrite(void const *const buf, size_t const count)
return count;
}

-static void *
-umalloc(size_t size)
+static void * umalloc(size_t size)
{
void *const addr = malloc(size);
if (addr == 0) {
@@ -394,8 +390,7 @@ static uint32_t (*w)(uint32_t);
static uint32_t (*w2)(uint16_t);

/* Names of the sections that could contain calls to mcount. */
-static int
-is_mcounted_section_name(char const *const txtname)
+static int is_mcounted_section_name(char const *const txtname)
{
return strncmp(".text", txtname, 5) == 0 ||
strcmp(".init.text", txtname) == 0 ||
@@ -446,8 +441,7 @@ static void MIPS64_r_info(Elf64_Rel *const rp, unsigned sym, unsigned type)
}).r_info;
}

-static int
-do_file(char const *const fname)
+static int do_file(char const *const fname)
{
Elf32_Ehdr *const ehdr = mmap_file(fname);
unsigned int reltype = 0;
@@ -595,8 +589,7 @@ do_file(char const *const fname)
return rc;
}

-int
-main(int argc, char *argv[])
+int main(int argc, char *argv[])
{
const char ftrace[] = "/ftrace.o";
int ftrace_size = sizeof(ftrace) - 1;
diff --git a/scripts/recordmcount.h b/scripts/recordmcount.h
index f863d6fce066..3198459f7431 100644
--- a/scripts/recordmcount.h
+++ b/scripts/recordmcount.h
@@ -475,11 +475,10 @@ static unsigned find_secsym_ndx(unsigned const txtndx,
char const *already_has_rel_mcount = "success"; /* our work here is done! */

/* Evade ISO C restriction: no declaration after statement in has_rel_mcount. */
-static char const *
-__has_rel_mcount(Elf_Shdr const *const relhdr, /* is SHT_REL or SHT_RELA */
- Elf_Shdr const *const shdr0,
- char const *const shstrtab,
- char const *const fname)
+static char const * __has_rel_mcount(Elf_Shdr const *const relhdr, /* reltype */
+ Elf_Shdr const *const shdr0,
+ char const *const shstrtab,
+ char const *const fname)
{
/* .sh_info depends on .sh_type == SHT_REL[,A] */
Elf_Shdr const *const txthdr = &shdr0[w(relhdr->sh_info)];
@@ -531,8 +530,8 @@ static unsigned tot_relsize(Elf_Shdr const *const shdr0,


/* Overall supervision for Elf32 ET_REL file. */
-static int
-do_func(Elf_Ehdr *const ehdr, char const *const fname, unsigned const reltype)
+static int do_func(Elf_Ehdr *const ehdr, char const *const fname,
+ unsigned const reltype)
{
Elf_Shdr *const shdr0 = (Elf_Shdr *)(_w(ehdr->e_shoff)
+ (void *)ehdr);
--
2.20.1

2019-06-12 04:57:50

by Matt Helsley

[permalink] [raw]
Subject: [PATCH v2 06/13] recordmcount: Kernel style formatting

Fix up the whitespace irregularity in the ELF switch
blocks.

Swapping the initial value of gpfx allows us to
simplify all but one of the one-line switch cases even
further.

Signed-off-by: Matt Helsley <[email protected]>
---
scripts/recordmcount.c | 47 ++++++++++++++++++++++--------------------
1 file changed, 25 insertions(+), 22 deletions(-)

diff --git a/scripts/recordmcount.c b/scripts/recordmcount.c
index 1c3599f07f9b..9ae975ccf2dc 100644
--- a/scripts/recordmcount.c
+++ b/scripts/recordmcount.c
@@ -487,15 +487,15 @@ static int do_file(char const *const fname)
push_bl_mcount_thumb = push_bl_mcount_thumb_be;
break;
} /* end switch */
- if (memcmp(ELFMAG, ehdr->e_ident, SELFMAG) != 0
- || w2(ehdr->e_type) != ET_REL
- || ehdr->e_ident[EI_VERSION] != EV_CURRENT) {
+ if (memcmp(ELFMAG, ehdr->e_ident, SELFMAG) != 0 ||
+ w2(ehdr->e_type) != ET_REL ||
+ ehdr->e_ident[EI_VERSION] != EV_CURRENT) {
fprintf(stderr, "unrecognized ET_REL file %s\n", fname);
cleanup();
goto out;
}

- gpfx = 0;
+ gpfx = '_';
switch (w2(ehdr->e_machine)) {
default:
fprintf(stderr, "unrecognized e_machine %u %s\n",
@@ -508,32 +508,35 @@ static int do_file(char const *const fname)
make_nop = make_nop_x86;
ideal_nop = ideal_nop5_x86_32;
mcount_adjust_32 = -1;
+ gpfx = 0;
+ break;
+ case EM_ARM:
+ reltype = R_ARM_ABS32;
+ altmcount = "__gnu_mcount_nc";
+ make_nop = make_nop_arm;
+ rel_type_nop = R_ARM_NONE;
+ gpfx = 0;
break;
- case EM_ARM: reltype = R_ARM_ABS32;
- altmcount = "__gnu_mcount_nc";
- make_nop = make_nop_arm;
- rel_type_nop = R_ARM_NONE;
- break;
case EM_AARCH64:
- reltype = R_AARCH64_ABS64;
- make_nop = make_nop_arm64;
- rel_type_nop = R_AARCH64_NONE;
- ideal_nop = ideal_nop4_arm64;
- gpfx = '_';
- break;
- case EM_IA_64: reltype = R_IA64_IMM64; gpfx = '_'; break;
- case EM_MIPS: /* reltype: e_class */ gpfx = '_'; break;
- case EM_PPC: reltype = R_PPC_ADDR32; gpfx = '_'; break;
- case EM_PPC64: reltype = R_PPC64_ADDR64; gpfx = '_'; break;
- 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;
+ reltype = R_AARCH64_ABS64;
+ make_nop = make_nop_arm64;
+ rel_type_nop = R_AARCH64_NONE;
+ ideal_nop = ideal_nop4_arm64;
+ break;
+ case EM_IA_64: reltype = R_IA64_IMM64; break;
+ case EM_MIPS: /* reltype: e_class */ break;
+ case EM_PPC: reltype = R_PPC_ADDR32; break;
+ case EM_PPC64: reltype = R_PPC64_ADDR64; break;
+ case EM_S390: /* reltype: e_class */ break;
+ case EM_SH: reltype = R_SH_DIR32; gpfx = 0; break;
+ case EM_SPARCV9: reltype = R_SPARC_64; break;
case EM_X86_64:
make_nop = make_nop_x86;
ideal_nop = ideal_nop5_x86_64;
reltype = R_X86_64_64;
rel_type_nop = R_X86_64_NONE;
mcount_adjust_64 = -1;
+ gpfx = 0;
break;
} /* end switch */

--
2.20.1

2019-06-12 04:59:32

by Matt Helsley

[permalink] [raw]
Subject: [PATCH v2 09/13] objtool: Prepare to merge recordmcount

Move recordmcount into the objtool directory. We keep this step separate
so changes which turn recordmcount into a subcommand of objtool don't
get obscured.

Signed-off-by: Matt Helsley <[email protected]>
---
scripts/.gitignore | 1 -
scripts/Makefile | 1 -
scripts/Makefile.build | 11 ++++++-----
tools/objtool/.gitignore | 1 +
tools/objtool/Build | 2 ++
tools/objtool/Makefile | 13 ++++++++++++-
{scripts => tools/objtool}/recordmcount.c | 0
{scripts => tools/objtool}/recordmcount.h | 0
{scripts => tools/objtool}/recordmcount.pl | 0
9 files changed, 21 insertions(+), 8 deletions(-)
rename {scripts => tools/objtool}/recordmcount.c (100%)
rename {scripts => tools/objtool}/recordmcount.h (100%)
rename {scripts => tools/objtool}/recordmcount.pl (100%)

diff --git a/scripts/.gitignore b/scripts/.gitignore
index 17f8cef88fa8..1b5b5d595d80 100644
--- a/scripts/.gitignore
+++ b/scripts/.gitignore
@@ -6,7 +6,6 @@ conmakehash
kallsyms
pnmtologo
unifdef
-recordmcount
sortextable
asn1_compiler
extract-cert
diff --git a/scripts/Makefile b/scripts/Makefile
index 9d442ee050bd..5fca50fee42b 100644
--- a/scripts/Makefile
+++ b/scripts/Makefile
@@ -14,7 +14,6 @@ hostprogs-$(CONFIG_BUILD_BIN2C) += bin2c
hostprogs-$(CONFIG_KALLSYMS) += kallsyms
hostprogs-$(CONFIG_LOGO) += pnmtologo
hostprogs-$(CONFIG_VT) += conmakehash
-hostprogs-$(BUILD_C_RECORDMCOUNT) += recordmcount
hostprogs-$(CONFIG_BUILDTIME_EXTABLE_SORT) += sortextable
hostprogs-$(CONFIG_ASN1) += asn1_compiler
hostprogs-$(CONFIG_MODULE_SIG) += sign-file
diff --git a/scripts/Makefile.build b/scripts/Makefile.build
index ae9cf740633e..f32cfe63bb0e 100644
--- a/scripts/Makefile.build
+++ b/scripts/Makefile.build
@@ -186,18 +186,19 @@ endif
# files, including recordmcount.
sub_cmd_record_mcount = \
if [ $(@) != "scripts/mod/empty.o" ]; then \
- $(objtree)/scripts/recordmcount $(RECORDMCOUNT_FLAGS) "$(@)"; \
+ $(objtree)/tools/objtool/recordmcount $(RECORDMCOUNT_FLAGS) "$(@)"; \
fi;
-recordmcount_source := $(srctree)/scripts/recordmcount.c \
- $(srctree)/scripts/recordmcount.h
+
+recordmcount_source := $(srctree)/tools/objtool/recordmcount.c \
+ $(srctree)/tools/objtool/recordmcount.h
else
-sub_cmd_record_mcount = perl $(srctree)/scripts/recordmcount.pl "$(ARCH)" \
+sub_cmd_record_mcount = perl $(srctree)/tools/objtool/recordmcount.pl "$(ARCH)" \
"$(if $(CONFIG_CPU_BIG_ENDIAN),big,little)" \
"$(if $(CONFIG_64BIT),64,32)" \
"$(OBJDUMP)" "$(OBJCOPY)" "$(CC) $(KBUILD_CPPFLAGS) $(KBUILD_CFLAGS)" \
"$(LD) $(KBUILD_LDFLAGS)" "$(NM)" "$(RM)" "$(MV)" \
"$(if $(part-of-module),1,0)" "$(@)";
-recordmcount_source := $(srctree)/scripts/recordmcount.pl
+recordmcount_source := $(srctree)/tools/objtool/recordmcount.pl
endif # BUILD_C_RECORDMCOUNT
cmd_record_mcount = $(if $(findstring $(strip $(CC_FLAGS_FTRACE)),$(_c_flags)), \
$(sub_cmd_record_mcount))
diff --git a/tools/objtool/.gitignore b/tools/objtool/.gitignore
index 914cff12899b..ee471f353caa 100644
--- a/tools/objtool/.gitignore
+++ b/tools/objtool/.gitignore
@@ -1,3 +1,4 @@
arch/x86/lib/inat-tables.c
objtool
+recordmcount
fixdep
diff --git a/tools/objtool/Build b/tools/objtool/Build
index 749becdf5b90..78c4a8a2f9e7 100644
--- a/tools/objtool/Build
+++ b/tools/objtool/Build
@@ -20,3 +20,5 @@ $(OUTPUT)libstring.o: ../lib/string.c FORCE
$(OUTPUT)str_error_r.o: ../lib/str_error_r.c FORCE
$(call rule_mkdir)
$(call if_changed_dep,cc_o_c)
+
+recordmcount-y += recordmcount.o
diff --git a/tools/objtool/Makefile b/tools/objtool/Makefile
index 88158239622b..bd9d0b6534cf 100644
--- a/tools/objtool/Makefile
+++ b/tools/objtool/Makefile
@@ -29,6 +29,12 @@ OBJTOOL_IN := $(OBJTOOL)-in.o
LIBELF_FLAGS := $(shell pkg-config libelf --cflags 2>/dev/null)
LIBELF_LIBS := $(shell pkg-config libelf --libs 2>/dev/null || echo -lelf)

+RECORDMCOUNT := $(OUTPUT)recordmcount
+RECORDMCOUNT_IN := $(RECORDMCOUNT)-in.o
+ifeq ($(BUILD_C_RECORDMCOUNT),y)
+all: $(RECORDMCOUNT)
+endif
+
all: $(OBJTOOL)

INCLUDES := -I$(srctree)/tools/include \
@@ -49,16 +55,21 @@ include $(srctree)/tools/build/Makefile.include
$(OBJTOOL_IN): fixdep FORCE
@$(MAKE) $(build)=objtool

+$(RECORDMCOUNT_IN): fixdep FORCE
+ @$(MAKE) $(build)=recordmcount
+
$(OBJTOOL): $(LIBSUBCMD) $(OBJTOOL_IN)
@$(CONFIG_SHELL) ./sync-check.sh
$(QUIET_LINK)$(CC) $(OBJTOOL_IN) $(LDFLAGS) -o $@

+$(RECORDMCOUNT): $(RECORDMCOUNT_IN)
+ $(QUIET_LINK)$(CC) $(RECORDMCOUNT_IN) $(KBUILD_HOSTLDFLAGS) -o $@

$(LIBSUBCMD): fixdep FORCE
$(Q)$(MAKE) -C $(SUBCMD_SRCDIR) OUTPUT=$(LIBSUBCMD_OUTPUT)

clean:
- $(call QUIET_CLEAN, objtool) $(RM) $(OBJTOOL)
+ $(call QUIET_CLEAN, objtool) $(RM) $(OBJTOOL) $(RECORDMCOUNT)
$(Q)find $(OUTPUT) -name '*.o' -delete -o -name '\.*.cmd' -delete -o -name '\.*.d' -delete
$(Q)$(RM) $(OUTPUT)arch/x86/lib/inat-tables.c $(OUTPUT)fixdep

diff --git a/scripts/recordmcount.c b/tools/objtool/recordmcount.c
similarity index 100%
rename from scripts/recordmcount.c
rename to tools/objtool/recordmcount.c
diff --git a/scripts/recordmcount.h b/tools/objtool/recordmcount.h
similarity index 100%
rename from scripts/recordmcount.h
rename to tools/objtool/recordmcount.h
diff --git a/scripts/recordmcount.pl b/tools/objtool/recordmcount.pl
similarity index 100%
rename from scripts/recordmcount.pl
rename to tools/objtool/recordmcount.pl
--
2.20.1

2019-06-12 05:00:43

by Matt Helsley

[permalink] [raw]
Subject: [PATCH v2 07/13] recordmcount: Remove redundant cleanup() calls

Redundant cleanup calls were introduced when transitioning from
the old error/success handling via setjmp/longjmp -- the longjmp
ensured the cleanup() call only happened once but replacing
the success_file()/fail_file() calls with cleanup() meant that
multiple cleanup() calls can happen as we return from function
calls.

In do_file(), looking just before and after the "goto out" jumps we
can see that multiple cleanups() are being performed. We remove
cleanup() calls from the nested functions because it makes the code
easier to review -- the resources being cleaned up are generally
allocated and initialized in the callers so freeing them there
makes more sense.

Other redundant cleanup() calls:

mmap_file() is only called from do_file() and, if mmap_file() fails,
then we goto out and do cleanup() there too.

write_file() is only called from do_file() and do_file()
calls cleanup() unconditionally after returning from write_file()
therefore the cleanup() calls in write_file() are not necessary.

find_secsym_ndx(), called from do_func()'s for-loop, when we are
cleaning up here it's obvious that we break out of the loop and
do another cleanup().

__has_rel_mcount() is called from two parts of do_func()
and calls cleanup(). In theory we move them into do_func(), however
these in turn prove redundant so another simplification step
removes them as well.

Signed-off-by: Matt Helsley <[email protected]>
---
scripts/recordmcount.c | 13 -------------
scripts/recordmcount.h | 2 --
2 files changed, 15 deletions(-)

diff --git a/scripts/recordmcount.c b/scripts/recordmcount.c
index 9ae975ccf2dc..111419c282d3 100644
--- a/scripts/recordmcount.c
+++ b/scripts/recordmcount.c
@@ -258,17 +258,14 @@ static void *mmap_file(char const *fname)
fd_map = open(fname, O_RDONLY);
if (fd_map < 0) {
perror(fname);
- cleanup();
return NULL;
}
if (fstat(fd_map, &sb) < 0) {
perror(fname);
- cleanup();
goto out;
}
if (!S_ISREG(sb.st_mode)) {
fprintf(stderr, "not a regular file: %s\n", fname);
- cleanup();
goto out;
}
file_map = mmap(0, sb.st_size, PROT_READ|PROT_WRITE, MAP_PRIVATE,
@@ -314,13 +311,11 @@ static int write_file(const char *fname)
fd_map = open(tmp_file, O_WRONLY | O_TRUNC | O_CREAT, sb.st_mode);
if (fd_map < 0) {
perror(fname);
- cleanup();
return -1;
}
n = write(fd_map, file_map, sb.st_size);
if (n != sb.st_size) {
perror("write");
- cleanup();
close(fd_map);
return -1;
}
@@ -328,7 +323,6 @@ static int write_file(const char *fname)
n = write(fd_map, file_append, file_append_size);
if (n != file_append_size) {
perror("write");
- cleanup();
close(fd_map);
return -1;
}
@@ -336,7 +330,6 @@ static int write_file(const char *fname)
close(fd_map);
if (rename(tmp_file, fname) < 0) {
perror(fname);
- cleanup();
return -1;
}
return 0;
@@ -458,7 +451,6 @@ static int do_file(char const *const fname)
default:
fprintf(stderr, "unrecognized ELF data encoding %d: %s\n",
ehdr->e_ident[EI_DATA], fname);
- cleanup();
goto out;
case ELFDATA2LSB:
if (*(unsigned char const *)&endian != 1) {
@@ -491,7 +483,6 @@ static int do_file(char const *const fname)
w2(ehdr->e_type) != ET_REL ||
ehdr->e_ident[EI_VERSION] != EV_CURRENT) {
fprintf(stderr, "unrecognized ET_REL file %s\n", fname);
- cleanup();
goto out;
}

@@ -500,7 +491,6 @@ static int do_file(char const *const fname)
default:
fprintf(stderr, "unrecognized e_machine %u %s\n",
w2(ehdr->e_machine), fname);
- cleanup();
goto out;
case EM_386:
reltype = R_386_32;
@@ -544,14 +534,12 @@ static int do_file(char const *const fname)
default:
fprintf(stderr, "unrecognized ELF class %d %s\n",
ehdr->e_ident[EI_CLASS], fname);
- cleanup();
goto out;
case ELFCLASS32:
if (w2(ehdr->e_ehsize) != sizeof(Elf32_Ehdr)
|| w2(ehdr->e_shentsize) != sizeof(Elf32_Shdr)) {
fprintf(stderr,
"unrecognized ET_REL file: %s\n", fname);
- cleanup();
goto out;
}
if (w2(ehdr->e_machine) == EM_MIPS) {
@@ -567,7 +555,6 @@ static int do_file(char const *const fname)
|| w2(ghdr->e_shentsize) != sizeof(Elf64_Shdr)) {
fprintf(stderr,
"unrecognized ET_REL file: %s\n", fname);
- cleanup();
goto out;
}
if (w2(ghdr->e_machine) == EM_S390) {
diff --git a/scripts/recordmcount.h b/scripts/recordmcount.h
index 3198459f7431..b7348f1af758 100644
--- a/scripts/recordmcount.h
+++ b/scripts/recordmcount.h
@@ -468,7 +468,6 @@ static unsigned find_secsym_ndx(unsigned const txtndx,
}
fprintf(stderr, "Cannot find symbol for section %u: %s.\n",
txtndx, txtname);
- cleanup();
return missing_sym;
}

@@ -487,7 +486,6 @@ static char const * __has_rel_mcount(Elf_Shdr const *const relhdr, /* reltype */
if (strcmp("__mcount_loc", txtname) == 0) {
fprintf(stderr, "warning: __mcount_loc already exists: %s\n",
fname);
- cleanup();
return already_has_rel_mcount;
}
if (w(txthdr->sh_type) != SHT_PROGBITS ||
--
2.20.1

2019-06-12 05:00:48

by Matt Helsley

[permalink] [raw]
Subject: [PATCH v2 10/13] objtool: Make recordmcount into an objtool subcmd

Rather than a standalone executable merge recordmcount as a sub command
of objtool. This is a small step towards cleaning up recordmcount and
eventually saving ELF code with objtool.

For the initial step all that's required is a bit of Makefile changes
and invoking the former main() function from recordmcount.c because the
subcommand code uses similar function arguments as main when dispatching.

objtool ignores some object files that tracing does not, specifically
those with OBJECT_FILES_NON_STANDARD Makefile variables. For this reason
we keep the recordmcount_dep separate from the objtool_dep. When using
objtool mcount we can also, like the other objtool invocations, just
depend on the binary rather than the source the binary is built from.

Subsequent patches will gradually convert recordmcount to use
more and more of libelf/objtool's ELF accessor code. This will both
clean up recordmcount to be more easily readable and remove
recordmcount's crude accessor wrapping code.

Signed-off-by: Matt Helsley <[email protected]>
---
Makefile | 6 +--
scripts/Makefile.build | 24 ++++++------
tools/objtool/Build | 3 +-
tools/objtool/Makefile | 12 +-----
tools/objtool/builtin-mcount.c | 72 ++++++++++++++++++++++++++++++++++
tools/objtool/builtin-mcount.h | 23 +++++++++++
tools/objtool/builtin.h | 1 +
tools/objtool/objtool.c | 1 +
tools/objtool/recordmcount.c | 29 +++++---------
9 files changed, 123 insertions(+), 48 deletions(-)
create mode 100644 tools/objtool/builtin-mcount.c
create mode 100644 tools/objtool/builtin-mcount.h

diff --git a/Makefile b/Makefile
index b81e17261250..b2b20057deab 100644
--- a/Makefile
+++ b/Makefile
@@ -813,11 +813,11 @@ KBUILD_CFLAGS += $(CC_FLAGS_FTRACE) $(CC_FLAGS_USING)
KBUILD_AFLAGS += $(CC_FLAGS_USING)
ifdef CONFIG_DYNAMIC_FTRACE
ifdef CONFIG_HAVE_C_RECORDMCOUNT
- BUILD_C_RECORDMCOUNT := y
- export BUILD_C_RECORDMCOUNT
+ USE_OBJTOOL_MCOUNT := y
+ export USE_OBJTOOL_MCOUNT
endif
endif
-endif
+endif # CONFIG_FUNCTION_TRACER

# We trigger additional mismatches with less inlining
ifdef CONFIG_DEBUG_SECTION_MISMATCH
diff --git a/scripts/Makefile.build b/scripts/Makefile.build
index f32cfe63bb0e..98034b21bf48 100644
--- a/scripts/Makefile.build
+++ b/scripts/Makefile.build
@@ -175,22 +175,21 @@ endif

ifdef CONFIG_FTRACE_MCOUNT_RECORD
ifndef CC_USING_RECORD_MCOUNT
-# compiler will not generate __mcount_loc use recordmcount or recordmcount.pl
-ifdef BUILD_C_RECORDMCOUNT
+# compiler will not generate __mcount_loc use objtool mcount record or recordmcount.pl
+ifdef USE_OBJTOOL_MCOUNT
ifeq ("$(origin RECORDMCOUNT_WARN)", "command line")
RECORDMCOUNT_FLAGS = -w
endif
# Due to recursion, we must skip empty.o.
# The empty.o file is created in the make process in order to determine
# the target endianness and word size. It is made before all other C
-# files, including recordmcount.
+# files, including objtool.
sub_cmd_record_mcount = \
if [ $(@) != "scripts/mod/empty.o" ]; then \
- $(objtree)/tools/objtool/recordmcount $(RECORDMCOUNT_FLAGS) "$(@)"; \
+ $(objtree)/tools/objtool/objtool mcount record $(RECORDMCOUNT_FLAGS) "$(@)"; \
fi;

-recordmcount_source := $(srctree)/tools/objtool/recordmcount.c \
- $(srctree)/tools/objtool/recordmcount.h
+recordmcount_dep := $(objtree)/tools/objtool/objtool
else
sub_cmd_record_mcount = perl $(srctree)/tools/objtool/recordmcount.pl "$(ARCH)" \
"$(if $(CONFIG_CPU_BIG_ENDIAN),big,little)" \
@@ -198,8 +197,8 @@ sub_cmd_record_mcount = perl $(srctree)/tools/objtool/recordmcount.pl "$(ARCH)"
"$(OBJDUMP)" "$(OBJCOPY)" "$(CC) $(KBUILD_CPPFLAGS) $(KBUILD_CFLAGS)" \
"$(LD) $(KBUILD_LDFLAGS)" "$(NM)" "$(RM)" "$(MV)" \
"$(if $(part-of-module),1,0)" "$(@)";
-recordmcount_source := $(srctree)/tools/objtool/recordmcount.pl
-endif # BUILD_C_RECORDMCOUNT
+recordmcount_dep := $(srctree)/tools/objtool/recordmcount.pl
+endif # USE_OBJTOOL_MCOUNT
cmd_record_mcount = $(if $(findstring $(strip $(CC_FLAGS_FTRACE)),$(_c_flags)), \
$(sub_cmd_record_mcount))
endif # CC_USING_RECORD_MCOUNT
@@ -241,9 +240,10 @@ endif # SKIP_STACK_VALIDATION
endif # CONFIG_STACK_VALIDATION

# Rebuild all objects when objtool changes, or is enabled/disabled.
-objtool_dep = $(objtool_obj) \
+objtool_dep += $(objtool_obj) \
$(wildcard include/config/orc/unwinder.h \
- include/config/stack/validation.h)
+ include/config/stack/validation.h \
+ include/config/ftrace/mcount/record.h)

ifdef CONFIG_TRIM_UNUSED_KSYMS
cmd_gen_ksymdeps = \
@@ -275,13 +275,13 @@ cmd_undef_syms = echo
endif

# Built-in and composite module parts
-$(obj)/%.o: $(src)/%.c $(recordmcount_source) $(objtool_dep) FORCE
+$(obj)/%.o: $(src)/%.c $(recordmcount_dep) $(objtool_dep) FORCE
$(call cmd,force_checksrc)
$(call if_changed_rule,cc_o_c)

# Single-part modules are special since we need to mark them in $(MODVERDIR)

-$(single-used-m): $(obj)/%.o: $(src)/%.c $(recordmcount_source) $(objtool_dep) FORCE
+$(single-used-m): $(obj)/%.o: $(src)/%.c $(recordmcount_dep) $(objtool_dep) FORCE
$(call cmd,force_checksrc)
$(call if_changed_rule,cc_o_c)
@{ echo $(@:.o=.ko); echo $@; \
diff --git a/tools/objtool/Build b/tools/objtool/Build
index 78c4a8a2f9e7..85e125e14c0d 100644
--- a/tools/objtool/Build
+++ b/tools/objtool/Build
@@ -1,6 +1,7 @@
objtool-y += arch/$(SRCARCH)/
objtool-y += builtin-check.o
objtool-y += builtin-orc.o
+objtool-y += builtin-mcount.o recordmcount.o
objtool-y += check.o
objtool-y += orc_gen.o
objtool-y += orc_dump.o
@@ -20,5 +21,3 @@ $(OUTPUT)libstring.o: ../lib/string.c FORCE
$(OUTPUT)str_error_r.o: ../lib/str_error_r.c FORCE
$(call rule_mkdir)
$(call if_changed_dep,cc_o_c)
-
-recordmcount-y += recordmcount.o
diff --git a/tools/objtool/Makefile b/tools/objtool/Makefile
index bd9d0b6534cf..30f7e98ee8ef 100644
--- a/tools/objtool/Makefile
+++ b/tools/objtool/Makefile
@@ -29,12 +29,6 @@ OBJTOOL_IN := $(OBJTOOL)-in.o
LIBELF_FLAGS := $(shell pkg-config libelf --cflags 2>/dev/null)
LIBELF_LIBS := $(shell pkg-config libelf --libs 2>/dev/null || echo -lelf)

-RECORDMCOUNT := $(OUTPUT)recordmcount
-RECORDMCOUNT_IN := $(RECORDMCOUNT)-in.o
-ifeq ($(BUILD_C_RECORDMCOUNT),y)
-all: $(RECORDMCOUNT)
-endif
-
all: $(OBJTOOL)

INCLUDES := -I$(srctree)/tools/include \
@@ -55,21 +49,17 @@ include $(srctree)/tools/build/Makefile.include
$(OBJTOOL_IN): fixdep FORCE
@$(MAKE) $(build)=objtool

-$(RECORDMCOUNT_IN): fixdep FORCE
- @$(MAKE) $(build)=recordmcount

$(OBJTOOL): $(LIBSUBCMD) $(OBJTOOL_IN)
@$(CONFIG_SHELL) ./sync-check.sh
$(QUIET_LINK)$(CC) $(OBJTOOL_IN) $(LDFLAGS) -o $@

-$(RECORDMCOUNT): $(RECORDMCOUNT_IN)
- $(QUIET_LINK)$(CC) $(RECORDMCOUNT_IN) $(KBUILD_HOSTLDFLAGS) -o $@

$(LIBSUBCMD): fixdep FORCE
$(Q)$(MAKE) -C $(SUBCMD_SRCDIR) OUTPUT=$(LIBSUBCMD_OUTPUT)

clean:
- $(call QUIET_CLEAN, objtool) $(RM) $(OBJTOOL) $(RECORDMCOUNT)
+ $(call QUIET_CLEAN, objtool) $(RM) $(OBJTOOL)
$(Q)find $(OUTPUT) -name '*.o' -delete -o -name '\.*.cmd' -delete -o -name '\.*.d' -delete
$(Q)$(RM) $(OUTPUT)arch/x86/lib/inat-tables.c $(OUTPUT)fixdep

diff --git a/tools/objtool/builtin-mcount.c b/tools/objtool/builtin-mcount.c
new file mode 100644
index 000000000000..0ed014b82b9d
--- /dev/null
+++ b/tools/objtool/builtin-mcount.c
@@ -0,0 +1,72 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (C) 2019 Matt Helsley <[email protected]>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+/*
+ * objtool mcount:
+ *
+ * This command analyzes a .o file and constructs a table of the locations of
+ * calls to 'mcount' useful to ftrace. We can optionally append this table to
+ * the object file ("objtool mcount record foo.o") or output it separately
+ * ("objtool mcount show"). The latter can be used to compare the expected
+ * callers of mcount to those actually found.
+ */
+
+#include <string.h>
+#include <subcmd/parse-options.h>
+#include "builtin.h"
+
+#ifndef cmd_mcount
+#include "builtin-mcount.h"
+
+static const char * const mcount_usage[] = {
+ "objtool mcount record [<options>] file.o [file2.o ...]",
+ NULL,
+};
+
+bool warn_on_notrace_sect;
+
+const static struct option mcount_options[] = {
+ OPT_BOOLEAN('w', "warn-on-notrace-section", &warn_on_notrace_sect,
+ "Emit a warning when a section omitting mcount "
+ "(possibly due to \"notrace\" marking) is encountered"),
+ OPT_END(),
+};
+
+int cmd_mcount(int argc, const char **argv)
+{
+ argc--; argv++;
+ if (argc <= 0)
+ usage_with_options(mcount_usage, mcount_options);
+
+ if (!strncmp(argv[0], "rec", 3)) {
+ if (argc != 2)
+ usage_with_options(mcount_usage, mcount_options);
+
+ argc = parse_options(argc, argv,
+ mcount_options, mcount_usage, 0);
+ if (argc < 1)
+ usage_with_options(mcount_usage, mcount_options);
+
+ return record_mcount(argc, argv);
+ }
+
+ usage_with_options(mcount_usage, mcount_options);
+
+ return 0;
+}
+#endif /* !def cmd_mcount */
diff --git a/tools/objtool/builtin-mcount.h b/tools/objtool/builtin-mcount.h
new file mode 100644
index 000000000000..b7b508781127
--- /dev/null
+++ b/tools/objtool/builtin-mcount.h
@@ -0,0 +1,23 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (C) 2019 Matt Helsley <[email protected]>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+#ifndef BUILTIN_SUBCMD_MCOUNT
+#define BUILTIN_SUBCMD_MCOUNT 1
+
+extern int record_mcount(int argc, const char **argv);
+
+#endif /* BUILTIN_SUBCMD_MCOUNT */
diff --git a/tools/objtool/builtin.h b/tools/objtool/builtin.h
index a32736f8d2a4..125207c6a2fa 100644
--- a/tools/objtool/builtin.h
+++ b/tools/objtool/builtin.h
@@ -12,5 +12,6 @@ extern bool no_fp, no_unreachable, retpoline, module, backtrace, uaccess;

extern int cmd_check(int argc, const char **argv);
extern int cmd_orc(int argc, const char **argv);
+extern int cmd_mcount(int argc, const char **argv);

#endif /* _BUILTIN_H */
diff --git a/tools/objtool/objtool.c b/tools/objtool/objtool.c
index 0b3528f05053..a2c45e70d74f 100644
--- a/tools/objtool/objtool.c
+++ b/tools/objtool/objtool.c
@@ -35,6 +35,7 @@ static const char objtool_usage_string[] =
static struct cmd_struct objtool_cmds[] = {
{"check", cmd_check, "Perform stack metadata validation on an object file" },
{"orc", cmd_orc, "Generate in-place ORC unwind tables for an object file" },
+ {"mcount", cmd_mcount, "Construct a table of locations of calls to mcount. Useful for ftrace."},
};

bool help;
diff --git a/tools/objtool/recordmcount.c b/tools/objtool/recordmcount.c
index 9f4af109277e..2de31e2913d1 100644
--- a/tools/objtool/recordmcount.c
+++ b/tools/objtool/recordmcount.c
@@ -24,7 +24,6 @@
#include <sys/types.h>
#include <sys/mman.h>
#include <sys/stat.h>
-#include <getopt.h>
#include <elf.h>
#include <fcntl.h>
#include <stdio.h>
@@ -32,6 +31,8 @@
#include <string.h>
#include <unistd.h>

+#include "builtin-mcount.h"
+
#ifndef EM_AARCH64
#define EM_AARCH64 183
#define R_AARCH64_NONE 0
@@ -470,7 +471,7 @@ static int do_file(char const *const fname)
goto out;
case ELFDATA2LSB:
if (*(unsigned char const *)&endian != 1) {
- /* main() is big endian, file.o is little endian. */
+ /* objtool is big endian, file.o is little endian. */
w = w4rev;
w2 = w2rev;
w8 = w8rev;
@@ -483,7 +484,7 @@ static int do_file(char const *const fname)
break;
case ELFDATA2MSB:
if (*(unsigned char const *)&endian != 0) {
- /* main() is little endian, file.o is big endian. */
+ /* objtool is little endian, file.o is big endian. */
w = w4rev;
w2 = w2rev;
w8 = w8rev;
@@ -596,33 +597,21 @@ static int do_file(char const *const fname)
return rc;
}

-int main(int argc, char *argv[])
+int record_mcount(int argc, const 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 - optind) < 1) {
- fprintf(stderr, "usage: recordmcount [-w] file.o...\n");
+ if (argc < 1) {
+ fprintf(stderr, "usage: objtool mcount record [-w] file.o...\n");
return 0;
}

/* Process each file in turn, allowing deep failure. */
- for (i = optind; i < argc; i++) {
- char *file = argv[i];
+ for (i = 0; i < argc; i++) {
+ const char *file = argv[i];
int len;

/*
--
2.20.1

2019-06-12 05:01:11

by Matt Helsley

[permalink] [raw]
Subject: [PATCH v2 13/13] objtool: recordmcount: Convert do_func() relhdrs

Use objtool's ELF data structures to visit the relocation
sections in the top-level ELF file walking function, do_func().
This means we can pass pointers to the relocation header structures
into nested functions and avoid the indexing patterns for them.

These conversions don't use libelf/objtool to change the ELF
file -- it only changes the way we walk the ELF sections and
touch pages for memory mapping made by the old recordmcount code.

Signed-off-by: Matt Helsley <[email protected]>
---
tools/objtool/recordmcount.h | 70 ++++++++++++++++++------------------
1 file changed, 36 insertions(+), 34 deletions(-)

diff --git a/tools/objtool/recordmcount.h b/tools/objtool/recordmcount.h
index 03643c68486b..89688648c7cd 100644
--- a/tools/objtool/recordmcount.h
+++ b/tools/objtool/recordmcount.h
@@ -288,7 +288,7 @@ static unsigned get_mcountsym(Elf_Sym const *const sym0,
return mcountsym;
}

-static void get_sym_str_and_relp(Elf_Shdr const *const relhdr,
+static void get_sym_str_and_relp(GElf_Shdr const *const relhdr,
Elf_Ehdr const *const ehdr,
Elf_Sym const **sym0,
char const **str0,
@@ -296,10 +296,10 @@ static void get_sym_str_and_relp(Elf_Shdr const *const relhdr,
{
Elf_Shdr *const shdr0 = (Elf_Shdr *)(_w(ehdr->e_shoff)
+ (void *)ehdr);
- unsigned const symsec_sh_link = w(relhdr->sh_link);
+ unsigned const symsec_sh_link = relhdr->sh_link;
Elf_Shdr const *const symsec = &shdr0[symsec_sh_link];
- Elf_Shdr const *const strsec = &shdr0[w(symsec->sh_link)];
- Elf_Rel const *const rel0 = (Elf_Rel const *)(_w(relhdr->sh_offset)
+ Elf_Shdr const *const strsec = &shdr0[symsec->sh_link];
+ Elf_Rel const *const rel0 = (Elf_Rel const *)(relhdr->sh_offset
+ (void *)ehdr);

*sym0 = (Elf_Sym const *)(_w(symsec->sh_offset)
@@ -319,9 +319,9 @@ static void get_sym_str_and_relp(Elf_Shdr const *const relhdr,
static uint_t *sift_rel_mcount(uint_t *mlocp,
unsigned const offbase,
Elf_Rel **const mrelpp,
- Elf_Shdr const *const relhdr,
+ GElf_Shdr const *const relhdr,
Elf_Ehdr const *const ehdr,
- unsigned const recsym,
+ unsigned const recsym_index,
uint_t const recval,
unsigned const reltype)
{
@@ -330,8 +330,8 @@ static uint_t *sift_rel_mcount(uint_t *mlocp,
Elf_Sym const *sym0;
char const *str0;
Elf_Rel const *relp;
- unsigned rel_entsize = _w(relhdr->sh_entsize);
- unsigned const nrel = _w(relhdr->sh_size) / rel_entsize;
+ unsigned int rel_entsize = relhdr->sh_entsize;
+ unsigned const nrel = relhdr->sh_size / rel_entsize;
unsigned mcountsym = 0;
unsigned t;

@@ -346,7 +346,7 @@ static uint_t *sift_rel_mcount(uint_t *mlocp,
_w(_w(relp->r_offset) - recval + mcount_adjust);
mrelp->r_offset = _w(offbase
+ ((void *)mlocp - (void *)mloc0));
- Elf_r_info(mrelp, recsym, reltype);
+ Elf_r_info(mrelp, recsym_index, reltype);
if (rel_entsize == sizeof(Elf_Rela)) {
((Elf_Rela *)mrelp)->r_addend = addend;
*mlocp++ = 0;
@@ -366,7 +366,7 @@ static uint_t *sift_rel_mcount(uint_t *mlocp,
* that are not going to be traced. The mcount calls here will be converted
* into nops.
*/
-static int nop_mcount(Elf_Shdr const *const relhdr,
+static int nop_mcount(GElf_Shdr const *const relhdr,
Elf_Ehdr const *const ehdr,
const char *const txtname)
{
@@ -375,9 +375,9 @@ static int nop_mcount(Elf_Shdr const *const relhdr,
Elf_Sym const *sym0;
char const *str0;
Elf_Rel const *relp;
- Elf_Shdr const *const shdr = &shdr0[w(relhdr->sh_info)];
- unsigned rel_entsize = _w(relhdr->sh_entsize);
- unsigned const nrel = _w(relhdr->sh_size) / rel_entsize;
+ Elf_Shdr const *const shdr = &shdr0[relhdr->sh_info];
+ unsigned int rel_entsize = relhdr->sh_entsize;
+ unsigned const nrel = relhdr->sh_size / rel_entsize;
unsigned mcountsym = 0;
unsigned t;
int once = 0;
@@ -469,13 +469,13 @@ static unsigned find_secsym_ndx(unsigned const txtndx,
}

/* Evade ISO C restriction: no declaration after statement in has_rel_mcount. */
-static char const * __has_rel_mcount(Elf_Shdr const *const relhdr, /* reltype */
+static char const * __has_rel_mcount(GElf_Shdr const *const relhdr, /* reltype */
Elf_Shdr const *const shdr0,
char const *const shstrtab,
char const *const fname)
{
/* .sh_info depends on .sh_type == SHT_REL[,A] */
- Elf_Shdr const *const txthdr = &shdr0[w(relhdr->sh_info)];
+ Elf_Shdr const *const txthdr = &shdr0[relhdr->sh_info];
char const *const txtname = &shstrtab[w(txthdr->sh_name)];

if (w(txthdr->sh_type) != SHT_PROGBITS ||
@@ -484,30 +484,29 @@ static char const * __has_rel_mcount(Elf_Shdr const *const relhdr, /* reltype */
return txtname;
}

-static char const *has_rel_mcount(Elf_Shdr const *const relhdr,
+static char const *has_rel_mcount(GElf_Shdr const *const relhdr,
Elf_Shdr const *const shdr0,
char const *const shstrtab,
char const *const fname)
{
- if (w(relhdr->sh_type) != SHT_REL && w(relhdr->sh_type) != SHT_RELA)
+ if (relhdr->sh_type != SHT_REL && relhdr->sh_type != SHT_RELA)
return NULL;
return __has_rel_mcount(relhdr, shdr0, shstrtab, fname);
}


static unsigned tot_relsize(Elf_Shdr const *const shdr0,
- unsigned nhdr,
const char *const shstrtab,
const char *const fname)
{
+ struct section *sec;
unsigned totrelsz = 0;
- Elf_Shdr const *shdrp = shdr0;
char const *txtname;

- for (; nhdr; --nhdr, ++shdrp) {
- txtname = has_rel_mcount(shdrp, shdr0, shstrtab, fname);
+ list_for_each_entry(sec, &lf->sections, list) {
+ txtname = has_rel_mcount(&sec->sh, shdr0, shstrtab, fname);
if (txtname && is_mcounted_section_name(txtname))
- totrelsz += _w(shdrp->sh_size);
+ totrelsz += sec->sh.sh_size;
}
return totrelsz;
}
@@ -519,13 +518,11 @@ static int do_func(Elf_Ehdr *const ehdr, char const *const fname,
{
Elf_Shdr *const shdr0 = (Elf_Shdr *)(_w(ehdr->e_shoff)
+ (void *)ehdr);
- unsigned const nhdr = w2(ehdr->e_shnum);
Elf_Shdr *const shstr = &shdr0[w2(ehdr->e_shstrndx)];
char const *const shstrtab = (char const *)(_w(shstr->sh_offset)
+ (void *)ehdr);

- Elf_Shdr const *relhdr;
- unsigned k;
+ GElf_Shdr const *relhdr;

/* Upper bound on space: assume all relevant relocs are for mcount. */
unsigned totrelsz;
@@ -539,12 +536,14 @@ static int do_func(Elf_Ehdr *const ehdr, char const *const fname,
unsigned rel_entsize = 0;
unsigned symsec_sh_link = 0;

+ struct section *sec;
+
int result = 0;

if (find_section_by_name(lf, "__mcount_loc") != NULL)
return 0;

- totrelsz = tot_relsize(shdr0, nhdr, shstrtab, fname);
+ totrelsz = tot_relsize(shdr0, shstrtab, fname);
if (totrelsz == 0)
return 0;
mrel0 = umalloc(totrelsz);
@@ -560,24 +559,27 @@ static int do_func(Elf_Ehdr *const ehdr, char const *const fname,
return -1;
}

- for (relhdr = shdr0, k = nhdr; k; --k, ++relhdr) {
- char const *const txtname = has_rel_mcount(relhdr, shdr0,
+ list_for_each_entry(sec, &lf->sections, list) {
+ char const *txtname;
+
+ relhdr = &sec->sh;
+ txtname = has_rel_mcount(relhdr, shdr0,
shstrtab, fname);
if (txtname && is_mcounted_section_name(txtname)) {
uint_t recval = 0;
- unsigned const int recsym = find_secsym_ndx(
- w(relhdr->sh_info), txtname, &recval,
- &shdr0[symsec_sh_link = w(relhdr->sh_link)],
+ unsigned const int recsym_index = find_secsym_ndx(
+ relhdr->sh_info, txtname, &recval,
+ &shdr0[symsec_sh_link = relhdr->sh_link],
ehdr);
- if (recsym == missing_sym) {
+ if (recsym_index == missing_sym) {
result = -1;
goto out;
}

- rel_entsize = _w(relhdr->sh_entsize);
+ rel_entsize = relhdr->sh_entsize;
mlocp = sift_rel_mcount(mlocp,
(void *)mlocp - (void *)mloc0, &mrelp,
- relhdr, ehdr, recsym, recval, reltype);
+ relhdr, ehdr, recsym_index, recval, reltype);
} else if (txtname && (warn_on_notrace_sect || make_nop)) {
/*
* This section is ignored by ftrace, but still
--
2.20.1

2019-06-12 05:01:13

by Matt Helsley

[permalink] [raw]
Subject: [PATCH v2 12/13] objtool: recordmcount: Search for __mcount_loc before walking the sections

recordmcount iterates over the sections in the order they're
listed in the ELF file and checks whether the section name
indicates it's of interest. Objtool's elf code works differently
-- it scans the elf file and builds up data structures
representing the headers, sections, etc. and then supplies
functions to search these structures. Both walk the elf file
in order, however objtool uses more memory to enable faster
searches it needs for other tools such as the reliable backtrace
support offered by the ORC unwinder.

Rather than walk the section table a second time in the recordmcount
code, we use objtool's elf code to search for the section
recordmcount is interested in. This also simplifies flow and means
we can easily check for already-processed object files before we
do any of the more complex things recordmcount does.

This also allows us to remove the already_has_rel_mcount string
pointer trick.

Signed-off-by: Matt Helsley <[email protected]>
---
tools/objtool/recordmcount.c | 2 --
tools/objtool/recordmcount.h | 22 +++-------------------
2 files changed, 3 insertions(+), 21 deletions(-)

diff --git a/tools/objtool/recordmcount.c b/tools/objtool/recordmcount.c
index 61050b78d5a0..649a03e463dd 100644
--- a/tools/objtool/recordmcount.c
+++ b/tools/objtool/recordmcount.c
@@ -204,8 +204,6 @@ static void *mmap_file(char const *fname)
} else
mmap_failed = 0;
out:
- elf_close(lf);
- lf = NULL;
fd_map = -1;

file_end = file_map + sb.st_size;
diff --git a/tools/objtool/recordmcount.h b/tools/objtool/recordmcount.h
index b7348f1af758..03643c68486b 100644
--- a/tools/objtool/recordmcount.h
+++ b/tools/objtool/recordmcount.h
@@ -26,7 +26,6 @@
#undef nop_mcount
#undef missing_sym
#undef find_secsym_ndx
-#undef already_has_rel_mcount
#undef __has_rel_mcount
#undef has_rel_mcount
#undef tot_relsize
@@ -58,7 +57,6 @@
# define nop_mcount nop_mcount_64
# define missing_sym missing_sym_64
# define find_secsym_ndx find64_secsym_ndx
-# define already_has_rel_mcount already_has_rel_mcount_64
# define __has_rel_mcount __has64_rel_mcount
# define has_rel_mcount has64_rel_mcount
# define tot_relsize tot64_relsize
@@ -93,7 +91,6 @@
# define nop_mcount nop_mcount_32
# define missing_sym missing_sym_32
# define find_secsym_ndx find32_secsym_ndx
-# define already_has_rel_mcount already_has_rel_mcount_32
# define __has_rel_mcount __has32_rel_mcount
# define has_rel_mcount has32_rel_mcount
# define tot_relsize tot32_relsize
@@ -471,8 +468,6 @@ static unsigned find_secsym_ndx(unsigned const txtndx,
return missing_sym;
}

-char const *already_has_rel_mcount = "success"; /* our work here is done! */
-
/* Evade ISO C restriction: no declaration after statement in has_rel_mcount. */
static char const * __has_rel_mcount(Elf_Shdr const *const relhdr, /* reltype */
Elf_Shdr const *const shdr0,
@@ -483,11 +478,6 @@ static char const * __has_rel_mcount(Elf_Shdr const *const relhdr, /* reltype */
Elf_Shdr const *const txthdr = &shdr0[w(relhdr->sh_info)];
char const *const txtname = &shstrtab[w(txthdr->sh_name)];

- if (strcmp("__mcount_loc", txtname) == 0) {
- fprintf(stderr, "warning: __mcount_loc already exists: %s\n",
- fname);
- return already_has_rel_mcount;
- }
if (w(txthdr->sh_type) != SHT_PROGBITS ||
!(_w(txthdr->sh_flags) & SHF_EXECINSTR))
return NULL;
@@ -516,10 +506,6 @@ static unsigned tot_relsize(Elf_Shdr const *const shdr0,

for (; nhdr; --nhdr, ++shdrp) {
txtname = has_rel_mcount(shdrp, shdr0, shstrtab, fname);
- if (txtname == already_has_rel_mcount) {
- totrelsz = 0;
- break;
- }
if (txtname && is_mcounted_section_name(txtname))
totrelsz += _w(shdrp->sh_size);
}
@@ -555,6 +541,9 @@ static int do_func(Elf_Ehdr *const ehdr, char const *const fname,

int result = 0;

+ if (find_section_by_name(lf, "__mcount_loc") != NULL)
+ return 0;
+
totrelsz = tot_relsize(shdr0, nhdr, shstrtab, fname);
if (totrelsz == 0)
return 0;
@@ -574,11 +563,6 @@ static int do_func(Elf_Ehdr *const ehdr, char const *const fname,
for (relhdr = shdr0, k = nhdr; k; --k, ++relhdr) {
char const *const txtname = has_rel_mcount(relhdr, shdr0,
shstrtab, fname);
- if (txtname == already_has_rel_mcount) {
- result = 0;
- file_updated = 0;
- goto out; /* Nothing to be done; don't append! */
- }
if (txtname && is_mcounted_section_name(txtname)) {
uint_t recval = 0;
unsigned const int recsym = find_secsym_ndx(
--
2.20.1

2019-06-12 05:02:07

by Matt Helsley

[permalink] [raw]
Subject: [PATCH v2 11/13] objtool: recordmcount: Start using objtool's elf wrapper

Use struct elf to grab the file descriptor. We will later
move these calls into other functions as we expand the
lifetime of the struct elf so that it can be passed to
objtool elf.[ch] functions.

This creates the libelf/objcount data structures and gives
us two separte ways to walk the ELF file -- the libelf/objtool
way and the old recordmcount wrapper way which avoids these
extra data structures by using indices, offsets, and pointers
into the mmapped ELF file.

Subsequent patches will convert from the old recordmcount
accessors to the libelf/objtool accessors.

Signed-off-by: Matt Helsley <[email protected]>
---
tools/objtool/recordmcount.c | 18 +++++++++++++-----
1 file changed, 13 insertions(+), 5 deletions(-)

diff --git a/tools/objtool/recordmcount.c b/tools/objtool/recordmcount.c
index 2de31e2913d1..61050b78d5a0 100644
--- a/tools/objtool/recordmcount.c
+++ b/tools/objtool/recordmcount.c
@@ -33,6 +33,8 @@

#include "builtin-mcount.h"

+#include "elf.h"
+
#ifndef EM_AARCH64
#define EM_AARCH64 183
#define R_AARCH64_NONE 0
@@ -53,6 +55,8 @@ static void *file_ptr; /* current file pointer location */
static void *file_append; /* added to the end of the file */
static size_t file_append_size; /* how much is added to end of file */

+static struct elf *lf;
+
/* Per-file resource cleanup when multiple files. */
static void file_append_cleanup(void)
{
@@ -69,6 +73,9 @@ static void mmap_cleanup(void)
else
free(file_map);
file_map = NULL;
+ if (lf)
+ elf_close(lf);
+ lf = NULL;
}

/* ulseek, uwrite, ...: Check return value for errors. */
@@ -166,11 +173,12 @@ static void *mmap_file(char const *fname)
file_updated = 0;
sb.st_size = 0;

- fd_map = open(fname, O_RDONLY);
- if (fd_map < 0) {
+ lf = elf_open(fname, O_RDONLY);
+ if (!lf) {
perror(fname);
return NULL;
}
+ fd_map = lf->fd;
if (fstat(fd_map, &sb) < 0) {
perror(fname);
goto out;
@@ -190,14 +198,14 @@ static void *mmap_file(char const *fname)
}
if (read(fd_map, file_map, sb.st_size) != sb.st_size) {
perror(fname);
- free(file_map);
- file_map = NULL;
+ mmap_cleanup();
goto out;
}
} else
mmap_failed = 0;
out:
- close(fd_map);
+ elf_close(lf);
+ lf = NULL;
fd_map = -1;

file_end = file_map + sb.st_size;
--
2.20.1

2019-06-12 05:03:58

by Matt Helsley

[permalink] [raw]
Subject: [PATCH v2 08/13] recordmcount: Clarify what cleanup() does

cleanup() mostly frees/unmaps the malloc'd/privately-mapped
copy of the ELF file recordmcount is working on, which is
set up in mmap_file(). It also deals with positioning within
the pseduo prive-mapping of the file and appending to the ELF
file.

Split into two steps:
mmap_cleanup() for the mapping itself
file_append_cleanup() for allocations storing the
appended ELF data.

Also, move the global variable initializations out of the main,
per-object-file loop and nearer to the alloc/init (mmap_file())
and two cleanup functions so we can more clearly see how they're
related.

Signed-off-by: Matt Helsley <[email protected]>
---
scripts/recordmcount.c | 151 ++++++++++++++++++++++-------------------
1 file changed, 81 insertions(+), 70 deletions(-)

diff --git a/scripts/recordmcount.c b/scripts/recordmcount.c
index 111419c282d3..9f4af109277e 100644
--- a/scripts/recordmcount.c
+++ b/scripts/recordmcount.c
@@ -48,21 +48,26 @@ static void *file_map; /* pointer of the mapped file */
static void *file_end; /* pointer to the end of the mapped file */
static int file_updated; /* flag to state file was changed */
static void *file_ptr; /* current file pointer location */
+
static void *file_append; /* added to the end of the file */
static size_t file_append_size; /* how much is added to end of file */

/* Per-file resource cleanup when multiple files. */
-static void cleanup(void)
+static void file_append_cleanup(void)
+{
+ free(file_append);
+ file_append = NULL;
+ file_append_size = 0;
+ file_updated = 0;
+}
+
+static void mmap_cleanup(void)
{
if (!mmap_failed)
munmap(file_map, sb.st_size);
else
free(file_map);
file_map = NULL;
- free(file_append);
- file_append = NULL;
- file_append_size = 0;
- file_updated = 0;
}

/* ulseek, uwrite, ...: Check return value for errors. */
@@ -103,7 +108,8 @@ static ssize_t uwrite(void const *const buf, size_t const count)
}
if (!file_append) {
perror("write");
- cleanup();
+ file_append_cleanup();
+ mmap_cleanup();
return -1;
}
if (file_ptr < file_end) {
@@ -129,12 +135,76 @@ static void * umalloc(size_t size)
void *const addr = malloc(size);
if (addr == 0) {
fprintf(stderr, "malloc failed: %zu bytes\n", size);
- cleanup();
+ file_append_cleanup();
+ mmap_cleanup();
return NULL;
}
return addr;
}

+/*
+ * Get the whole file as a programming convenience in order to avoid
+ * malloc+lseek+read+free of many pieces. If successful, then mmap
+ * avoids copying unused pieces; else just read the whole file.
+ * Open for both read and write; new info will be appended to the file.
+ * Use MAP_PRIVATE so that a few changes to the in-memory ElfXX_Ehdr
+ * do not propagate to the file until an explicit overwrite at the last.
+ * This preserves most aspects of consistency (all except .st_size)
+ * for simultaneous readers of the file while we are appending to it.
+ * However, multiple writers still are bad. We choose not to use
+ * locking because it is expensive and the use case of kernel build
+ * makes multiple writers unlikely.
+ */
+static void *mmap_file(char const *fname)
+{
+ /* Avoid problems if early cleanup() */
+ fd_map = -1;
+ mmap_failed = 1;
+ file_map = NULL;
+ file_ptr = NULL;
+ file_updated = 0;
+ sb.st_size = 0;
+
+ fd_map = open(fname, O_RDONLY);
+ if (fd_map < 0) {
+ perror(fname);
+ return NULL;
+ }
+ if (fstat(fd_map, &sb) < 0) {
+ perror(fname);
+ goto out;
+ }
+ if (!S_ISREG(sb.st_mode)) {
+ fprintf(stderr, "not a regular file: %s\n", fname);
+ goto out;
+ }
+ file_map = mmap(0, sb.st_size, PROT_READ|PROT_WRITE, MAP_PRIVATE,
+ fd_map, 0);
+ if (file_map == MAP_FAILED) {
+ mmap_failed = 1;
+ file_map = umalloc(sb.st_size);
+ if (!file_map) {
+ perror(fname);
+ goto out;
+ }
+ if (read(fd_map, file_map, sb.st_size) != sb.st_size) {
+ perror(fname);
+ free(file_map);
+ file_map = NULL;
+ goto out;
+ }
+ } else
+ mmap_failed = 0;
+out:
+ close(fd_map);
+ fd_map = -1;
+
+ file_end = file_map + sb.st_size;
+
+ return file_map;
+}
+
+
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;
@@ -238,61 +308,6 @@ static int make_nop_arm64(void *map, size_t const offset)
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
- * avoids copying unused pieces; else just read the whole file.
- * Open for both read and write; new info will be appended to the file.
- * Use MAP_PRIVATE so that a few changes to the in-memory ElfXX_Ehdr
- * do not propagate to the file until an explicit overwrite at the last.
- * This preserves most aspects of consistency (all except .st_size)
- * for simultaneous readers of the file while we are appending to it.
- * However, multiple writers still are bad. We choose not to use
- * locking because it is expensive and the use case of kernel build
- * makes multiple writers unlikely.
- */
-static void *mmap_file(char const *fname)
-{
- file_map = NULL;
- sb.st_size = 0;
- fd_map = open(fname, O_RDONLY);
- if (fd_map < 0) {
- perror(fname);
- return NULL;
- }
- if (fstat(fd_map, &sb) < 0) {
- perror(fname);
- goto out;
- }
- if (!S_ISREG(sb.st_mode)) {
- fprintf(stderr, "not a regular file: %s\n", fname);
- goto out;
- }
- file_map = mmap(0, sb.st_size, PROT_READ|PROT_WRITE, MAP_PRIVATE,
- fd_map, 0);
- mmap_failed = 0;
- if (file_map == MAP_FAILED) {
- mmap_failed = 1;
- file_map = umalloc(sb.st_size);
- if (!file_map) {
- perror(fname);
- goto out;
- }
- if (read(fd_map, file_map, sb.st_size) != sb.st_size) {
- perror(fname);
- free(file_map);
- file_map = NULL;
- goto out;
- }
- }
-out:
- close(fd_map);
-
- file_end = file_map + sb.st_size;
-
- return file_map;
-}
-
static int write_file(const char *fname)
{
char tmp_file[strlen(fname) + 4];
@@ -436,10 +451,11 @@ static void MIPS64_r_info(Elf64_Rel *const rp, unsigned sym, unsigned type)

static int do_file(char const *const fname)
{
- Elf32_Ehdr *const ehdr = mmap_file(fname);
+ Elf32_Ehdr *ehdr;
unsigned int reltype = 0;
int rc = -1;

+ ehdr = mmap_file(fname);
if (!ehdr)
goto out;

@@ -575,7 +591,8 @@ static int do_file(char const *const fname)

rc = write_file(fname);
out:
- cleanup();
+ file_append_cleanup();
+ mmap_cleanup();
return rc;
}

@@ -618,12 +635,6 @@ int main(int argc, char *argv[])
strcmp(file + (len - ftrace_size), ftrace) == 0)
continue;

- /* Avoid problems if early cleanup() */
- fd_map = -1;
- mmap_failed = 1;
- file_map = NULL;
- file_ptr = NULL;
- file_updated = 0;
if (do_file(file)) {
fprintf(stderr, "%s: failed\n", file);
++n_error;
--
2.20.1

2019-06-12 05:07:03

by Matt Helsley

[permalink] [raw]
Subject: [PATCH v2 03/13] recordmcount: Remove unused fd from uwrite() and ulseek()

uwrite() works within the pseudo-mapping and extends it as necessary
without needing the file descriptor (fd) parameter passed to it.
Similarly, ulseek() doesn't need its fd parameter. These parameters
were only added because the functions bear a conceptual resemblance
to write() and lseek(). Worse, they obscure the fact that at the time
uwrite() and ulseek() are called fd_map is not a valid file descriptor.

Remove the unused file descriptor parameters that make it look like
fd_map is still valid.

Signed-off-by: Matt Helsley <[email protected]>
---
scripts/recordmcount.c | 16 ++++++++--------
scripts/recordmcount.h | 26 +++++++++++++-------------
2 files changed, 21 insertions(+), 21 deletions(-)

diff --git a/scripts/recordmcount.c b/scripts/recordmcount.c
index c0dd46344063..1fe5fba99959 100644
--- a/scripts/recordmcount.c
+++ b/scripts/recordmcount.c
@@ -92,7 +92,7 @@ succeed_file(void)
/* ulseek, uwrite, ...: Check return value for errors. */

static off_t
-ulseek(int const fd, off_t const offset, int const whence)
+ulseek(off_t const offset, int const whence)
{
switch (whence) {
case SEEK_SET:
@@ -113,7 +113,7 @@ ulseek(int const fd, off_t const offset, int const whence)
}

static size_t
-uwrite(int const fd, void const *const buf, size_t const count)
+uwrite(void const *const buf, size_t const count)
{
size_t cnt = count;
off_t idx = 0;
@@ -183,8 +183,8 @@ static int make_nop_x86(void *map, size_t const offset)
return -1;

/* convert to nop */
- ulseek(fd_map, offset - 1, SEEK_SET);
- uwrite(fd_map, ideal_nop, 5);
+ ulseek(offset - 1, SEEK_SET);
+ uwrite(ideal_nop, 5);
return 0;
}

@@ -232,10 +232,10 @@ static int make_nop_arm(void *map, size_t const offset)
return -1;

/* Convert to nop */
- ulseek(fd_map, off, SEEK_SET);
+ ulseek(off, SEEK_SET);

do {
- uwrite(fd_map, ideal_nop, nop_size);
+ uwrite(ideal_nop, nop_size);
} while (--cnt > 0);

return 0;
@@ -252,8 +252,8 @@ static int make_nop_arm64(void *map, size_t const offset)
return -1;

/* Convert to nop */
- ulseek(fd_map, offset, SEEK_SET);
- uwrite(fd_map, ideal_nop, 4);
+ ulseek(offset, SEEK_SET);
+ uwrite(ideal_nop, 4);
return 0;
}

diff --git a/scripts/recordmcount.h b/scripts/recordmcount.h
index 13c5e6c8829c..690fa86ded59 100644
--- a/scripts/recordmcount.h
+++ b/scripts/recordmcount.h
@@ -202,14 +202,14 @@ static void append_func(Elf_Ehdr *const ehdr,
new_e_shoff = t;

/* body for new shstrtab */
- ulseek(fd_map, sb.st_size, SEEK_SET);
- uwrite(fd_map, old_shstr_sh_offset + (void *)ehdr, old_shstr_sh_size);
- uwrite(fd_map, mc_name, 1 + strlen(mc_name));
+ ulseek(sb.st_size, SEEK_SET);
+ uwrite(old_shstr_sh_offset + (void *)ehdr, old_shstr_sh_size);
+ uwrite(mc_name, 1 + strlen(mc_name));

/* old(modified) Elf_Shdr table, word-byte aligned */
- ulseek(fd_map, t, SEEK_SET);
+ ulseek(t, SEEK_SET);
t += sizeof(Elf_Shdr) * old_shnum;
- uwrite(fd_map, old_shoff + (void *)ehdr,
+ uwrite(old_shoff + (void *)ehdr,
sizeof(Elf_Shdr) * old_shnum);

/* new sections __mcount_loc and .rel__mcount_loc */
@@ -225,7 +225,7 @@ static void append_func(Elf_Ehdr *const ehdr,
mcsec.sh_info = 0;
mcsec.sh_addralign = _w(_size);
mcsec.sh_entsize = _w(_size);
- uwrite(fd_map, &mcsec, sizeof(mcsec));
+ uwrite(&mcsec, sizeof(mcsec));

mcsec.sh_name = w(old_shstr_sh_size);
mcsec.sh_type = (sizeof(Elf_Rela) == rel_entsize)
@@ -239,15 +239,15 @@ static void append_func(Elf_Ehdr *const ehdr,
mcsec.sh_info = w(old_shnum);
mcsec.sh_addralign = _w(_size);
mcsec.sh_entsize = _w(rel_entsize);
- uwrite(fd_map, &mcsec, sizeof(mcsec));
+ uwrite(&mcsec, sizeof(mcsec));

- uwrite(fd_map, mloc0, (void *)mlocp - (void *)mloc0);
- uwrite(fd_map, mrel0, (void *)mrelp - (void *)mrel0);
+ uwrite(mloc0, (void *)mlocp - (void *)mloc0);
+ uwrite(mrel0, (void *)mrelp - (void *)mrel0);

ehdr->e_shoff = _w(new_e_shoff);
ehdr->e_shnum = w2(2 + w2(ehdr->e_shnum)); /* {.rel,}__mcount_loc */
- ulseek(fd_map, 0, SEEK_SET);
- uwrite(fd_map, ehdr, sizeof(*ehdr));
+ ulseek(0, SEEK_SET);
+ uwrite(ehdr, sizeof(*ehdr));
}

static unsigned get_mcountsym(Elf_Sym const *const sym0,
@@ -395,8 +395,8 @@ static void nop_mcount(Elf_Shdr const *const relhdr,
Elf_Rel rel;
rel = *(Elf_Rel *)relp;
Elf_r_info(&rel, Elf_r_sym(relp), rel_type_nop);
- ulseek(fd_map, (void *)relp - (void *)ehdr, SEEK_SET);
- uwrite(fd_map, &rel, sizeof(rel));
+ ulseek((void *)relp - (void *)ehdr, SEEK_SET);
+ uwrite(&rel, sizeof(rel));
}
relp = (Elf_Rel const *)(rel_entsize + (void *)relp);
}
--
2.20.1

2019-06-12 05:07:06

by Matt Helsley

[permalink] [raw]
Subject: [PATCH v2 02/13] recordmcount: Remove uread()

uread() is only used to initialize the ELF file's pseudo
private-memory mapping while uwrite() and ulseek() work within
the pseudo-mapping and extend it as necessary. Thus it is not
a complementary function to uwrite() and ulseek(). It also makes
no sense to do cleanups inside uread() when its only caller,
mmap_file(), is doing the relevant allocations and associated
initializations.

Therefore it's clearer to use a plain read() call to initialize the
data in mmap_file() and remove uread().

Signed-off-by: Matt Helsley <[email protected]>
---
scripts/recordmcount.c | 18 +++++-------------
1 file changed, 5 insertions(+), 13 deletions(-)

diff --git a/scripts/recordmcount.c b/scripts/recordmcount.c
index ebe98c39f3cd..c0dd46344063 100644
--- a/scripts/recordmcount.c
+++ b/scripts/recordmcount.c
@@ -89,7 +89,7 @@ succeed_file(void)
longjmp(jmpenv, SJ_SUCCEED);
}

-/* ulseek, uread, ...: Check return value for errors. */
+/* ulseek, uwrite, ...: Check return value for errors. */

static off_t
ulseek(int const fd, off_t const offset, int const whence)
@@ -112,17 +112,6 @@ ulseek(int const fd, off_t const offset, int const whence)
return file_ptr - file_map;
}

-static size_t
-uread(int const fd, void *const buf, size_t const count)
-{
- size_t const n = read(fd, buf, count);
- if (n != count) {
- perror("read");
- fail_file();
- }
- return n;
-}
-
static size_t
uwrite(int const fd, void const *const buf, size_t const count)
{
@@ -298,7 +287,10 @@ static void *mmap_file(char const *fname)
if (file_map == MAP_FAILED) {
mmap_failed = 1;
file_map = umalloc(sb.st_size);
- uread(fd_map, file_map, sb.st_size);
+ if (read(fd_map, file_map, sb.st_size) != sb.st_size) {
+ perror(fname);
+ fail_file();
+ }
}
close(fd_map);

--
2.20.1

2019-07-10 17:13:09

by Steven Rostedt

[permalink] [raw]
Subject: Re: [PATCH v2 00/13] Cleanup recordmcount and begin objtool conversion


Josh,

Can you have a look at these? I can apply them if you think they are OK.

-- Steve


On Tue, 11 Jun 2019 15:21:42 -0700
Matt Helsley <[email protected]> wrote:

> This series cleans up recordmcount and then makes it into
> an objtool subcommand.
>
> The series starts with 8 cleanup patches which make recordmcount
> easier to review and integrate with objtool. The final 5 patches
> show the beginning steps of converting recordmcount to use objtool's
> ELF code rather than its own open-coded methods of accessing ELF
> files.
>
> ---
>
> v2:
> Fix whitespace before line continuation
>
> Add ftrace/mcount/record.h to objtool_dep
>
> Rename the Makefile variable BUILD_C_RECORDMCOUNT to
> better reflect its purpose
>
> Similar: rename recordmcount_source => recordmcount_dep
> When using objtool we can just depend on the
> binary rather than the source the binary is
> built from. This should address Josh's feedback and
> make the Makefile code a bit clearer
>
> Add a comment to make reading the Makefile a little
> easier
>
> Rebased to latest mainline -rc
>
> Collected some build time measurements
>
> Build times measurements -- median of multiple runs in a VM measured
> with "time":
>
> mainline (5.2.0-rc4) build times (median of 3 runs):
> real 2m58.379s
> user 2m29.621s
> sys 1m35.116s
>
> Post recordmcount-cleanup build times (median of 5 runs):
> real 2m51.973s
> user 2m29.094s
> sys 1m33.688s
>
> objtool mcount build times (median of 7 runs):
> real 2m57.92s
> user 2m33.73s
> sys 1m37.06s
>
> Note: I saw some significant variation especially in the "real" time
> measurements probably because it was in a VM on a machine with
> various "idle" GUI tasks running. This is why I took the median
> rather than the mean. Though I haven't run the statistics, my
> sense is the numbers don't support concluding that things really
> got any faster or slower.
>
> I'm working on a separate, follow-on RFC set which implements the
> pseudo-pipe idea.
>
> Matt Helsley (13):
> recordmcount: Remove redundant strcmp
> recordmcount: Remove uread()
> recordmcount: Remove unused fd from uwrite() and ulseek()
> recordmcount: Rewrite error/success handling
> recordmcount: Kernel style function signature formatting
> recordmcount: Kernel style formatting
> recordmcount: Remove redundant cleanup() calls
> recordmcount: Clarify what cleanup() does
> objtool: Prepare to merge recordmcount
> objtool: Make recordmcount into an objtool subcmd
> objtool: recordmcount: Start using objtool's elf wrapper
> objtool: recordmcount: Search for __mcount_loc before walking the
> sections
> objtool: recordmcount: Convert do_func() relhdrs
>
> Makefile | 6 +-
> scripts/.gitignore | 1 -
> scripts/Makefile | 1 -
> scripts/Makefile.build | 27 +-
> tools/objtool/.gitignore | 1 +
> tools/objtool/Build | 1 +
> tools/objtool/Makefile | 1 +
> tools/objtool/builtin-mcount.c | 72 +++++
> tools/objtool/builtin-mcount.h | 23 ++
> tools/objtool/builtin.h | 1 +
> tools/objtool/objtool.c | 1 +
> {scripts => tools/objtool}/recordmcount.c | 350 ++++++++++-----------
> {scripts => tools/objtool}/recordmcount.h | 197 +++++++-----
> {scripts => tools/objtool}/recordmcount.pl | 0
> 14 files changed, 407 insertions(+), 275 deletions(-)
> create mode 100644 tools/objtool/builtin-mcount.c
> create mode 100644 tools/objtool/builtin-mcount.h
> rename {scripts => tools/objtool}/recordmcount.c (78%)
> rename {scripts => tools/objtool}/recordmcount.h (78%)
> rename {scripts => tools/objtool}/recordmcount.pl (100%)
>

2019-07-10 18:13:00

by Josh Poimboeuf

[permalink] [raw]
Subject: Re: [PATCH v2 00/13] Cleanup recordmcount and begin objtool conversion

On Wed, Jul 10, 2019 at 01:09:24PM -0400, Steven Rostedt wrote:
>
> Josh,
>
> Can you have a look at these? I can apply them if you think they are OK.

Sorry for the delay. I didn't forget about it, it's just been a hectic
month. I plan to give it a proper review soon (in the next week or so).

--
Josh

2019-07-24 17:07:28

by Steven Rostedt

[permalink] [raw]
Subject: Re: [PATCH v2 00/13] Cleanup recordmcount and begin objtool conversion

On Wed, 10 Jul 2019 12:19:00 -0500
Josh Poimboeuf <[email protected]> wrote:

> On Wed, Jul 10, 2019 at 01:09:24PM -0400, Steven Rostedt wrote:
> >
> > Josh,
> >
> > Can you have a look at these? I can apply them if you think they are OK.
>
> Sorry for the delay. I didn't forget about it, it's just been a hectic
> month. I plan to give it a proper review soon (in the next week or so).
>

Friendly reminder ;-)

-- Steve

2019-07-24 17:51:39

by Matt Helsley

[permalink] [raw]
Subject: Re: [PATCH v2 00/13] Cleanup recordmcount and begin objtool conversion



> On Jul 24, 2019, at 9:46 AM, Steven Rostedt <[email protected]> wrote:
>
> On Wed, 10 Jul 2019 12:19:00 -0500
> Josh Poimboeuf <[email protected]> wrote:
>
>> On Wed, Jul 10, 2019 at 01:09:24PM -0400, Steven Rostedt wrote:
>>>
>>> Josh,
>>>
>>> Can you have a look at these? I can apply them if you think they are OK.
>>
>> Sorry for the delay. I didn't forget about it, it's just been a hectic
>> month. I plan to give it a proper review soon (in the next week or so).
>>
>
> Friendly reminder ;-)
>
> -- Steve

Just thought I’d add:

I rebased yesterday and noticed a few minor changes are needed to resolve conflicts with mainline. I will send a v3 out today with these changes:

renaming elf_open to elf_read

some kernel build changes (in Makefile.build)

Also, I’ve finished removing all of the old recordmcount ELF wrapper code. I can send a follow-on RFC series by Friday.

Cheers,
-Matt Helsley

2019-07-24 17:53:19

by Josh Poimboeuf

[permalink] [raw]
Subject: Re: [PATCH v2 00/13] Cleanup recordmcount and begin objtool conversion

On Wed, Jul 24, 2019 at 05:26:10PM +0000, Matt Helsley wrote:
>
>
> > On Jul 24, 2019, at 9:46 AM, Steven Rostedt <[email protected]> wrote:
> >
> > On Wed, 10 Jul 2019 12:19:00 -0500
> > Josh Poimboeuf <[email protected]> wrote:
> >
> >> On Wed, Jul 10, 2019 at 01:09:24PM -0400, Steven Rostedt wrote:
> >>>
> >>> Josh,
> >>>
> >>> Can you have a look at these? I can apply them if you think they are OK.
> >>
> >> Sorry for the delay. I didn't forget about it, it's just been a hectic
> >> month. I plan to give it a proper review soon (in the next week or so).
> >>
> >
> > Friendly reminder ;-)
> >
> > -- Steve
>
> Just thought I’d add:
>
> I rebased yesterday and noticed a few minor changes are needed to resolve conflicts with mainline. I will send a v3 out today with these changes:
>
> renaming elf_open to elf_read
>
> some kernel build changes (in Makefile.build)
>
> Also, I’ve finished removing all of the old recordmcount ELF wrapper code. I can send a follow-on RFC series by Friday.

Matt, thanks for your patience. As I told Steven, I'm unfortunately
very behind on reviews. Yours is (almost) at the top of the list.

--
Josh