2020-04-10 19:37:34

by Matt Helsley

[permalink] [raw]
Subject: [RFC][PATCH 00/36] 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.

The initial 5 patches make objtool compilable for more than x86.
Unlike recordmcount the check command and orc tools are not currently
checking other architectures so we need a way to cleanly build
objtool for those architectures that don't support check / orc. I
went with using weak symbols and added a "missing" architecture
which can be used to indicate the tool is not implemented while
avoiding the need for every architecture to explicitly specify
which subcommands / features are not implemented. I'm curious if
there are better approaches folks recommend though -- this is the
one I landed on. The patches do not add HAVE_OBJTOOL to all
architectures.

Note:
I've been following some of the discussion around making check work
for arm64. So I'd say this series moves check into arch/x86 to
reflect its current status and demonstrates how a command relevant
to a single arch could be handled -- not necessarily what
will/should happen to check.

Subsequent patches, the bulk of the set, very gradually convert
recordmcount to become a subcommand of objtool and then reuse
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 one critical offset and then rely on
future (tooling in this case) to drop the unused bits. So 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.

Testing so far:

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

Matt Helsley (36):
objtool: Exit successfully when requesting help
objtool: Move struct objtool_file into arch-independent header
objtool: Enable compilation of objtool for all architectures
objtool: Report missing support for subcommands
objtool: Add support for relocations without addends
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: 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: 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 helpers out of ELF wrapper
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: 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 wordsized endian wrappers

Documentation/dontdiff | 2 +-
Documentation/trace/ftrace-design.rst | 4 +-
Documentation/trace/ftrace.rst | 6 +-
Makefile | 6 +-
arch/arm64/include/asm/ftrace.h | 2 +-
arch/x86/include/asm/ftrace.h | 2 +-
kernel/trace/Kconfig | 2 +-
scripts/.gitignore | 1 -
scripts/Makefile | 1 -
scripts/Makefile.build | 24 +-
scripts/recordmcount.c | 663 --------------------
scripts/recordmcount.h | 606 ------------------
scripts/sorttable.h | 2 +-
tools/objtool/.gitignore | 1 +
tools/objtool/Build | 6 +-
tools/objtool/Makefile | 1 +
tools/objtool/arch/missing/Build | 4 +
tools/objtool/arch/missing/check.c | 16 +
tools/objtool/arch/missing/mcount.c | 16 +
tools/objtool/arch/missing/orc_dump.c | 13 +
tools/objtool/arch/missing/orc_gen.c | 16 +
tools/objtool/arch/x86/Build | 4 +
tools/objtool/{ => arch/x86}/arch.h | 42 +-
tools/objtool/{ => arch/x86}/cfi.h | 0
tools/objtool/{ => arch/x86}/check.c | 11 +-
tools/objtool/arch/x86/decode.c | 2 +-
tools/objtool/{ => arch/x86}/orc_dump.c | 5 +-
tools/objtool/{ => arch/x86}/orc_gen.c | 9 +-
tools/objtool/{ => arch/x86}/special.c | 4 +-
tools/objtool/{ => arch/x86}/special.h | 2 +-
tools/objtool/builtin-check.c | 5 +
tools/objtool/builtin-mcount.c | 56 ++
tools/objtool/builtin-orc.c | 9 +-
tools/objtool/builtin.h | 4 +
tools/objtool/check.h | 48 +-
tools/objtool/elf.c | 60 +-
tools/objtool/elf.h | 7 +-
tools/objtool/mcount.h | 14 +
tools/objtool/objtool.c | 40 +-
tools/objtool/objtool.h | 20 +
tools/objtool/orc.h | 3 +-
tools/objtool/recordmcount.c | 682 +++++++++++++++++++++
{scripts => tools/objtool}/recordmcount.pl | 0
43 files changed, 1038 insertions(+), 1383 deletions(-)
delete mode 100644 scripts/recordmcount.c
delete mode 100644 scripts/recordmcount.h
create mode 100644 tools/objtool/arch/missing/Build
create mode 100644 tools/objtool/arch/missing/check.c
create mode 100644 tools/objtool/arch/missing/mcount.c
create mode 100644 tools/objtool/arch/missing/orc_dump.c
create mode 100644 tools/objtool/arch/missing/orc_gen.c
rename tools/objtool/{ => arch/x86}/arch.h (59%)
rename tools/objtool/{ => arch/x86}/cfi.h (100%)
rename tools/objtool/{ => arch/x86}/check.c (99%)
rename tools/objtool/{ => arch/x86}/orc_dump.c (98%)
rename tools/objtool/{ => arch/x86}/orc_gen.c (96%)
rename tools/objtool/{ => arch/x86}/special.c (98%)
rename tools/objtool/{ => arch/x86}/special.h (95%)
create mode 100644 tools/objtool/builtin-mcount.c
create mode 100644 tools/objtool/mcount.h
create mode 100644 tools/objtool/objtool.h
create mode 100644 tools/objtool/recordmcount.c
rename {scripts => tools/objtool}/recordmcount.pl (100%)

--
2.20.1


2020-04-10 19:37:44

by Matt Helsley

[permalink] [raw]
Subject: [RFC][PATCH 03/36] objtool: Enable compilation of objtool for all architectures

objtool currently only compiles for x86 architectures. This is
fine as it presently does not support tooling for other
architectures. However, we would like to be able to convert other
kernel tools to run as objtool sub commands because they too
process ELF object files. This will allow us to convert tools
such as recordmcount to use objtool's ELF code.

Since much of recordmcount's ELF code is copy-paste code to/from
a variety of other kernel tools (look at modpost for example) this
means that if we can convert recordmcount we can convert more.

We define a "missing" architecture which contains weak definitions
for tools that do not exist on all architectures. In this case the
"check" and "orc" tools do not exist on all architectures.

To test building for other architectures ($arch below):

cd tools/objtool/arch
ln -s missing $arch
make O=build-$arch ARCH=$arch tools/objtool

This uses the weak, no-op definitions of the "check" and "orc"
commands for the newly-supported architecture. Presently these
exit with 127 to indicate that the subcommands are missing.
Subsequent patches can then be made to determine if the weak
definitions are used and explicitly report a missing command,
and even to list which subcommands are supported (perhaps if
no subcommand is specified it can list the supported subcommands).

objtool is not currently wired in to KConfig to be built for other
architectures because it's not needed for those architectures and
there are no commands it supports other than those for x86.

This commit allows us to demonstrate the pattern of adding
architecture support and isolates moving the various files from
adding support for more objtool subcommands.

Signed-off-by: Matt Helsley <[email protected]>
---
tools/objtool/Build | 4 ---
tools/objtool/arch/missing/Build | 3 ++
tools/objtool/arch/missing/check.c | 14 +++++++++
tools/objtool/arch/missing/orc_dump.c | 11 +++++++
tools/objtool/arch/missing/orc_gen.c | 16 ++++++++++
tools/objtool/arch/x86/Build | 4 +++
tools/objtool/{ => arch/x86}/arch.h | 42 ++++++++++++++++++++++++-
tools/objtool/{ => arch/x86}/cfi.h | 0
tools/objtool/{ => arch/x86}/check.c | 11 ++++---
tools/objtool/arch/x86/decode.c | 2 +-
tools/objtool/{ => arch/x86}/orc_dump.c | 5 +--
tools/objtool/{ => arch/x86}/orc_gen.c | 9 ++++--
tools/objtool/{ => arch/x86}/special.c | 4 +--
tools/objtool/{ => arch/x86}/special.h | 2 +-
tools/objtool/builtin-orc.c | 2 +-
tools/objtool/check.h | 37 ----------------------
tools/objtool/objtool.h | 2 +-
tools/objtool/orc.h | 2 --
18 files changed, 110 insertions(+), 60 deletions(-)
create mode 100644 tools/objtool/arch/missing/Build
create mode 100644 tools/objtool/arch/missing/check.c
create mode 100644 tools/objtool/arch/missing/orc_dump.c
create mode 100644 tools/objtool/arch/missing/orc_gen.c
rename tools/objtool/{ => arch/x86}/arch.h (59%)
rename tools/objtool/{ => arch/x86}/cfi.h (100%)
rename tools/objtool/{ => arch/x86}/check.c (99%)
rename tools/objtool/{ => arch/x86}/orc_dump.c (98%)
rename tools/objtool/{ => arch/x86}/orc_gen.c (96%)
rename tools/objtool/{ => arch/x86}/special.c (98%)
rename tools/objtool/{ => arch/x86}/special.h (95%)

diff --git a/tools/objtool/Build b/tools/objtool/Build
index 66f44f5cd2a6..3178c00072f5 100644
--- a/tools/objtool/Build
+++ b/tools/objtool/Build
@@ -1,11 +1,7 @@
objtool-y += arch/$(SRCARCH)/
objtool-y += builtin-check.o
objtool-y += builtin-orc.o
-objtool-y += check.o
-objtool-y += orc_gen.o
-objtool-y += orc_dump.o
objtool-y += elf.o
-objtool-y += special.o
objtool-y += objtool.o

objtool-y += libstring.o
diff --git a/tools/objtool/arch/missing/Build b/tools/objtool/arch/missing/Build
new file mode 100644
index 000000000000..a2478db59484
--- /dev/null
+++ b/tools/objtool/arch/missing/Build
@@ -0,0 +1,3 @@
+objtool-y += check.o
+objtool-y += orc_gen.o
+objtool-y += orc_dump.o
diff --git a/tools/objtool/arch/missing/check.c b/tools/objtool/arch/missing/check.c
new file mode 100644
index 000000000000..5eac14c8c6a5
--- /dev/null
+++ b/tools/objtool/arch/missing/check.c
@@ -0,0 +1,14 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (C) 2020 Matt Helsley <[email protected]>
+ */
+
+#include <stdbool.h>
+#include "../../check.h"
+
+const char *objname;
+
+int __attribute__ ((weak)) check(const char *_objname, bool orc)
+{
+ return 127;
+}
diff --git a/tools/objtool/arch/missing/orc_dump.c b/tools/objtool/arch/missing/orc_dump.c
new file mode 100644
index 000000000000..f7ebb3a2ce9e
--- /dev/null
+++ b/tools/objtool/arch/missing/orc_dump.c
@@ -0,0 +1,11 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (C) 2017 Josh Poimboeuf <[email protected]>
+ */
+
+#include "../../orc.h"
+
+int __attribute__ ((weak)) orc_dump(const char *_objname)
+{
+ return 127;
+}
diff --git a/tools/objtool/arch/missing/orc_gen.c b/tools/objtool/arch/missing/orc_gen.c
new file mode 100644
index 000000000000..4bf62ddf58a4
--- /dev/null
+++ b/tools/objtool/arch/missing/orc_gen.c
@@ -0,0 +1,16 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (C) 2017 Josh Poimboeuf <[email protected]>
+ */
+
+#include "../../orc.h"
+
+int __attribute__ ((weak)) create_orc(struct objtool_file *file)
+{
+ return 127;
+}
+
+int __attribute__ ((weak)) create_orc_sections(struct objtool_file *file)
+{
+ return 127;
+}
diff --git a/tools/objtool/arch/x86/Build b/tools/objtool/arch/x86/Build
index 7c5004008e97..b5669c3f7a0e 100644
--- a/tools/objtool/arch/x86/Build
+++ b/tools/objtool/arch/x86/Build
@@ -1,4 +1,8 @@
objtool-y += decode.o
+objtool-y += check.o
+objtool-y += orc_gen.o
+objtool-y += orc_dump.o
+objtool-y += special.o

inat_tables_script = ../arch/x86/tools/gen-insn-attr-x86.awk
inat_tables_maps = ../arch/x86/lib/x86-opcode-map.txt
diff --git a/tools/objtool/arch.h b/tools/objtool/arch/x86/arch.h
similarity index 59%
rename from tools/objtool/arch.h
rename to tools/objtool/arch/x86/arch.h
index ced3765c4f44..81d07a5c3d29 100644
--- a/tools/objtool/arch.h
+++ b/tools/objtool/arch/x86/arch.h
@@ -8,9 +8,12 @@

#include <stdbool.h>
#include <linux/list.h>
-#include "elf.h"
+#include "../../elf.h"
#include "cfi.h"

