Skip to content

Commit

Permalink
dtrace: handle .init.scratch section in /proc/kallmodsyms
Browse files Browse the repository at this point in the history
The introduction of the .init.scratch section in Linux 5.2-rc6 via e1bfa87
("x86/mm: Create a workarea in the kernel for SME early encryption") led to
the consistent failure of
- test/unittest/aggs/tst.aggmod_full2.sh
- test/unittest/consumer/tst.merge_ranges_bug25767469.c
- test/unittest/consumer/tst.symbols.c
This init section, related to the kernel, appears in /proc/kall[mod]syms
after the end of kernel addresses, causing problems for DTrace's ways of
reading /proc/kallmodsyms.

Until the kernel is fixed not to write this init section to
/proc/kall[mod]syms, add fixes to DTrace userspace code wherever, including
in tests, it reads /proc/kallmodsyms.

[Orabug: 30149066]
Signed-off-by: Eugene Loh <eugene.loh@oracle.com>
Reviewed-by: Nick Alcock <nick.alcock@oracle.com>
  • Loading branch information
euloh authored and nickalcock committed Nov 25, 2020
1 parent 5185de6 commit 2c9db50
Show file tree
Hide file tree
Showing 4 changed files with 63 additions and 17 deletions.
51 changes: 36 additions & 15 deletions libdtrace/dt_module.c
Original file line number Diff line number Diff line change
Expand Up @@ -1056,6 +1056,27 @@ dt_kern_module_find_ctf(dtrace_hdl_t *dtp, dt_module_t *dmp)
}
}

/*
* We will use kernel_flag to track which symbols we are reading.
*
* /proc/kallmodsyms starts with kernel (and built-in-module) symbols.
*
* The last kernel address is expected to have the name "_end",
* but there might also be a symbol "__brk_limit" with that address.
* Set the KERNEL_FLAG_KERNEL_END flag while these addresses are read.
*
* Otherwise, symbols in /proc/kallmodsyms will normally belong to
* loadable modules. Set the KERNEL_FLAG_LOADABLE flag once these
* symbols are reached.
*
* Another odd case is the .init.scratch section introduced by e1bfa87
* ("x86/mm: Create a workarea in the kernel for SME early encryption"),
* which appears in 5.2-rc6. We ignore this section by setting the
* KERNEL_FLAG_INIT_SCRATCH flag.
*/
#define KERNEL_FLAG_KERNEL_END 1
#define KERNEL_FLAG_LOADABLE 2
#define KERNEL_FLAG_INIT_SCRATCH 4
/*
* Update our module cache. For each line in /proc/kallmodsyms, create or
* populate the dt_module_t for this module (if necessary), extend its address
Expand All @@ -1069,7 +1090,7 @@ dt_kern_module_find_ctf(dtrace_hdl_t *dtp, dt_module_t *dmp)
static int
dt_modsym_update(dtrace_hdl_t *dtp, const char *line)
{
static int kernel_flag = 1;
static uint_t kernel_flag = 0;
static dt_module_t *last_dmp = NULL;
static int last_sym_text = -1;

Expand Down Expand Up @@ -1110,23 +1131,23 @@ dt_modsym_update(dtrace_hdl_t *dtp, const char *line)
return 0;

/*
* /proc/kallmodsyms starts with kernel (and built-in-module) symbols.
* The last kernel address is expected to have the name "_end".
* (There might also be a symbol "__brk_limit" with that address.)
* Thereafter, symbols in /proc/kallmodsyms will belong to loadable
* modules.
*
* kernel_flag==+1 means normal kernel (and built-in-module) symbols
* kernel_flag==-1 means loadable-module symbols
* kernel_flag==0 is an odd in-between case for the section markers
* (they signal the imminent end of the kernel section)
* Skip over the .init.scratch section.
*/
if (strcmp(sym_name, "__init_scratch_begin") == 0) {
kernel_flag |= KERNEL_FLAG_INIT_SCRATCH;
return 0;
} else if (strcmp(sym_name, "__init_scratch_end") == 0) {
kernel_flag &= ~ KERNEL_FLAG_INIT_SCRATCH;
return 0;
} else if (kernel_flag & KERNEL_FLAG_INIT_SCRATCH) {
return 0;
}

