2020-06-18 20:57:28

by Matt Helsley

[permalink] [raw]
Subject: [RFC][PATCH v5 00/51] objtool: Make recordmcount a subcommand

recordmcount has its own ELF wrapper code and could utilize
objtool's ELF code to more-portably handle architecture variations.
This series makes recordmcount a subcommand of objtool. It very
gradually converts recordmcount to become a subcommand of objtool and
then reuses parts of objtool's ELF code.

recordmcount maps the file in and collects simple information it needs to
append a section to the object file. The only part of the original file it
modifies is the address of new section tables -- interestingly enough this
resembles RCU in that we don't really trim the old tables so
much as unlink them via a critical offset and then rely on
future tooling, in this case, to drop the unused bits.

Much of the recordmcount ELF code is only reading and walking the data
structures to collect the mcount locations it records in a separate
area of memory. This means it's safe to mix access to the mapped
file with access to the objtool-style linked data
structures as we gradually convert it to using only the linked data
structures. Once the old ELF code is no longer in use we can drop it
and use objtool to take over the task of writing the results without
using the RCU-like trick any more.

After that we greatly simplify the mcount subcommand by adding a
few flags to the ELF reading code in objtool. Overall the series
removes about 600 lines of recordmcount while adding little to
objtool's ELF code.

Testing so far:

I've been using scripts to test cross compilation and execution of
objtool, and mcount on objects built for x86, ppc64le, arm64, s390, and
sparc.


Applies on top of:
objtool/core

Peter Zijlstra's "x86/entry: noinstr fixes" [2]

Sami Tolvanen's patch enabling support for more than 64k
sections in recordmcount, already going upstream. [3]

Changes since v4[1]:
v5:
Updated the HAVE_C_RECORDMCOUNT Kconfig description.

Removed unused extern is_cmd_mcount_available() spotted by Julien Thierry.

Issue with symbol info handling reported and fixed by Kamalesh Babulal.

Removed the giant per-supported-arch series of ifdef blocks in
the objtool Makefile and replaced with new CONFIG_ variables
as suggested by Julien Thierry.

Moved the first pass through the sections into objtool's ELF
code as suggested by Peter Zijlstra.

Removed a redundant section lookup.

Removed old comments that no longer apply since conversion to objtool.

v4:
Split out recordmcount cleanups and upstreamed. [5]

Split out, iterated on objtool multi-arch support, and upstreamed. [6]

Split out expanded relocation support, renamed types, and functions
to reflect expanded relocation support, and upstreamed. [4]

This set is based on the patches sent upstream and posted above.

Adapted to renames by Ingo and Peter: s/elf_open/elf_open_read/

Added weak symbols for mcount subcommand
This nicely eliminated the need for the mcount.h header.

Added tools/objtool/Makefile per-arch SUBCMD_ blocks for each
arch recordmcount / mcount supports.

Moved ftrace/mcount/record.h from objtool_dep to recordmcount_dep
This keeps the dependencies better organized.

Fixed Makefile issue reported for PowerPC and a couple other archs
by kbuild test robot. The always-$(BUILD_C_RECORDMCOUNT)
line wasn't sufficiently replaced. Added to prepare-objtool
target in top level Makefile.

Split up dependencies to be independent of CONFIG_STACK_VALIDATION
and CONFIG_UNWINDER_ORC since these are x86-specific.
Now any arch which uses the C version of recordmcount
will build objtool if dynamic tracing is enabled.

Added a second rename at the end to be consistent with other
objtool subcommands.

v3:
Rebased on mainline. s/elf_open/elf_read/ in recordmcount.c

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

[1] https://lore.kernel.org/lkml/[email protected]/
[2] https://lore.kernel.org/lkml/[email protected]
[3] https://lore.kernel.org/lkml/[email protected]
[4] https://lore.kernel.org/lkml/[email protected]/
[5] https://lore.kernel.org/lkml/[email protected]/
[6] https://lore.kernel.org/lkml/[email protected]/


Matt Helsley (51):
objtool: Factor out reasons to build objtool
objtool: Prepare to merge recordmcount
objtool: Make recordmcount into mcount 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
objtool: mcount: Move nhdr into find_symtab()
objtool: mcount: Remove unused fname parameter
objtool: mcount: Use libelf for section header names
objtool: mcount: Walk objtool Elf structs in find_secsym_ndx
objtool: mcount: Use symbol structs to find mcount relocations
objtool: mcount: Walk relocation lists
objtool: mcount: Return symbol from mcountsym
objtool: mcount: Move get_mcountsym
objtool: mcount: Replace MIPS offset types
objtool: mcount: Move is_fake_mcount()
objtool: mcount: Stop using ehdr in find_section_sym_index
objtool: mcount: Move find_section_sym_index()
objtool: mcount: Restrict using ehdr in append_func()
objtool: mcount: Use objtool ELF to write
objtool: mcount: Move nop_mcount()
objtool: mcount: Move has_rel_mcount() and tot_relsize()
objtool: mcount: Move relocation entry size detection
objtool: mcount: Only keep ELF file size
objtool: mcount: Use ELF header from objtool
objtool: mcount: Remove unused file mapping
objtool: mcount: Reduce usage of _size wrapper
objtool: mcount: Move mcount_adjust out of wrapper
objtool: mcount: Pre-allocate new ELF sections
objtool: mcount: Generic location and relocation table types
objtool: mcount: Use objtool relocation section
objtool: mcount: Move sift_rel_mcount out of wrapper file
objtool: mcount: Remove wrapper for ELF relocation type
objtool: mcount: Remove wrapper double-include trick
objtool: mcount: Remove endian wrappers
objtool: mcount: Rename to mcount.c
objtool: mcount: Simplify mcount name matching
objtool: mcount: mcount symbol name simplification
objtool: mcount: Verify x86 instruction with memcmp()
objtool: mcount: const-ify ARM instruction patterns
objtool: mcount: Convert nop writes to elf_write_insn()
objtool: mcount: Move mcount symbol name testing
objtool: check: Use class to recognize kcov calls
objtool: mcount: Keep lists locations and relocations
objtool: mcount: Move mcount section test to objtool ELF
objtool: mcount: Flag mcount relocation sections
objtool: mcount: Merge section mcount flags
objtool: mcount: Eliminate first pass
objtool: mcount: Remove relocation size check
objtool: mcount: Remove useless lookup
objtool: mcount: Remove stale description

Documentation/dontdiff | 2 +-
Documentation/trace/ftrace-design.rst | 4 +-
Documentation/trace/ftrace.rst | 6 +-
Makefile | 39 +-
arch/Kconfig | 23 +
arch/arm64/include/asm/ftrace.h | 2 +-
arch/x86/Kconfig.debug | 1 +
arch/x86/include/asm/ftrace.h | 2 +-
kernel/trace/Kconfig | 9 +-
lib/Kconfig.debug | 1 +
scripts/.gitignore | 1 -
scripts/Makefile | 1 -
scripts/Makefile.build | 22 +-
scripts/recordmcount.c | 663 --------------------
scripts/recordmcount.h | 692 ---------------------
scripts/sorttable.h | 2 +-
tools/objtool/.gitignore | 1 +
tools/objtool/Build | 2 +
tools/objtool/Makefile | 14 +-
tools/objtool/builtin-mcount.c | 50 ++
tools/objtool/builtin.h | 1 +
tools/objtool/check.c | 3 +-
tools/objtool/elf.c | 60 +-
tools/objtool/elf.h | 12 +-
tools/objtool/mcount.c | 596 ++++++++++++++++++
tools/objtool/objtool.c | 1 +
tools/objtool/objtool.h | 1 +
{scripts => tools/objtool}/recordmcount.pl | 0
tools/objtool/weak.c | 5 +
29 files changed, 806 insertions(+), 1410 deletions(-)
delete mode 100644 scripts/recordmcount.c
delete mode 100644 scripts/recordmcount.h
create mode 100644 tools/objtool/builtin-mcount.c
create mode 100644 tools/objtool/mcount.c
rename {scripts => tools/objtool}/recordmcount.pl (100%)


base-commit: 14bda4e5293ed9722f1dc39b543024e37707d6c6
prerequisite-patch-id: b9f6483185e4e80fccbb6ec7276bf61ce0329472
prerequisite-patch-id: 6d3fec64974cdce64fec35141ff71f0532cb8c82
prerequisite-patch-id: b71e084f3d2adeb4d05e4327183b75b388a20e6d
prerequisite-patch-id: 261f5d8102f4ecee86df2eb93be6a29495702717
prerequisite-patch-id: 64fa3e2f92e5dfd1b64289b4118288b6d2a25a67
prerequisite-patch-id: e5671d612490912b263505907657f3197c4a0833
prerequisite-patch-id: cba407d3dc82ad54095a9b5149b0c851c4e30b19
prerequisite-patch-id: bcf669a844506eec601cba1797f954e59cc7a2ad
--
2.20.1