+#include <asm/orc_types.h>
+#include "../../orc.h"
+
enum insn_type {
INSN_JUMP_CONDITIONAL,
INSN_JUMP_UNCONDITIONAL,
@@ -66,6 +69,43 @@ struct stack_op {
struct op_src src;
};

+struct insn_state {
+ struct cfi_reg cfa;
+ struct cfi_reg regs[CFI_NUM_REGS];
+ int stack_size;
+ unsigned char type;
+ bool bp_scratch;
+ bool drap, end, uaccess, df;
+ bool noinstr;
+ s8 instr;
+ unsigned int uaccess_stack;
+ int drap_reg, drap_offset;
+ struct cfi_reg vals[CFI_NUM_REGS];
+};
+
+struct instruction {
+ struct list_head list;
+ struct hlist_node hash;
+ struct section *sec;
+ unsigned long offset;
+ unsigned int len;
+ enum insn_type type;
+ unsigned long immediate;
+ bool alt_group, dead_end, ignore, hint, save, restore, ignore_alts;
+ bool retpoline_safe;
+ s8 instr;
+ u8 visited;
+ struct symbol *call_dest;
+ struct instruction *jump_dest;
+ struct instruction *first_jump_src;
+ struct rela *jump_table;
+ struct list_head alts;
+ struct symbol *func;
+ struct stack_op stack_op;
+ struct insn_state state;
+ struct orc_entry orc;
+};
+
void arch_initial_func_cfi_state(struct cfi_state *state);

int arch_decode_instruction(struct elf *elf, struct section *sec,
diff --git a/tools/objtool/cfi.h b/tools/objtool/arch/x86/cfi.h
similarity index 100%
rename from tools/objtool/cfi.h
rename to tools/objtool/arch/x86/cfi.h
diff --git a/tools/objtool/check.c b/tools/objtool/arch/x86/check.c
similarity index 99%
rename from tools/objtool/check.c
rename to tools/objtool/arch/x86/check.c
index 8dd01f986fbb..3663a6c47146 100644
--- a/tools/objtool/check.c
+++ b/tools/objtool/arch/x86/check.c
@@ -6,12 +6,13 @@
#include <string.h>
#include <stdlib.h>

-#include "builtin.h"
-#include "check.h"
-#include "elf.h"
-#include "special.h"
+#include "../../builtin.h"
+#include "cfi.h"
#include "arch.h"
-#include "warn.h"
+#include "../../check.h"
+#include "../../elf.h"
+#include "special.h"
+#include "../../warn.h"

#include <linux/hashtable.h>
#include <linux/kernel.h>
diff --git a/tools/objtool/arch/x86/decode.c b/tools/objtool/arch/x86/decode.c
index a62e032863a8..3052b11f5eeb 100644
--- a/tools/objtool/arch/x86/decode.c
+++ b/tools/objtool/arch/x86/decode.c
@@ -12,7 +12,7 @@
#include "../../../arch/x86/lib/insn.c"

#include "../../elf.h"
-#include "../../arch.h"
+#include "arch.h"
#include "../../warn.h"

static unsigned char op_to_cfi_reg[][2] = {
diff --git a/tools/objtool/orc_dump.c b/tools/objtool/arch/x86/orc_dump.c
similarity index 98%
rename from tools/objtool/orc_dump.c
rename to tools/objtool/arch/x86/orc_dump.c
index 13ccf775a83a..6eb8e595463d 100644
--- a/tools/objtool/orc_dump.c
+++ b/tools/objtool/arch/x86/orc_dump.c
@@ -4,8 +4,9 @@
*/

#include <unistd.h>
-#include "orc.h"
-#include "warn.h"
+#include <asm/orc_types.h>
+#include "../../orc.h"
+#include "../../warn.h"

static const char *reg_name(unsigned int reg)
{
diff --git a/tools/objtool/orc_gen.c b/tools/objtool/arch/x86/orc_gen.c
similarity index 96%
rename from tools/objtool/orc_gen.c
rename to tools/objtool/arch/x86/orc_gen.c
index 41e4a2754da4..0c9d3a2b3094 100644
--- a/tools/objtool/orc_gen.c
+++ b/tools/objtool/arch/x86/orc_gen.c
@@ -5,10 +5,13 @@

#include <stdlib.h>
#include <string.h>
+#include <asm/orc_types.h>

-#include "orc.h"
-#include "check.h"
-#include "warn.h"
+#include "../../orc.h"
+#include "cfi.h"
+#include "arch.h"
+#include "../../check.h"
+#include "../../warn.h"

int create_orc(struct objtool_file *file)
{
diff --git a/tools/objtool/special.c b/tools/objtool/arch/x86/special.c
similarity index 98%
rename from tools/objtool/special.c
rename to tools/objtool/arch/x86/special.c
index e74e0189de22..677b6efe1446 100644
--- a/tools/objtool/special.c
+++ b/tools/objtool/arch/x86/special.c
@@ -11,9 +11,9 @@
#include <stdlib.h>
#include <string.h>

-#include "builtin.h"
+#include "../../builtin.h"
#include "special.h"
-#include "warn.h"
+#include "../../warn.h"

#define EX_ENTRY_SIZE 12
#define EX_ORIG_OFFSET 0
diff --git a/tools/objtool/special.h b/tools/objtool/arch/x86/special.h
similarity index 95%
rename from tools/objtool/special.h
rename to tools/objtool/arch/x86/special.h
index 35061530e46e..beba41950725 100644
--- a/tools/objtool/special.h
+++ b/tools/objtool/arch/x86/special.h
@@ -7,7 +7,7 @@
#define _SPECIAL_H

#include <stdbool.h>
-#include "elf.h"
+#include "../../elf.h"

struct special_alt {
struct list_head list;
diff --git a/tools/objtool/builtin-orc.c b/tools/objtool/builtin-orc.c
index 5f7cc6157edd..e6e54ae4ab75 100644
--- a/tools/objtool/builtin-orc.c
+++ b/tools/objtool/builtin-orc.c
@@ -15,7 +15,7 @@
#include <string.h>
#include "builtin.h"
#include "check.h"
-
+#include "orc.h"

static const char *orc_usage[] = {
"objtool orc generate [<options>] file.o",
diff --git a/tools/objtool/check.h b/tools/objtool/check.h
index ec6ff7f0970c..4d34bfc84dc7 100644
--- a/tools/objtool/check.h
+++ b/tools/objtool/check.h
@@ -8,43 +8,6 @@

#include <stdbool.h>
#include "objtool.h"
-#include "cfi.h"
-#include "arch.h"
-#include "orc.h"
-
-struct insn_state {
- struct cfi_reg cfa;
- struct cfi_reg regs[CFI_NUM_REGS];
- int stack_size;
- unsigned char type;
- bool bp_scratch;
- bool drap, end, uaccess, df;
- unsigned int uaccess_stack;
- int drap_reg, drap_offset;
- struct cfi_reg vals[CFI_NUM_REGS];
-};
-
-struct instruction {
- struct list_head list;
- struct hlist_node hash;
- struct section *sec;
- unsigned long offset;
- unsigned int len;
- enum insn_type type;
- unsigned long immediate;
- bool alt_group, dead_end, ignore, hint, save, restore, ignore_alts;
- bool retpoline_safe;
- u8 visited;
- struct symbol *call_dest;
- struct instruction *jump_dest;
- struct instruction *first_jump_src;
- struct rela *jump_table;
- struct list_head alts;
- struct symbol *func;
- struct stack_op stack_op;
- struct insn_state state;
- struct orc_entry orc;
-};

int check(const char *objname, bool orc);

diff --git a/tools/objtool/objtool.h b/tools/objtool/objtool.h
index afa52fe6f644..5ff352083056 100644
--- a/tools/objtool/objtool.h
+++ b/tools/objtool/objtool.h
@@ -17,4 +17,4 @@ struct objtool_file {
DECLARE_HASHTABLE(insn_hash, 20);
bool ignore_unreachables, c_file, hints, rodata;
};
-#endif
+#endif /* _OBJTOOL_H */
diff --git a/tools/objtool/orc.h b/tools/objtool/orc.h
index ee2832221e62..c67f451d7610 100644
--- a/tools/objtool/orc.h
+++ b/tools/objtool/orc.h
@@ -6,8 +6,6 @@
#ifndef _ORC_H
#define _ORC_H

-#include <asm/orc_types.h>
-
struct objtool_file;

int create_orc(struct objtool_file *file);
--
2.20.1

2020-04-10 19:37:53

by Matt Helsley

[permalink] [raw]
Subject: [RFC][PATCH 05/36] objtool: Add support for relocations without addends

Currently objtool only collects information about relocations with
addends. In recordmcount, which we are about to merge into objtool,
some supported architectures do not use rela relocations. Since
object files use one or the other the list can be reused.

Signed-off-by: Matt Helsley <[email protected]>
---
tools/objtool/elf.c | 55 ++++++++++++++++++++++++++++++++++++---------
tools/objtool/elf.h | 5 ++++-
2 files changed, 49 insertions(+), 11 deletions(-)

diff --git a/tools/objtool/elf.c b/tools/objtool/elf.c
index 09ddc8f1def3..88ce3efa394c 100644
--- a/tools/objtool/elf.c
+++ b/tools/objtool/elf.c
@@ -465,12 +465,14 @@ static int read_relas(struct elf *elf)
unsigned long nr_rela, max_rela = 0, tot_rela = 0;

list_for_each_entry(sec, &elf->sections, list) {
- if (sec->sh.sh_type != SHT_RELA)
+ if ((sec->sh.sh_type != SHT_RELA) &&
+ (sec->sh.sh_type != SHT_REL))
continue;

- sec->base = find_section_by_name(elf, sec->name + 5);
+ sec->base = find_section_by_name(elf, sec->name +
+ ((sec->sh.sh_type != SHT_REL) ? 5 : 4));
if (!sec->base) {
- WARN("can't find base section for rela section %s",
+ WARN("can't find base section for relocation section %s",
sec->name);
return -1;
}
@@ -486,13 +488,26 @@ static int read_relas(struct elf *elf)
}
memset(rela, 0, sizeof(*rela));

- if (!gelf_getrela(sec->data, i, &rela->rela)) {
- WARN_ELF("gelf_getrela");
- return -1;
+ switch(sec->sh.sh_type) {
+ case SHT_REL:
+ if (!gelf_getrel(sec->data, i, &rela->rel)) {
+ WARN_ELF("gelf_getrel");
+ return -1;
+ }
+ rela->addend = 0;
+ break;
+ case SHT_RELA:
+ if (!gelf_getrela(sec->data, i, &rela->rela)) {
+ WARN_ELF("gelf_getrela");
+ return -1;
+ }
+ rela->addend = rela->rela.r_addend;
+ break;
+ default:
+ break;
}

rela->type = GELF_R_TYPE(rela->rela.r_info);
- rela->addend = rela->rela.r_addend;
rela->offset = rela->rela.r_offset;
symndx = GELF_R_SYM(rela->rela.r_info);
rela->sym = find_symbol_by_index(elf, symndx);
@@ -717,17 +732,27 @@ int elf_rebuild_rela_section(struct section *sec)
struct rela *rela;
int nr, idx = 0, size;
GElf_Rela *relas;
+ GElf_Rel *rels;

nr = 0;
list_for_each_entry(rela, &sec->rela_list, list)
nr++;

+ /*
+ * Allocate a buffer for relocations with addends but also use
+ * it for other relocations too. The section type determines
+ * the size of the section, the buffer used, and the entries.
+ */
size = nr * sizeof(*relas);
relas = malloc(size);
if (!relas) {
perror("malloc");
return -1;
}
+ rels = (void *)relas;
+ if (sec->sh.sh_type == SHT_REL) {
+ size = nr * sizeof(*rels);
+ }

sec->data->d_buf = relas;
sec->data->d_size = size;
@@ -736,9 +761,19 @@ int elf_rebuild_rela_section(struct section *sec)

idx = 0;
list_for_each_entry(rela, &sec->rela_list, list) {
- relas[idx].r_offset = rela->offset;
- relas[idx].r_addend = rela->addend;
- relas[idx].r_info = GELF_R_INFO(rela->sym->idx, rela->type);
+ switch(sec->sh.sh_type) {
+ case SHT_REL:
+ rels[idx].r_offset = rela->offset;
+ rels[idx].r_info = GELF_R_INFO(rela->sym->idx, rela->type);
+ break;
+ case SHT_RELA:
+ relas[idx].r_addend = rela->addend;
+ relas[idx].r_offset = rela->offset;
+ relas[idx].r_info = GELF_R_INFO(rela->sym->idx, rela->type);
+ break;
+ default:
+ break;
+ }
idx++;
}

diff --git a/tools/objtool/elf.h b/tools/objtool/elf.h
index ebbb10c61e24..5ad29bb84692 100644
--- a/tools/objtool/elf.h
+++ b/tools/objtool/elf.h
@@ -61,7 +61,10 @@ struct symbol {
struct rela {
struct list_head list;
struct hlist_node hash;
- GElf_Rela rela;
+ union {
+ GElf_Rela rela;
+ GElf_Rel rel;
+ };
struct section *sec;
struct symbol *sym;
unsigned int type;
--
2.20.1

2020-04-10 19:38:09

by Matt Helsley

[permalink] [raw]
Subject: [RFC][PATCH 07/36] objtool: Make recordmcount into mcount 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]>
---
Documentation/dontdiff | 2 +-
Documentation/trace/ftrace.rst | 6 ++--
Makefile | 6 ++--
arch/arm64/include/asm/ftrace.h | 2 +-
arch/x86/include/asm/ftrace.h | 2 +-
kernel/trace/Kconfig | 2 +-
scripts/Makefile.build | 21 +++++------
scripts/sorttable.h | 2 +-
tools/objtool/Build | 3 +-
tools/objtool/Makefile | 12 +------
tools/objtool/arch/missing/Build | 1 +
tools/objtool/arch/missing/mcount.c | 16 +++++++++
tools/objtool/builtin-mcount.c | 56 +++++++++++++++++++++++++++++
tools/objtool/builtin.h | 2 ++
tools/objtool/mcount.h | 14 ++++++++
tools/objtool/objtool.c | 1 +
tools/objtool/recordmcount.c | 32 +++++------------
17 files changed, 122 insertions(+), 58 deletions(-)
create mode 100644 tools/objtool/arch/missing/mcount.c
create mode 100644 tools/objtool/builtin-mcount.c
create mode 100644 tools/objtool/mcount.h

diff --git a/Documentation/dontdiff b/Documentation/dontdiff
index 72fc2e9e2b63..d7e0ec691e02 100644
--- a/Documentation/dontdiff
+++ b/Documentation/dontdiff
@@ -211,7 +211,7 @@ r420_reg_safe.h
r600_reg_safe.h
randomize_layout_hash.h
randomize_layout_seed.h
-recordmcount
+objtool
relocs
rlim_names.h
rn50_reg_safe.h
diff --git a/Documentation/trace/ftrace.rst b/Documentation/trace/ftrace.rst
index 9adefcc3c7a8..6b9fc7cad543 100644
--- a/Documentation/trace/ftrace.rst
+++ b/Documentation/trace/ftrace.rst
@@ -2684,8 +2684,8 @@ every kernel function, produced by the -pg switch in gcc),
starts of pointing to a simple return. (Enabling FTRACE will
include the -pg switch in the compiling of the kernel.)

-At compile time every C file object is run through the
-recordmcount program (located in the tools/objtool directory). This
+At compile time every C file object is run through objtool's
+mcount subcommand (located in the tools/objtool directory). This
program will parse the ELF headers in the C object to find all
the locations in the .text section that call mcount. Starting
with gcc version 4.6, the -mfentry has been added for x86, which
@@ -2699,7 +2699,7 @@ can be traced.

A section called "__mcount_loc" is created that holds
references to all the mcount/fentry call sites in the .text section.
-The recordmcount program re-links this section back into the
+Running "objtool mcount" re-links this section back into the
original object. The final linking stage of the kernel will add all these
references into a single table.

diff --git a/Makefile b/Makefile
index c91342953d9e..d160720637e8 100644
--- a/Makefile
+++ b/Makefile
@@ -831,11 +831,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/arch/arm64/include/asm/ftrace.h b/arch/arm64/include/asm/ftrace.h
index 91fa4baa1a93..5fd71bf592d5 100644
--- a/arch/arm64/include/asm/ftrace.h
+++ b/arch/arm64/include/asm/ftrace.h
@@ -62,7 +62,7 @@ static inline unsigned long ftrace_call_adjust(unsigned long addr)
return addr + AARCH64_INSN_SIZE;
/*
* addr is the address of the mcount call instruction.
- * recordmcount does the necessary offset calculation.
+ * "objtool mcount" does the necessary offset calculation.
*/
return addr;
}
diff --git a/arch/x86/include/asm/ftrace.h b/arch/x86/include/asm/ftrace.h
index 85be2f506272..4beb3c446910 100644
--- a/arch/x86/include/asm/ftrace.h
+++ b/arch/x86/include/asm/ftrace.h
@@ -23,7 +23,7 @@ static inline unsigned long ftrace_call_adjust(unsigned long addr)
{
/*
* addr is the address of the mcount call instruction.
- * recordmcount does the necessary offset calculation.
+ * "objtool mcount" does the necessary offset calculation.
*/
return addr;
}
diff --git a/kernel/trace/Kconfig b/kernel/trace/Kconfig
index 402eef84c859..e46376e61be8 100644
--- a/kernel/trace/Kconfig
+++ b/kernel/trace/Kconfig
@@ -59,7 +59,7 @@ config HAVE_NOP_MCOUNT
config HAVE_C_RECORDMCOUNT
bool
help
- C version of recordmcount available?
+ C version of objtool mcount available?

config TRACER_MAX_TRACE
bool
diff --git a/scripts/Makefile.build b/scripts/Makefile.build
index 5bc668dbfb61..fdd2ded80f1e 100644
--- a/scripts/Makefile.build
+++ b/scripts/Makefile.build
@@ -164,22 +164,22 @@ 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
+# The compiler does not support generation of the __mcount_loc section.
+# Generate it manually with "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)" \
@@ -187,8 +187,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
@@ -232,7 +232,8 @@ endif # CONFIG_STACK_VALIDATION
# Rebuild all objects when objtool changes, or is enabled/disabled.
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 = \
@@ -264,7 +265,7 @@ 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)

diff --git a/scripts/sorttable.h b/scripts/sorttable.h
index a2baa2fefb13..986aa3414cf6 100644
--- a/scripts/sorttable.h
+++ b/scripts/sorttable.h
@@ -11,7 +11,7 @@
* Some of code was taken out of arch/x86/kernel/unwind_orc.c, written by:
* Copyright (C) 2017 Josh Poimboeuf <[email protected]>
*
- * Some of this code was taken out of recordmcount.h written by:
+ * Some of this code was taken out of objtool mcount written by:
*
* Copyright 2009 John F. Reiser <[email protected]>. All rights reserved.
* Copyright 2010 Steven Rostedt <[email protected]>, Red Hat Inc.
diff --git a/tools/objtool/Build b/tools/objtool/Build
index 35385b1bf313..c68cc8d42a1f 100644
--- a/tools/objtool/Build
+++ b/tools/objtool/Build
@@ -2,6 +2,7 @@ objtool-y += arch/missing/
objtool-y += arch/$(SRCARCH)/
objtool-y += builtin-check.o
objtool-y += builtin-orc.o
+objtool-y += builtin-mcount.o recordmcount.o
objtool-y += elf.o
objtool-y += objtool.o

@@ -27,5 +28,3 @@ $(OUTPUT)str_error_r.o: ../lib/str_error_r.c FORCE
$(OUTPUT)librbtree.o: ../lib/rbtree.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 e9cbf8728e67..5ab022c16d0f 100644
--- a/tools/objtool/Makefile
+++ b/tools/objtool/Makefile
@@ -25,12 +25,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 \
@@ -51,21 +45,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/inat-tables.c $(OUTPUT)fixdep

diff --git a/tools/objtool/arch/missing/Build b/tools/objtool/arch/missing/Build
index a2478db59484..5bfd8a600e35 100644
--- a/tools/objtool/arch/missing/Build
+++ b/tools/objtool/arch/missing/Build
@@ -1,3 +1,4 @@
objtool-y += check.o
+objtool-y += mcount.o
objtool-y += orc_gen.o
objtool-y += orc_dump.o
diff --git a/tools/objtool/arch/missing/mcount.c b/tools/objtool/arch/missing/mcount.c
new file mode 100644
index 000000000000..53d403bb14f0
--- /dev/null
+++ b/tools/objtool/arch/missing/mcount.c
@@ -0,0 +1,16 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (C) 2020 Matt Helsley <[email protected]>
+ */
+
+#include <stdbool.h>
+#include "../../mcount.h"
+
+const char *objname;
+
+int missing_record_mcount(int argc, const char **argv)
+{
+ return 127;
+}
+
+int __attribute__ ((weak, alias("missing_record_mcount"))) record_mcount(int argc, const char **argv);
diff --git a/tools/objtool/builtin-mcount.c b/tools/objtool/builtin-mcount.c
new file mode 100644
index 000000000000..3f80615d366f
--- /dev/null
+++ b/tools/objtool/builtin-mcount.c
@@ -0,0 +1,56 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+/*
+ * 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"
+
+#include "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(),
+};
+
+bool is_cmd_mcount_available(void)
+{
+ return record_mcount != missing_record_mcount;
+}
+
+int cmd_mcount(int argc, const char **argv)
+{
+ argc--; argv++;
+ if (argc <= 0)
+ usage_with_options(mcount_usage, mcount_options);
+
+ if (!strncmp(argv[0], "record", 6)) {
+ 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;
+}
diff --git a/tools/objtool/builtin.h b/tools/objtool/builtin.h
index 478558d38007..3e4123ac4a04 100644
--- a/tools/objtool/builtin.h
+++ b/tools/objtool/builtin.h
@@ -14,5 +14,7 @@ extern bool is_cmd_check_available(void);
extern int cmd_check(int argc, const char **argv);
extern bool is_cmd_orc_available(void);
extern int cmd_orc(int argc, const char **argv);
+extern bool is_cmd_mcount_available(void);
+extern int cmd_mcount(int argc, const char **argv);

#endif /* _BUILTIN_H */
diff --git a/tools/objtool/mcount.h b/tools/objtool/mcount.h
new file mode 100644
index 000000000000..1dae84b653e1
--- /dev/null
+++ b/tools/objtool/mcount.h
@@ -0,0 +1,14 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * Copyright (C) 2020 Matt Helsley <[email protected]>
+ */
+
+#ifndef _MCOUNT_H
+#define _MCOUNT_H
+
+#include <stdbool.h>
+#include "objtool.h"
+
+int missing_record_mcount(int argc, const char **argv);
+int record_mcount(int argc, const char **argv);
+#endif /* _MCOUNT_H */
diff --git a/tools/objtool/objtool.c b/tools/objtool/objtool.c
index e901c40c76ef..2f2f6f81d0af 100644
--- a/tools/objtool/objtool.c
+++ b/tools/objtool/objtool.c
@@ -36,6 +36,7 @@ static const char objtool_usage_string[] =
static struct cmd_struct objtool_cmds[] = {
{"check", cmd_check, "Perform stack metadata validation on an object file", is_cmd_check_available },
{"orc", cmd_orc, "Generate in-place ORC unwind tables for an object file", is_cmd_orc_available },
+ {"mcount", cmd_mcount, "Construct a table of locations of calls to mcount. Useful for ftrace.", is_cmd_mcount_available},
};

bool help;
diff --git a/tools/objtool/recordmcount.c b/tools/objtool/recordmcount.c
index 7225107a9aaf..f9844166fdaf 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 "mcount.h"
+
#ifndef EM_AARCH64
#define EM_AARCH64 183
#define R_AARCH64_NONE 0
@@ -47,7 +48,7 @@ static int mmap_failed; /* Boolean flag. */
static char gpfx; /* prefix for global symbol name (sometimes '_') */
static struct stat sb; /* Remember .st_size, etc. */
static const char *altmcount; /* alternate mcount symbol name */
-static int warn_on_notrace_sect; /* warn when section has mcount not being recorded */
+extern int warn_on_notrace_sect; /* warn when section has mcount not being recorded */
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 */
@@ -488,7 +489,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;
@@ -501,7 +502,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;
@@ -615,33 +616,16 @@ 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");
- 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

2020-04-10 19:38:15

by Matt Helsley

[permalink] [raw]
Subject: [RFC][PATCH 08/36] 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 separate 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 f9844166fdaf..69da5339575f 100644
--- a/tools/objtool/recordmcount.c
+++ b/tools/objtool/recordmcount.c
@@ -33,6 +33,8 @@

#include "mcount.h"

+#include "elf.h"
+
#ifndef EM_AARCH64
#define EM_AARCH64 183
#define R_AARCH64_NONE 0
@@ -57,6 +59,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)
{
@@ -73,6 +77,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. */
@@ -170,11 +177,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_read(fname, O_RDONLY);
+ if (!lf) {
perror(fname);
return NULL;
}
+ fd_map = lf->fd;
if (fstat(fd_map, &sb) < 0) {
perror(fname);
goto out;
@@ -194,14 +202,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

2020-04-10 19:38:23

by Matt Helsley

[permalink] [raw]
Subject: [RFC][PATCH 09/36] 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 | 4 ----
tools/objtool/recordmcount.h | 17 +++--------------
2 files changed, 3 insertions(+), 18 deletions(-)

diff --git a/tools/objtool/recordmcount.c b/tools/objtool/recordmcount.c
index 69da5339575f..46a275a393a8 100644
--- a/tools/objtool/recordmcount.c
+++ b/tools/objtool/recordmcount.c
@@ -208,8 +208,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;
@@ -424,8 +422,6 @@ static int is_mcounted_section_name(char const *const txtname)
strcmp(".cpuidle.text", txtname) == 0;
}

-static char const *already_has_rel_mcount = "success"; /* our work here is done! */
-
/* 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 74eab03e31d4..1a848b8104c8 100644
--- a/tools/objtool/recordmcount.h
+++ b/tools/objtool/recordmcount.h
@@ -473,11 +473,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;
@@ -506,10 +501,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);
}
@@ -545,6 +536,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;
@@ -564,11 +558,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)) {
unsigned int recsym;
uint_t recval = 0;
--
2.20.1

2020-04-10 19:38:34

by Matt Helsley

[permalink] [raw]
Subject: [RFC][PATCH 11/36] objtool: mcount: Remove unused fname parameter

The name of the object file being processed is unused in
leaf functions and only passed down to reach them so we
can remove it.

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

diff --git a/tools/objtool/recordmcount.c b/tools/objtool/recordmcount.c
index 46a275a393a8..df16783434ae 100644
--- a/tools/objtool/recordmcount.c
+++ b/tools/objtool/recordmcount.c
@@ -586,7 +586,7 @@ static int do_file(char const *const fname)
reltype = R_MIPS_32;
is_fake_mcount32 = MIPS32_is_fake_mcount;
}
- if (do32(ehdr, fname, reltype) < 0)
+ if (do32(ehdr, reltype) < 0)
goto out;
break;
case ELFCLASS64: {
@@ -607,7 +607,7 @@ static int do_file(char const *const fname)
Elf64_r_info = MIPS64_r_info;
is_fake_mcount64 = MIPS64_is_fake_mcount;
}
- if (do64(ghdr, fname, reltype) < 0)
+ if (do64(ghdr, reltype) < 0)
goto out;
break;
}
diff --git a/tools/objtool/recordmcount.h b/tools/objtool/recordmcount.h
index 3c4807dca3d0..3250a461895d 100644
--- a/tools/objtool/recordmcount.h
+++ b/tools/objtool/recordmcount.h
@@ -466,8 +466,7 @@ 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(GElf_Shdr const *const relhdr, /* reltype */
Elf_Shdr const *const shdr0,
- char const *const shstrtab,
- char const *const fname)
+ char const *const shstrtab)
{
/* .sh_info depends on .sh_type == SHT_REL[,A] */
Elf_Shdr const *const txthdr = &shdr0[relhdr->sh_info];
@@ -481,25 +480,23 @@ static char const * __has_rel_mcount(GElf_Shdr const *const relhdr, /* reltype *

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


static unsigned tot_relsize(Elf_Shdr const *const shdr0,
- const char *const shstrtab,
- const char *const fname)
+ const char *const shstrtab)
{
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, fname);
+ txtname = has_rel_mcount(&sec->sh, shdr0, shstrtab);
if (txtname && is_mcounted_section_name(txtname))
totrelsz += sec->sh.sh_size;
}
@@ -508,7 +505,7 @@ 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,
+static int do_func(Elf_Ehdr *const ehdr,
unsigned const reltype)
{
Elf_Shdr *const shdr0 = (Elf_Shdr *)(_w(ehdr->e_shoff)
@@ -538,7 +535,7 @@ static int do_func(Elf_Ehdr *const ehdr, char const *const fname,
if (find_section_by_name(lf, "__mcount_loc") != NULL)
return 0;

- totrelsz = tot_relsize(shdr0, shstrtab, fname);
+ totrelsz = tot_relsize(shdr0, shstrtab);
if (totrelsz == 0)
return 0;
mrel0 = umalloc(totrelsz);
@@ -559,7 +556,7 @@ static int do_func(Elf_Ehdr *const ehdr, char const *const fname,

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

2020-04-10 19:38:49

by Matt Helsley

[permalink] [raw]
Subject: [RFC][PATCH 13/36] objtool: mcount: Walk objtool Elf structs in find_secsym_ndx

Rather than using indices into raw ELF32/64 tables mapped for the
wrapper, use the objtool and libelf structures.

Also take advantage of this commit to rename the function to
something that reads more easily.

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

diff --git a/tools/objtool/recordmcount.c b/tools/objtool/recordmcount.c
index e69d2cccce2d..5a05a08f0e28 100644
--- a/tools/objtool/recordmcount.c
+++ b/tools/objtool/recordmcount.c
@@ -422,6 +422,8 @@ static int is_mcounted_section_name(char const *const txtname)
strcmp(".cpuidle.text", txtname) == 0;
}

+static const unsigned int missing_sym = (unsigned int)-1;
+
/* 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 b487308992ce..dba1c385106f 100644
--- a/tools/objtool/recordmcount.h
+++ b/tools/objtool/recordmcount.h
@@ -24,7 +24,7 @@
#undef mcount_adjust
#undef sift_rel_mcount
#undef nop_mcount
-#undef find_secsym_ndx
+#undef find_section_sym_index
#undef has_rel_mcount
#undef tot_relsize
#undef get_mcountsym
@@ -53,7 +53,7 @@
# define append_func append64
# define sift_rel_mcount sift64_rel_mcount
# define nop_mcount nop_mcount_64
-# define find_secsym_ndx find64_secsym_ndx
+# define find_section_sym_index find64_section_sym_index
# define has_rel_mcount has64_rel_mcount
# define tot_relsize tot64_relsize
# define get_sym_str_and_relp get_sym_str_and_relp_64
@@ -85,7 +85,7 @@
# define append_func append32
# define sift_rel_mcount sift32_rel_mcount
# define nop_mcount nop_mcount_32
-# define find_secsym_ndx find32_secsym_ndx
+# define find_section_sym_index find32_section_sym_index
# define has_rel_mcount has32_rel_mcount
# define tot_relsize tot32_relsize
# define get_sym_str_and_relp get_sym_str_and_relp_32
@@ -427,38 +427,36 @@ static int nop_mcount(const struct section * const rels,
* Num: Value Size Type Bind Vis Ndx Name
* 2: 00000000 0 SECTION LOCAL DEFAULT 1
*/
-static int find_secsym_ndx(unsigned const txtndx,
+static int find_section_sym_index(unsigned const txtndx,
char const *const txtname,
uint_t *const recvalp,
unsigned int *sym_index,
- Elf_Shdr const *const symhdr,
Elf_Ehdr const *const ehdr)
{
- Elf_Sym const *const sym0 = (Elf_Sym const *)(_w(symhdr->sh_offset)
- + (void *)ehdr);
- unsigned const nsym = _w(symhdr->sh_size) / _w(symhdr->sh_entsize);
- Elf_Sym const *symp;
- unsigned t;
+ struct symbol *sym;
+ struct section *txts = find_section_by_index(lf, txtndx);

- for (symp = sym0, t = nsym; t; --t, ++symp) {
- unsigned int const st_bind = ELF_ST_BIND(symp->st_info);
+ if (!txts) {
+ fprintf(stderr, "Cannot find section %u: %s.\n",
+ txtndx, txtname);
+ return missing_sym;
+ }

- if (txtndx == w2(symp->st_shndx)
- /* avoid STB_WEAK */
- && (STB_LOCAL == st_bind || STB_GLOBAL == st_bind)) {
+ list_for_each_entry(sym, &txts->symbol_list, list) {
+ if ((sym->bind == STB_LOCAL) || (sym->bind == STB_GLOBAL)) {
/* function symbols on ARM have quirks, avoid them */
if (w2(ehdr->e_machine) == EM_ARM
- && ELF_ST_TYPE(symp->st_info) == STT_FUNC)
+ && sym->type == STT_FUNC)
continue;

- *recvalp = _w(symp->st_value);
- *sym_index = symp - sym0;
+ *recvalp = sym->sym.st_value;
+ *sym_index = sym->idx;
return 0;
}
}
fprintf(stderr, "Cannot find symbol for section %u: %s.\n",
txtndx, txtname);
- return -1;
+ return missing_sym;
}

static char const *has_rel_mcount(const struct section * const rels)
@@ -540,10 +538,8 @@ static int do_func(Elf_Ehdr *const ehdr,
uint_t recval = 0;

symsec_sh_link = sec->sh.sh_link;
- result = find_secsym_ndx(sec->sh.sh_info, txtname,
- &recval, &recsym,
- &shdr0[symsec_sh_link],
- ehdr);
+ result = find_section_sym_index(sec->sh.sh_info,
+ txtname, &recval, &recsym, ehdr);
if (result)
goto out;

--
2.20.1

2020-04-10 19:38:55

by Matt Helsley

[permalink] [raw]
Subject: [RFC][PATCH 14/36] objtool: mcount: Use symbol structs to find mcount relocations

Rather than open coding symbol name lookups in get_sym_and_*()
we rename the structure and use objtool's lookup function to
get the symbol name for a relocation. We also change the name
of the function to better reflect its purpose.

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

diff --git a/tools/objtool/elf.c b/tools/objtool/elf.c
index 4528d2669ac2..e2ffcd8b68a0 100644
--- a/tools/objtool/elf.c
+++ b/tools/objtool/elf.c
@@ -133,7 +133,7 @@ struct section *find_section_by_index(struct elf *elf, unsigned int idx)
return NULL;
}

-static struct symbol *find_symbol_by_index(struct elf *elf, unsigned int idx)
+struct symbol *find_symbol_by_index(struct elf *elf, unsigned int idx)
{
struct symbol *sym;

diff --git a/tools/objtool/elf.h b/tools/objtool/elf.h
index 317da07ee10d..362344903f6c 100644
--- a/tools/objtool/elf.h
+++ b/tools/objtool/elf.h
@@ -120,6 +120,7 @@ struct section *find_section_by_index(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(struct elf *elf, const char *name);
+struct symbol *find_symbol_by_index(struct elf *elf, unsigned int idx);
struct symbol *find_symbol_containing(struct section *sec, unsigned long offset);
struct rela *find_rela_by_dest(struct elf *elf, struct section *sec, unsigned long offset);
struct rela *find_rela_by_dest_range(struct elf *elf, struct section *sec,
diff --git a/tools/objtool/recordmcount.h b/tools/objtool/recordmcount.h
index dba1c385106f..d49da1e32315 100644
--- a/tools/objtool/recordmcount.h
+++ b/tools/objtool/recordmcount.h
@@ -28,7 +28,7 @@
#undef has_rel_mcount
#undef tot_relsize
#undef get_mcountsym
-#undef get_sym_str_and_relp
+#undef get_relp
#undef do_func
#undef Elf_Addr
#undef Elf_Ehdr
@@ -56,7 +56,7 @@
# define find_section_sym_index find64_section_sym_index
# define has_rel_mcount has64_rel_mcount
# define tot_relsize tot64_relsize
-# define get_sym_str_and_relp get_sym_str_and_relp_64
+# define get_relp get_relp_64
# define do_func do64
# define get_mcountsym get_mcountsym_64
# define is_fake_mcount is_fake_mcount64
@@ -88,7 +88,7 @@
# define find_section_sym_index find32_section_sym_index
# define has_rel_mcount has32_rel_mcount
# define tot_relsize tot32_relsize
-# define get_sym_str_and_relp get_sym_str_and_relp_32
+# define get_relp get_relp_32
# define do_func do32
# define get_mcountsym get_mcountsym_32
# define is_fake_mcount is_fake_mcount32
@@ -261,15 +261,10 @@ static int append_func(Elf_Ehdr *const ehdr,
return elf_write(lf);
}

-static unsigned get_mcountsym(Elf_Sym const *const sym0,
- Elf_Rel const *relp,
- char const *const str0)
+static unsigned get_mcountsym(Elf_Rel const *relp)
{
- unsigned mcountsym = 0;
-
- Elf_Sym const *const symp =
- &sym0[Elf_r_sym(relp)];
- char const *symname = &str0[w(symp->st_name)];
+ struct symbol *sym = find_symbol_by_index(lf, Elf_r_sym(relp));
+ char const *symname = sym->name;
char const *mcount = gpfx == '_' ? "_mcount" : "mcount";
char const *fentry = "__fentry__";

@@ -278,31 +273,16 @@ static unsigned get_mcountsym(Elf_Sym const *const sym0,
if (strcmp(mcount, symname) == 0 ||
(altmcount && strcmp(altmcount, symname) == 0) ||
(strcmp(fentry, symname) == 0))
- mcountsym = Elf_r_sym(relp);
-
- return mcountsym;
+ return Elf_r_sym(relp);
+ return 0;
}

-static void get_sym_str_and_relp(const struct section * const rels,
- Elf_Ehdr const *const ehdr,
- Elf_Sym const **sym0,
- char const **str0,
- Elf_Rel const **relp)
+static void get_relp(const struct section * const rels,
+ Elf_Ehdr const *const ehdr,
+ Elf_Rel const **relp)
{
- Elf_Shdr *const shdr0 = (Elf_Shdr *)(_w(ehdr->e_shoff)
- + (void *)ehdr);
- 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 *)(rels->sh.sh_offset
+ (void *)ehdr);
-
- *sym0 = (Elf_Sym const *)(_w(symsec->sh_offset)
- + (void *)ehdr);
-
- *str0 = (char const *)(_w(strsec->sh_offset)
- + (void *)ehdr);
-
*relp = rel0;
}

@@ -322,19 +302,17 @@ static uint_t *sift_rel_mcount(uint_t *mlocp,
{
uint_t *const mloc0 = mlocp;
Elf_Rel *mrelp = *mrelpp;
- Elf_Sym const *sym0;
- char const *str0;
Elf_Rel const *relp;
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(rels, ehdr, &sym0, &str0, &relp);
+ get_relp(rels, ehdr, &relp);

for (t = nrel; t; --t) {
if (!mcountsym)
- mcountsym = get_mcountsym(sym0, relp, str0);
+ mcountsym = get_mcountsym(relp);

if (mcountsym && mcountsym == Elf_r_sym(relp) &&
!is_fake_mcount(relp)) {
@@ -368,8 +346,6 @@ static int nop_mcount(const struct section * const rels,
{
Elf_Shdr *const shdr0 = (Elf_Shdr *)(_w(ehdr->e_shoff)
+ (void *)ehdr);
- Elf_Sym const *sym0;
- char const *str0;
Elf_Rel const *relp;
Elf_Shdr const *const shdr = &shdr0[rels->sh.sh_info];
unsigned rel_entsize = rels->sh.sh_entsize;
@@ -378,13 +354,13 @@ static int nop_mcount(const struct section * const rels,
unsigned t;
int once = 0;

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

for (t = nrel; t; --t) {
int ret = -1;

if (!mcountsym)
- mcountsym = get_mcountsym(sym0, relp, str0);
+ mcountsym = get_mcountsym(relp);

if (mcountsym == Elf_r_sym(relp) && !is_fake_mcount(relp)) {
if (make_nop)
--
2.20.1

2020-04-10 19:39:04

by Matt Helsley

[permalink] [raw]
Subject: [RFC][PATCH 04/36] objtool: Report missing support for subcommands

The check and orc-related subcommands for objtool are x86-specific.
To make this clear to anyone using the tool return a non-zero exit
code and indicate in the help and usage output which commands are
(and are not) available.

Signed-off-by: Matt Helsley <[email protected]>
---
tools/objtool/Build | 1 +
tools/objtool/arch/missing/check.c | 4 +++-
tools/objtool/arch/missing/orc_dump.c | 4 +++-
tools/objtool/builtin-check.c | 5 ++++
tools/objtool/builtin-orc.c | 7 ++++++
tools/objtool/builtin.h | 2 ++
tools/objtool/check.h | 1 +
tools/objtool/objtool.c | 34 +++++++++++++++++++++++----
tools/objtool/orc.h | 1 +
9 files changed, 52 insertions(+), 7 deletions(-)

diff --git a/tools/objtool/Build b/tools/objtool/Build
index 3178c00072f5..e372cddd86e0 100644
--- a/tools/objtool/Build
+++ b/tools/objtool/Build
@@ -1,3 +1,4 @@
+objtool-y += arch/missing/
objtool-y += arch/$(SRCARCH)/
objtool-y += builtin-check.o
objtool-y += builtin-orc.o
diff --git a/tools/objtool/arch/missing/check.c b/tools/objtool/arch/missing/check.c
index 5eac14c8c6a5..7f9deb0451bb 100644
--- a/tools/objtool/arch/missing/check.c
+++ b/tools/objtool/arch/missing/check.c
@@ -8,7 +8,9 @@

const char *objname;

-int __attribute__ ((weak)) check(const char *_objname, bool orc)
+int missing_check(const char *_objname, bool orc)
{
return 127;
}
+
+int __attribute__ ((weak, alias("missing_check"))) check(const char *_objname, bool orc);
diff --git a/tools/objtool/arch/missing/orc_dump.c b/tools/objtool/arch/missing/orc_dump.c
index f7ebb3a2ce9e..45367ddd08a4 100644
--- a/tools/objtool/arch/missing/orc_dump.c
+++ b/tools/objtool/arch/missing/orc_dump.c
@@ -5,7 +5,9 @@

#include "../../orc.h"

-int __attribute__ ((weak)) orc_dump(const char *_objname)
+int missing_orc_dump(const char *_objname)
{
return 127;
}
+
+int __attribute__ ((weak, alias("missing_orc_dump"))) orc_dump(const char *_objname);
diff --git a/tools/objtool/builtin-check.c b/tools/objtool/builtin-check.c
index 10fbe75ab43d..7e7ad576ebc0 100644
--- a/tools/objtool/builtin-check.c
+++ b/tools/objtool/builtin-check.c
@@ -35,6 +35,11 @@ const struct option check_options[] = {
OPT_END(),
};

+bool is_cmd_check_available(void)
+{
+ return check != missing_check;
+}
+
int cmd_check(int argc, const char **argv)
{
const char *objname;
diff --git a/tools/objtool/builtin-orc.c b/tools/objtool/builtin-orc.c
index e6e54ae4ab75..043b93f68e83 100644
--- a/tools/objtool/builtin-orc.c
+++ b/tools/objtool/builtin-orc.c
@@ -23,6 +23,13 @@ static const char *orc_usage[] = {
NULL,
};

+bool is_cmd_orc_available(void)
+{
+ if (check == missing_check)
+ return false;
+ return orc_dump != missing_orc_dump;
+}
+
int cmd_orc(int argc, const char **argv)
{
const char *objname;
diff --git a/tools/objtool/builtin.h b/tools/objtool/builtin.h
index 0b907902ee79..478558d38007 100644
--- a/tools/objtool/builtin.h
+++ b/tools/objtool/builtin.h
@@ -10,7 +10,9 @@
extern const struct option check_options[];
extern bool no_fp, no_unreachable, retpoline, module, backtrace, uaccess, stats;

+extern bool is_cmd_check_available(void);
extern int cmd_check(int argc, const char **argv);
+extern bool is_cmd_orc_available(void);
extern int cmd_orc(int argc, const char **argv);

#endif /* _BUILTIN_H */
diff --git a/tools/objtool/check.h b/tools/objtool/check.h
index 4d34bfc84dc7..c54fb9f5c8e6 100644
--- a/tools/objtool/check.h
+++ b/tools/objtool/check.h
@@ -9,6 +9,7 @@
#include <stdbool.h>
#include "objtool.h"

+int missing_check(const char *objname, bool orc);
int check(const char *objname, bool orc);

struct instruction *find_insn(struct objtool_file *file,
diff --git a/tools/objtool/objtool.c b/tools/objtool/objtool.c
index 593ec85915a9..e901c40c76ef 100644
--- a/tools/objtool/objtool.c
+++ b/tools/objtool/objtool.c
@@ -27,21 +27,22 @@ struct cmd_struct {
const char *name;
int (*fn)(int, const char **);
const char *help;
+ bool (*is_available)(void);
};

static const char objtool_usage_string[] =
"objtool COMMAND [ARGS]";

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" },
+ {"check", cmd_check, "Perform stack metadata validation on an object file", is_cmd_check_available },
+ {"orc", cmd_orc, "Generate in-place ORC unwind tables for an object file", is_cmd_orc_available },
};

bool help;

static void cmd_usage(void)
{
- unsigned int i, longest = 0;
+ unsigned int i, longest = 0, num_unavail = 0;

printf("\n usage: %s\n\n", objtool_usage_string);

@@ -52,8 +53,26 @@ static void cmd_usage(void)

puts(" Commands:");
for (i = 0; i < ARRAY_SIZE(objtool_cmds); i++) {
- printf(" %-*s ", longest, objtool_cmds[i].name);
- puts(objtool_cmds[i].help);
+ struct cmd_struct *p = objtool_cmds+i;
+
+ if (!p->is_available()) {
+ num_unavail++;
+ continue;
+ }
+ printf(" %-*s ", longest, p->name);
+ puts(p->help);
+ }
+
+ if (num_unavail > 0) {
+ puts("\n Unavailable commands on this architecture:");
+ for (i = 0; i < ARRAY_SIZE(objtool_cmds); i++) {
+ struct cmd_struct *p = objtool_cmds+i;
+
+ if (p->is_available())
+ continue;
+ printf(" %-*s ", longest, p->name);
+ puts(p->help);
+ }
}

printf("\n");
@@ -96,6 +115,11 @@ static void handle_internal_command(int argc, const char **argv)
if (strcmp(p->name, cmd))
continue;

+ if (!p->is_available()) {
+ fprintf(stderr, "command %s is not available on this architecture\n", cmd);
+ exit(127);
+ }
+
ret = p->fn(argc, argv);

exit(ret);
diff --git a/tools/objtool/orc.h b/tools/objtool/orc.h
index c67f451d7610..9174356ba0fa 100644
--- a/tools/objtool/orc.h
+++ b/tools/objtool/orc.h
@@ -11,6 +11,7 @@ struct objtool_file;
int create_orc(struct objtool_file *file);
int create_orc_sections(struct objtool_file *file);

+int missing_orc_dump(const char *objname);
int orc_dump(const char *objname);

#endif /* _ORC_H */
--
2.20.1

2020-04-10 19:39:08

by Matt Helsley

[permalink] [raw]
Subject: [RFC][PATCH 17/36] objtool: mcount: Replace MIPS offset types

Replace MIPS is_fake_mcount code using Elf_Addr with
unsigned long for the offsets. This is consistent with the way
that objtool more generally treats offsets and removes the
last use of the Elf_Addr wrapper.

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

diff --git a/tools/objtool/recordmcount.h b/tools/objtool/recordmcount.h
index 9bba41ee2db2..f99851034fa8 100644
--- a/tools/objtool/recordmcount.h
+++ b/tools/objtool/recordmcount.h
@@ -28,7 +28,6 @@
#undef has_rel_mcount
#undef tot_relsize
#undef do_func
-#undef Elf_Addr
#undef Elf_Ehdr
#undef Elf_Shdr
#undef Elf_Rel
@@ -53,7 +52,6 @@
# 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_Addr Elf64_Addr
# define Elf_Ehdr Elf64_Ehdr
# define Elf_Shdr Elf64_Shdr
# define Elf_Rel Elf64_Rel
@@ -77,7 +75,6 @@
# 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_Addr Elf32_Addr
# define Elf_Ehdr Elf32_Ehdr
# define Elf_Shdr Elf32_Shdr
# define Elf_Rel Elf32_Rel
@@ -129,11 +126,11 @@ static int mcount_adjust = 0;

static int MIPS_is_fake_mcount(struct rela const *rela)
{
- static Elf_Addr old_r_offset = ~(Elf_Addr)0;
- Elf_Addr current_r_offset = rela->offset;
+ static unsigned long old_r_offset = ~0UL;
+ unsigned long current_r_offset = rela->offset;
int is_fake;

- is_fake = (old_r_offset != ~(Elf_Addr)0) &&
+ is_fake = (old_r_offset != ~0UL) &&
(current_r_offset - old_r_offset == MIPS_FAKEMCOUNT_OFFSET);
old_r_offset = current_r_offset;

--
2.20.1

2020-04-10 19:39:13

by Matt Helsley

[permalink] [raw]
Subject: [RFC][PATCH 06/36] 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]>
---
Documentation/trace/ftrace-design.rst | 4 ++--
Documentation/trace/ftrace.rst | 2 +-
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
11 files changed, 24 insertions(+), 11 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/Documentation/trace/ftrace-design.rst b/Documentation/trace/ftrace-design.rst
index a8e22e0db63c..dea8db5e79d0 100644
--- a/Documentation/trace/ftrace-design.rst
+++ b/Documentation/trace/ftrace-design.rst
@@ -261,7 +261,7 @@ You need very few things to get the syscalls tracing in an arch.
HAVE_FTRACE_MCOUNT_RECORD
-------------------------

-See scripts/recordmcount.pl for more info. Just fill in the arch-specific
+See tools/objtool/recordmcount.pl for more info. Just fill in the arch-specific
details for how to locate the addresses of mcount call sites via objdump.
This option doesn't make much sense without also implementing dynamic ftrace.

@@ -379,7 +379,7 @@ linux/ftrace.h for the functions::
ftrace_make_call()

The rec->ip value is the address of the mcount call site that was collected
-by the scripts/recordmcount.pl during build time.
+by the tools/objtool/recordmcount.pl during build time.

The last function is used to do runtime patching of the active tracer. This
will be modifying the assembly code at the location of the ftrace_call symbol
diff --git a/Documentation/trace/ftrace.rst b/Documentation/trace/ftrace.rst
index 3b5614b1d1a5..9adefcc3c7a8 100644
--- a/Documentation/trace/ftrace.rst
+++ b/Documentation/trace/ftrace.rst
@@ -2685,7 +2685,7 @@ starts of pointing to a simple return. (Enabling FTRACE will
include the -pg switch in the compiling of the kernel.)

At compile time every C file object is run through the
-recordmcount program (located in the scripts directory). This
+recordmcount program (located in the tools/objtool directory). This
program will parse the ELF headers in the C object to find all
the locations in the .text section that call mcount. Starting
with gcc version 4.6, the -mfentry has been added for x86, which
diff --git a/scripts/.gitignore b/scripts/.gitignore
index 0d1c8e217cd7..dafda6d2c306 100644
--- a/scripts/.gitignore
+++ b/scripts/.gitignore
@@ -2,7 +2,6 @@
bin2c
kallsyms
unifdef
-recordmcount
sorttable
asn1_compiler
extract-cert
diff --git a/scripts/Makefile b/scripts/Makefile
index 5e75802b1a44..f0f869364e5a 100644
--- a/scripts/Makefile
+++ b/scripts/Makefile
@@ -9,7 +9,6 @@ HOST_EXTRACFLAGS += -I$(srctree)/tools/include

always-$(CONFIG_BUILD_BIN2C) += bin2c
always-$(CONFIG_KALLSYMS) += kallsyms
-always-$(BUILD_C_RECORDMCOUNT) += recordmcount
always-$(CONFIG_BUILDTIME_TABLE_SORT) += sorttable
always-$(CONFIG_ASN1) += asn1_compiler
always-$(CONFIG_MODULE_SIG_FORMAT) += sign-file
diff --git a/scripts/Makefile.build b/scripts/Makefile.build
index a1730d42e5f3..5bc668dbfb61 100644
--- a/scripts/Makefile.build
+++ b/scripts/Makefile.build
@@ -175,18 +175,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 45cefda24c7b..ea441abcd1d3 100644
--- a/tools/objtool/.gitignore
+++ b/tools/objtool/.gitignore
@@ -1,4 +1,5 @@
# SPDX-License-Identifier: GPL-2.0-only
arch/x86/lib/inat-tables.c
objtool
+recordmcount
fixdep
diff --git a/tools/objtool/Build b/tools/objtool/Build
index e372cddd86e0..35385b1bf313 100644
--- a/tools/objtool/Build
+++ b/tools/objtool/Build
@@ -27,3 +27,5 @@ $(OUTPUT)str_error_r.o: ../lib/str_error_r.c FORCE
$(OUTPUT)librbtree.o: ../lib/rbtree.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 ee08aeff30a1..e9cbf8728e67 100644
--- a/tools/objtool/Makefile
+++ b/tools/objtool/Makefile
@@ -25,6 +25,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 \
@@ -45,16 +51,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/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

2020-04-10 19:39:18

by Matt Helsley

[permalink] [raw]
Subject: [RFC][PATCH 12/36] 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 88ce3efa394c..4528d2669ac2 100644
--- a/tools/objtool/elf.c
+++ b/tools/objtool/elf.c
@@ -122,8 +122,7 @@ struct section *find_section_by_name(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(struct elf *elf, unsigned int idx)
{
struct section *sec;

diff --git a/tools/objtool/elf.h b/tools/objtool/elf.h
index 5ad29bb84692..317da07ee10d 100644
--- a/tools/objtool/elf.h
+++ b/tools/objtool/elf.h
@@ -116,6 +116,7 @@ static inline u32 rela_hash(struct rela *rela)

struct elf *elf_read(const char *name, int flags);
struct section *find_section_by_name(struct elf *elf, const char *name);
+struct section *find_section_by_index(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(struct elf *elf, const char *name);
diff --git a/tools/objtool/recordmcount.c b/tools/objtool/recordmcount.c
index df16783434ae..e69d2cccce2d 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_read(fname, O_RDONLY);
+ lf = elf_read(fname, O_RDWR);
if (!lf) {
perror(fname);
return NULL;
diff --git a/tools/objtool/recordmcount.h b/tools/objtool/recordmcount.h
index 3250a461895d..b487308992ce 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
@@ -55,7 +54,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 get_sym_str_and_relp get_sym_str_and_relp_64
@@ -88,7 +86,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 get_sym_str_and_relp get_sym_str_and_relp_32
@@ -197,6 +194,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;
@@ -260,7 +258,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,
@@ -285,7 +283,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,
@@ -293,10 +291,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)
@@ -316,7 +314,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,
@@ -327,12 +325,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)
@@ -364,7 +362,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)
{
@@ -373,14 +371,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;
@@ -463,40 +461,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;
}
@@ -510,11 +495,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[w2(ehdr->e_shstrndx)];
- char const *const shstrtab = (char const *)(_w(shstr->sh_offset)
- + (void *)ehdr);
-
- GElf_Shdr const *relhdr;

/* Upper bound on space: assume all relevant relocs are for mcount. */
unsigned totrelsz;
@@ -528,14 +508,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);
@@ -554,38 +534,37 @@ 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],
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[w2(ehdr->e_shstrndx)],
+ mloc0, mlocp, mrel0, mrelp,
rel_entsize, symsec_sh_link);
out:
free(mrel0);
--
2.20.1

2020-04-10 19:39:32

by Matt Helsley

[permalink] [raw]
Subject: [RFC][PATCH 19/36] objtool: mcount: Stop using ehdr in find_section_sym_index

We can use the objtool GElf_Ehdr structure to access ehdr here.
This makes the function completely independent of the old
recordmcount ELF wrapper. The next step will be to promote it
to the C file.

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

diff --git a/tools/objtool/recordmcount.h b/tools/objtool/recordmcount.h
index d61892597731..066923dd70a9 100644
--- a/tools/objtool/recordmcount.h
+++ b/tools/objtool/recordmcount.h
@@ -188,7 +188,7 @@ static uint_t *sift_rel_mcount(uint_t *mlocp,
Elf_Rel **const mrelpp,
const struct section * const rels,
unsigned const recsym_index,
- uint_t const recval,
+ unsigned long const recval,
unsigned const reltype)
{
uint_t *const mloc0 = mlocp;
@@ -282,9 +282,8 @@ static int nop_mcount(struct section * const rels,
*/
static int find_section_sym_index(unsigned const txtndx,
char const *const txtname,
- uint_t *const recvalp,
- unsigned int *sym_index,
- Elf_Ehdr const *const ehdr)
+ unsigned long *const recvalp,
+ unsigned int *sym_index)
{
struct symbol *sym;
struct section *txts = find_section_by_index(lf, txtndx);
@@ -298,7 +297,7 @@ static int find_section_sym_index(unsigned const txtndx,
list_for_each_entry(sym, &txts->symbol_list, list) {
if ((sym->bind == STB_LOCAL) || (sym->bind == STB_GLOBAL)) {
/* function symbols on ARM have quirks, avoid them */
- if (w2(ehdr->e_machine) == EM_ARM
+ if (lf->ehdr.e_machine == EM_ARM
&& sym->type == STT_FUNC)
continue;

@@ -387,12 +386,12 @@ static int do_func(Elf_Ehdr *const ehdr,

txtname = has_rel_mcount(sec);
if (txtname && is_mcounted_section_name(txtname)) {
+ unsigned long recval = 0;
unsigned int recsym;
- uint_t recval = 0;

symsec_sh_link = sec->sh.sh_link;
result = find_section_sym_index(sec->sh.sh_info,
- txtname, &recval, &recsym, ehdr);
+ txtname, &recval, &recsym);
if (result)
goto out;

--
2.20.1

2020-04-10 19:39:42

by Matt Helsley

[permalink] [raw]
Subject: [RFC][PATCH 10/36] 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 | 62 +++++++++++++++++++-----------------
1 file changed, 32 insertions(+), 30 deletions(-)

diff --git a/tools/objtool/recordmcount.h b/tools/objtool/recordmcount.h
index 1a848b8104c8..3c4807dca3d0 100644
--- a/tools/objtool/recordmcount.h
+++ b/tools/objtool/recordmcount.h
@@ -285,7 +285,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,
@@ -293,10 +293,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)
@@ -316,9 +316,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)
{
@@ -327,8 +327,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;

@@ -344,7 +344,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;
@@ -364,7 +364,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)
{
@@ -373,9 +373,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;
@@ -464,13 +464,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 ||
@@ -479,30 +479,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;
}
@@ -514,13 +513,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;
@@ -534,12 +531,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);
@@ -555,22 +554,25 @@ 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)) {
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],
ehdr);
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-04-10 19:39:50

by Matt Helsley

[permalink] [raw]
Subject: [RFC][PATCH 20/36] objtool: mcount: Move find_section_sym_index()

This function is no longer dependent upon the old recordmcount
ELF wrapper code -- it doesn't use the wrapper's Elf_* types nor
does it call wrapped functions. Move it into the C file.

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

diff --git a/tools/objtool/recordmcount.c b/tools/objtool/recordmcount.c
index 6c499fe86132..61901b1c7bd3 100644
--- a/tools/objtool/recordmcount.c
+++ b/tools/objtool/recordmcount.c
@@ -482,6 +482,47 @@ static int (*is_fake_mcount)(struct rela const *rela) = fn_is_fake_mcount;

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

+/*
+ * Find a symbol in the given section, to be used as the base for relocating
+ * the table of offsets of calls to mcount. A local or global symbol suffices,
+ * but avoid a Weak symbol because it may be overridden; the change in value
+ * would invalidate the relocations of the offsets of the calls to mcount.
+ * Often the found symbol will be the unnamed local symbol generated by
+ * GNU 'as' for the start of each section. For example:
+ * 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)
+{
+ 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) {
+ 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;
+ }
+ }
+ fprintf(stderr, "Cannot find symbol for section %u: %s.\n",
+ txtndx, txtname);
+ return missing_sym;
+}
+
/* 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 066923dd70a9..3c7afb9a2eac 100644
--- a/tools/objtool/recordmcount.h
+++ b/tools/objtool/recordmcount.h
@@ -21,7 +21,6 @@
#undef mcount_adjust
#undef sift_rel_mcount
#undef nop_mcount
-#undef find_section_sym_index
#undef has_rel_mcount
#undef tot_relsize
#undef do_func
@@ -41,7 +40,6 @@
# define append_func append64
# define sift_rel_mcount sift64_rel_mcount
# define nop_mcount nop_mcount_64
-# define find_section_sym_index find64_section_sym_index
# define has_rel_mcount has64_rel_mcount
# define tot_relsize tot64_relsize
# define do_func do64
@@ -61,7 +59,6 @@
# define append_func append32
# define sift_rel_mcount sift32_rel_mcount
# define nop_mcount nop_mcount_32
-# define find_section_sym_index find32_section_sym_index
# define has_rel_mcount has32_rel_mcount
# define tot_relsize tot32_relsize
# define do_func do32
@@ -270,47 +267,6 @@ static int nop_mcount(struct section * const rels,
return 0;
}

-/*
- * Find a symbol in the given section, to be used as the base for relocating
- * the table of offsets of calls to mcount. A local or global symbol suffices,
- * but avoid a Weak symbol because it may be overridden; the change in value
- * would invalidate the relocations of the offsets of the calls to mcount.
- * Often the found symbol will be the unnamed local symbol generated by
- * GNU 'as' for the start of each section. For example:
- * 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)
-{
- 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) {
- 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;
- }
- }
- fprintf(stderr, "Cannot find symbol for section %u: %s.\n",
- txtndx, txtname);
- return missing_sym;
-}
-
static char const *has_rel_mcount(const struct section * const rels)
{
const struct section *txts;
@@ -398,7 +354,7 @@ static int do_func(Elf_Ehdr *const ehdr,
rel_entsize = sec->sh.sh_entsize;
mlocp = sift_rel_mcount(mlocp,
(void *)mlocp - (void *)mloc0, &mrelp,
- sec, recsym, recval, reltype);
+ sec, recsym, (uint_t)recval, reltype);
} else if (txtname && (warn_on_notrace_sect || make_nop)) {
/*
* This section is ignored by ftrace, but still
--
2.20.1

2020-04-10 19:39:58

by Matt Helsley

[permalink] [raw]
Subject: [RFC][PATCH 21/36] objtool: mcount: Restrict using ehdr in append_func()

To use as a pointer to an ehdr to modify. Extract the
read-only bits from objtool's GElf_Ehdr.

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 3c7afb9a2eac..3c98c379f472 100644
--- a/tools/objtool/recordmcount.h
+++ b/tools/objtool/recordmcount.h
@@ -99,8 +99,8 @@ static int append_func(Elf_Ehdr *const ehdr,
char const *mc_name = (sizeof(Elf_Rela) == rel_entsize)
? ".rela__mcount_loc"
: ".rel__mcount_loc";
- unsigned const old_shnum = w2(ehdr->e_shnum);
- uint_t const old_shoff = _w(ehdr->e_shoff);
+ unsigned const old_shnum = lf->ehdr.e_shnum;
+ uint_t const old_shoff = lf->ehdr.e_shoff;
uint_t const old_shstr_sh_size = _w(shstr->sh_size);
uint_t const old_shstr_sh_offset = _w(shstr->sh_offset);
uint_t t = 1 + strlen(mc_name) + _w(shstr->sh_size);
@@ -167,7 +167,7 @@ static int append_func(Elf_Ehdr *const ehdr,
return -1;

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

2020-04-10 19:40:12

by Matt Helsley

[permalink] [raw]
Subject: [RFC][PATCH 23/36] objtool: mcount: Move nop_mcount()

The nop_mcount() function overwrites mcount calls that should be
ignored with no-ops. This operation varies by architecture and
wordsize so we retain the function pointers used to implement
the fundamental operation while nop_mcount() itself is responsible
for walking the relocations, determining if they should be turned
into no-ops, then calling the arch-specific code. Since none of
these use the recordmcount ELF wrappers anymore we can move it out
of the wrapper.

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

diff --git a/tools/objtool/recordmcount.c b/tools/objtool/recordmcount.c
index 65b7a34f2619..99938d5a5bb1 100644
--- a/tools/objtool/recordmcount.c
+++ b/tools/objtool/recordmcount.c
@@ -398,6 +398,53 @@ static int find_section_sym_index(unsigned const txtndx,
return missing_sym;
}

+/*
+ * Read the relocation table again, but this time its called on sections
+ * that are not going to be traced. The mcount calls here will be converted
+ * into nops.
+ */
+static int nop_mcount(struct section * const rels,
+ const char *const txtname)
+{
+ struct rela *rela;
+ struct section *txts = find_section_by_index(lf, rels->sh.sh_info);
+ unsigned mcountsym = 0;
+ int once = 0;
+
+ list_for_each_entry(rela, &rels->rela_list, list) {
+ int ret = -1;
+
+ if (!mcountsym)
+ mcountsym = get_mcountsym(rela);
+
+ if (mcountsym == GELF_R_INFO(rela->sym->idx, rela->type) && !is_fake_mcount(rela)) {
+ if (make_nop) {
+ ret = make_nop(txts, rela->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 0;
+ }
+ }
+
+ /*
+ * If we successfully removed the mcount, mark the relocation
+ * as a nop (don't do anything with it).
+ */
+ if (!ret) {
+ rela->type = rel_type_nop;
+ rels->changed = true;
+ }
+ }
+ return 0;
+}
+
/* 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 4971258a2ab7..4bbdb6c107b8 100644
--- a/tools/objtool/recordmcount.h
+++ b/tools/objtool/recordmcount.h
@@ -20,7 +20,6 @@
#undef append_func
#undef mcount_adjust
#undef sift_rel_mcount
-#undef nop_mcount
#undef has_rel_mcount
#undef tot_relsize
#undef do_func
@@ -37,7 +36,6 @@
#ifdef RECORD_MCOUNT_64
# define append_func append64
# define sift_rel_mcount sift64_rel_mcount
-# define nop_mcount nop_mcount_64
# define has_rel_mcount has64_rel_mcount
# define tot_relsize tot64_relsize
# define do_func do64
@@ -53,7 +51,6 @@
#else
# define append_func append32
# define sift_rel_mcount sift32_rel_mcount
-# define nop_mcount nop_mcount_32
# define has_rel_mcount has32_rel_mcount
# define tot_relsize tot32_relsize
# define do_func do32
@@ -171,53 +168,6 @@ static uint_t *sift_rel_mcount(uint_t *mlocp,
return mlocp;
}

-/*
- * Read the relocation table again, but this time its called on sections
- * that are not going to be traced. The mcount calls here will be converted
- * into nops.
- */
-static int nop_mcount(struct section * const rels,
- const char *const txtname)
-{
- struct rela *rela;
- struct section *txts = find_section_by_index(lf, rels->sh.sh_info);
- unsigned mcountsym = 0;
- int once = 0;
-
- list_for_each_entry(rela, &rels->rela_list, list) {
- int ret = -1;
-
- if (!mcountsym)
- mcountsym = get_mcountsym(rela);
-
- if (mcountsym == GELF_R_INFO(rela->sym->idx, rela->type) && !is_fake_mcount(rela)) {
- if (make_nop) {
- ret = make_nop(txts, rela->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 0;
- }
- }
-
- /*
- * If we successfully removed the mcount, mark the relocation
- * as a nop (don't do anything with it).
- */
- if (!ret) {
- rela->type = rel_type_nop;
- rels->changed = true;
- }
- }
- return 0;
-}
-
static char const *has_rel_mcount(const struct section * const rels)
{
const struct section *txts;
--
2.20.1

2020-04-10 19:40:14

by Matt Helsley

[permalink] [raw]
Subject: [RFC][PATCH 16/36] objtool: mcount: Move get_mcountsym

Now that it's been stripped of using the old recordmcount ELF
wrapper get_mcountsym() is ready to be promoted out of the
double-included wrapper header. If we don't move it to
recordmcount.c we will get multiple definitions of the function.

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

diff --git a/tools/objtool/recordmcount.c b/tools/objtool/recordmcount.c
index f0edc9ed6021..91d14743218a 100644
--- a/tools/objtool/recordmcount.c
+++ b/tools/objtool/recordmcount.c
@@ -422,6 +422,22 @@ static int is_mcounted_section_name(char const *const txtname)
strcmp(".cpuidle.text", txtname) == 0;
}

+static unsigned get_mcountsym(struct rela *rela)
+{
+ struct symbol *sym = rela->sym;
+ char const *symname = sym->name;
+ char const *mcount = gpfx == '_' ? "_mcount" : "mcount";
+ char const *fentry = "__fentry__";
+
+ if (symname[0] == '.')
+ ++symname; /* ppc64 hack */
+ if (strcmp(mcount, symname) == 0 ||
+ (altmcount && strcmp(altmcount, symname) == 0) ||
+ (strcmp(fentry, symname) == 0))
+ return GELF_R_INFO(rela->sym->idx, rela->type);
+ return 0;
+}
+
static const unsigned int missing_sym = (unsigned int)-1;

/* 32 bit and 64 bit are very similar */
diff --git a/tools/objtool/recordmcount.h b/tools/objtool/recordmcount.h
index 5fa51118cab0..9bba41ee2db2 100644
--- a/tools/objtool/recordmcount.h
+++ b/tools/objtool/recordmcount.h
@@ -27,7 +27,6 @@
#undef find_section_sym_index
#undef has_rel_mcount
#undef tot_relsize
-#undef get_mcountsym
#undef do_func
#undef Elf_Addr
#undef Elf_Ehdr
@@ -50,7 +49,6 @@
# define has_rel_mcount has64_rel_mcount
# define tot_relsize tot64_relsize
# define do_func do64
-# define get_mcountsym get_mcountsym_64
# 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
@@ -75,7 +73,6 @@
# define has_rel_mcount has32_rel_mcount
# define tot_relsize tot32_relsize
# define do_func do32
-# define get_mcountsym get_mcountsym_32
# 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
@@ -234,22 +231,6 @@ static int append_func(Elf_Ehdr *const ehdr,
return elf_write(lf);
}

-static unsigned get_mcountsym(struct rela *rela)
-{
- struct symbol *sym = rela->sym;
- char const *symname = sym->name;
- char const *mcount = gpfx == '_' ? "_mcount" : "mcount";
- char const *fentry = "__fentry__";
-
- if (symname[0] == '.')
- ++symname; /* ppc64 hack */
- if (strcmp(mcount, symname) == 0 ||
- (altmcount && strcmp(altmcount, symname) == 0) ||
- (strcmp(fentry, symname) == 0))
- return GELF_R_INFO(rela->sym->idx, rela->type);
- return 0;
-}
-
/*
* Look at the relocations in order to find the calls to mcount.
* Accumulate the section offsets that are found, and their relocation info,
--
2.20.1

2020-04-10 19:40:26

by Matt Helsley

[permalink] [raw]
Subject: [RFC][PATCH 15/36] objtool: mcount: Walk relocation lists

Rather than walk the section tables using the old recordmcount mapping
of the ELF file, walk the section list provided by objtool's ELF code.
This removes the last use of of the Elf_r_sym wrapper so we remove
that too.

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

diff --git a/tools/objtool/recordmcount.c b/tools/objtool/recordmcount.c
index 5a05a08f0e28..f0edc9ed6021 100644
--- a/tools/objtool/recordmcount.c
+++ b/tools/objtool/recordmcount.c
@@ -429,9 +429,9 @@ static const unsigned int missing_sym = (unsigned int)-1;
#define RECORD_MCOUNT_64
#include "recordmcount.h"

-static int arm_is_fake_mcount(Elf32_Rel const *rp)
+static int arm_is_fake_mcount(struct rela const *rp)
{
- switch (ELF32_R_TYPE(w(rp->r_info))) {
+ switch (rp->type) {
case R_ARM_THM_CALL:
case R_ARM_CALL:
case R_ARM_PC24:
@@ -462,11 +462,6 @@ union mips_r_info {
} r_mips;
};

-static uint64_t MIPS64_r_sym(Elf64_Rel const *rp)
-{
- return w(((union mips_r_info){ .r_info = rp->r_info }).r_mips.r_sym);
-}
-
static void MIPS64_r_info(Elf64_Rel *const rp, unsigned sym, unsigned type)
{
rp->r_info = ((union mips_r_info){
@@ -605,7 +600,6 @@ static int do_file(char const *const fname)
}
if (w2(ghdr->e_machine) == EM_MIPS) {
reltype = R_MIPS_64;
- Elf64_r_sym = MIPS64_r_sym;
Elf64_r_info = MIPS64_r_info;
is_fake_mcount64 = MIPS64_is_fake_mcount;
}
diff --git a/tools/objtool/recordmcount.h b/tools/objtool/recordmcount.h
index d49da1e32315..5fa51118cab0 100644
--- a/tools/objtool/recordmcount.h
+++ b/tools/objtool/recordmcount.h
@@ -28,21 +28,14 @@
#undef has_rel_mcount
#undef tot_relsize
#undef get_mcountsym
-#undef get_relp
#undef do_func
#undef Elf_Addr
#undef Elf_Ehdr
#undef Elf_Shdr
#undef Elf_Rel
#undef Elf_Rela
-#undef Elf_Sym
-#undef ELF_R_SYM
-#undef Elf_r_sym
#undef ELF_R_INFO
#undef Elf_r_info
-#undef ELF_ST_BIND
-#undef ELF_ST_TYPE
-#undef fn_ELF_R_SYM
#undef fn_ELF_R_INFO
#undef uint_t
#undef _w
@@ -56,7 +49,6 @@
# define find_section_sym_index find64_section_sym_index
# define has_rel_mcount has64_rel_mcount
# define tot_relsize tot64_relsize
-# define get_relp get_relp_64
# define do_func do64
# define get_mcountsym get_mcountsym_64
# define is_fake_mcount is_fake_mcount64
@@ -68,14 +60,8 @@
# define Elf_Shdr Elf64_Shdr
# define Elf_Rel Elf64_Rel
# define Elf_Rela Elf64_Rela
-# define Elf_Sym Elf64_Sym
-# define ELF_R_SYM ELF64_R_SYM
-# define Elf_r_sym Elf64_r_sym
# define ELF_R_INFO ELF64_R_INFO
# define Elf_r_info Elf64_r_info
-# define ELF_ST_BIND ELF64_ST_BIND
-# define ELF_ST_TYPE ELF64_ST_TYPE
-# define fn_ELF_R_SYM fn_ELF64_R_SYM
# define fn_ELF_R_INFO fn_ELF64_R_INFO
# define uint_t uint64_t
# define _w w8
@@ -88,7 +74,6 @@
# define find_section_sym_index find32_section_sym_index
# define has_rel_mcount has32_rel_mcount
# define tot_relsize tot32_relsize
-# define get_relp get_relp_32
# define do_func do32
# define get_mcountsym get_mcountsym_32
# define is_fake_mcount is_fake_mcount32
@@ -100,14 +85,8 @@
# define Elf_Shdr Elf32_Shdr
# define Elf_Rel Elf32_Rel
# define Elf_Rela Elf32_Rela
-# define Elf_Sym Elf32_Sym
-# define ELF_R_SYM ELF32_R_SYM
-# define Elf_r_sym Elf32_r_sym
# define ELF_R_INFO ELF32_R_INFO
# define Elf_r_info Elf32_r_info
-# define ELF_ST_BIND ELF32_ST_BIND
-# define ELF_ST_TYPE ELF32_ST_TYPE
-# define fn_ELF_R_SYM fn_ELF32_R_SYM
# define fn_ELF_R_INFO fn_ELF32_R_INFO
# define uint_t uint32_t
# define _w w
@@ -116,17 +95,11 @@
#endif

/* Functions and pointers that do_file() may override for specific e_machine. */
-static int fn_is_fake_mcount(Elf_Rel const *rp)
+static int fn_is_fake_mcount(struct rela const *rela)
{
return 0;
}
-static int (*is_fake_mcount)(Elf_Rel const *rp) = fn_is_fake_mcount;
-
-static uint_t fn_ELF_R_SYM(Elf_Rel const *rp)
-{
- return ELF_R_SYM(_w(rp->r_info));
-}
-static uint_t (*Elf_r_sym)(Elf_Rel const *rp) = fn_ELF_R_SYM;
+static int (*is_fake_mcount)(struct rela const *rela) = fn_is_fake_mcount;

static void fn_ELF_R_INFO(Elf_Rel *const rp, unsigned sym, unsigned type)
{
@@ -157,10 +130,10 @@ static int mcount_adjust = 0;
*/
#define MIPS_FAKEMCOUNT_OFFSET 4

-static int MIPS_is_fake_mcount(Elf_Rel const *rp)
+static int MIPS_is_fake_mcount(struct rela const *rela)
{
static Elf_Addr old_r_offset = ~(Elf_Addr)0;
- Elf_Addr current_r_offset = _w(rp->r_offset);
+ Elf_Addr current_r_offset = rela->offset;
int is_fake;

is_fake = (old_r_offset != ~(Elf_Addr)0) &&
@@ -261,9 +234,9 @@ static int append_func(Elf_Ehdr *const ehdr,
return elf_write(lf);
}

-static unsigned get_mcountsym(Elf_Rel const *relp)
+static unsigned get_mcountsym(struct rela *rela)
{
- struct symbol *sym = find_symbol_by_index(lf, Elf_r_sym(relp));
+ struct symbol *sym = rela->sym;
char const *symname = sym->name;
char const *mcount = gpfx == '_' ? "_mcount" : "mcount";
char const *fentry = "__fentry__";
@@ -273,19 +246,10 @@ static unsigned get_mcountsym(Elf_Rel const *relp)
if (strcmp(mcount, symname) == 0 ||
(altmcount && strcmp(altmcount, symname) == 0) ||
(strcmp(fentry, symname) == 0))
- return Elf_r_sym(relp);
+ return GELF_R_INFO(rela->sym->idx, rela->type);
return 0;
}

-static void get_relp(const struct section * const rels,
- Elf_Ehdr const *const ehdr,
- Elf_Rel const **relp)
-{
- Elf_Rel const *const rel0 = (Elf_Rel const *)(rels->sh.sh_offset
- + (void *)ehdr);
- *relp = rel0;
-}
-
/*
* Look at the relocations in order to find the calls to mcount.
* Accumulate the section offsets that are found, and their relocation info,
@@ -295,29 +259,23 @@ static uint_t *sift_rel_mcount(uint_t *mlocp,
unsigned const offbase,
Elf_Rel **const mrelpp,
const struct section * const rels,
- Elf_Ehdr const *const ehdr,
unsigned const recsym_index,
uint_t const recval,
unsigned const reltype)
{
uint_t *const mloc0 = mlocp;
Elf_Rel *mrelp = *mrelpp;
- Elf_Rel const *relp;
unsigned int rel_entsize = rels->sh.sh_entsize;
- unsigned const nrel = rels->sh.sh_size / rel_entsize;
unsigned mcountsym = 0;
- unsigned t;
-
- get_relp(rels, ehdr, &relp);
+ struct rela *rela;

- for (t = nrel; t; --t) {
+ list_for_each_entry(rela, &rels->rela_list, list) {
if (!mcountsym)
- mcountsym = get_mcountsym(relp);
+ mcountsym = get_mcountsym(rela);

- if (mcountsym && mcountsym == Elf_r_sym(relp) &&
- !is_fake_mcount(relp)) {
+ if (mcountsym == GELF_R_INFO(rela->sym->idx, rela->type) && !is_fake_mcount(rela)) {
uint_t const addend =
- _w(_w(relp->r_offset) - recval + mcount_adjust);
+ _w(rela->offset - recval + mcount_adjust);
mrelp->r_offset = _w(offbase
+ ((void *)mlocp - (void *)mloc0));
Elf_r_info(mrelp, recsym_index, reltype);
@@ -329,7 +287,6 @@ static uint_t *sift_rel_mcount(uint_t *mlocp,

mrelp = (Elf_Rel *)(rel_entsize + (void *)mrelp);
}
- relp = (Elf_Rel const *)(rel_entsize + (void *)relp);
}
*mrelpp = mrelp;
return mlocp;
@@ -340,31 +297,29 @@ 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(const struct section * const rels,
+static int nop_mcount(struct section * const rels,
Elf_Ehdr const *const ehdr,
const char *const txtname)
{
Elf_Shdr *const shdr0 = (Elf_Shdr *)(_w(ehdr->e_shoff)
+ (void *)ehdr);
- Elf_Rel const *relp;
+ struct rela *rela;
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_relp(rels, ehdr, &relp);
-
- for (t = nrel; t; --t) {
+ list_for_each_entry(rela, &rels->rela_list, list) {
int ret = -1;

if (!mcountsym)
- mcountsym = get_mcountsym(relp);
+ mcountsym = get_mcountsym(rela);

- if (mcountsym == Elf_r_sym(relp) && !is_fake_mcount(relp)) {
- if (make_nop)
- ret = make_nop((void *)ehdr, _w(shdr->sh_offset) + _w(relp->r_offset));
+ if (mcountsym == GELF_R_INFO(rela->sym->idx, rela->type) && !is_fake_mcount(rela)) {
+ if (make_nop) {
+ ret = make_nop((void *)ehdr, _w(shdr->sh_offset) + rela->offset);
+ if (ret < 0)
+ return -1;
+ }
if (warn_on_notrace_sect && !once) {
printf("Section %s has mcount callers being ignored\n",
txtname);
@@ -380,15 +335,9 @@ static int nop_mcount(const struct section * const rels,
* as a nop (don't do anything with it).
*/
if (!ret) {
- Elf_Rel rel;
- rel = *(Elf_Rel *)relp;
- Elf_r_info(&rel, Elf_r_sym(relp), rel_type_nop);
- if (ulseek((void *)relp - (void *)ehdr, SEEK_SET) < 0)
- return -1;
- if (uwrite(&rel, sizeof(rel)) < 0)
- return -1;
+ rela->type = rel_type_nop;
+ rels->changed = true;
}
- relp = (Elf_Rel const *)(rel_entsize + (void *)relp);
}
return 0;
}
@@ -482,7 +431,7 @@ static int do_func(Elf_Ehdr *const ehdr,
unsigned rel_entsize = 0;
unsigned symsec_sh_link = 0;

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

int result = 0;

@@ -522,7 +471,7 @@ static int do_func(Elf_Ehdr *const ehdr,
rel_entsize = sec->sh.sh_entsize;
mlocp = sift_rel_mcount(mlocp,
(void *)mlocp - (void *)mloc0, &mrelp,
- sec, ehdr, recsym, recval, reltype);
+ sec, recsym, recval, reltype);
} else if (txtname && (warn_on_notrace_sect || make_nop)) {
/*
* This section is ignored by ftrace, but still
--
2.20.1

2020-04-10 19:40:35

by Matt Helsley

[permalink] [raw]
Subject: [RFC][PATCH 18/36] objtool: mcount: Move is_fake_mcount()

Promote this now-bit-independent code 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 91d14743218a..6c499fe86132 100644
--- a/tools/objtool/recordmcount.c
+++ b/tools/objtool/recordmcount.c
@@ -438,6 +438,48 @@ static unsigned get_mcountsym(struct rela *rela)
return 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 rela const *rela)
+{
+ unsigned long old_r_offset = ~0UL;
+ unsigned long current_r_offset = rela->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 rela const *rela)
+{
+ return 0;
+}
+
+static int (*is_fake_mcount)(struct rela const *rela) = 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 f99851034fa8..d61892597731 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
@@ -48,9 +45,6 @@
# define has_rel_mcount has64_rel_mcount
# define tot_relsize tot64_relsize
# 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
@@ -71,9 +65,6 @@
# define has_rel_mcount has32_rel_mcount
# define tot_relsize tot32_relsize
# 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
@@ -88,13 +79,6 @@
# define _size 4
#endif

-/* Functions and pointers that do_file() may override for specific e_machine. */
-static int fn_is_fake_mcount(struct rela const *rela)
-{
- return 0;
-}
-static int (*is_fake_mcount)(struct rela const *rela) = 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));
@@ -103,40 +87,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 rela const *rela)
-{
- static unsigned long old_r_offset = ~0UL;
- unsigned long current_r_offset = rela->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;
-}
-
/* Append the new shstrtab, Elf_Shdr[], __mcount_loc and its relocations. */
static int append_func(Elf_Ehdr *const ehdr,
Elf_Shdr *const shstr,
--
2.20.1

2020-04-10 19:40:39

by Matt Helsley

[permalink] [raw]
Subject: [RFC][PATCH 26/36] objtool: mcount: Only keep ELF file size

Since we're no longer writing to the ELF file mapping and we're
not appending to it we don't need to keep more information from the
stat structure. At the same time we can give the smaller global
variable a better name.

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

diff --git a/tools/objtool/recordmcount.c b/tools/objtool/recordmcount.c
index 95b93767d6eb..6de744aaf4c8 100644
--- a/tools/objtool/recordmcount.c
+++ b/tools/objtool/recordmcount.c
@@ -48,17 +48,17 @@
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 const char *altmcount; /* alternate mcount symbol name */
extern int warn_on_notrace_sect; /* warn when section has mcount not being recorded */
static void *file_map; /* pointer of the mapped file */
+static size_t file_map_size; /* original ELF file size */

static struct elf *lf;

static void mmap_cleanup(void)
{
if (!mmap_failed)
- munmap(file_map, sb.st_size);
+ munmap(file_map, file_map_size);
else
free(file_map);
file_map = NULL;
@@ -93,11 +93,13 @@ static void * umalloc(size_t size)
*/
static void *mmap_file(char const *fname)
{
+ struct stat sb;
+
/* Avoid problems if early cleanup() */
fd_map = -1;
mmap_failed = 1;
file_map = NULL;
- sb.st_size = 0;
+ file_map_size = 0;

lf = elf_read(fname, O_RDWR);
if (!lf) {
@@ -129,6 +131,7 @@ static void *mmap_file(char const *fname)
}
} else
mmap_failed = 0;
+ file_map_size = sb.st_size;
out:
fd_map = -1;

--
2.20.1

2020-04-10 19:40:51

by Matt Helsley

[permalink] [raw]
Subject: [RFC][PATCH 35/36] objtool: mcount: Remove wrapper double-include trick

We no longer need to double-include the recordmcount.h wrapper
All of the types and functions that rely on them have been converted
to using objtool's ELF code. This moves the remaining function to
recordmcount.c and changes the function name to something slightly
more descriptive while dropping the wrapped naming.

Signed-off-by: Matt Helsley <[email protected]>
---
tools/objtool/recordmcount.c | 122 ++++++++++++++++++++++++++++--
tools/objtool/recordmcount.h | 141 -----------------------------------
2 files changed, 116 insertions(+), 147 deletions(-)
delete mode 100644 tools/objtool/recordmcount.h

diff --git a/tools/objtool/recordmcount.c b/tools/objtool/recordmcount.c
index e6aa1feb234d..50834b065e16 100644
--- a/tools/objtool/recordmcount.c
+++ b/tools/objtool/recordmcount.c
@@ -441,10 +441,120 @@ static void sift_rel_mcount(GElf_Addr **mlocpp,
*mrelpp = is_rela ? (void *)mrelap : (void *)mrelp;
}

-/* 32 bit and 64 bit are very similar */
-#include "recordmcount.h"
-#define RECORD_MCOUNT_64
-#include "recordmcount.h"
+/* Overall supervision for Elf32 ET_REL file. */
+static int do_mcount(unsigned const reltype, size_t rela_size)
+{
+ /* Upper bound on space: assume all relevant relocs are for mcount. */
+ unsigned totrelsz;
+
+ void *mrel0;
+ void *mrelp;
+
+ GElf_Addr *mloc0;
+ GElf_Addr *mlocp;
+ GElf_Sxword r_offset; /* Used in the added relocations */
+
+ unsigned int rel_entsize = 0;
+
+ struct section *sec, *mlocs, *mrels;
+ unsigned int const old_shnum = lf->ehdr.e_shnum;
+
+ int result = -1;
+ char const *mc_name;
+ bool is_rela;
+
+ 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;
+ }
+
+ is_rela = (rela_size == rel_entsize);
+ mc_name = is_rela
+ ? ".rela__mcount_loc"
+ : ".rel__mcount_loc";
+
+ /* add section: __mcount_loc */
+ 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 = 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;
+ /* Like elf_create_rela_section() without the name bits */
+ mrels->sh.sh_type = is_rela ? SHT_RELA : SHT_REL;
+ mrels->sh.sh_flags = 0;
+ mrels->sh.sh_link = find_section_by_name(lf, ".symtab")->idx;
+ mrels->sh.sh_info = old_shnum;
+ 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;
+
+ txtname = has_rel_mcount(sec);
+ if (txtname && is_mcounted_section_name(txtname)) {
+ unsigned long recval = 0;
+ unsigned int recsym;
+
+ if (find_section_sym_index(sec->sh.sh_info,
+ txtname, &recval, &recsym))
+ goto out;
+
+ 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
+ * has mcount calls. Convert them to nops now.
+ */
+ if (nop_mcount(sec, txtname) < 0)
+ goto out;
+ }
+ }
+
+ if (mloc0 != mlocp) {
+ /* 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;
+
+ mrels->sh.sh_size = mrelp - mrel0;
+ mrels->len = mrels->sh.sh_size;
+ mrels->data->d_size = mrels->len;
+
+ /* overwrite the ELF file */
+ result = elf_write(lf);
+ } else
+ result = 0;
+out:
+ free(mrel0);
+ free(mloc0);
+ return result;
+}

static int arm_is_fake_mcount(struct rela const *rp)
{
@@ -574,7 +684,7 @@ static int do_file(char const *const fname)
is_fake_mcount = MIPS_is_fake_mcount;
}
loc_size = 4;
- rc = do32(reltype, sizeof(Elf32_Rela));
+ rc = do_mcount(reltype, sizeof(Elf32_Rela));
break;
case ELFCLASS64: {
if (lf->ehdr.e_ehsize != sizeof(Elf64_Ehdr)
@@ -592,7 +702,7 @@ static int do_file(char const *const fname)
is_fake_mcount = MIPS_is_fake_mcount;
}
loc_size = 8;
- rc = do64(reltype, sizeof(Elf64_Rela));
+ rc = do_mcount(reltype, sizeof(Elf64_Rela));
break;
}
} /* end switch */
diff --git a/tools/objtool/recordmcount.h b/tools/objtool/recordmcount.h
deleted file mode 100644
index d116032522e1..000000000000
--- a/tools/objtool/recordmcount.h
+++ /dev/null
@@ -1,141 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0-only */
-/*
- * recordmcount.h
- *
- * This code was taken out of recordmcount.c written by
- * Copyright 2009 John F. Reiser <[email protected]>. All rights reserved.
- *
- * The original code had the same algorithms for both 32bit
- * and 64bit ELF files, but the code was duplicated to support
- * the difference in structures that were used. This
- * file creates a macro of everything that is different between
- * the 64 and 32 bit code, such that by including this header
- * twice we can create both sets of functions by including this
- * header once with RECORD_MCOUNT_64 undefined, and again with
- * it defined.
- *
- * This conversion to macros was done by:
- * Copyright 2010 Steven Rostedt <[email protected]>, Red Hat Inc.
- */
-#undef do_func
-
-#ifdef RECORD_MCOUNT_64
-# define do_func do64
-#else
-# define do_func do32
-#endif
-
-/* Overall supervision for Elf32 ET_REL file. */
-static int do_func(unsigned const reltype, size_t rela_size)
-{
- /* Upper bound on space: assume all relevant relocs are for mcount. */
- unsigned totrelsz;
-
- void *mrel0;
- void *mrelp;
-
- GElf_Addr *mloc0;
- GElf_Addr *mlocp;
- GElf_Sxword r_offset = 0;
-
- unsigned int rel_entsize = 0;
-
- struct section *sec, *mlocs, *mrels;
- unsigned int const old_shnum = lf->ehdr.e_shnum;
-
- int result = -1;
- char const *mc_name;
- bool is_rela;
-
- 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;
- }
-
- is_rela = (rela_size == rel_entsize);
- mc_name = is_rela
- ? ".rela__mcount_loc"
- : ".rel__mcount_loc";
-
- /* add section: __mcount_loc */
- 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 = 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;
- /* Like elf_create_rela_section() without the name bits */
- mrels->sh.sh_type = is_rela ? SHT_RELA : SHT_REL;
- mrels->sh.sh_flags = 0;
- mrels->sh.sh_link = find_section_by_name(lf, ".symtab")->idx;
- mrels->sh.sh_info = old_shnum;
- 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;
-
- txtname = has_rel_mcount(sec);
- if (txtname && is_mcounted_section_name(txtname)) {
- unsigned long recval = 0;
- unsigned int recsym;
-
- if (find_section_sym_index(sec->sh.sh_info,
- txtname, &recval, &recsym))
- goto out;
-
- 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
- * has mcount calls. Convert them to nops now.
- */
- if (nop_mcount(sec, txtname) < 0)
- goto out;
- }
- }
-
- if (mloc0 != mlocp) {
- /* 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;
-
- mrels->sh.sh_size = mrelp - mrel0;
- mrels->len = mrels->sh.sh_size;
- mrels->data->d_size = mrels->len;
-
- /* overwrite the ELF file */
- result = elf_write(lf);
- } else
- result = 0;
-out:
- free(mrel0);
- free(mloc0);
- return result;
-}
--
2.20.1

2020-04-10 19:41:33

by Matt Helsley

[permalink] [raw]
Subject: [RFC][PATCH 24/36] objtool: mcount: Move helpers out of ELF wrapper

These helpers are no longer dependent on the old ELF wrapper and can
be moved into the wrapper-independent code of recordmcount.c

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

diff --git a/tools/objtool/recordmcount.c b/tools/objtool/recordmcount.c
index 99938d5a5bb1..f39919e1ea7e 100644
--- a/tools/objtool/recordmcount.c
+++ b/tools/objtool/recordmcount.c
@@ -445,6 +445,31 @@ 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 4bbdb6c107b8..e6efdd34958e 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
@@ -168,33 +162,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-04-10 19:41:40

by Matt Helsley

[permalink] [raw]
Subject: [RFC][PATCH 25/36] objtool: mcount: Move relocation entry size detection

Move where we detect the size of relocation entries we wish to
use into the first loop over the sections. This will allow us
to allocate the mcount location and relocation sections before
the next loop that collects them.

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

diff --git a/tools/objtool/recordmcount.c b/tools/objtool/recordmcount.c
index f39919e1ea7e..95b93767d6eb 100644
--- a/tools/objtool/recordmcount.c
+++ b/tools/objtool/recordmcount.c
@@ -457,7 +457,7 @@ static char const *has_rel_mcount(const struct section * const rels)
return txts->name;
}

-static unsigned tot_relsize(void)
+static unsigned tot_relsize(unsigned int *rel_entsize)
{
const struct section *sec;
unsigned totrelsz = 0;
@@ -465,8 +465,10 @@ static unsigned tot_relsize(void)

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;
+ if (!(txtname && is_mcounted_section_name(txtname)))
+ continue;
+ totrelsz += sec->sh.sh_size;
+ *rel_entsize = sec->sh.sh_entsize;
}
return totrelsz;
}
diff --git a/tools/objtool/recordmcount.h b/tools/objtool/recordmcount.h
index e6efdd34958e..084f1eff0df0 100644
--- a/tools/objtool/recordmcount.h
+++ b/tools/objtool/recordmcount.h
@@ -175,7 +175,7 @@ static int do_func(unsigned const reltype)
uint_t * mloc0;
uint_t * mlocp;

- unsigned rel_entsize = 0;
+ unsigned int rel_entsize = 0;
unsigned symsec_sh_link = 0;

struct section *sec;
@@ -185,7 +185,7 @@ static int do_func(unsigned const reltype)
if (find_section_by_name(lf, "__mcount_loc") != NULL)
return 0;

- totrelsz = tot_relsize();
+ totrelsz = tot_relsize(&rel_entsize);
if (totrelsz == 0)
return 0;
mrel0 = umalloc(totrelsz);
@@ -215,7 +215,6 @@ static int do_func(unsigned const reltype)
if (result)
goto out;

- rel_entsize = sec->sh.sh_entsize;
mlocp = sift_rel_mcount(mlocp,
(void *)mlocp - (void *)mloc0, &mrelp,
sec, recsym, (uint_t)recval, reltype);
--
2.20.1

2020-04-10 19:41:54

by Matt Helsley

[permalink] [raw]
Subject: [RFC][PATCH 29/36] objtool: mcount: Reduce usage of _size wrapper

Use loc_size, which will be passed in from outside the wrapper, rather
than the _size wrapper since the location size is determined outside
the wrapper anyway.

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

diff --git a/tools/objtool/recordmcount.h b/tools/objtool/recordmcount.h
index 9ce2d74df89a..353c7d082631 100644
--- a/tools/objtool/recordmcount.h
+++ b/tools/objtool/recordmcount.h
@@ -72,6 +72,7 @@ static int append_func(uint_t const *const mloc0,
uint_t const *const mlocp,
Elf_Rel const *const mrel0,
Elf_Rel const *const mrelp,
+ unsigned int const loc_size,
unsigned int const rel_entsize,
unsigned int const symsec_sh_link)
{
@@ -83,14 +84,14 @@ static int append_func(uint_t const *const mloc0,
unsigned const old_shnum = lf->ehdr.e_shnum;

/* add section: __mcount_loc */
- sec = elf_create_section(lf, mc_name + (sizeof(Elf_Rela) == rel_entsize) + strlen(".rel"), _size, mlocp - mloc0);
+ sec = elf_create_section(lf, mc_name + (sizeof(Elf_Rela) == rel_entsize) + strlen(".rel"), loc_size, mlocp - mloc0);
if (!sec)
return -1;

// created sec->sh.sh_size = (void *)mlocp - (void *)mloc0;
sec->sh.sh_link = 0;/* TODO objtool uses this? */
sec->sh.sh_info = 0;/* TODO objtool uses this? */
- sec->sh.sh_addralign = _size;
+ sec->sh.sh_addralign = loc_size;
// created sec->sh.sh_entsize = _size;

// assert sec->data->d_size == (void *)mlocp - (void *)mloc0
@@ -109,7 +110,7 @@ static int append_func(uint_t const *const mloc0,
sec->sh.sh_flags = 0;
sec->sh.sh_link = find_section_by_name(lf, ".symtab")->idx;
sec->sh.sh_info = old_shnum;
- sec->sh.sh_addralign = _size;
+ sec->sh.sh_addralign = loc_size;

// assert sec->data->d_size == (void *)mrelp - (void *)mrel0
memcpy(sec->data->d_buf, mrel0, sec->data->d_size);
@@ -231,7 +232,7 @@ static int do_func(unsigned const reltype)
}
if (!result && mloc0 != mlocp)
result = append_func(mloc0, mlocp, mrel0, mrelp,
- rel_entsize, symsec_sh_link);
+ _size, rel_entsize, symsec_sh_link);
out:
free(mrel0);
free(mloc0);
--
2.20.1

2020-04-10 19:41:57

by Matt Helsley

[permalink] [raw]
Subject: [RFC][PATCH 32/36] 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 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 | 120 ++++++++++++++---------------------
2 files changed, 59 insertions(+), 105 deletions(-)

diff --git a/tools/objtool/recordmcount.c b/tools/objtool/recordmcount.c
index 52d8d9800bf9..89765870b0dd 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 unsigned get_mcountsym(struct rela *rela)
+static unsigned int get_mcount_sym_info(struct rela *rela)
{
struct symbol *sym = rela->sym;
char const *symname = sym->name;
@@ -321,16 +321,16 @@ static int nop_mcount(struct section * const rels,
{
struct rela *rela;
struct section *txts = find_section_by_index(lf, rels->sh.sh_info);
- unsigned mcountsym = 0;
+ unsigned int mcount_sym_info = 0;
int once = 0;

list_for_each_entry(rela, &rels->rela_list, list) {
int ret = -1;

- if (!mcountsym)
- mcountsym = get_mcountsym(rela);
+ if (!mcount_sym_info)
+ mcount_sym_info = get_mcount_sym_info(rela);

- if (mcountsym == GELF_R_INFO(rela->sym->idx, rela->type) && !is_fake_mcount(rela)) {
+ if (mcount_sym_info == GELF_R_INFO(rela->sym->idx, rela->type) && !is_fake_mcount(rela)) {
if (make_nop) {
ret = make_nop(txts, rela->offset);
if (ret < 0)
@@ -391,6 +391,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
@@ -408,34 +411,6 @@ static int arm_is_fake_mcount(struct rela 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;
@@ -551,6 +526,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: {
@@ -566,9 +542,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 cee5bc91d666..bdf77172da58 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;
- unsigned mcountsym = 0;
+ GElf_Rel *mrelp = *mrelpp;
+ GElf_Rela *mrelap = *mrelpp;
+ unsigned int mcount_sym_info = 0;
struct rela *rela;

list_for_each_entry(rela, &rels->rela_list, list) {
- if (!mcountsym)
- mcountsym = get_mcountsym(rela);
-
- if (mcountsym == GELF_R_INFO(rela->sym->idx, rela->type) && !is_fake_mcount(rela)) {
- uint_t const addend =
- _w(rela->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_info)
+ mcount_sym_info = get_mcount_sym_info(rela);
+
+ if (mcount_sym_info != GELF_R_INFO(rela->sym->idx, rela->type) || is_fake_mcount(rela))
+ continue;
+
+ addend = rela->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;
}


@@ -108,11 +85,12 @@ 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;

unsigned int rel_entsize = 0;

@@ -149,25 +127,28 @@ 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;
mrels->sh.sh_link = find_section_by_name(lf, ".symtab")->idx;
mrels->sh.sh_info = old_shnum;
- 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;
@@ -181,9 +162,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
@@ -195,16 +175,14 @@ 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;

- 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;

/* overwrite the ELF file */
result = elf_write(lf);
--
2.20.1

2020-04-10 19:42:03

by Matt Helsley

[permalink] [raw]
Subject: [RFC][PATCH 33/36] objtool: mcount: Move sift_rel_mcount out of wrapper file

Now that this function no longer uses any of the old recordmcount
wrapper code we can move it out of the wrapper too.

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

diff --git a/tools/objtool/recordmcount.c b/tools/objtool/recordmcount.c
index 89765870b0dd..a16611a352e5 100644
--- a/tools/objtool/recordmcount.c
+++ b/tools/objtool/recordmcount.c
@@ -394,6 +394,53 @@ static int mcount_adjust = 0;
/* Size of an entry in __mcount_loc; 4 or 8 */
static size_t loc_size;

+/*
+ * 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 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,
+ bool is_rela)
+{
+ GElf_Rel *mrelp = *mrelpp;
+ GElf_Rela *mrelap = *mrelpp;
+ unsigned int mcount_sym_info = 0;
+ struct rela *rela;
+
+ list_for_each_entry(rela, &rels->rela_list, list) {
+ unsigned long addend;
+
+ if (!mcount_sym_info)
+ mcount_sym_info = get_mcount_sym_info(rela);
+
+ if (mcount_sym_info != GELF_R_INFO(rela->sym->idx, rela->type) || is_fake_mcount(rela))
+ continue;
+
+ addend = rela->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 = is_rela ? (void *)mrelap : (void *)mrelp;
+}
+
/* 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 bdf77172da58..7db08ad9b4a7 100644
--- a/tools/objtool/recordmcount.h
+++ b/tools/objtool/recordmcount.h
@@ -17,68 +17,17 @@
* This conversion to macros was done by:
* Copyright 2010 Steven Rostedt <[email protected]>, Red Hat Inc.
*/
-#undef sift_rel_mcount
#undef do_func
#undef Elf_Rela

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

-/*
- * 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 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,
- bool is_rela)
-{
- GElf_Rel *mrelp = *mrelpp;
- GElf_Rela *mrelap = *mrelpp;
- unsigned int mcount_sym_info = 0;
- struct rela *rela;
-
- list_for_each_entry(rela, &rels->rela_list, list) {
- unsigned long addend;
-
- if (!mcount_sym_info)
- mcount_sym_info = get_mcount_sym_info(rela);
-
- if (mcount_sym_info != GELF_R_INFO(rela->sym->idx, rela->type) || is_fake_mcount(rela))
- continue;
-
- addend = rela->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 = is_rela ? (void *)mrelap : (void *)mrelp;
-}
-
-
/* Overall supervision for Elf32 ET_REL file. */
static int do_func(unsigned const reltype)
{
--
2.20.1

2020-04-10 19:42:32

by Matt Helsley

[permalink] [raw]
Subject: [RFC][PATCH 36/36] objtool: mcount: Remove wordsized endian wrappers

Now that they're no longer used we can remove these endian wrappers.

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

diff --git a/tools/objtool/recordmcount.c b/tools/objtool/recordmcount.c
index 50834b065e16..fd66e26f21a8 100644
--- a/tools/objtool/recordmcount.c
+++ b/tools/objtool/recordmcount.c
@@ -149,53 +149,6 @@ static int make_nop_arm64(struct section *txts, size_t const offset)
return 0;
}

-/* w8rev, w8nat, ...: Handle endianness. */
-
-static uint64_t w8rev(uint64_t const x)
-{
- return ((0xff & (x >> (0 * 8))) << (7 * 8))
- | ((0xff & (x >> (1 * 8))) << (6 * 8))
- | ((0xff & (x >> (2 * 8))) << (5 * 8))
- | ((0xff & (x >> (3 * 8))) << (4 * 8))
- | ((0xff & (x >> (4 * 8))) << (3 * 8))
- | ((0xff & (x >> (5 * 8))) << (2 * 8))
- | ((0xff & (x >> (6 * 8))) << (1 * 8))
- | ((0xff & (x >> (7 * 8))) << (0 * 8));
-}
-
-static uint32_t w4rev(uint32_t const x)
-{
- return ((0xff & (x >> (0 * 8))) << (3 * 8))
- | ((0xff & (x >> (1 * 8))) << (2 * 8))
- | ((0xff & (x >> (2 * 8))) << (1 * 8))
- | ((0xff & (x >> (3 * 8))) << (0 * 8));
-}
-
-static uint32_t w2rev(uint16_t const x)
-{
- return ((0xff & (x >> (0 * 8))) << (1 * 8))
- | ((0xff & (x >> (1 * 8))) << (0 * 8));
-}
-
-static uint64_t w8nat(uint64_t const x)
-{
- return x;
-}
-
-static uint32_t w4nat(uint32_t const x)
-{
- return x;
-}
-
-static uint32_t w2nat(uint16_t const x)
-{
- return x;
-}
-
-static uint64_t (*w8)(uint64_t);
-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)
{
@@ -579,22 +532,12 @@ static int do_file(char const *const fname)
goto out;
}

- w = w4nat;
- w2 = w2nat;
- w8 = w8nat;
switch (lf->ehdr.e_ident[EI_DATA]) {
- static unsigned int const endian = 1;
default:
fprintf(stderr, "unrecognized ELF data encoding %d: %s\n",
lf->ehdr.e_ident[EI_DATA], fname);
goto out;
case ELFDATA2LSB:
- if (*(unsigned char const *)&endian != 1) {
- /* objtool is big endian, file.o is little endian. */
- w = w4rev;
- w2 = w2rev;
- w8 = w8rev;
- }
ideal_nop4_arm = ideal_nop4_arm_le;
bl_mcount_arm = bl_mcount_arm_le;
push_arm = push_arm_le;
@@ -602,12 +545,6 @@ static int do_file(char const *const fname)
push_bl_mcount_thumb = push_bl_mcount_thumb_le;
break;
case ELFDATA2MSB:
- if (*(unsigned char const *)&endian != 0) {
- /* objtool is little endian, file.o is big endian. */
- w = w4rev;
- w2 = w2rev;
- w8 = w8rev;
- }
ideal_nop4_arm = ideal_nop4_arm_be;
bl_mcount_arm = bl_mcount_arm_be;
push_arm = push_arm_be;
--
2.20.1

2020-04-10 19:42:38

by Matt Helsley

[permalink] [raw]
Subject: [RFC][PATCH 34/36] objtool: mcount: Remove wrapper for ELF relocation type

Remove the last use of the Elf_Rela wrapper #defines 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 a16611a352e5..e6aa1feb234d 100644
--- a/tools/objtool/recordmcount.c
+++ b/tools/objtool/recordmcount.c
@@ -574,7 +574,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)
@@ -592,7 +592,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 7db08ad9b4a7..d116032522e1 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;
@@ -70,7 +67,7 @@ static int do_func(unsigned const reltype)
return -1;
}

- is_rela = (sizeof(Elf_Rela) == rel_entsize);
+ is_rela = (rela_size == rel_entsize);
mc_name = is_rela
? ".rela__mcount_loc"
: ".rel__mcount_loc";
--
2.20.1

2020-04-10 19:42:51

by Matt Helsley

[permalink] [raw]
Subject: [RFC][PATCH 28/36] objtool: mcount: Remove unused file mapping

The ELF data is now accessed completely through objtool's
ELF code. We can remove the mapping of the original ELF
file and propagate elf_open(), elf_close(), and malloc()
up in place of mmap_file(), mmap_cleanup(), and umalloc()
respectively. This also eliminates the last use of the
umalloc() wrapper, reduces the number of global
variables, and limits the use of globals to:

The struct elf for the file we're working on. This
saves passing it to nearly every function as a parameter.

Variables set depending on the ELF file endian, wordsize,
and arch so that the appropriate relocation structures,
offset sizes, architecture quirks, and nop encodings will
be used.

One command-line option

Note that we're still using the recordmcount wrapper to change
variable sizes and structure definitions we use to build the
mcount relocation data and call instruction offsets.

RFC Reviewer Question: Should these arch bits be broken out to fit
objtool's arch directories similar to the way instruction
parsing is done? (e.g. arch-specific nop insn writes)

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

diff --git a/tools/objtool/recordmcount.c b/tools/objtool/recordmcount.c
index 409f0ef82211..5fdef8b2ac28 100644
--- a/tools/objtool/recordmcount.c
+++ b/tools/objtool/recordmcount.c
@@ -41,104 +41,14 @@
#define R_AARCH64_ABS64 257
#endif

-#define R_ARM_PC24 1
#define R_ARM_THM_CALL 10
-#define R_ARM_CALL 28

-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 const char *altmcount; /* alternate mcount symbol name */
extern int warn_on_notrace_sect; /* warn when section has mcount not being recorded */
-static void *file_map; /* pointer of the mapped file */
-static size_t file_map_size; /* original ELF file size */

static struct elf *lf;

-static void mmap_cleanup(void)
-{
- if (!mmap_failed)
- munmap(file_map, file_map_size);
- else
- free(file_map);
- file_map = NULL;
- if (lf)
- elf_close(lf);
- lf = NULL;
-}
-
-static void * umalloc(size_t size)
-{
- void *const addr = malloc(size);
- if (addr == 0) {
- fprintf(stderr, "malloc failed: %zu bytes\n", size);
- 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)
-{
- struct stat sb;
-
- /* Avoid problems if early cleanup() */
- fd_map = -1;
- mmap_failed = 1;
- file_map = NULL;
- file_map_size = 0;
-
- lf = elf_read(fname, O_RDWR);
- if (!lf) {
- perror(fname);
- return NULL;
- }
- fd_map = lf->fd;
- 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);
- mmap_cleanup();
- goto out;
- }
- } else
- mmap_failed = 0;
- file_map_size = sb.st_size;
-out:
- fd_map = -1;
-
- 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;
@@ -525,8 +435,11 @@ static int do_file(char const *const fname)
unsigned int reltype = 0;
int rc = -1;

- if (!mmap_file(fname))
+ lf = elf_read(fname, O_RDWR);
+ if (!lf) {
+ perror(fname);
goto out;
+ }

w = w4nat;
w2 = w2nat;
@@ -656,7 +569,9 @@ static int do_file(char const *const fname)
} /* end switch */

out:
- mmap_cleanup();
+ if (lf)
+ elf_close(lf);
+ lf = NULL;
return rc;
}

diff --git a/tools/objtool/recordmcount.h b/tools/objtool/recordmcount.h
index 084f1eff0df0..9ce2d74df89a 100644
--- a/tools/objtool/recordmcount.h
+++ b/tools/objtool/recordmcount.h
@@ -188,13 +188,13 @@ static int do_func(unsigned const reltype)
totrelsz = tot_relsize(&rel_entsize);
if (totrelsz == 0)
return 0;
- mrel0 = umalloc(totrelsz);
+ mrel0 = malloc(totrelsz);
mrelp = mrel0;
if (!mrel0)
return -1;

/* 2*sizeof(address) <= sizeof(Elf_Rel) */
- mloc0 = umalloc(totrelsz>>1);
+ mloc0 = malloc(totrelsz>>1);
mlocp = mloc0;
if (!mloc0) {
free(mrel0);
--
2.20.1

2020-04-10 19:42:52

by Matt Helsley

[permalink] [raw]
Subject: [RFC][PATCH 27/36] objtool: mcount: Use ELF header from objtool

The ELF header is the very first structure in an ELF file.
Rather than cast it from the file mapping we use the ELF
header extracted via objtool's ELF code.

This should be the last usage of the open-coded mapping of
the ELF file. We will remove the mapping in a later step.

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

diff --git a/tools/objtool/recordmcount.c b/tools/objtool/recordmcount.c
index 6de744aaf4c8..409f0ef82211 100644
--- a/tools/objtool/recordmcount.c
+++ b/tools/objtool/recordmcount.c
@@ -523,21 +523,19 @@ static void MIPS64_r_info(Elf64_Rel *const rp, unsigned sym, unsigned type)
static int do_file(char const *const fname)
{
unsigned int reltype = 0;
- Elf32_Ehdr *ehdr;
int rc = -1;

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

w = w4nat;
w2 = w2nat;
w8 = w8nat;
- switch (ehdr->e_ident[EI_DATA]) {
+ switch (lf->ehdr.e_ident[EI_DATA]) {
static unsigned int const endian = 1;
default:
fprintf(stderr, "unrecognized ELF data encoding %d: %s\n",
- ehdr->e_ident[EI_DATA], fname);
+ lf->ehdr.e_ident[EI_DATA], fname);
goto out;
case ELFDATA2LSB:
if (*(unsigned char const *)&endian != 1) {
@@ -566,18 +564,18 @@ 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, lf->ehdr.e_ident, SELFMAG) != 0 ||
+ lf->ehdr.e_type != ET_REL ||
+ lf->ehdr.e_ident[EI_VERSION] != EV_CURRENT) {
fprintf(stderr, "unrecognized ET_REL file %s\n", fname);
goto out;
}

gpfx = '_';
- switch (w2(ehdr->e_machine)) {
+ switch (lf->ehdr.e_machine) {
default:
fprintf(stderr, "unrecognized e_machine %u %s\n",
- w2(ehdr->e_machine), fname);
+ lf->ehdr.e_machine, fname);
goto out;
case EM_386:
reltype = R_386_32;
@@ -618,37 +616,36 @@ static int do_file(char const *const fname)
break;
} /* end switch */

- switch (ehdr->e_ident[EI_CLASS]) {
+ switch (lf->ehdr.e_ident[EI_CLASS]) {
default:
fprintf(stderr, "unrecognized ELF class %d %s\n",
- ehdr->e_ident[EI_CLASS], fname);
+ lf->ehdr.e_ident[EI_CLASS], fname);
goto out;
case ELFCLASS32:
- if (w2(ehdr->e_ehsize) != sizeof(Elf32_Ehdr)
- || w2(ehdr->e_shentsize) != sizeof(Elf32_Shdr)) {
+ if (lf->ehdr.e_ehsize != sizeof(Elf32_Ehdr)
+ || lf->ehdr.e_shentsize != sizeof(Elf32_Shdr)) {
fprintf(stderr,
"unrecognized ET_REL file: %s\n", fname);
goto out;
}
- if (w2(ehdr->e_machine) == EM_MIPS) {
+ if (lf->ehdr.e_machine == EM_MIPS) {
reltype = R_MIPS_32;
is_fake_mcount = MIPS_is_fake_mcount;
}
rc = do32(reltype);
break;
case ELFCLASS64: {
- Elf64_Ehdr *const ghdr = (Elf64_Ehdr *)ehdr;
- if (w2(ghdr->e_ehsize) != sizeof(Elf64_Ehdr)
- || w2(ghdr->e_shentsize) != sizeof(Elf64_Shdr)) {
+ if (lf->ehdr.e_ehsize != sizeof(Elf64_Ehdr)
+ || lf->ehdr.e_shentsize != sizeof(Elf64_Shdr)) {
fprintf(stderr,
"unrecognized ET_REL file: %s\n", fname);
goto out;
}
- if (w2(ghdr->e_machine) == EM_S390) {
+ if (lf->ehdr.e_machine == EM_S390) {
reltype = R_390_64;
mcount_adjust_64 = -14;
}
- if (w2(ghdr->e_machine) == EM_MIPS) {
+ if (lf->ehdr.e_machine == EM_MIPS) {
reltype = R_MIPS_64;
Elf64_r_info = MIPS64_r_info;
is_fake_mcount = MIPS_is_fake_mcount;
--
2.20.1

2020-04-10 19:42:52

by Matt Helsley

[permalink] [raw]
Subject: [RFC][PATCH 30/36] objtool: mcount: Move mcount_adjust out of wrapper

The mcount_adjust variable defines how many bytes to move back
from the relocation address in order to be able to get to the
start of the function call instruction(s) needed to turn it
into a no-op. The values are very small and signed so we don't
need to worry about changing the size of the variable's type
inside the wrapper -- we can just use a regular int.

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

diff --git a/tools/objtool/recordmcount.c b/tools/objtool/recordmcount.c
index 5fdef8b2ac28..52d8d9800bf9 100644
--- a/tools/objtool/recordmcount.c
+++ b/tools/objtool/recordmcount.c
@@ -385,6 +385,12 @@ static unsigned tot_relsize(unsigned int *rel_entsize)
}
return totrelsz;
}
+
+/* zero or a small negative offset added to get the start of the call
+ * instruction
+ */
+static int mcount_adjust = 0;
+
/* 32 bit and 64 bit are very similar */
#include "recordmcount.h"
#define RECORD_MCOUNT_64
@@ -495,7 +501,7 @@ static int do_file(char const *const fname)
rel_type_nop = R_386_NONE;
make_nop = make_nop_x86;
ideal_nop = ideal_nop5_x86_32;
- mcount_adjust_32 = -1;
+ mcount_adjust = -1;
gpfx = 0;
break;
case EM_ARM:
@@ -524,7 +530,7 @@ static int do_file(char const *const fname)
ideal_nop = ideal_nop5_x86_64;
reltype = R_X86_64_64;
rel_type_nop = R_X86_64_NONE;
- mcount_adjust_64 = -1;
+ mcount_adjust = -1;
gpfx = 0;
break;
} /* end switch */
@@ -556,7 +562,7 @@ static int do_file(char const *const fname)
}
if (lf->ehdr.e_machine == EM_S390) {
reltype = R_390_64;
- mcount_adjust_64 = -14;
+ mcount_adjust = -14;
}
if (lf->ehdr.e_machine == EM_MIPS) {
reltype = R_MIPS_64;
diff --git a/tools/objtool/recordmcount.h b/tools/objtool/recordmcount.h
index 353c7d082631..b4d3c55f2c9c 100644
--- a/tools/objtool/recordmcount.h
+++ b/tools/objtool/recordmcount.h
@@ -18,7 +18,6 @@
* Copyright 2010 Steven Rostedt <[email protected]>, Red Hat Inc.
*/
#undef append_func
-#undef mcount_adjust
#undef sift_rel_mcount
#undef do_func
#undef Elf_Shdr
@@ -35,7 +34,6 @@
# define append_func append64
# define sift_rel_mcount sift64_rel_mcount
# define do_func do64
-# define mcount_adjust mcount_adjust_64
# define Elf_Rel Elf64_Rel
# define Elf_Rela Elf64_Rela
# define ELF_R_INFO ELF64_R_INFO
@@ -48,7 +46,6 @@
# define append_func append32
# define sift_rel_mcount sift32_rel_mcount
# define do_func do32
-# define mcount_adjust mcount_adjust_32
# define Elf_Rel Elf32_Rel
# define Elf_Rela Elf32_Rela
# define ELF_R_INFO ELF32_R_INFO
@@ -65,8 +62,6 @@ static void fn_ELF_R_INFO(Elf_Rel *const rp, unsigned sym, unsigned type)
}
static void (*Elf_r_info)(Elf_Rel *const rp, unsigned sym, unsigned type) = fn_ELF_R_INFO;

-static int mcount_adjust = 0;
-
/* Append the new __mcount_loc and its relocations. */
static int append_func(uint_t const *const mloc0,
uint_t const *const mlocp,
--
2.20.1

2020-04-10 19:43:02

by Matt Helsley

[permalink] [raw]
Subject: [RFC][PATCH 31/36] objtool: mcount: Pre-allocate new ELF sections

Rather than allocating the ELF sections after collecting the
mcount locations and building the relocation entries, create
the empty sections beforehand. This has the benefit of
removing the memcpy() and just using the resulting buffers
directly.

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

diff --git a/tools/objtool/recordmcount.h b/tools/objtool/recordmcount.h
index b4d3c55f2c9c..cee5bc91d666 100644
--- a/tools/objtool/recordmcount.h
+++ b/tools/objtool/recordmcount.h
@@ -17,7 +17,6 @@
* This conversion to macros was done by:
* Copyright 2010 Steven Rostedt <[email protected]>, Red Hat Inc.
*/
-#undef append_func
#undef sift_rel_mcount
#undef do_func
#undef Elf_Shdr
@@ -31,7 +30,6 @@
#undef _size

#ifdef RECORD_MCOUNT_64
-# define append_func append64
# define sift_rel_mcount sift64_rel_mcount
# define do_func do64
# define Elf_Rel Elf64_Rel
@@ -43,7 +41,6 @@
# define _w w8
# define _size 8
#else
-# define append_func append32
# define sift_rel_mcount sift32_rel_mcount
# define do_func do32
# define Elf_Rel Elf32_Rel
@@ -62,60 +59,6 @@ static void fn_ELF_R_INFO(Elf_Rel *const rp, unsigned sym, unsigned type)
}
static void (*Elf_r_info)(Elf_Rel *const rp, unsigned sym, unsigned type) = fn_ELF_R_INFO;

-/* Append the new __mcount_loc and its relocations. */
-static int append_func(uint_t const *const mloc0,
- uint_t const *const mlocp,
- Elf_Rel const *const mrel0,
- Elf_Rel const *const mrelp,
- unsigned int const loc_size,
- unsigned int const rel_entsize,
- unsigned int const symsec_sh_link)
-{
- /* Begin constructing output file */
- struct section *sec;
- char const *mc_name = (sizeof(Elf_Rela) == rel_entsize)
- ? ".rela__mcount_loc"
- : ".rel__mcount_loc";
- unsigned const old_shnum = lf->ehdr.e_shnum;
-
- /* add section: __mcount_loc */
- sec = elf_create_section(lf, mc_name + (sizeof(Elf_Rela) == rel_entsize) + strlen(".rel"), loc_size, mlocp - mloc0);
- if (!sec)
- return -1;
-
- // created sec->sh.sh_size = (void *)mlocp - (void *)mloc0;
- sec->sh.sh_link = 0;/* TODO objtool uses this? */
- sec->sh.sh_info = 0;/* TODO objtool uses this? */
- sec->sh.sh_addralign = loc_size;
- // created sec->sh.sh_entsize = _size;
-
- // assert sec->data->d_size == (void *)mlocp - (void *)mloc0
- memcpy(sec->data->d_buf, mloc0, sec->data->d_size);
- /* HACK link in Pre-assembled buffer ?
- sec->data->d_buf = mloc0;
- sec->data->d_size = sec->sh.sh_size;*/
-
- /* add section .rel[a]__mcount_loc */
- sec = elf_create_section(lf, mc_name, rel_entsize, mrelp - mrel0);
- if (!sec)
- return -1;
- sec->sh.sh_type = (sizeof(Elf_Rela) == rel_entsize)
- ? SHT_RELA
- : SHT_REL;
- sec->sh.sh_flags = 0;
- sec->sh.sh_link = find_section_by_name(lf, ".symtab")->idx;
- sec->sh.sh_info = old_shnum;
- sec->sh.sh_addralign = loc_size;
-
- // assert sec->data->d_size == (void *)mrelp - (void *)mrel0
- memcpy(sec->data->d_buf, mrel0, sec->data->d_size);
- /* HACK link in Pre-assembled buffer ?
- sec->data->d_buf = mrel0;
- sec->data->d_size = sec->sh.sh_size;*/
-
- return elf_write(lf);
-}
-
/*
* Look at the relocations in order to find the calls to mcount.
* Accumulate the section offsets that are found, and their relocation info,
@@ -172,11 +115,13 @@ static int do_func(unsigned const reltype)
uint_t * mlocp;

unsigned int rel_entsize = 0;
- unsigned symsec_sh_link = 0;

- struct section *sec;
+ struct section *sec, *mlocs, *mrels;
+ unsigned int const old_shnum = lf->ehdr.e_shnum;

- int result = 0;
+ int result = -1;
+ char const *mc_name;
+ bool is_rela;

if (find_section_by_name(lf, "__mcount_loc") != NULL)
return 0;
@@ -184,6 +129,7 @@ static int do_func(unsigned const reltype)
totrelsz = tot_relsize(&rel_entsize);
if (totrelsz == 0)
return 0;
+
mrel0 = malloc(totrelsz);
mrelp = mrel0;
if (!mrel0)
@@ -197,6 +143,32 @@ static int do_func(unsigned const reltype)
return -1;
}

+ is_rela = (sizeof(Elf_Rela) == rel_entsize);
+ mc_name = is_rela
+ ? ".rela__mcount_loc"
+ : ".rel__mcount_loc";
+
+ /* add section: __mcount_loc */
+ mlocs = elf_create_section(lf, mc_name + (is_rela ? 1 : 0) + strlen(".rel"), _size, 0);
+ if (!mlocs)
+ goto out;
+
+ mlocs->sh.sh_link = 0;
+ mlocs->sh.sh_info = 0;
+ mlocs->sh.sh_addralign = _size;
+
+ /* 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;
+ mrels->sh.sh_flags = 0;
+ mrels->sh.sh_link = find_section_by_name(lf, ".symtab")->idx;
+ mrels->sh.sh_info = old_shnum;
+ mrels->sh.sh_addralign = _size;
+
list_for_each_entry(sec, &lf->sections, list) {
char const *txtname;

@@ -205,10 +177,8 @@ static int do_func(unsigned const reltype)
unsigned long recval = 0;
unsigned int recsym;

- symsec_sh_link = sec->sh.sh_link;
- result = find_section_sym_index(sec->sh.sh_info,
- txtname, &recval, &recsym);
- if (result)
+ if (find_section_sym_index(sec->sh.sh_info,
+ txtname, &recval, &recsym))
goto out;

mlocp = sift_rel_mcount(mlocp,
@@ -219,15 +189,27 @@ static int do_func(unsigned const reltype)
* This section is ignored by ftrace, but still
* has mcount calls. Convert them to nops now.
*/
- if (nop_mcount(sec, txtname) < 0) {
- result = -1;
+ if (nop_mcount(sec, txtname) < 0)
goto out;
- }
}
}
- if (!result && mloc0 != mlocp)
- result = append_func(mloc0, mlocp, mrel0, mrelp,
- _size, rel_entsize, symsec_sh_link);
+
+ if (mloc0 != mlocp) {
+ /* Update the section sizes */
+ 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;
+
+ mrels->sh.sh_size = (void *)mrelp - (void *)mrel0;
+ mrels->len = mrels->sh.sh_size;
+ mrels->data->d_size = mrels->len;
+ mrels->data->d_buf = mrel0;
+
+ /* overwrite the ELF file */
+ result = elf_write(lf);
+ } else
+ result = 0;
out:
free(mrel0);
free(mloc0);
--
2.20.1

2020-04-10 19:43:40

by Matt Helsley

[permalink] [raw]
Subject: [RFC][PATCH 22/36] objtool: mcount: Use objtool ELF to write

Rather than modify the pseudo-mapping of the ELF file directly,
which is the recordmcount way of operating, use the objtool
section list and generic ELF functions to modify the ELF file.

This eliminates a bunch of code -- the ulseek() and uwrite()
functions -- because it's used to patch the ELF data. Instead
we rely on objtool's ELF code to handle updating the ELF file.
This means a bunch of the odd bits in append_func() also go
away since they did things like update the ELF header, add
to the section table, and append the new section names to the
string table -- all handled by objtool's ELF code.

One unusual part, with respect to objtool is the way we handle
writing nops. Objtool is not designed to modify the an ELF
text section directly (or at least I could not find and example
to base this work on). So we break layering to access the
"data" of the text section via the section's "data buffer".
This is still cleaner -- we can now pass in the section struct
and offset as separate parameters.

Note that this patch does not move the associated parts out
of the wrapper file. We postpone that cleanup for later so that
it's easier to see the changes to the functions rather than
obscuring them with the move.

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

diff --git a/tools/objtool/recordmcount.c b/tools/objtool/recordmcount.c
index 61901b1c7bd3..65b7a34f2619 100644
--- a/tools/objtool/recordmcount.c
+++ b/tools/objtool/recordmcount.c
@@ -52,24 +52,9 @@ static struct stat sb; /* Remember .st_size, etc. */
static const char *altmcount; /* alternate mcount symbol name */
extern int warn_on_notrace_sect; /* warn when section has mcount not being recorded */
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 */

static struct elf *lf;

-/* Per-file resource cleanup when multiple files. */
-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)
@@ -82,72 +67,11 @@ static void mmap_cleanup(void)
lf = NULL;
}

-/* ulseek, uwrite, ...: Check return value for errors. */
-
-static off_t ulseek(off_t const offset, int const whence)
-{
- switch (whence) {
- case SEEK_SET:
- file_ptr = file_map + offset;
- break;
- case SEEK_CUR:
- file_ptr += offset;
- break;
- case SEEK_END:
- file_ptr = file_map + (sb.st_size - offset);
- break;
- }
- if (file_ptr < file_map) {
- fprintf(stderr, "lseek: seek before file\n");
- return -1;
- }
- return file_ptr - file_map;
-}
-
-static ssize_t uwrite(void const *const buf, size_t const count)
-{
- size_t cnt = count;
- off_t idx = 0;
-
- file_updated = 1;
-
- if (file_ptr + count >= file_end) {
- off_t aoffset = (file_ptr + count) - file_end;
-
- if (aoffset > file_append_size) {
- file_append = realloc(file_append, aoffset);
- file_append_size = aoffset;
- }
- if (!file_append) {
- perror("write");
- file_append_cleanup();
- mmap_cleanup();
- return -1;
- }
- if (file_ptr < file_end) {
- cnt = file_end - file_ptr;
- } else {
- cnt = 0;
- idx = aoffset - count;
- }
- }
-
- if (cnt)
- memcpy(file_ptr, buf, cnt);
-
- if (cnt < count)
- memcpy(file_append + idx, buf + cnt, count - cnt);
-
- file_ptr += count;
- return count;
-}
-
static void * umalloc(size_t size)
{
void *const addr = malloc(size);
if (addr == 0) {
fprintf(stderr, "malloc failed: %zu bytes\n", size);
- file_append_cleanup();
mmap_cleanup();
return NULL;
}
@@ -173,8 +97,6 @@ static void *mmap_file(char const *fname)
fd_map = -1;
mmap_failed = 1;
file_map = NULL;
- file_ptr = NULL;
- file_updated = 0;
sb.st_size = 0;

lf = elf_read(fname, O_RDWR);
@@ -210,8 +132,6 @@ static void *mmap_file(char const *fname)
out:
fd_map = -1;

- file_end = file_map + sb.st_size;
-
return file_map;
}

@@ -222,12 +142,16 @@ static unsigned char *ideal_nop;

static char rel_type_nop;

-static int (*make_nop)(void *map, size_t const offset);
+static int (*make_nop)(struct section *, size_t const offset);

-static int make_nop_x86(void *map, size_t const offset)
+static int make_nop_x86(struct section *txts, size_t const offset)
{
uint32_t *ptr;
unsigned char *op;
+ void *map = txts->data->d_buf;
+
+ if (offset < 1)
+ return -1;

/* Confirm we have 0xe8 0x0 0x0 0x0 0x0 */
ptr = map + offset;
@@ -239,10 +163,7 @@ static int make_nop_x86(void *map, size_t const offset)
return -1;

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

@@ -266,12 +187,13 @@ static unsigned char push_bl_mcount_thumb_le[6] = { 0x00, 0xb5, 0xff, 0xf7, 0xfe
static unsigned char push_bl_mcount_thumb_be[6] = { 0xb5, 0x00, 0xf7, 0xff, 0xff, 0xfe }; /* push {lr}, bl */
static unsigned char *push_bl_mcount_thumb;

-static int make_nop_arm(void *map, size_t const offset)
+static int make_nop_arm(struct section *txts, size_t const offset)
{
char *ptr;
int cnt = 1;
int nop_size;
size_t off = offset;
+ void *map = txts->data->d_buf;

ptr = map + offset;
if (memcmp(ptr, bl_mcount_arm, 4) == 0) {
@@ -290,21 +212,19 @@ static int make_nop_arm(void *map, size_t const offset)
return -1;

/* Convert to nop */
- if (ulseek(off, SEEK_SET) < 0)
- return -1;
-
do {
- if (uwrite(ideal_nop, nop_size) < 0)
- return -1;
+ memcpy(map + off, ideal_nop, nop_size);
+ off += nop_size;
} while (--cnt > 0);

return 0;
}

static unsigned char ideal_nop4_arm64[4] = {0x1f, 0x20, 0x03, 0xd5};
-static int make_nop_arm64(void *map, size_t const offset)
+static int make_nop_arm64(struct section *txts, size_t const offset)
{
uint32_t *ptr;
+ void *map = txts->data->d_buf;

ptr = map + offset;
/* bl <_mcount> is 0x94000000 before relocation */
@@ -312,52 +232,7 @@ static int make_nop_arm64(void *map, size_t const offset)
return -1;

/* Convert to nop */
- if (ulseek(offset, SEEK_SET) < 0)
- return -1;
- if (uwrite(ideal_nop, 4) < 0)
- return -1;
- return 0;
-}
-
-static int write_file(const char *fname)
-{
- char tmp_file[strlen(fname) + 4];
- size_t n;
-
- if (!file_updated)
- return 0;
-
- sprintf(tmp_file, "%s.rc", fname);
-
- /*
- * After reading the entire file into memory, delete it
- * and write it back, to prevent weird side effects of modifying
- * an object file in place.
- */
- fd_map = open(tmp_file, O_WRONLY | O_TRUNC | O_CREAT, sb.st_mode);
- if (fd_map < 0) {
- perror(fname);
- return -1;
- }
- n = write(fd_map, file_map, sb.st_size);
- if (n != sb.st_size) {
- perror("write");
- 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");
- close(fd_map);
- return -1;
- }
- }
- close(fd_map);
- if (rename(tmp_file, fname) < 0) {
- perror(fname);
- return -1;
- }
+ memcpy(map + offset, ideal_nop, 4);
return 0;
}

@@ -682,8 +557,7 @@ static int do_file(char const *const fname)
reltype = R_MIPS_32;
is_fake_mcount = MIPS_is_fake_mcount;
}
- if (do32(ehdr, reltype) < 0)
- goto out;
+ rc = do32(reltype);
break;
case ELFCLASS64: {
Elf64_Ehdr *const ghdr = (Elf64_Ehdr *)ehdr;
@@ -702,15 +576,12 @@ static int do_file(char const *const fname)
Elf64_r_info = MIPS64_r_info;
is_fake_mcount = MIPS_is_fake_mcount;
}
- if (do64(ghdr, reltype) < 0)
- goto out;
+ rc = do64(reltype);
break;
}
} /* end switch */

- rc = write_file(fname);
out:
- file_append_cleanup();
mmap_cleanup();
return rc;
}
diff --git a/tools/objtool/recordmcount.h b/tools/objtool/recordmcount.h
index 3c98c379f472..4971258a2ab7 100644
--- a/tools/objtool/recordmcount.h
+++ b/tools/objtool/recordmcount.h
@@ -24,7 +24,6 @@
#undef has_rel_mcount
#undef tot_relsize
#undef do_func
-#undef Elf_Ehdr
#undef Elf_Shdr
#undef Elf_Rel
#undef Elf_Rela
@@ -33,7 +32,6 @@
#undef fn_ELF_R_INFO
#undef uint_t
#undef _w
-#undef _align
#undef _size

#ifdef RECORD_MCOUNT_64
@@ -44,8 +42,6 @@
# define tot_relsize tot64_relsize
# define do_func do64
# define mcount_adjust mcount_adjust_64
-# define Elf_Ehdr Elf64_Ehdr
-# define Elf_Shdr Elf64_Shdr
# define Elf_Rel Elf64_Rel
# define Elf_Rela Elf64_Rela
# define ELF_R_INFO ELF64_R_INFO
@@ -53,7 +49,6 @@
# define fn_ELF_R_INFO fn_ELF64_R_INFO
# define uint_t uint64_t
# define _w w8
-# define _align 7u
# define _size 8
#else
# define append_func append32
@@ -63,8 +58,6 @@
# define tot_relsize tot32_relsize
# define do_func do32
# define mcount_adjust mcount_adjust_32
-# define Elf_Ehdr Elf32_Ehdr
-# define Elf_Shdr Elf32_Shdr
# define Elf_Rel Elf32_Rel
# define Elf_Rela Elf32_Rela
# define ELF_R_INFO ELF32_R_INFO
@@ -72,7 +65,6 @@
# define fn_ELF_R_INFO fn_ELF32_R_INFO
# define uint_t uint32_t
# define _w w
-# define _align 3u
# define _size 4
#endif

@@ -84,10 +76,8 @@ static void (*Elf_r_info)(Elf_Rel *const rp, unsigned sym, unsigned type) = fn_E

static int mcount_adjust = 0;

-/* Append the new shstrtab, Elf_Shdr[], __mcount_loc and its relocations. */
-static int append_func(Elf_Ehdr *const ehdr,
- Elf_Shdr *const shstr,
- uint_t const *const mloc0,
+/* Append the new __mcount_loc and its relocations. */
+static int append_func(uint_t const *const mloc0,
uint_t const *const mlocp,
Elf_Rel const *const mrel0,
Elf_Rel const *const mrelp,
@@ -95,83 +85,47 @@ static int append_func(Elf_Ehdr *const ehdr,
unsigned int const symsec_sh_link)
{
/* Begin constructing output file */
- Elf_Shdr mcsec;
+ struct section *sec;
char const *mc_name = (sizeof(Elf_Rela) == rel_entsize)
? ".rela__mcount_loc"
: ".rel__mcount_loc";
unsigned const old_shnum = lf->ehdr.e_shnum;
- uint_t const old_shoff = lf->ehdr.e_shoff;
- uint_t const old_shstr_sh_size = _w(shstr->sh_size);
- uint_t const old_shstr_sh_offset = _w(shstr->sh_offset);
- uint_t t = 1 + strlen(mc_name) + _w(shstr->sh_size);
- uint_t new_e_shoff;
-
- 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;
-
- /* body for new shstrtab */
- 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 */
- if (ulseek(t, SEEK_SET) < 0)
- return -1;
- t += 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);
- mcsec.sh_name = w((sizeof(Elf_Rela) == rel_entsize) + strlen(".rel")
- + old_shstr_sh_size);
- mcsec.sh_type = w(SHT_PROGBITS);
- mcsec.sh_flags = _w(SHF_ALLOC);
- mcsec.sh_addr = 0;
- mcsec.sh_offset = _w(t);
- mcsec.sh_size = _w((void *)mlocp - (void *)mloc0);
- mcsec.sh_link = 0;
- mcsec.sh_info = 0;
- mcsec.sh_addralign = _w(_size);
- mcsec.sh_entsize = _w(_size);
- if (uwrite(&mcsec, sizeof(mcsec)) < 0)
- return -1;

- mcsec.sh_name = w(old_shstr_sh_size);
- mcsec.sh_type = (sizeof(Elf_Rela) == rel_entsize)
- ? w(SHT_RELA)
- : w(SHT_REL);
- mcsec.sh_flags = 0;
- mcsec.sh_addr = 0;
- mcsec.sh_offset = _w((void *)mlocp - (void *)mloc0 + t);
- mcsec.sh_size = _w((void *)mrelp - (void *)mrel0);
- mcsec.sh_link = w(symsec_sh_link);
- mcsec.sh_info = w(old_shnum);
- mcsec.sh_addralign = _w(_size);
- mcsec.sh_entsize = _w(rel_entsize);
-
- if (uwrite(&mcsec, sizeof(mcsec)) < 0)
+ /* add section: __mcount_loc */
+ sec = elf_create_section(lf, mc_name + (sizeof(Elf_Rela) == rel_entsize) + strlen(".rel"), _size, mlocp - mloc0);
+ if (!sec)
return -1;

- if (uwrite(mloc0, (void *)mlocp - (void *)mloc0) < 0)
- return -1;
- if (uwrite(mrel0, (void *)mrelp - (void *)mrel0) < 0)
+ // created sec->sh.sh_size = (void *)mlocp - (void *)mloc0;
+ sec->sh.sh_link = 0;/* TODO objtool uses this? */
+ sec->sh.sh_info = 0;/* TODO objtool uses this? */
+ sec->sh.sh_addralign = _size;
+ // created sec->sh.sh_entsize = _size;
+
+ // assert sec->data->d_size == (void *)mlocp - (void *)mloc0
+ memcpy(sec->data->d_buf, mloc0, sec->data->d_size);
+ /* HACK link in Pre-assembled buffer ?
+ sec->data->d_buf = mloc0;
+ sec->data->d_size = sec->sh.sh_size;*/
+
+ /* add section .rel[a]__mcount_loc */
+ sec = elf_create_section(lf, mc_name, rel_entsize, mrelp - mrel0);
+ if (!sec)
return -1;
+ sec->sh.sh_type = (sizeof(Elf_Rela) == rel_entsize)
+ ? SHT_RELA
+ : SHT_REL;
+ sec->sh.sh_flags = 0;
+ sec->sh.sh_link = find_section_by_name(lf, ".symtab")->idx;
+ sec->sh.sh_info = old_shnum;
+ sec->sh.sh_addralign = _size;
+
+ // assert sec->data->d_size == (void *)mrelp - (void *)mrel0
+ memcpy(sec->data->d_buf, mrel0, sec->data->d_size);
+ /* HACK link in Pre-assembled buffer ?
+ sec->data->d_buf = mrel0;
+ sec->data->d_size = sec->sh.sh_size;*/

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

@@ -223,13 +177,10 @@ static uint_t *sift_rel_mcount(uint_t *mlocp,
* into nops.
*/
static int nop_mcount(struct section * const rels,
- Elf_Ehdr const *const ehdr,
const char *const txtname)
{
- Elf_Shdr *const shdr0 = (Elf_Shdr *)(_w(ehdr->e_shoff)
- + (void *)ehdr);
struct rela *rela;
- Elf_Shdr const *const shdr = &shdr0[rels->sh.sh_info];
+ struct section *txts = find_section_by_index(lf, rels->sh.sh_info);
unsigned mcountsym = 0;
int once = 0;

@@ -241,7 +192,7 @@ static int nop_mcount(struct section * const rels,

if (mcountsym == GELF_R_INFO(rela->sym->idx, rela->type) && !is_fake_mcount(rela)) {
if (make_nop) {
- ret = make_nop((void *)ehdr, _w(shdr->sh_offset) + rela->offset);
+ ret = make_nop(txts, rela->offset);
if (ret < 0)
return -1;
}
@@ -296,12 +247,8 @@ static unsigned tot_relsize(void)


/* Overall supervision for Elf32 ET_REL file. */
-static int do_func(Elf_Ehdr *const ehdr,
- unsigned const reltype)
+static int do_func(unsigned const reltype)
{
- Elf_Shdr *const shdr0 = (Elf_Shdr *)(_w(ehdr->e_shoff)
- + (void *)ehdr);
-
/* Upper bound on space: assume all relevant relocs are for mcount. */
unsigned totrelsz;

@@ -360,15 +307,14 @@ static int do_func(Elf_Ehdr *const ehdr,
* This section is ignored by ftrace, but still
* has mcount calls. Convert them to nops now.
*/
- if (nop_mcount(sec, ehdr, txtname) < 0) {
+ if (nop_mcount(sec, txtname) < 0) {
result = -1;
goto out;
}
}
}
if (!result && mloc0 != mlocp)
- result = append_func(ehdr, &shdr0[w2(ehdr->e_shstrndx)],
- mloc0, mlocp, mrel0, mrelp,
+ result = append_func(mloc0, mlocp, mrel0, mrelp,
rel_entsize, symsec_sh_link);
out:
free(mrel0);
--
2.20.1

2020-04-14 14:48:56

by Julien Thierry

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

Hi Matt,

On 4/10/20 8:35 PM, 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.
>
> The initial 5 patches make objtool compilable for more than x86.
> Unlike recordmcount the check command and orc tools are not currently
> checking other architectures so we need a way to cleanly build
> objtool for those architectures that don't support check / orc. I
> went with using weak symbols and added a "missing" architecture
> which can be used to indicate the tool is not implemented while
> avoiding the need for every architecture to explicitly specify
> which subcommands / features are not implemented. I'm curious if
> there are better approaches folks recommend though -- this is the
> one I landed on. The patches do not add HAVE_OBJTOOL to all
> architectures.
>

If all you need from objtool it the elf parsing code, wouldn't it make
more sense to move that out of objtool, as a utility library that both
objtool and recordmcount could use (and perhaps other tools in the future?)

In patch 3 you seem to mention that other tools already have their own
code to parse elf. So instead of converting everything as an objtool
subcommand, maybe just have the library with the required functionality.

Any opinions on the above? What do people prefer?

Cheers,

--
Julien Thierry

2020-04-14 14:55:50

by Julien Thierry

[permalink] [raw]
Subject: Re: [RFC][PATCH 03/36] objtool: Enable compilation of objtool for all architectures

Hi Matt,

On 4/10/20 8:35 PM, Matt Helsley wrote:
> objtool currently only compiles for x86 architectures. This is
> fine as it presently does not support tooling for other
> architectures. However, we would like to be able to convert other
> kernel tools to run as objtool sub commands because they too
> process ELF object files. This will allow us to convert tools
> such as recordmcount to use objtool's ELF code.
>
> Since much of recordmcount's ELF code is copy-paste code to/from
> a variety of other kernel tools (look at modpost for example) this
> means that if we can convert recordmcount we can convert more.
>
> We define a "missing" architecture which contains weak definitions
> for tools that do not exist on all architectures. In this case the
> "check" and "orc" tools do not exist on all architectures.
>
> To test building for other architectures ($arch below):
>
> cd tools/objtool/arch
> ln -s missing $arch
> make O=build-$arch ARCH=$arch tools/objtool
>
> This uses the weak, no-op definitions of the "check" and "orc"
> commands for the newly-supported architecture. Presently these
> exit with 127 to indicate that the subcommands are missing.
> Subsequent patches can then be made to determine if the weak
> definitions are used and explicitly report a missing command,
> and even to list which subcommands are supported (perhaps if
> no subcommand is specified it can list the supported subcommands).
>
> objtool is not currently wired in to KConfig to be built for other
> architectures because it's not needed for those architectures and
> there are no commands it supports other than those for x86.
>
> This commit allows us to demonstrate the pattern of adding
> architecture support and isolates moving the various files from
> adding support for more objtool subcommands.
>
> Signed-off-by: Matt Helsley <[email protected]>
> ---
> tools/objtool/Build | 4 ---
> tools/objtool/arch/missing/Build | 3 ++
> tools/objtool/arch/missing/check.c | 14 +++++++++
> tools/objtool/arch/missing/orc_dump.c | 11 +++++++
> tools/objtool/arch/missing/orc_gen.c | 16 ++++++++++
> tools/objtool/arch/x86/Build | 4 +++
> tools/objtool/{ => arch/x86}/arch.h | 42 ++++++++++++++++++++++++-
> tools/objtool/{ => arch/x86}/cfi.h | 0
> tools/objtool/{ => arch/x86}/check.c | 11 ++++---
> tools/objtool/arch/x86/decode.c | 2 +-
> tools/objtool/{ => arch/x86}/orc_dump.c | 5 +--
> tools/objtool/{ => arch/x86}/orc_gen.c | 9 ++++--
> tools/objtool/{ => arch/x86}/special.c | 4 +--
> tools/objtool/{ => arch/x86}/special.h | 2 +-
> tools/objtool/builtin-orc.c | 2 +-
> tools/objtool/check.h | 37 ----------------------
> tools/objtool/objtool.h | 2 +-
> tools/objtool/orc.h | 2 --
> 18 files changed, 110 insertions(+), 60 deletions(-)
> create mode 100644 tools/objtool/arch/missing/Build
> create mode 100644 tools/objtool/arch/missing/check.c
> create mode 100644 tools/objtool/arch/missing/orc_dump.c
> create mode 100644 tools/objtool/arch/missing/orc_gen.c
> rename tools/objtool/{ => arch/x86}/arch.h (59%)
> rename tools/objtool/{ => arch/x86}/cfi.h (100%)
> rename tools/objtool/{ => arch/x86}/check.c (99%)
> rename tools/objtool/{ => arch/x86}/orc_dump.c (98%)
> rename tools/objtool/{ => arch/x86}/orc_gen.c (96%)
> rename tools/objtool/{ => arch/x86}/special.c (98%)
> rename tools/objtool/{ => arch/x86}/special.h (95%)
>

My concern with this it that most of the structures and code in arch.h
and check.c can/should be reused across architectures. So, when
providing support for a new architecutre, the first thing that will be
needed is to move those back under tools/objtool whithout disturbing the
arches that don't yet provide support for "check" subcommand.

So, if it is decided that recordmcount should be an objtool subcommand,
the code itself should probably stay under tools/objtool and then have
different compilation configurations for objtool depending on the
architecture (e.g. HAVE_OBJTOOL_CHECK, HAVE_OBJTOOL_ORC) or something of
the sort.

Cheers,

--
Julien Thierry

2020-04-14 16:07:04

by Julien Thierry

[permalink] [raw]
Subject: Re: [RFC][PATCH 03/36] objtool: Enable compilation of objtool for all architectures



On 4/14/20 2:41 PM, Steven Rostedt wrote:
> On Tue, 14 Apr 2020 08:39:23 +0100
> Julien Thierry <[email protected]> wrote:
>
>> My concern with this it that most of the structures and code in arch.h
>> and check.c can/should be reused across architectures. So, when
>> providing support for a new architecutre, the first thing that will be
>> needed is to move those back under tools/objtool whithout disturbing the
>> arches that don't yet provide support for "check" subcommand.
>
> Are all the enums and structs in arch.h non-arch specific?

While some definitions are very x86 specific (in particular PUSH/POP
related definition), most other other things have similar concept in
other architectures.

And the "non-generic" definition here do not necessarily interfere with
other architectures. E.g. if the instruction decoder never produces
INSN_PUSH or INSN_POP, the corresponding branches in the validation code
will simply not be taken.

>
> Or would they need to be split?
>

So far, for the arm64 work, I've left all those definitions where they
are. In the future, some cleanup could encourage to split for some "arch
specific" and "non-arch specific" instruction/stack-ops types, but this
is not a hard requirement for introducing new architechtures. And I'd
rather encourage to have complex arch specific instructions be divided
into several simpler instructions (e.g. PUSH is just sub stack pointer +
memory access) that could be reused for other architectures, as long as
that is possible of course.


>>
>> So, if it is decided that recordmcount should be an objtool subcommand,
>> the code itself should probably stay under tools/objtool and then have
>> different compilation configurations for objtool depending on the
>> architecture (e.g. HAVE_OBJTOOL_CHECK, HAVE_OBJTOOL_ORC) or something of
>> the sort.
>
> That could work.
>
> -- Steve
>

--
Julien Thierry

2020-04-14 16:09:33

by Julien Thierry

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



On 4/14/20 2:35 PM, Steven Rostedt wrote:
> On Tue, 14 Apr 2020 08:24:15 +0100
> Julien Thierry <[email protected]> wrote:
>
>> If all you need from objtool it the elf parsing code, wouldn't it make
>> more sense to move that out of objtool, as a utility library that both
>> objtool and recordmcount could use (and perhaps other tools in the future?)
>>
>> In patch 3 you seem to mention that other tools already have their own
>> code to parse elf. So instead of converting everything as an objtool
>> subcommand, maybe just have the library with the required functionality.
>>
>> Any opinions on the above? What do people prefer?
>
> I think we discussed this before (and originally that was the plan), but I
> believe one of the goals for bringing recordmcount into objtool is to speed
> up the processing. Instead of having to read the elf sections for each use
> case, we do it once, and then execute all the necessary operations for that
> build.
>
> If we just have a elf parsing library, then each object file is going to
> have that read redundantly for each operation that is done on it.
>
> I was hoping to have objtool handle all the operations needed that required
> reading elf headers.
>

That makes sense, however, having each operation as an objtool
subcommand doesn't solve that issue, right? Each invocation of objtool
will re-read the elf object.

I guess having all the relevant code in objtool as subcommand would be a
first step towards that goal.

> But if that's not what objtool maintainers want, then we can certainly go
> back to looking at pulling out the elf headers, and have each tool be a
> standalone again.
>

I'm no maintainer nor know their feeling about this and I haven't been
part of the initial discussion. My main concern was about the approach
of moving existing subcommand code to arch specific folders.

Thanks for the explanations.

Cheers,

--
Julien Thierry

2020-04-15 13:40:33

by Matt Helsley

[permalink] [raw]
Subject: Re: [RFC][PATCH 03/36] objtool: Enable compilation of objtool for all architectures

On Tue, Apr 14, 2020 at 08:39:23AM +0100, Julien Thierry wrote:
> Hi Matt,
>
> On 4/10/20 8:35 PM, Matt Helsley wrote:
> > objtool currently only compiles for x86 architectures. This is
> > fine as it presently does not support tooling for other
> > architectures. However, we would like to be able to convert other
> > kernel tools to run as objtool sub commands because they too
> > process ELF object files. This will allow us to convert tools
> > such as recordmcount to use objtool's ELF code.
> >
> > Since much of recordmcount's ELF code is copy-paste code to/from
> > a variety of other kernel tools (look at modpost for example) this
> > means that if we can convert recordmcount we can convert more.
> >
> > We define a "missing" architecture which contains weak definitions
> > for tools that do not exist on all architectures. In this case the
> > "check" and "orc" tools do not exist on all architectures.
> >
> > To test building for other architectures ($arch below):
> >
> > cd tools/objtool/arch
> > ln -s missing $arch
> > make O=build-$arch ARCH=$arch tools/objtool
> >
> > This uses the weak, no-op definitions of the "check" and "orc"
> > commands for the newly-supported architecture. Presently these
> > exit with 127 to indicate that the subcommands are missing.
> > Subsequent patches can then be made to determine if the weak
> > definitions are used and explicitly report a missing command,
> > and even to list which subcommands are supported (perhaps if
> > no subcommand is specified it can list the supported subcommands).
> >
> > objtool is not currently wired in to KConfig to be built for other
> > architectures because it's not needed for those architectures and
> > there are no commands it supports other than those for x86.
> >
> > This commit allows us to demonstrate the pattern of adding
> > architecture support and isolates moving the various files from
> > adding support for more objtool subcommands.
> >
> > Signed-off-by: Matt Helsley <[email protected]>
> > ---
> > tools/objtool/Build | 4 ---
> > tools/objtool/arch/missing/Build | 3 ++
> > tools/objtool/arch/missing/check.c | 14 +++++++++
> > tools/objtool/arch/missing/orc_dump.c | 11 +++++++
> > tools/objtool/arch/missing/orc_gen.c | 16 ++++++++++
> > tools/objtool/arch/x86/Build | 4 +++
> > tools/objtool/{ => arch/x86}/arch.h | 42 ++++++++++++++++++++++++-
> > tools/objtool/{ => arch/x86}/cfi.h | 0
> > tools/objtool/{ => arch/x86}/check.c | 11 ++++---
> > tools/objtool/arch/x86/decode.c | 2 +-
> > tools/objtool/{ => arch/x86}/orc_dump.c | 5 +--
> > tools/objtool/{ => arch/x86}/orc_gen.c | 9 ++++--
> > tools/objtool/{ => arch/x86}/special.c | 4 +--
> > tools/objtool/{ => arch/x86}/special.h | 2 +-
> > tools/objtool/builtin-orc.c | 2 +-
> > tools/objtool/check.h | 37 ----------------------
> > tools/objtool/objtool.h | 2 +-
> > tools/objtool/orc.h | 2 --
> > 18 files changed, 110 insertions(+), 60 deletions(-)
> > create mode 100644 tools/objtool/arch/missing/Build
> > create mode 100644 tools/objtool/arch/missing/check.c
> > create mode 100644 tools/objtool/arch/missing/orc_dump.c
> > create mode 100644 tools/objtool/arch/missing/orc_gen.c
> > rename tools/objtool/{ => arch/x86}/arch.h (59%)
> > rename tools/objtool/{ => arch/x86}/cfi.h (100%)
> > rename tools/objtool/{ => arch/x86}/check.c (99%)
> > rename tools/objtool/{ => arch/x86}/orc_dump.c (98%)
> > rename tools/objtool/{ => arch/x86}/orc_gen.c (96%)
> > rename tools/objtool/{ => arch/x86}/special.c (98%)
> > rename tools/objtool/{ => arch/x86}/special.h (95%)
> >
>
> My concern with this it that most of the structures and code in arch.h and
> check.c can/should be reused across architectures. So, when providing
> support for a new architecutre, the first thing that will be needed is to
> move those back under tools/objtool whithout disturbing the arches that
> don't yet provide support for "check" subcommand.

Agreed. I tried to note this in my cover letter but perhaps I could have
written it better.

I still included it because I think the check.c portion of this RFC shows
what it would look like to add a hypothetical objtool subcommand implemented
for only one architecture (which "check" is, currently, an example of). I
don't think this RFC shows what should happen to check.c in particular.
You folks have been working on that here and I don't wish to disturb your
work.

>
> So, if it is decided that recordmcount should be an objtool subcommand, the
> code itself should probably stay under tools/objtool and then have different
> compilation configurations for objtool depending on the architecture (e.g.
> HAVE_OBJTOOL_CHECK, HAVE_OBJTOOL_ORC) or something of the sort.

Yeah. HAVE_C_RECORDMCOUNT is used in the Makefiles to select building
an running objtool mcount versus recordmcount.pl (which is another piece
that needs some attention -- my preference is to slowly move arch
support from there into recordmcount.c. So far it looks like s390 and mips
are the ones needing a little special attention there..)

My recollection is Josh wanted to avoid a bunch of architecture/config
checks in the code if I recall. It leaks into the code that implements the
subcommand tables, for example, and that's why I chose to use weak symbols --
we can unconditionally add the table entries and we don't need to play
linker script + macro games to build the array.

As for managing minor architectural variations in a single subcommand, either
those can use more weak symbols via arch/foo/subcmd.[ch] files or via explicit
checks in the code (see the arch, endian, and class switches in recordmcount.c
for the latter). If folks are OK with using weak symbols I'm curious what
preferences are on choosing when to use which method -- the RFC reflects
mine of course but I want to know what makes it more maintainable for
other folks.

Cheers,
-Matt Helsley

2020-04-15 13:53:33

by Peter Zijlstra

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

On Tue, Apr 14, 2020 at 05:05:20PM -0400, Steven Rostedt wrote:
> On Tue, 14 Apr 2020 22:47:29 +0200
> Peter Zijlstra <[email protected]> wrote:
>
> > On Tue, Apr 14, 2020 at 01:09:10PM -0700, Matt Helsley wrote:
> > > I also noticed that, for example, sorttable uses the same ELF code /
> > > patterns as recordmcount -- like the double-include trick. Of course
> > > it operates on a larger scale than per-object-file and so there might
> > > only be code maintenance savings there...
> >
> > I'm >< close to having objtool run on vmlinux in the link stage too :-)
>
> Do we want that? Matters how long that takes.

We do want that, however it is conditional on CONFIG_DEBUG_ENTRY and
does some rather specific validation. On a defconfig based kernel it
takes ~2.5 seconds, significantly more an an allyesconfig.

2020-04-15 14:13:42

by Steven Rostedt

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

On Tue, 14 Apr 2020 23:17:54 +0200
Peter Zijlstra <[email protected]> wrote:

> > Do we want that? Matters how long that takes.
>
> We do want that, however it is conditional on CONFIG_DEBUG_ENTRY and
> does some rather specific validation. On a defconfig based kernel it
> takes ~2.5 seconds, significantly more an an allyesconfig.

Is that timed on your laptop, or on the monster machine you normally do your
builds on?

2.5 seconds for you may be 2.5 minutes for others! ;-)

-- Steve

2020-04-15 14:21:42

by Peter Zijlstra

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

On Tue, Apr 14, 2020 at 05:47:02PM -0400, Steven Rostedt wrote:
> On Tue, 14 Apr 2020 23:17:54 +0200
> Peter Zijlstra <[email protected]> wrote:
>
> > > Do we want that? Matters how long that takes.
> >
> > We do want that, however it is conditional on CONFIG_DEBUG_ENTRY and
> > does some rather specific validation. On a defconfig based kernel it
> > takes ~2.5 seconds, significantly more an an allyesconfig.
>
> Is that timed on your laptop, or on the monster machine you normally do your
> builds on?
>
> 2.5 seconds for you may be 2.5 minutes for others! ;-)

Final link pass, and objtool, is single threaded, the ~2.5s were on an
old-ish 2.8GHz part, ie, most laptops are faster today.

The machine has a few more cores than laptops have, so total build time
is still managable, unlike laptops. Also, it being a server part, it
suffers less thermal issues.

2020-04-15 21:37:31

by Steven Rostedt

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

On Tue, 14 Apr 2020 08:24:15 +0100
Julien Thierry <[email protected]> wrote:

> If all you need from objtool it the elf parsing code, wouldn't it make
> more sense to move that out of objtool, as a utility library that both
> objtool and recordmcount could use (and perhaps other tools in the future?)
>
> In patch 3 you seem to mention that other tools already have their own
> code to parse elf. So instead of converting everything as an objtool
> subcommand, maybe just have the library with the required functionality.
>
> Any opinions on the above? What do people prefer?

I think we discussed this before (and originally that was the plan), but I
believe one of the goals for bringing recordmcount into objtool is to speed
up the processing. Instead of having to read the elf sections for each use
case, we do it once, and then execute all the necessary operations for that
build.

If we just have a elf parsing library, then each object file is going to
have that read redundantly for each operation that is done on it.

I was hoping to have objtool handle all the operations needed that required
reading elf headers.

But if that's not what objtool maintainers want, then we can certainly go
back to looking at pulling out the elf headers, and have each tool be a
standalone again.

-- Steve

2020-04-15 21:38:05

by Steven Rostedt

[permalink] [raw]
Subject: Re: [RFC][PATCH 03/36] objtool: Enable compilation of objtool for all architectures

On Tue, 14 Apr 2020 08:39:23 +0100
Julien Thierry <[email protected]> wrote:

> My concern with this it that most of the structures and code in arch.h
> and check.c can/should be reused across architectures. So, when
> providing support for a new architecutre, the first thing that will be
> needed is to move those back under tools/objtool whithout disturbing the
> arches that don't yet provide support for "check" subcommand.

Are all the enums and structs in arch.h non-arch specific?

Or would they need to be split?

>
> So, if it is decided that recordmcount should be an objtool subcommand,
> the code itself should probably stay under tools/objtool and then have
> different compilation configurations for objtool depending on the
> architecture (e.g. HAVE_OBJTOOL_CHECK, HAVE_OBJTOOL_ORC) or something of
> the sort.

That could work.

-- Steve

2020-04-15 21:44:47

by Steven Rostedt

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

On Tue, 14 Apr 2020 15:17:39 +0100
Julien Thierry <[email protected]> wrote:

> > I was hoping to have objtool handle all the operations needed that required
> > reading elf headers.
> >
>
> That makes sense, however, having each operation as an objtool
> subcommand doesn't solve that issue, right? Each invocation of objtool
> will re-read the elf object.
>
> I guess having all the relevant code in objtool as subcommand would be a
> first step towards that goal.

Exactly. I believe the goal (it's been a while since we discussed this),
was that we could "batch" the sub commands into a single command. That way,
the executable will be executed once per object file, load all the elf
headers, than iterate over all the sub commands that we set on the command
line.

-- Steve

2020-04-15 21:54:13

by Matt Helsley

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

On Tue, Apr 14, 2020 at 11:54:58AM -0400, Steven Rostedt wrote:
> On Tue, 14 Apr 2020 15:17:39 +0100
> Julien Thierry <[email protected]> wrote:
>
> > > I was hoping to have objtool handle all the operations needed that required
> > > reading elf headers.
> > >
> >
> > That makes sense, however, having each operation as an objtool
> > subcommand doesn't solve that issue, right? Each invocation of objtool
> > will re-read the elf object.
> >
> > I guess having all the relevant code in objtool as subcommand would be a
> > first step towards that goal.
>
> Exactly. I believe the goal (it's been a while since we discussed this),
> was that we could "batch" the sub commands into a single command. That way,
> the executable will be executed once per object file, load all the elf
> headers, than iterate over all the sub commands that we set on the command
> line.

Yup. The idea is it's somewhat like a pipe but instead of reloading the file
and re-creating the linked data structures each time, each sub command would
simply hand off the ELF section/symbol/relocation structures to the next tool.

If we look in scripts/Makefile.build for example we can see the rule_cc_o_c
definition, after producing the initial .o with the compiler, does:

$(call cmd,gen_ksymdeps)
$(call cmd,checkdoc)
$(call cmd,objtool)
$(call cmd,modversions_c)
$(call cmd,record_mcount)

The latter 3 all deal with loading and walking the ELF file output
from the previous step. If we could merge that into a single "call" to
objtool then we can avoid the extra write-close-open-read cycles. I also
wonder if we could move "checkdoc" because then 4 tools in a row could
be relevant to convert (genksyms makes simple use of nm).

I also noticed that, for example, sorttable uses the same ELF code /
patterns as recordmcount -- like the double-include trick. Of course
it operates on a larger scale than per-object-file and so there might
only be code maintenance savings there...

Also, the follow-on is definitely more speculative -- these patches show
that things like recordmcount can be converted to share the same ELF code
as objtool. The benefits of chaining commands together, how easy/hard
that would be, etc. haven't been fully fleshed out. For instance, I was
only looking at "check" and "mcount" chained together.

But even aside from those changes, having all of the tools use the same
ELF code and keeping that ELF code in one place rather than copy-paste
it seems like it would be useful for maintenance.

Cheers,
-Matt

2020-04-15 21:56:09

by Steven Rostedt

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

On Tue, 14 Apr 2020 22:47:29 +0200
Peter Zijlstra <[email protected]> wrote:

> On Tue, Apr 14, 2020 at 01:09:10PM -0700, Matt Helsley wrote:
> > I also noticed that, for example, sorttable uses the same ELF code /
> > patterns as recordmcount -- like the double-include trick. Of course
> > it operates on a larger scale than per-object-file and so there might
> > only be code maintenance savings there...
>
> I'm >< close to having objtool run on vmlinux in the link stage too :-)

Do we want that? Matters how long that takes. One reason I avoided running
recordmcount on vmlinux was because I didn't want to add to the build time
that much if I only needed to compile a single object.

If it's fast, then there shouldn't be anything to worry about, but if it
takes a minute on a common machine, that's one minute added to all builds,
no matter how little you had to compile.

-- Steve

2020-04-15 21:57:16

by Peter Zijlstra

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

On Tue, Apr 14, 2020 at 01:09:10PM -0700, Matt Helsley wrote:
> I also noticed that, for example, sorttable uses the same ELF code /
> patterns as recordmcount -- like the double-include trick. Of course
> it operates on a larger scale than per-object-file and so there might
> only be code maintenance savings there...

I'm >< close to having objtool run on vmlinux in the link stage too :-)

2020-04-15 22:16:20

by Julien Thierry

[permalink] [raw]
Subject: Re: [RFC][PATCH 03/36] objtool: Enable compilation of objtool for all architectures

Hi Matt,

On 4/14/20 9:56 PM, Matt Helsley wrote:
> On Tue, Apr 14, 2020 at 08:39:23AM +0100, Julien Thierry wrote:
>> So, if it is decided that recordmcount should be an objtool subcommand, the
>> code itself should probably stay under tools/objtool and then have different
>> compilation configurations for objtool depending on the architecture (e.g.
>> HAVE_OBJTOOL_CHECK, HAVE_OBJTOOL_ORC) or something of the sort.
>
> Yeah. HAVE_C_RECORDMCOUNT is used in the Makefiles to select building
> an running objtool mcount versus recordmcount.pl (which is another piece
> that needs some attention -- my preference is to slowly move arch
> support from there into recordmcount.c. So far it looks like s390 and mips
> are the ones needing a little special attention there..)
>
> My recollection is Josh wanted to avoid a bunch of architecture/config
> checks in the code if I recall. It leaks into the code that implements the
> subcommand tables, for example, and that's why I chose to use weak symbols --
> we can unconditionally add the table entries and we don't need to play
> linker script + macro games to build the array.
>
> As for managing minor architectural variations in a single subcommand, either
> those can use more weak symbols via arch/foo/subcmd.[ch] files or via explicit
> checks in the code (see the arch, endian, and class switches in recordmcount.c
> for the latter). If folks are OK with using weak symbols I'm curious what
> preferences are on choosing when to use which method -- the RFC reflects
> mine of course but I want to know what makes it more maintainable for
> other folks.
>

Thanks for providing the background reasoning.

I think that using weak symbols instead of macros to conditionally
compile is fine. However, I still think that temporarily moving code
that could be shared across architectures once the necessary back-end is
implemented is not the right way. For instance, in the case of check(),
it should be arch specific parts it relies on that should be weak
symbols (e.g. arch_decode_instruction()).

And in order to have a correct list of supported subcommands, maybe that
could be done in arch specific back end (e.g. arch_get_subcommand_set()
), which would fill the array of subcommands for the target
architecture. And you could have a default "weak" implementation that
fills the array with subcommands that do not rely on any arch specific
support.

This way we don't introduce #ifdef into the code and we don't move the
generic code.

Might not be the prettiest option, but would it be a good enough
compromise? Or are there other suggestions?

Thanks,

--
Julien Thierry