if ((strcmp(sym_name, "_end") == 0) ||
(strcmp(sym_name, "__brk_limit") == 0))
kernel_flag = 0;
else if (kernel_flag == 0)
kernel_flag = -1;
kernel_flag |= KERNEL_FLAG_KERNEL_END;
else if (kernel_flag & KERNEL_FLAG_KERNEL_END)
kernel_flag = KERNEL_FLAG_LOADABLE;

/*
* Special case: rename the 'ctf' module to 'shared_ctf': the
Expand Down Expand Up @@ -1208,7 +1229,7 @@ dt_modsym_update(dtrace_hdl_t *dtp, const char *line)
if (sym_size == 0)
return 0;

if (kernel_flag >= 0) {
if ((kernel_flag & KERNEL_FLAG_LOADABLE) == 0) {
/*
* The kernel and built-in modules are in address order
* in /proc/kallmodsyms.
Expand Down
13 changes: 13 additions & 0 deletions test/unittest/aggs/tst.aggmod_full2.sh
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,8 @@ int main(int argc, char **argv) {
char *line = NULL;
size_t line_n = 0;
FILE *fd;
unsigned int kernel_flag = 0;
if ((fd = fopen("/proc/kallmodsyms", "r")) == NULL) return 1;
while ((getline(&line, &line_n, fd)) > 0) {
long long unsigned addr, size;
Expand All @@ -72,6 +74,17 @@ int main(int argc, char **argv) {
/* see dt_module.c dt_modsym_update() */
if (type == 'a' || type == 'A')
continue;
#define KERNEL_FLAG_INIT_SCRATCH 4
if (strcmp(symname, "__init_scratch_begin") == 0) {
kernel_flag |= KERNEL_FLAG_INIT_SCRATCH;
continue;
} else if (strcmp(symname, "__init_scratch_end") == 0) {
kernel_flag &= ~ KERNEL_FLAG_INIT_SCRATCH;
continue;
} else if (kernel_flag & KERNEL_FLAG_INIT_SCRATCH) {
continue;
}
#undef KERNEL_FLAG_INIT_SCRATCH
/* zero-size symbol might mark the end of a range */
if (size == 0)
Expand Down
2 changes: 1 addition & 1 deletion test/unittest/consumer/tst.merge_ranges_bug25767469.c
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ int nerrors = 0;
*/

void check_module_ranges
(size_t n, dtrace_addr_range_t *addrs, char *name, char type)
(size_t n, dtrace_addr_range_t *addrs, const char *name, char type)
{
int i;
/*
Expand Down
14 changes: 13 additions & 1 deletion test/unittest/consumer/tst.symbols.c
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ int read_symbols() {
size_t line_n = 0;
FILE *fd;
int n_skip = 0, n_absolute = 0;
unsigned int kernel_flag = 0;

printf("read_symbols():\n");
if ((fd = fopen("/proc/kallmodsyms", "r")) == NULL) return 1;
Expand Down Expand Up @@ -90,11 +91,22 @@ int read_symbols() {
}

/*
* Skip absolute symbols. See dt_module.c, dt_modsym_update().
* See dt_module.c, dt_modsym_update().
*/
if (symbols[nsymbols].type == 'a' ||
symbols[nsymbols].type == 'A')
continue;
#define KERNEL_FLAG_INIT_SCRATCH 4
if (strcmp(symname, "__init_scratch_begin") == 0) {
kernel_flag |= KERNEL_FLAG_INIT_SCRATCH;
continue;
} else if (strcmp(symname, "__init_scratch_end") == 0) {
kernel_flag &= ~ KERNEL_FLAG_INIT_SCRATCH;
continue;
} else if (kernel_flag & KERNEL_FLAG_INIT_SCRATCH) {
continue;
}
#undef KERNEL_FLAG_INIT_SCRATCH

/*
* In libdtrace/dt_module.c function dt_modsym_update(),
Expand Down

0 comments on commit 2c9db50

Please sign in to comment.