2020-06-18 22:18:11

by Matt Helsley

[permalink] [raw]
Subject: [RFC][PATCH v5 09/51] objtool: mcount: Use libelf for section header names

Rather than passing in the string table contents as a parameter,
pass in the section index of the string table and rely on libelf
string table accessor functions to look up section names.

Note that modifying the string table with libelf will come later
so append_func() is unchanged.

Signed-off-by: Matt Helsley <[email protected]>
---
tools/objtool/elf.c | 3 +-
tools/objtool/elf.h | 1 +
tools/objtool/recordmcount.c | 2 +-
tools/objtool/recordmcount.h | 89 ++++++++++++++----------------------
4 files changed, 37 insertions(+), 58 deletions(-)

diff --git a/tools/objtool/elf.c b/tools/objtool/elf.c
index 6812cf74be9a..17e39b3a1719 100644
--- a/tools/objtool/elf.c
+++ b/tools/objtool/elf.c
@@ -185,8 +185,7 @@ struct section *find_section_by_name(const struct elf *elf, const char *name)
return NULL;
}

-static struct section *find_section_by_index(struct elf *elf,
- unsigned int idx)
+struct section *find_section_by_index(const struct elf *elf, unsigned int idx)
{
struct section *sec;

diff --git a/tools/objtool/elf.h b/tools/objtool/elf.h
index 6cc80a075166..60eb44661658 100644
--- a/tools/objtool/elf.h
+++ b/tools/objtool/elf.h
@@ -131,6 +131,7 @@ int elf_write(struct elf *elf);
void elf_close(struct elf *elf);

struct section *find_section_by_name(const struct elf *elf, const char *name);
+struct section *find_section_by_index(const struct elf *elf, unsigned int idx);
struct symbol *find_func_by_offset(struct section *sec, unsigned long offset);
struct symbol *find_symbol_by_offset(struct section *sec, unsigned long offset);
struct symbol *find_symbol_by_name(const struct elf *elf, const char *name);
diff --git a/tools/objtool/recordmcount.c b/tools/objtool/recordmcount.c
index 9941683b3f60..f20582ac99e2 100644
--- a/tools/objtool/recordmcount.c
+++ b/tools/objtool/recordmcount.c
@@ -177,7 +177,7 @@ static void *mmap_file(char const *fname)
file_updated = 0;
sb.st_size = 0;

- lf = elf_open_read(fname, O_RDONLY);
+ lf = elf_open_read(fname, O_RDWR);
if (!lf) {
perror(fname);
return NULL;
diff --git a/tools/objtool/recordmcount.h b/tools/objtool/recordmcount.h
index 53abfd49a537..30f8913aa841 100644
--- a/tools/objtool/recordmcount.h
+++ b/tools/objtool/recordmcount.h
@@ -25,7 +25,6 @@
#undef sift_rel_mcount
#undef nop_mcount
#undef find_secsym_ndx
-#undef __has_rel_mcount
#undef has_rel_mcount
#undef tot_relsize
#undef get_mcountsym
@@ -60,7 +59,6 @@
# define sift_rel_mcount sift64_rel_mcount
# define nop_mcount nop_mcount_64
# define find_secsym_ndx find64_secsym_ndx
-# define __has_rel_mcount __has64_rel_mcount
# define has_rel_mcount has64_rel_mcount
# define tot_relsize tot64_relsize
# define find_symtab find_symtab64
@@ -98,7 +96,6 @@
# define sift_rel_mcount sift32_rel_mcount
# define nop_mcount nop_mcount_32
# define find_secsym_ndx find32_secsym_ndx
-# define __has_rel_mcount __has32_rel_mcount
# define has_rel_mcount has32_rel_mcount
# define tot_relsize tot32_relsize
# define find_symtab find_symtab32
@@ -276,6 +273,7 @@ static int append_func(Elf_Ehdr *const ehdr,

shstr->sh_size = _w(t);
shstr->sh_offset = _w(sb.st_size);
+
t += sb.st_size;
t += (_align & -t); /* word-byte align */
new_e_shoff = t;
@@ -340,7 +338,7 @@ static int append_func(Elf_Ehdr *const ehdr,
return -1;
if (uwrite(ehdr, sizeof(*ehdr)) < 0)
return -1;
- return 0;
+ return elf_write(lf);
}

static unsigned get_mcountsym(Elf_Sym const *const sym0,
@@ -365,7 +363,7 @@ static unsigned get_mcountsym(Elf_Sym const *const sym0,
return mcountsym;
}

-static void get_sym_str_and_relp(GElf_Shdr const *const relhdr,
+static void get_sym_str_and_relp(const struct section * const rels,
Elf_Ehdr const *const ehdr,
Elf_Sym const **sym0,
char const **str0,
@@ -373,10 +371,10 @@ static void get_sym_str_and_relp(GElf_Shdr const *const relhdr,
{
Elf_Shdr *const shdr0 = (Elf_Shdr *)(_w(ehdr->e_shoff)
+ (void *)ehdr);
- unsigned const symsec_sh_link = relhdr->sh_link;
+ unsigned const symsec_sh_link = rels->sh.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 *)(relhdr->sh_offset
+ Elf_Rel const *const rel0 = (Elf_Rel const *)(rels->sh.sh_offset
+ (void *)ehdr);

*sym0 = (Elf_Sym const *)(_w(symsec->sh_offset)
@@ -396,7 +394,7 @@ static void get_sym_str_and_relp(GElf_Shdr const *const relhdr,
static uint_t *sift_rel_mcount(uint_t *mlocp,
unsigned const offbase,
Elf_Rel **const mrelpp,
- GElf_Shdr const *const relhdr,
+ const struct section * const rels,
Elf_Ehdr const *const ehdr,
unsigned const recsym_index,
uint_t const recval,
@@ -407,12 +405,12 @@ static uint_t *sift_rel_mcount(uint_t *mlocp,
Elf_Sym const *sym0;
char const *str0;
Elf_Rel const *relp;
- unsigned int rel_entsize = relhdr->sh_entsize;
- unsigned const nrel = relhdr->sh_size / rel_entsize;
+ unsigned int rel_entsize = rels->sh.sh_entsize;
+ unsigned const nrel = rels->sh.sh_size / rel_entsize;
unsigned mcountsym = 0;
unsigned t;

- get_sym_str_and_relp(relhdr, ehdr, &sym0, &str0, &relp);
+ get_sym_str_and_relp(rels, ehdr, &sym0, &str0, &relp);

for (t = nrel; t; --t) {
if (!mcountsym)
@@ -444,7 +442,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(GElf_Shdr const *const relhdr,
+static int nop_mcount(const struct section * const rels,
Elf_Ehdr const *const ehdr,
const char *const txtname)
{
@@ -453,14 +451,14 @@ static int nop_mcount(GElf_Shdr const *const relhdr,
Elf_Sym const *sym0;
char const *str0;
Elf_Rel const *relp;
- Elf_Shdr const *const shdr = &shdr0[relhdr->sh_info];
- unsigned int rel_entsize = relhdr->sh_entsize;
- unsigned const nrel = relhdr->sh_size / rel_entsize;
+ Elf_Shdr const *const shdr = &shdr0[rels->sh.sh_info];
+ unsigned rel_entsize = rels->sh.sh_entsize;
+ unsigned const nrel = rels->sh.sh_size / rel_entsize;
unsigned mcountsym = 0;
unsigned t;
int once = 0;

- get_sym_str_and_relp(relhdr, ehdr, &sym0, &str0, &relp);
+ get_sym_str_and_relp(rels, ehdr, &sym0, &str0, &relp);

for (t = nrel; t; --t) {
int ret = -1;
@@ -545,40 +543,27 @@ static int find_secsym_ndx(unsigned const txtndx,
return -1;
}

-/* Evade ISO C restriction: no declaration after statement in has_rel_mcount. */
-static char const * __has_rel_mcount(GElf_Shdr const *const relhdr, /* reltype */
- Elf_Shdr const *const shdr0,
- char const *const shstrtab)
+static char const *has_rel_mcount(const struct section * const rels)
{
- /* .sh_info depends on .sh_type == SHT_REL[,A] */
- 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 ||
- !(_w(txthdr->sh_flags) & SHF_EXECINSTR))
+ const struct section *txts;
+ if (rels->sh.sh_type != SHT_REL && rels->sh.sh_type != SHT_RELA)
return NULL;
- return txtname;
-}
-
-static char const *has_rel_mcount(GElf_Shdr const *const relhdr,
- Elf_Shdr const *const shdr0,
- char const *const shstrtab)
-{
- if (relhdr->sh_type != SHT_REL && relhdr->sh_type != SHT_RELA)
+ txts = find_section_by_index(lf, rels->sh.sh_info);
+ if ((txts->sh.sh_type != SHT_PROGBITS) ||
+ !(txts->sh.sh_flags & SHF_EXECINSTR))
return NULL;
- return __has_rel_mcount(relhdr, shdr0, shstrtab);
+ return txts->name;
}


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

list_for_each_entry(sec, &lf->sections, list) {
- txtname = has_rel_mcount(&sec->sh, shdr0, shstrtab);
+ txtname = has_rel_mcount(sec);
if (txtname && is_mcounted_section_name(txtname))
totrelsz += sec->sh.sh_size;
}
@@ -591,11 +576,6 @@ static int do_func(Elf_Ehdr *const ehdr,
{
Elf_Shdr *const shdr0 = (Elf_Shdr *)(_w(ehdr->e_shoff)
+ (void *)ehdr);
- Elf_Shdr *const shstr = &shdr0[get_shstrndx(ehdr, shdr0)];
- char const *const shstrtab = (char const *)(_w(shstr->sh_offset)
- + (void *)ehdr);
-
- GElf_Shdr const *relhdr;

Elf32_Word *symtab;
Elf32_Word *symtab_shndx;
@@ -612,14 +592,14 @@ static int do_func(Elf_Ehdr *const ehdr,
unsigned rel_entsize = 0;
unsigned symsec_sh_link = 0;

- struct section *sec;
+ const struct section *sec;

int result = 0;

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

- totrelsz = tot_relsize(shdr0, shstrtab);
+ totrelsz = tot_relsize();
if (totrelsz == 0)
return 0;
mrel0 = umalloc(totrelsz);
@@ -640,15 +620,13 @@ static int do_func(Elf_Ehdr *const ehdr,
list_for_each_entry(sec, &lf->sections, list) {
char const *txtname;

- relhdr = &sec->sh;
- txtname = has_rel_mcount(relhdr, shdr0,
- shstrtab);
+ txtname = has_rel_mcount(sec);
if (txtname && is_mcounted_section_name(txtname)) {
unsigned int recsym;
uint_t recval = 0;

- symsec_sh_link = relhdr->sh_link;
- result = find_secsym_ndx(relhdr->sh_info, txtname,
+ symsec_sh_link = sec->sh.sh_link;
+ result = find_secsym_ndx(sec->sh.sh_info, txtname,
&recval, &recsym,
&shdr0[symsec_sh_link],
symtab, symtab_shndx,
@@ -656,23 +634,24 @@ static int do_func(Elf_Ehdr *const ehdr,
if (result)
goto out;

- rel_entsize = relhdr->sh_entsize;
+ rel_entsize = sec->sh.sh_entsize;
mlocp = sift_rel_mcount(mlocp,
(void *)mlocp - (void *)mloc0, &mrelp,
- relhdr, ehdr, recsym, recval, reltype);
+ sec, ehdr, recsym, recval, reltype);
} else if (txtname && (warn_on_notrace_sect || make_nop)) {
/*
* This section is ignored by ftrace, but still
* has mcount calls. Convert them to nops now.
*/
- if (nop_mcount(relhdr, ehdr, txtname) < 0) {
+ if (nop_mcount(sec, ehdr, txtname) < 0) {
result = -1;
goto out;
}
}
}
if (!result && mloc0 != mlocp)
- result = append_func(ehdr, shstr, mloc0, mlocp, mrel0, mrelp,
+ result = append_func(ehdr, &shdr0[get_shstrndx(ehdr, shdr0)],
+ mloc0, mlocp, mrel0, mrelp,
rel_entsize, symsec_sh_link);
out:
free(mrel0);
--
2.20.1

2020-06-18 22:18:34

by Matt Helsley

[permalink] [raw]
Subject: [RFC][PATCH v5 44/51] objtool: mcount: Keep lists locations and relocations

To reduce the need for an initial pass through the sections
we need to keep lists of mcount call locations and suitable
relocations. A subsequent patch will eliminate the need for
the first pass entirely.

Introduce a new list for the locations and reuse objtool's
relocation lists respectively.

Signed-off-by: Matt Helsley <[email protected]>
---
tools/objtool/mcount.c | 133 +++++++++++++++++++++++------------------
1 file changed, 75 insertions(+), 58 deletions(-)

diff --git a/tools/objtool/mcount.c b/tools/objtool/mcount.c
index 7fbde6ce6eb8..7d7843f7cd44 100644
--- a/tools/objtool/mcount.c
+++ b/tools/objtool/mcount.c
@@ -43,9 +43,15 @@

#define R_ARM_THM_CALL 10

+struct mcount_loc {
+ struct list_head list;
+ GElf_Addr loc;
+};
+
extern int warn_on_notrace_sect; /* warn when section has mcount not being recorded */

static struct elf *lf;
+static struct list_head mcount_locs;

static const char ip_relative_call_x86[5] = { 0xe8, 0x00, 0x00, 0x00, 0x00 };
static const char ideal_nop5_x86_64[5] = { 0x0f, 0x1f, 0x44, 0x00, 0x00 };
@@ -294,20 +300,17 @@ static char const *has_rel_mcount(const struct section * const rels)
return txts->name;
}

-static unsigned tot_relsize(unsigned int *rel_entsize)
+static void tot_relsize(unsigned int *rel_entsize)
{
const struct section *sec;
- unsigned totrelsz = 0;
char const *txtname;

list_for_each_entry(sec, &lf->sections, list) {
txtname = has_rel_mcount(sec);
if (!(txtname && is_mcounted_section_name(txtname)))
continue;
- totrelsz += sec->sh.sh_size;
*rel_entsize = sec->sh.sh_entsize;
}
- return totrelsz;
}

/* zero or a small negative offset added to get the start of the call
@@ -323,55 +326,89 @@ static size_t loc_size;
* Accumulate the section offsets that are found, and their relocation info,
* onto the end of the existing arrays.
*/
-static void sift_rel_mcount(GElf_Addr **mlocpp,
- GElf_Sxword *r_offsetp,
- void **const mrelpp,
+static void sift_rel_mcount(GElf_Sxword *r_offsetp,
const struct section * const rels,
+ struct section *mc_relocs,
+ struct section *mc_locs,
unsigned const recsym_index,
unsigned long const recval,
unsigned const reltype,
bool is_rela)
{
- GElf_Rel *mrelp = *mrelpp;
- GElf_Rela *mrelap = *mrelpp;
struct reloc *reloc;

list_for_each_entry(reloc, &rels->reloc_list, list) {
unsigned long addend;
+ struct mcount_loc *mc_loc;
+ struct reloc *mc_reloc;
+
+ if (reloc->sym->class != SYM_MCOUNT || is_fake_mcount(reloc))
+ continue;

- if (reloc->sym->class == SYM_MCOUNT || is_fake_mcount(reloc))
+ mc_loc = malloc(sizeof(*mc_loc));
+ if (!mc_loc) {
+ perror("malloc");
continue;
+ }
+ mc_reloc = malloc(sizeof(*mc_reloc));
+ if (!mc_reloc) {
+ perror("malloc");
+ free(mc_loc);
+ continue;
+ }
+ memset(mc_reloc, 0, sizeof(*mc_reloc));
+ memset(mc_loc, 0, sizeof(*mc_loc));
+ mc_reloc->sec = mc_relocs;

addend = reloc->offset - recval + mcount_adjust;
if (is_rela) {
- mrelap->r_offset = *r_offsetp;
- mrelap->r_info = GELF_R_INFO(recsym_index, reltype);
- mrelap->r_addend = addend;
- mrelap++;
- **mlocpp = 0;
+ mc_reloc->rela.r_offset = *r_offsetp;
+ mc_reloc->rela.r_info = GELF_R_INFO(recsym_index, reltype);
+ mc_reloc->rela.r_addend = addend;
+ mc_loc->loc = 0;
} else {
- mrelp->r_offset = *r_offsetp;
- mrelp->r_info = GELF_R_INFO(recsym_index, reltype);
- mrelp++;
- **mlocpp = addend;
+ mc_reloc->rel.r_offset = *r_offsetp;
+ mc_reloc->rel.r_info = GELF_R_INFO(recsym_index, reltype);
+ mc_loc->loc = addend;
}
- (*mlocpp)++;
+ mc_reloc->offset = *r_offsetp;
+ mc_reloc->type = reltype;
+ mc_reloc->sec = mc_locs;
+ elf_add_reloc(lf, mc_reloc);
+
+ list_add_tail(&mc_loc->list, &mcount_locs);
*r_offsetp += loc_size;
}
- *mrelpp = is_rela ? (void *)mrelap : (void *)mrelp;
}

-/* Overall supervision for Elf32 ET_REL file. */
-static int do_mcount(unsigned const reltype, size_t rela_size)
+/* Convert list of mcount locations to an array/buffer for libelf */
+static void fill_mcount_locs(GElf_Sxword r_offset, GElf_Addr **rbuf,
+ size_t *rsize)
{
- /* Upper bound on space: assume all relevant relocs are for mcount. */
- unsigned totrelsz;
+ GElf_Addr *buf, *loc;
+ struct mcount_loc *entry, *next;
+ size_t size = sizeof(*loc) * r_offset / loc_size;
+
+ buf = malloc(size);
+ if (!buf) {
+ perror("malloc");
+ return;
+ }

- void *mrel0;
- void *mrelp;
+ loc = buf;
+ list_for_each_entry_safe(entry, next, &mcount_locs, list) {
+ *loc = entry->loc;
+ list_del(&entry->list);
+ free(entry);
+ loc++;
+ }
+ *rbuf = buf;
+ *rsize = size;
+}

- GElf_Addr *mloc0;
- GElf_Addr *mlocp;
+/* Overall supervision for Elf32 ET_REL file. */
+static int do_mcount(unsigned const reltype, size_t rela_size)
+{
GElf_Sxword r_offset = 0;

struct section *sec, *mlocs, *mrels;
@@ -384,33 +421,16 @@ static int do_mcount(unsigned const reltype, size_t rela_size)
if (find_section_by_name(lf, "__mcount_loc") != NULL)
return 0;

- totrelsz = tot_relsize(&rel_entsize);
- if (totrelsz == 0)
- return 0;
-
- mrel0 = malloc(totrelsz);
- mrelp = mrel0;
- if (!mrel0)
- return -1;
-
- /* 2*sizeof(address) <= sizeof(Elf_Rel) */
- mloc0 = malloc(totrelsz>>1);
- mlocp = mloc0;
- if (!mloc0) {
- free(mrel0);
- return -1;
- }
-
+ tot_relsize(&rel_entsize);
is_rela = (rela_size == rel_entsize);

/* add section: __mcount_loc */
- mlocs = elf_create_section(lf, mc_name, sizeof(*mloc0), 0);
+ mlocs = elf_create_section(lf, mc_name, sizeof(GElf_Addr), 0);
if (!mlocs)
goto out;
mlocs->sh.sh_link = 0;
mlocs->sh.sh_info = 0;
mlocs->sh.sh_addralign = 8;
- mlocs->data->d_buf = mloc0;
mlocs->data->d_type = ELF_T_ADDR; /* elf_xlatetof() conversion */

/* add section .rel[a]__mcount_loc */
@@ -419,7 +439,6 @@ static int do_mcount(unsigned const reltype, size_t rela_size)
if (!mrels)
goto out;
mrels->sh.sh_flags = 0; /* clear SHF_INFO_LINK */
- mrels->data->d_buf = mrel0;

list_for_each_entry(sec, &lf->sections, list) {
char const *txtname;
@@ -433,7 +452,7 @@ static int do_mcount(unsigned const reltype, size_t rela_size)
txtname, &recval, &recsym))
goto out;

- sift_rel_mcount(&mlocp, &r_offset, &mrelp, sec,
+ sift_rel_mcount(&r_offset, sec, mrels, mlocs,
recsym, recval, reltype, is_rela);
} else if (txtname && (warn_on_notrace_sect || make_nop)) {
/*
@@ -445,25 +464,21 @@ static int do_mcount(unsigned const reltype, size_t rela_size)
}
}

- if (mloc0 != mlocp) {
+ if (!list_empty(&mcount_locs)) {
+ fill_mcount_locs(r_offset, (GElf_Addr **)&mlocs->data->d_buf,
+ &mlocs->sh.sh_size);
/* Update the section size and Elf_Data size */
- mlocs->sh.sh_size = (void *)mlocp - (void *)mloc0;
mlocs->len = mlocs->sh.sh_size;
mlocs->data->d_size = mlocs->len;
elf_flagdata(mlocs->data, ELF_C_SET, ELF_F_DIRTY);

- mrels->sh.sh_size = mrelp - mrel0;
- mrels->len = mrels->sh.sh_size;
- mrels->data->d_size = mrels->len;
- elf_flagdata(mrels->data, ELF_C_SET, ELF_F_DIRTY);
+ elf_rebuild_reloc_section(lf, mrels);

/* overwrite the ELF file */
result = elf_write(lf);
} else
result = 0;
out:
- free(mrel0);
- free(mloc0);
return result;
}

@@ -490,6 +505,8 @@ static int do_file(char const *const fname)
goto out;
}

+ INIT_LIST_HEAD(&mcount_locs);
+
switch (lf->ehdr.e_ident[EI_DATA]) {
default:
fprintf(stderr, "unrecognized ELF data encoding %d: %s\n",
--
2.20.1

2020-06-18 22:29:02

by Matt Helsley

[permalink] [raw]
Subject: [RFC][PATCH v5 06/51] 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 modify the ELF
file -- it only changes the way we walk the ELF sections and do
lookups to find the relocations.

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

diff --git a/tools/objtool/recordmcount.h b/tools/objtool/recordmcount.h
index a96ffcef515a..b46e855d32bf 100644
--- a/tools/objtool/recordmcount.h
+++ b/tools/objtool/recordmcount.h
@@ -364,7 +364,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,
@@ -372,10 +372,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_Rel const *const rel0 = (Elf_Rel const *)(relhdr->sh_offset
+ (void *)ehdr);

*sym0 = (Elf_Sym const *)(_w(symsec->sh_offset)
@@ -395,9 +395,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)
{
@@ -406,8 +406,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;

@@ -423,7 +423,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;
@@ -443,7 +443,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)
{
@@ -452,9 +452,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;
@@ -545,13 +545,13 @@ static int 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 ||
@@ -560,30 +560,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;
}
@@ -599,8 +598,7 @@ static int do_func(Elf_Ehdr *const ehdr, char const *const fname,
char const *const shstrtab = (char const *)(_w(shstr->sh_offset)
+ (void *)ehdr);

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

Elf32_Word *symtab;
Elf32_Word *symtab_shndx;
@@ -617,12 +615,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);
@@ -640,15 +640,18 @@ static int do_func(Elf_Ehdr *const ehdr, char const *const fname,

find_symtab(ehdr, shdr0, nhdr, &symtab, &symtab_shndx);

- 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)) {
unsigned int recsym;
uint_t recval = 0;

- symsec_sh_link = w(relhdr->sh_link);
- result = find_secsym_ndx(w(relhdr->sh_info), txtname,
+ symsec_sh_link = relhdr->sh_link;
+ result = find_secsym_ndx(relhdr->sh_info, txtname,
&recval, &recsym,
&shdr0[symsec_sh_link],
symtab, symtab_shndx,
@@ -656,7 +659,7 @@ static int do_func(Elf_Ehdr *const ehdr, char const *const fname,
if (result)
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);
--
2.20.1

2020-06-18 22:29:19

by Matt Helsley

[permalink] [raw]
Subject: [RFC][PATCH v5 50/51] objtool: mcount: Remove useless lookup

Since the relocation section's sh_info points back to the text
section it applies to and we already have that we can just pass
it in and greatly simplify find_section_sym_index().

Signed-off-by: Matt Helsley <[email protected]>
---
tools/objtool/mcount.c | 39 +++++++++++++++------------------------
1 file changed, 15 insertions(+), 24 deletions(-)

diff --git a/tools/objtool/mcount.c b/tools/objtool/mcount.c
index 084bbc02de0c..a74625aed09b 100644
--- a/tools/objtool/mcount.c
+++ b/tools/objtool/mcount.c
@@ -198,35 +198,27 @@ static const unsigned int missing_sym = (unsigned int)-1;
* Num: Value Size Type Bind Vis Ndx Name
* 2: 00000000 0 SECTION LOCAL DEFAULT 1
*/
-static int find_section_sym_index(unsigned const txtndx,
- char const *const txtname,
- unsigned long *const recvalp,
- unsigned int *sym_index)
+static int find_section_sym_index(const struct section * const txts,
+ unsigned long *const recvalp,
+ unsigned int *sym_index)
{
struct symbol *sym;
- struct section *txts = find_section_by_index(lf, txtndx);
-
- if (!txts) {
- fprintf(stderr, "Cannot find section %u: %s.\n",
- txtndx, txtname);
- return missing_sym;
- }

list_for_each_entry(sym, &txts->symbol_list, list) {
/* avoid symbols with weak binding */
- if ((sym->bind == STB_LOCAL) || (sym->bind == STB_GLOBAL)) {
- /* function symbols on ARM have quirks, avoid them */
- if (lf->ehdr.e_machine == EM_ARM
- && sym->type == STT_FUNC)
- continue;
-
- *recvalp = sym->sym.st_value;
- *sym_index = sym->idx;
- return 0;
- }
+ if ((sym->bind != STB_LOCAL) && (sym->bind != STB_GLOBAL))
+ continue;
+
+ /* function symbols on ARM have quirks, avoid them */
+ if (lf->ehdr.e_machine == EM_ARM && sym->type == STT_FUNC)
+ continue;
+
+ *recvalp = sym->sym.st_value;
+ *sym_index = sym->idx;
+ return 0;
}
fprintf(stderr, "Cannot find symbol for section %u: %s.\n",
- txtndx, txtname);
+ txts->idx, txts->name);
return missing_sym;
}

@@ -414,8 +406,7 @@ static int do_mcount(unsigned const reltype)
unsigned long recval = 0;
unsigned int recsym;

- if (find_section_sym_index(sec->sh.sh_info,
- txts->name, &recval, &recsym))
+ if (find_section_sym_index(txts, &recval, &recsym))
goto out;

sift_rel_mcount(&r_offset, sec, mrels, mlocs,
--
2.20.1

2020-06-19 00:14:55

by Matt Helsley

[permalink] [raw]
Subject: [RFC][PATCH v5 07/51] objtool: mcount: Move nhdr into find_symtab()

Since it's no longer needed in the rest of do_func() we can move
it to where it's needed rather than pass it as a parameter.

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

diff --git a/tools/objtool/recordmcount.h b/tools/objtool/recordmcount.h
index b46e855d32bf..4bd61c9d1fd5 100644
--- a/tools/objtool/recordmcount.h
+++ b/tools/objtool/recordmcount.h
@@ -229,9 +229,10 @@ static int get_shstrndx(Elf_Ehdr const *ehdr, Elf_Shdr const *shdr0)
}

static void find_symtab(Elf_Ehdr *const ehdr, Elf_Shdr const *shdr0,
- unsigned const nhdr, Elf32_Word **symtab,
+ Elf32_Word **symtab,
Elf32_Word **symtab_shndx)
{
+ unsigned const nhdr = get_shnum(ehdr, shdr0);
Elf_Shdr const *relhdr;
unsigned k;

@@ -593,7 +594,6 @@ 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 = get_shnum(ehdr, shdr0);
Elf_Shdr *const shstr = &shdr0[get_shstrndx(ehdr, shdr0)];
char const *const shstrtab = (char const *)(_w(shstr->sh_offset)
+ (void *)ehdr);
@@ -638,7 +638,7 @@ static int do_func(Elf_Ehdr *const ehdr, char const *const fname,
return -1;
}

- find_symtab(ehdr, shdr0, nhdr, &symtab, &symtab_shndx);
+ find_symtab(ehdr, shdr0, &symtab, &symtab_shndx);

list_for_each_entry(sec, &lf->sections, list) {
char const *txtname;
--
2.20.1

2020-06-19 00:15:47

by Matt Helsley

[permalink] [raw]
Subject: [RFC][PATCH v5 22/51] objtool: mcount: Move has_rel_mcount() and tot_relsize()

The has_rel_mcount() and tot_relsize() helpers are no longer
dependent on the ELF wrapper so we can move them.

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

diff --git a/tools/objtool/recordmcount.c b/tools/objtool/recordmcount.c
index fae0b15d0632..918e47217379 100644
--- a/tools/objtool/recordmcount.c
+++ b/tools/objtool/recordmcount.c
@@ -446,6 +446,32 @@ static int nop_mcount(struct section * const rels,
return 0;
}

+static char const *has_rel_mcount(const struct section * const rels)
+{
+ const struct section *txts;
+ if (rels->sh.sh_type != SHT_REL && rels->sh.sh_type != SHT_RELA)
+ return NULL;
+ txts = find_section_by_index(lf, rels->sh.sh_info);
+ if ((txts->sh.sh_type != SHT_PROGBITS) ||
+ !(txts->sh.sh_flags & SHF_EXECINSTR))
+ return NULL;
+ return txts->name;
+}
+
+static unsigned tot_relsize(void)
+{
+ const struct section *sec;
+ unsigned totrelsz = 0;
+ char const *txtname;
+
+ list_for_each_entry(sec, &lf->sections, list) {
+ txtname = has_rel_mcount(sec);
+ if (txtname && is_mcounted_section_name(txtname))
+ totrelsz += sec->sh.sh_size;
+ }
+ return totrelsz;
+}
+
/* 32 bit and 64 bit are very similar */
#include "recordmcount.h"
#define RECORD_MCOUNT_64
diff --git a/tools/objtool/recordmcount.h b/tools/objtool/recordmcount.h
index 25028c61da2b..2733f7fde51d 100644
--- a/tools/objtool/recordmcount.h
+++ b/tools/objtool/recordmcount.h
@@ -20,8 +20,6 @@
#undef append_func
#undef mcount_adjust
#undef sift_rel_mcount
-#undef has_rel_mcount
-#undef tot_relsize
#undef do_func
#undef Elf_Shdr
#undef Elf_Rel
@@ -36,8 +34,6 @@
#ifdef RECORD_MCOUNT_64
# define append_func append64
# define sift_rel_mcount sift64_rel_mcount
-# define has_rel_mcount has64_rel_mcount
-# define tot_relsize tot64_relsize
# define do_func do64
# define mcount_adjust mcount_adjust_64
# define Elf_Rel Elf64_Rel
@@ -51,8 +47,6 @@
#else
# define append_func append32
# define sift_rel_mcount sift32_rel_mcount
-# define has_rel_mcount has32_rel_mcount
-# define tot_relsize tot32_relsize
# define do_func do32
# define mcount_adjust mcount_adjust_32
# define Elf_Rel Elf32_Rel
@@ -165,33 +159,6 @@ static uint_t *sift_rel_mcount(uint_t *mlocp,
return mlocp;
}

-static char const *has_rel_mcount(const struct section * const rels)
-{
- const struct section *txts;
- if (rels->sh.sh_type != SHT_REL && rels->sh.sh_type != SHT_RELA)
- return NULL;
- txts = find_section_by_index(lf, rels->sh.sh_info);
- if ((txts->sh.sh_type != SHT_PROGBITS) ||
- !(txts->sh.sh_flags & SHF_EXECINSTR))
- return NULL;
- return txts->name;
-}
-
-
-static unsigned tot_relsize(void)
-{
- const struct section *sec;
- unsigned totrelsz = 0;
- char const *txtname;
-
- list_for_each_entry(sec, &lf->sections, list) {
- txtname = has_rel_mcount(sec);
- if (txtname && is_mcounted_section_name(txtname))
- totrelsz += sec->sh.sh_size;
- }
- return totrelsz;
-}
-
/* Overall supervision for Elf32 ET_REL file. */
static int do_func(unsigned const reltype)
{
--
2.20.1

2020-06-19 00:20:38

by Matt Helsley

[permalink] [raw]
Subject: [RFC][PATCH v5 49/51] objtool: mcount: Remove relocation size check

Rather than use the size of the relocations check the section
header type directly to see if the mcount relocations should
be rel or rela relocations.

Signed-off-by: Matt Helsley <[email protected]>
---
tools/objtool/elf.c | 4 ++--
tools/objtool/elf.h | 2 +-
tools/objtool/mcount.c | 15 +++++----------
3 files changed, 8 insertions(+), 13 deletions(-)

diff --git a/tools/objtool/elf.c b/tools/objtool/elf.c
index 733e10d4a574..4948df31bba0 100644
--- a/tools/objtool/elf.c
+++ b/tools/objtool/elf.c
@@ -642,8 +642,8 @@ static int read_relocs(struct elf *elf)

sec->base->reloc = sec;
sec->mcountable = relocs_mcountable(sec);
- if (sec->mcountable && !elf->mcount_rel_entsize)
- elf->mcount_rel_entsize = sec->sh.sh_entsize;
+ if (sec->mcountable)
+ elf->mcount_r_addends = (sec->sh.sh_type == SHT_RELA);

nr_reloc = 0;
for (i = 0; i < sec->sh.sh_size / sec->sh.sh_entsize; i++) {
diff --git a/tools/objtool/elf.h b/tools/objtool/elf.h
index 8ece1ca79cca..f298e327af01 100644
--- a/tools/objtool/elf.h
+++ b/tools/objtool/elf.h
@@ -87,8 +87,8 @@ struct elf {
Elf *elf;
GElf_Ehdr ehdr;
int fd;
- size_t mcount_rel_entsize;
bool changed;
+ bool mcount_r_addends;
char *name;
struct list_head sections;
DECLARE_HASHTABLE(symbol_hash, ELF_HASH_BITS);
diff --git a/tools/objtool/mcount.c b/tools/objtool/mcount.c
index 9527924af56b..084bbc02de0c 100644
--- a/tools/objtool/mcount.c
+++ b/tools/objtool/mcount.c
@@ -368,22 +368,17 @@ static void fill_mcount_locs(GElf_Sxword r_offset, GElf_Addr **rbuf,
}

/* Overall supervision for Elf32 ET_REL file. */
-static int do_mcount(unsigned const reltype, size_t rela_size)
+static int do_mcount(unsigned const reltype)
{
- GElf_Sxword r_offset = 0;
-
struct section *sec, *mlocs, *mrels;
const char * const mc_name = "__mcount_loc";
-
- const unsigned int rel_entsize = lf->mcount_rel_entsize;
+ GElf_Sxword r_offset = 0;
int result = -1;
- bool is_rela;
+ const bool is_rela = lf->mcount_r_addends;

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

- is_rela = (rela_size == rel_entsize);
-
/* add section: __mcount_loc */
mlocs = elf_create_section(lf, mc_name, sizeof(GElf_Addr), 0);
if (!mlocs)
@@ -562,7 +557,7 @@ static int do_file(char const *const fname)
is_fake_mcount = MIPS_is_fake_mcount;
}
loc_size = 4;
- rc = do_mcount(reltype, sizeof(Elf32_Rela));
+ rc = do_mcount(reltype);
break;
case ELFCLASS64: {
if (lf->ehdr.e_ehsize != sizeof(Elf64_Ehdr)
@@ -580,7 +575,7 @@ static int do_file(char const *const fname)
is_fake_mcount = MIPS_is_fake_mcount;
}
loc_size = 8;
- rc = do_mcount(reltype, sizeof(Elf64_Rela));
+ rc = do_mcount(reltype);
break;
}
} /* end switch */
--
2.20.1

2020-06-19 00:21:02

by Matt Helsley

[permalink] [raw]
Subject: [RFC][PATCH v5 33/51] objtool: mcount: Remove wrapper for ELF relocation type

Remove the last uses of the Elf_Rela wrapper by passing the
size of the relocations we're dealing with as a parameter.

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

diff --git a/tools/objtool/recordmcount.c b/tools/objtool/recordmcount.c
index b9f15fc1f40e..6db035252b6c 100644
--- a/tools/objtool/recordmcount.c
+++ b/tools/objtool/recordmcount.c
@@ -575,7 +575,7 @@ static int do_file(char const *const fname)
is_fake_mcount = MIPS_is_fake_mcount;
}
loc_size = 4;
- rc = do32(reltype);
+ rc = do32(reltype, sizeof(Elf32_Rela));
break;
case ELFCLASS64: {
if (lf->ehdr.e_ehsize != sizeof(Elf64_Ehdr)
@@ -593,7 +593,7 @@ static int do_file(char const *const fname)
is_fake_mcount = MIPS_is_fake_mcount;
}
loc_size = 8;
- rc = do64(reltype);
+ rc = do64(reltype, sizeof(Elf64_Rela));
break;
}
} /* end switch */
diff --git a/tools/objtool/recordmcount.h b/tools/objtool/recordmcount.h
index 2dd303d51b78..07fc93917736 100644
--- a/tools/objtool/recordmcount.h
+++ b/tools/objtool/recordmcount.h
@@ -18,18 +18,15 @@
* Copyright 2010 Steven Rostedt <[email protected]>, Red Hat Inc.
*/
#undef do_func
-#undef Elf_Rela

#ifdef RECORD_MCOUNT_64
# define do_func do64
-# define Elf_Rela Elf64_Rela
#else
# define do_func do32
-# define Elf_Rela Elf32_Rela
#endif

/* Overall supervision for Elf32 ET_REL file. */
-static int do_func(unsigned const reltype)
+static int do_func(unsigned const reltype, size_t rela_size)
{
/* Upper bound on space: assume all relevant relocs are for mcount. */
unsigned totrelsz;
@@ -68,7 +65,7 @@ static int do_func(unsigned const reltype)
return -1;
}

- is_rela = (sizeof(Elf_Rela) == rel_entsize);
+ is_rela = (rela_size == rel_entsize);

/* add section: __mcount_loc */
mlocs = elf_create_section(lf, mc_name, sizeof(*mloc0), 0);
--
2.20.1

2020-06-19 00:21:02

by Matt Helsley

[permalink] [raw]
Subject: [RFC][PATCH v5 30/51] objtool: mcount: Generic location and relocation table types

Rather than building the exact ELF section data we need and
avoiding libelf's conversion step, use more GElf types
and then libelf's elfxx_xlatetof() functions to convert
the mcount locations (GElf_Addr) and associated relocations.

This converts sift_rel_mcount() so that it doesn't use the
recordmcount wrapper. The next patch will move it out of the
wrapper.

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

diff --git a/tools/objtool/recordmcount.c b/tools/objtool/recordmcount.c
index bb53927612fb..34976f3294ac 100644
--- a/tools/objtool/recordmcount.c
+++ b/tools/objtool/recordmcount.c
@@ -210,7 +210,7 @@ static int is_mcounted_section_name(char const *const txtname)
strcmp(".cpuidle.text", txtname) == 0;
}

-static struct symbol *get_mcountsym(struct reloc *reloc)
+static struct symbol *get_mcount_sym(struct reloc *reloc)
{
struct symbol *sym = reloc->sym;
char const *symname = sym->name;
@@ -322,16 +322,16 @@ static int nop_mcount(struct section * const rels,
{
struct reloc *reloc;
struct section *txts = find_section_by_index(lf, rels->sh.sh_info);
- struct symbol *mcountsym = NULL;
+ struct symbol *mcount_sym = NULL;
int once = 0;

list_for_each_entry(reloc, &rels->reloc_list, list) {
int ret = -1;

- if (!mcountsym)
- mcountsym = get_mcountsym(reloc);
+ if (!mcount_sym)
+ mcount_sym = get_mcount_sym(reloc);

- if (mcountsym == reloc->sym && !is_fake_mcount(reloc)) {
+ if (mcount_sym == reloc->sym && !is_fake_mcount(reloc)) {
if (make_nop) {
ret = make_nop(txts, reloc->offset);
if (ret < 0)
@@ -392,6 +392,9 @@ static unsigned tot_relsize(unsigned int *rel_entsize)
*/
static int mcount_adjust = 0;

+/* Size of an entry in __mcount_loc; 4 or 8 */
+static size_t loc_size;
+
/* 32 bit and 64 bit are very similar */
#include "recordmcount.h"
#define RECORD_MCOUNT_64
@@ -409,34 +412,6 @@ static int arm_is_fake_mcount(struct reloc const *rp)
return 1;
}

-/* 64-bit EM_MIPS has weird ELF64_Rela.r_info.
- * http://techpubs.sgi.com/library/manuals/4000/007-4658-001/pdf/007-4658-001.pdf
- * We interpret Table 29 Relocation Operation (Elf64_Rel, Elf64_Rela) [p.40]
- * to imply the order of the members; the spec does not say so.
- * typedef unsigned char Elf64_Byte;
- * fails on MIPS64 because their <elf.h> already has it!
- */
-
-typedef uint8_t myElf64_Byte; /* Type for a 8-bit quantity. */
-
-union mips_r_info {
- Elf64_Xword r_info;
- struct {
- Elf64_Word r_sym; /* Symbol index. */
- myElf64_Byte r_ssym; /* Special symbol. */
- myElf64_Byte r_type3; /* Third relocation. */
- myElf64_Byte r_type2; /* Second relocation. */
- myElf64_Byte r_type; /* First relocation. */
- } r_mips;
-};
-
-static void MIPS64_r_info(Elf64_Rel *const rp, unsigned sym, unsigned type)
-{
- rp->r_info = ((union mips_r_info){
- .r_mips = { .r_sym = w(sym), .r_type = type }
- }).r_info;
-}
-
static int do_file(char const *const fname)
{
unsigned int reltype = 0;
@@ -552,6 +527,7 @@ static int do_file(char const *const fname)
reltype = R_MIPS_32;
is_fake_mcount = MIPS_is_fake_mcount;
}
+ loc_size = 4;
rc = do32(reltype);
break;
case ELFCLASS64: {
@@ -567,9 +543,9 @@ static int do_file(char const *const fname)
}
if (lf->ehdr.e_machine == EM_MIPS) {
reltype = R_MIPS_64;
- Elf64_r_info = MIPS64_r_info;
is_fake_mcount = MIPS_is_fake_mcount;
}
+ loc_size = 8;
rc = do64(reltype);
break;
}
diff --git a/tools/objtool/recordmcount.h b/tools/objtool/recordmcount.h
index ce88f0c2f79b..1d11dfc40d09 100644
--- a/tools/objtool/recordmcount.h
+++ b/tools/objtool/recordmcount.h
@@ -19,86 +19,63 @@
*/
#undef sift_rel_mcount
#undef do_func
-#undef Elf_Shdr
-#undef Elf_Rel
#undef Elf_Rela
-#undef ELF_R_INFO
-#undef Elf_r_info
-#undef fn_ELF_R_INFO
-#undef uint_t
-#undef _w
-#undef _size

#ifdef RECORD_MCOUNT_64
# define sift_rel_mcount sift64_rel_mcount
# define do_func do64
-# define Elf_Rel Elf64_Rel
# define Elf_Rela Elf64_Rela
-# define ELF_R_INFO ELF64_R_INFO
-# define Elf_r_info Elf64_r_info
-# define fn_ELF_R_INFO fn_ELF64_R_INFO
-# define uint_t uint64_t
-# define _w w8
-# define _size 8
#else
# define sift_rel_mcount sift32_rel_mcount
# define do_func do32
-# define Elf_Rel Elf32_Rel
# define Elf_Rela Elf32_Rela
-# define ELF_R_INFO ELF32_R_INFO
-# define Elf_r_info Elf32_r_info
-# define fn_ELF_R_INFO fn_ELF32_R_INFO
-# define uint_t uint32_t
-# define _w w
-# define _size 4
#endif

-static void fn_ELF_R_INFO(Elf_Rel *const rp, unsigned sym, unsigned type)
-{
- rp->r_info = _w(ELF_R_INFO(sym, type));
-}
-static void (*Elf_r_info)(Elf_Rel *const rp, unsigned sym, unsigned type) = fn_ELF_R_INFO;
-
/*
* Look at the relocations in order to find the calls to mcount.
* Accumulate the section offsets that are found, and their relocation info,
* onto the end of the existing arrays.
*/
-static uint_t *sift_rel_mcount(uint_t *mlocp,
- unsigned const offbase,
- Elf_Rel **const mrelpp,
+static void sift_rel_mcount(GElf_Addr **mlocpp,
+ GElf_Sxword *r_offsetp,
+ void **const mrelpp,
const struct section * const rels,
unsigned const recsym_index,
unsigned long const recval,
- unsigned const reltype)
+ unsigned const reltype,
+ bool is_rela)
{
- uint_t *const mloc0 = mlocp;
- Elf_Rel *mrelp = *mrelpp;
- unsigned int rel_entsize = rels->sh.sh_entsize;
- struct symbol *mcountsym = NULL;
+ GElf_Rel *mrelp = *mrelpp;
+ GElf_Rela *mrelap = *mrelpp;
+ struct symbol *mcount_sym = NULL;
struct reloc *reloc;

list_for_each_entry(reloc, &rels->reloc_list, list) {
- if (!mcountsym)
- mcountsym = get_mcountsym(reloc);
-
- if (mcountsym == reloc->sym && !is_fake_mcount(reloc)) {
- uint_t const addend =
- _w(reloc->offset - recval + mcount_adjust);
- mrelp->r_offset = _w(offbase
- + ((void *)mlocp - (void *)mloc0));
- Elf_r_info(mrelp, recsym_index, reltype);
- if (rel_entsize == sizeof(Elf_Rela)) {
- ((Elf_Rela *)mrelp)->r_addend = addend;
- *mlocp++ = 0;
- } else
- *mlocp++ = addend;
-
- mrelp = (Elf_Rel *)(rel_entsize + (void *)mrelp);
+ unsigned long addend;
+
+ if (!mcount_sym)
+ mcount_sym = get_mcount_sym(reloc);
+
+ if (mcount_sym != reloc->sym || is_fake_mcount(reloc))
+ continue;
+
+ addend = reloc->offset - recval + mcount_adjust;
+ if (is_rela) {
+ mrelap->r_offset = *r_offsetp;
+ mrelap->r_info = GELF_R_INFO(recsym_index, reltype);
+ mrelap->r_addend = addend;
+ mrelap++;
+ **mlocpp = 0;
+ } else {
+ mrelp->r_offset = *r_offsetp;
+ mrelp->r_info = GELF_R_INFO(recsym_index, reltype);
+ mrelp++;
+ **mlocpp = addend;
}
+ (*mlocpp)++;
+ *r_offsetp += loc_size;
}
- *mrelpp = mrelp;
- return mlocp;
+ *mrelpp = is_rela ? (void *)mrelap : (void *)mrelp;
}

/* Overall supervision for Elf32 ET_REL file. */
@@ -107,14 +84,15 @@ static int do_func(unsigned const reltype)
/* Upper bound on space: assume all relevant relocs are for mcount. */
unsigned totrelsz;

- Elf_Rel * mrel0;
- Elf_Rel * mrelp;
+ void *mrel0;
+ void *mrelp;

- uint_t * mloc0;
- uint_t * mlocp;
+ GElf_Addr *mloc0;
+ GElf_Addr *mlocp;
+ GElf_Sxword r_offset = 0;

struct section *sec, *mlocs, *mrels;
- char const *mc_name;
+ const char *mc_name;

unsigned int rel_entsize = 0;
int result = -1;
@@ -146,24 +124,27 @@ static int do_func(unsigned const reltype)
: ".rel__mcount_loc";

/* add section: __mcount_loc */
- mlocs = elf_create_section(lf, mc_name + (is_rela ? 1 : 0) + strlen(".rel"), _size, 0);
+ mlocs = elf_create_section(lf, mc_name + (is_rela ? 1 : 0) + strlen(".rel"), sizeof(*mloc0), 0);
if (!mlocs)
goto out;
mlocs->sh.sh_link = 0;
mlocs->sh.sh_info = 0;
- mlocs->sh.sh_addralign = _size;
+ mlocs->sh.sh_addralign = 8;
+ mlocs->data->d_buf = mloc0;
+ mlocs->data->d_type = ELF_T_ADDR; /* elf_xlatetof() conversion */

/* add section .rel[a]__mcount_loc */
mrels = elf_create_section(lf, mc_name, rel_entsize, 0);
if (!mrels)
goto out;
- mrels->sh.sh_type = is_rela
- ? SHT_RELA
- : SHT_REL;
+ /* Like elf_create_rela_section() without the name bits */
+ mrels->sh.sh_type = is_rela ? SHT_RELA : SHT_REL;
mrels->sh.sh_flags = 0; /* clear SHF_ALLOC */
mrels->sh.sh_link = find_section_by_name(lf, ".symtab")->idx;
mrels->sh.sh_info = mlocs->idx;
- mrels->sh.sh_addralign = _size;
+ mrels->sh.sh_addralign = 8;
+ mrels->data->d_buf = mrel0;
+ mrels->data->d_type = is_rela ? ELF_T_RELA : ELF_T_REL; /* elf_xlatetof() conversion */

list_for_each_entry(sec, &lf->sections, list) {
char const *txtname;
@@ -177,9 +158,8 @@ static int do_func(unsigned const reltype)
txtname, &recval, &recsym))
goto out;

- mlocp = sift_rel_mcount(mlocp,
- (void *)mlocp - (void *)mloc0, &mrelp,
- sec, recsym, (uint_t)recval, reltype);
+ sift_rel_mcount(&mlocp, &r_offset, &mrelp, sec,
+ recsym, recval, reltype, is_rela);
} else if (txtname && (warn_on_notrace_sect || make_nop)) {
/*
* This section is ignored by ftrace, but still
@@ -191,17 +171,15 @@ static int do_func(unsigned const reltype)
}

if (mloc0 != mlocp) {
- /* Update the section sizes */
+ /* Update the section size and Elf_Data size */
mlocs->sh.sh_size = (void *)mlocp - (void *)mloc0;
mlocs->len = mlocs->sh.sh_size;
mlocs->data->d_size = mlocs->len;
- mlocs->data->d_buf = mloc0;
elf_flagdata(mlocs->data, ELF_C_SET, ELF_F_DIRTY);

- mrels->sh.sh_size = (void *)mrelp - (void *)mrel0;
+ mrels->sh.sh_size = mrelp - mrel0;
mrels->len = mrels->sh.sh_size;
mrels->data->d_size = mrels->len;
- mrels->data->d_buf = mrel0;
elf_flagdata(mrels->data, ELF_C_SET, ELF_F_DIRTY);

/* overwrite the ELF file */
--
2.20.1

2020-06-19 00:36:42

by Matt Helsley

[permalink] [raw]
Subject: [RFC][PATCH v5 16/51] objtool: mcount: Move is_fake_mcount()

Promote the now-bit-independent is_fake_mcount() out of the old
recordmcount ELF wrapper.

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

diff --git a/tools/objtool/recordmcount.c b/tools/objtool/recordmcount.c
index d5f7c06afd57..24b019b82795 100644
--- a/tools/objtool/recordmcount.c
+++ b/tools/objtool/recordmcount.c
@@ -438,6 +438,48 @@ static struct symbol *get_mcountsym(struct reloc *reloc)
return NULL;
}

+/*
+ * MIPS mcount long call has 2 _mcount symbols, only the position of the 1st
+ * _mcount symbol is needed for dynamic function tracer, with it, to disable
+ * tracing(ftrace_make_nop), the instruction in the position is replaced with
+ * the "b label" instruction, to enable tracing(ftrace_make_call), replace the
+ * instruction back. So, here, we set the 2nd one as fake and filter it.
+ *
+ * c: 3c030000 lui v1,0x0 <--> b label
+ * c: R_MIPS_HI16 _mcount
+ * c: R_MIPS_NONE *ABS*
+ * c: R_MIPS_NONE *ABS*
+ * 10: 64630000 daddiu v1,v1,0
+ * 10: R_MIPS_LO16 _mcount
+ * 10: R_MIPS_NONE *ABS*
+ * 10: R_MIPS_NONE *ABS*
+ * 14: 03e0082d move at,ra
+ * 18: 0060f809 jalr v1
+ * label:
+ */
+#define MIPS_FAKEMCOUNT_OFFSET 4
+
+static int MIPS_is_fake_mcount(struct reloc const *reloc)
+{
+ static unsigned long old_r_offset = ~0UL;
+ unsigned long current_r_offset = reloc->offset;
+ int is_fake;
+
+ is_fake = (old_r_offset != ~0UL) &&
+ (current_r_offset - old_r_offset == MIPS_FAKEMCOUNT_OFFSET);
+ old_r_offset = current_r_offset;
+
+ return is_fake;
+}
+
+/* Functions and pointers that do_file() may override for specific e_machine. */
+static int fn_is_fake_mcount(struct reloc const *reloc)
+{
+ return 0;
+}
+
+static int (*is_fake_mcount)(struct reloc const *reloc) = fn_is_fake_mcount;
+
static const unsigned int missing_sym = (unsigned int)-1;

/* 32 bit and 64 bit are very similar */
@@ -557,7 +599,7 @@ static int do_file(char const *const fname)
altmcount = "__gnu_mcount_nc";
make_nop = make_nop_arm;
rel_type_nop = R_ARM_NONE;
- is_fake_mcount32 = arm_is_fake_mcount;
+ is_fake_mcount = arm_is_fake_mcount;
gpfx = 0;
break;
case EM_AARCH64:
@@ -597,7 +639,7 @@ static int do_file(char const *const fname)
}
if (w2(ehdr->e_machine) == EM_MIPS) {
reltype = R_MIPS_32;
- is_fake_mcount32 = MIPS32_is_fake_mcount;
+ is_fake_mcount = MIPS_is_fake_mcount;
}
if (do32(ehdr, reltype) < 0)
goto out;
@@ -617,7 +659,7 @@ static int do_file(char const *const fname)
if (w2(ghdr->e_machine) == EM_MIPS) {
reltype = R_MIPS_64;
Elf64_r_info = MIPS64_r_info;
- is_fake_mcount64 = MIPS64_is_fake_mcount;
+ is_fake_mcount = MIPS_is_fake_mcount;
}
if (do64(ghdr, reltype) < 0)
goto out;
diff --git a/tools/objtool/recordmcount.h b/tools/objtool/recordmcount.h
index dde2ec054e51..941f96e4f74b 100644
--- a/tools/objtool/recordmcount.h
+++ b/tools/objtool/recordmcount.h
@@ -18,9 +18,6 @@
* Copyright 2010 Steven Rostedt <[email protected]>, Red Hat Inc.
*/
#undef append_func
-#undef is_fake_mcount
-#undef fn_is_fake_mcount
-#undef MIPS_is_fake_mcount
#undef mcount_adjust
#undef sift_rel_mcount
#undef nop_mcount
@@ -54,9 +51,6 @@
# define set_shnum set_shnum64
# define get_shstrndx get_shstrndx64
# define do_func do64
-# define is_fake_mcount is_fake_mcount64
-# define fn_is_fake_mcount fn_is_fake_mcount64
-# define MIPS_is_fake_mcount MIPS64_is_fake_mcount
# define mcount_adjust mcount_adjust_64
# define Elf_Ehdr Elf64_Ehdr
# define Elf_Shdr Elf64_Shdr
@@ -80,9 +74,6 @@
# define set_shnum set_shnum32
# define get_shstrndx get_shstrndx32
# define do_func do32
-# define is_fake_mcount is_fake_mcount32
-# define fn_is_fake_mcount fn_is_fake_mcount32
-# define MIPS_is_fake_mcount MIPS32_is_fake_mcount
# define mcount_adjust mcount_adjust_32
# define Elf_Ehdr Elf32_Ehdr
# define Elf_Shdr Elf32_Shdr
@@ -97,13 +88,6 @@
# define _size 4
#endif

-/* Functions and pointers that do_file() may override for specific e_machine. */
-static int fn_is_fake_mcount(struct reloc const *reloc)
-{
- return 0;
-}
-static int (*is_fake_mcount)(struct reloc const *reloc) = fn_is_fake_mcount;
-
static void fn_ELF_R_INFO(Elf_Rel *const rp, unsigned sym, unsigned type)
{
rp->r_info = _w(ELF_R_INFO(sym, type));
@@ -112,40 +96,6 @@ static void (*Elf_r_info)(Elf_Rel *const rp, unsigned sym, unsigned type) = fn_E

static int mcount_adjust = 0;

-/*
- * MIPS mcount long call has 2 _mcount symbols, only the position of the 1st
- * _mcount symbol is needed for dynamic function tracer, with it, to disable
- * tracing(ftrace_make_nop), the instruction in the position is replaced with
- * the "b label" instruction, to enable tracing(ftrace_make_call), replace the
- * instruction back. So, here, we set the 2nd one as fake and filter it.
- *
- * c: 3c030000 lui v1,0x0 <--> b label
- * c: R_MIPS_HI16 _mcount
- * c: R_MIPS_NONE *ABS*
- * c: R_MIPS_NONE *ABS*
- * 10: 64630000 daddiu v1,v1,0
- * 10: R_MIPS_LO16 _mcount
- * 10: R_MIPS_NONE *ABS*
- * 10: R_MIPS_NONE *ABS*
- * 14: 03e0082d move at,ra
- * 18: 0060f809 jalr v1
- * label:
- */
-#define MIPS_FAKEMCOUNT_OFFSET 4
-
-static int MIPS_is_fake_mcount(struct reloc const *reloc)
-{
- static unsigned long old_r_offset = ~0UL;
- unsigned long current_r_offset = reloc->offset;
- int is_fake;
-
- is_fake = (old_r_offset != ~0UL) &&
- (current_r_offset - old_r_offset == MIPS_FAKEMCOUNT_OFFSET);
- old_r_offset = current_r_offset;
-
- return is_fake;
-}
-
static unsigned int get_shnum(Elf_Ehdr const *ehdr, Elf_Shdr const *shdr0)
{
if (shdr0 && !ehdr->e_shnum)
--
2.20.1

2020-06-23 14:15:00

by Matt Helsley

[permalink] [raw]
Subject: Re: [RFC][PATCH v5 00/51] objtool: Make recordmcount a subcommand

On Thu, Jun 18, 2020 at 01:37:46PM -0700, Matt Helsley wrote:
> recordmcount has its own ELF wrapper code and could utilize
> objtool's ELF code to more-portably handle architecture variations.
> This series makes recordmcount a subcommand of objtool. It very
> gradually converts recordmcount to become a subcommand of objtool and
> then reuses parts of objtool's ELF code.
>
> recordmcount maps the file in and collects simple information it needs to
> append a section to the object file. The only part of the original file it
> modifies is the address of new section tables -- interestingly enough this
> resembles RCU in that we don't really trim the old tables so
> much as unlink them via a critical offset and then rely on
> future tooling, in this case, to drop the unused bits.
>
> Much of the recordmcount ELF code is only reading and walking the data
> structures to collect the mcount locations it records in a separate
> area of memory. This means it's safe to mix access to the mapped
> file with access to the objtool-style linked data
> structures as we gradually convert it to using only the linked data
> structures. Once the old ELF code is no longer in use we can drop it
> and use objtool to take over the task of writing the results without
> using the RCU-like trick any more.
>
> After that we greatly simplify the mcount subcommand by adding a
> few flags to the ELF reading code in objtool. Overall the series
> removes about 600 lines of recordmcount while adding little to
> objtool's ELF code.
>
> Testing so far:
>
> I've been using scripts to test cross compilation and execution of
> objtool, and mcount on objects built for x86, ppc64le, arm64, s390, and
> sparc.
>
>
> Applies on top of:
> objtool/core
>
> Peter Zijlstra's "x86/entry: noinstr fixes" [2]

Just thought I'd note for anyone reviewing/playing with this series:

Peter's patches are now in objtool/core

> Sami Tolvanen's patch enabling support for more than 64k
> sections in recordmcount, already going upstream. [3]

Sami's patch is now in Linus' master branch

Cheers,
-Matt