|
|
4eb2a4 |
commit da9bd35afc2269529b029dd22815e04362e89e5b
|
|
|
4eb2a4 |
Author: Dave Anderson <anderson@redhat.com>
|
|
|
4eb2a4 |
Date: Wed Oct 11 11:17:30 2017 -0400
|
|
|
4eb2a4 |
|
|
|
4eb2a4 |
Fix for the "runq" command on Linux 4.14 and later kernels that
|
|
|
4eb2a4 |
contain commit cd9e61ed1eebbcd5dfad59475d41ec58d9b64b6a, titled
|
|
|
4eb2a4 |
"rbtree: cache leftmost node internally". Without the patch,
|
|
|
4eb2a4 |
the command fails with the error message "runq: invalid structure
|
|
|
4eb2a4 |
member offset: cfs_rq_rb_leftmost".
|
|
|
4eb2a4 |
(anderson@redhat.com)
|
|
|
4eb2a4 |
|
|
|
4eb2a4 |
diff --git a/task.c b/task.c
|
|
|
4eb2a4 |
index 88706bf..2b12af0 100644
|
|
|
4eb2a4 |
--- a/task.c
|
|
|
4eb2a4 |
+++ b/task.c
|
|
|
4eb2a4 |
@@ -8765,10 +8765,15 @@ cfs_rq_offset_init(void)
|
|
|
4eb2a4 |
MEMBER_OFFSET_INIT(sched_rt_entity_my_q, "sched_rt_entity",
|
|
|
4eb2a4 |
"my_q");
|
|
|
4eb2a4 |
MEMBER_OFFSET_INIT(sched_entity_on_rq, "sched_entity", "on_rq");
|
|
|
4eb2a4 |
- MEMBER_OFFSET_INIT(cfs_rq_rb_leftmost, "cfs_rq", "rb_leftmost");
|
|
|
4eb2a4 |
- MEMBER_OFFSET_INIT(cfs_rq_nr_running, "cfs_rq", "nr_running");
|
|
|
4eb2a4 |
MEMBER_OFFSET_INIT(cfs_rq_tasks_timeline, "cfs_rq",
|
|
|
4eb2a4 |
"tasks_timeline");
|
|
|
4eb2a4 |
+ MEMBER_OFFSET_INIT(cfs_rq_rb_leftmost, "cfs_rq", "rb_leftmost");
|
|
|
4eb2a4 |
+ if (INVALID_MEMBER(cfs_rq_rb_leftmost) &&
|
|
|
4eb2a4 |
+ VALID_MEMBER(cfs_rq_tasks_timeline) &&
|
|
|
4eb2a4 |
+ MEMBER_EXISTS("rb_root_cached", "rb_leftmost"))
|
|
|
4eb2a4 |
+ ASSIGN_OFFSET(cfs_rq_rb_leftmost) = OFFSET(cfs_rq_tasks_timeline) +
|
|
|
4eb2a4 |
+ MEMBER_OFFSET("rb_root_cached", "rb_leftmost");
|
|
|
4eb2a4 |
+ MEMBER_OFFSET_INIT(cfs_rq_nr_running, "cfs_rq", "nr_running");
|
|
|
4eb2a4 |
MEMBER_OFFSET_INIT(cfs_rq_curr, "cfs_rq", "curr");
|
|
|
4eb2a4 |
MEMBER_OFFSET_INIT(rt_rq_active, "rt_rq", "active");
|
|
|
4eb2a4 |
MEMBER_OFFSET_INIT(task_struct_run_list, "task_struct",
|
|
|
4eb2a4 |
|
|
|
4eb2a4 |
commit 9e5255af26233e7ef051ebdd8bdccbd15d0d9256
|
|
|
4eb2a4 |
Author: Dave Anderson <anderson@redhat.com>
|
|
|
4eb2a4 |
Date: Wed Oct 11 16:11:34 2017 -0400
|
|
|
4eb2a4 |
|
|
|
4eb2a4 |
Fix to prevent a useless message during session inialization.
|
|
|
4eb2a4 |
Without the patch, if the highest possible node bit in the
|
|
|
4eb2a4 |
node_states[N_ONLINE] multi-word bitmask is set, then a message
|
|
|
4eb2a4 |
such as "crash: next_online_node: 256 is too large!" will be
|
|
|
4eb2a4 |
displayed.
|
|
|
4eb2a4 |
(anderson@redhat.com)
|
|
|
4eb2a4 |
|
|
|
4eb2a4 |
diff --git a/memory.c b/memory.c
|
|
|
4eb2a4 |
index 8efe0b2..9c9a40d 100644
|
|
|
4eb2a4 |
--- a/memory.c
|
|
|
4eb2a4 |
+++ b/memory.c
|
|
|
4eb2a4 |
@@ -17200,10 +17200,8 @@ next_online_node(int first)
|
|
|
4eb2a4 |
int i, j, node;
|
|
|
4eb2a4 |
ulong mask, *maskptr;
|
|
|
4eb2a4 |
|
|
|
4eb2a4 |
- if ((first/BITS_PER_LONG) >= vt->node_online_map_len) {
|
|
|
4eb2a4 |
- error(INFO, "next_online_node: %d is too large!\n", first);
|
|
|
4eb2a4 |
+ if ((first/BITS_PER_LONG) >= vt->node_online_map_len)
|
|
|
4eb2a4 |
return -1;
|
|
|
4eb2a4 |
- }
|
|
|
4eb2a4 |
|
|
|
4eb2a4 |
maskptr = (ulong *)vt->node_online_map;
|
|
|
4eb2a4 |
for (i = node = 0; i < vt->node_online_map_len; i++, maskptr++) {
|
|
|
4eb2a4 |
|
|
|
4eb2a4 |
commit 2b93c036edf2a5cc21a06a14f377cd9b365f858a
|
|
|
4eb2a4 |
Author: Dave Anderson <anderson@redhat.com>
|
|
|
4eb2a4 |
Date: Tue Oct 17 15:40:17 2017 -0400
|
|
|
4eb2a4 |
|
|
|
4eb2a4 |
Additional fixes for the ARM64 "bt" command for Linux 4.14 kernels.
|
|
|
4eb2a4 |
The patch corrects the contents of in-kernel exception frame register
|
|
|
4eb2a4 |
dumps, and properly transitions the backtrace from the IRQ stack
|
|
|
4eb2a4 |
to the process stack.
|
|
|
4eb2a4 |
(takahiro.akashi@linaro.org)
|
|
|
4eb2a4 |
|
|
|
4eb2a4 |
diff --git a/arm64.c b/arm64.c
|
|
|
4eb2a4 |
index 20c5d34..c75669b 100644
|
|
|
4eb2a4 |
--- a/arm64.c
|
|
|
4eb2a4 |
+++ b/arm64.c
|
|
|
4eb2a4 |
@@ -72,6 +72,7 @@ static void arm64_cmd_mach(void);
|
|
|
4eb2a4 |
static void arm64_display_machine_stats(void);
|
|
|
4eb2a4 |
static int arm64_get_smp_cpus(void);
|
|
|
4eb2a4 |
static void arm64_clear_machdep_cache(void);
|
|
|
4eb2a4 |
+static int arm64_on_process_stack(struct bt_info *, ulong);
|
|
|
4eb2a4 |
static int arm64_in_alternate_stack(int, ulong);
|
|
|
4eb2a4 |
static int arm64_on_irq_stack(int, ulong);
|
|
|
4eb2a4 |
static void arm64_set_irq_stack(struct bt_info *);
|
|
|
4eb2a4 |
@@ -1333,34 +1334,64 @@ arm64_irq_stack_init(void)
|
|
|
4eb2a4 |
int i;
|
|
|
4eb2a4 |
struct syment *sp;
|
|
|
4eb2a4 |
struct gnu_request request, *req;
|
|
|
4eb2a4 |
- req = &request;
|
|
|
4eb2a4 |
struct machine_specific *ms = machdep->machspec;
|
|
|
4eb2a4 |
+ ulong p;
|
|
|
4eb2a4 |
+ req = &request;
|
|
|
4eb2a4 |
|
|
|
4eb2a4 |
- if (!symbol_exists("irq_stack") ||
|
|
|
4eb2a4 |
- !(sp = per_cpu_symbol_search("irq_stack")) ||
|
|
|
4eb2a4 |
- !get_symbol_type("irq_stack", NULL, req) ||
|
|
|
4eb2a4 |
- (req->typecode != TYPE_CODE_ARRAY) ||
|
|
|
4eb2a4 |
- (req->target_typecode != TYPE_CODE_INT))
|
|
|
4eb2a4 |
- return;
|
|
|
4eb2a4 |
-
|
|
|
4eb2a4 |
- if (CRASHDEBUG(1)) {
|
|
|
4eb2a4 |
- fprintf(fp, "irq_stack: \n");
|
|
|
4eb2a4 |
- fprintf(fp, " type: %s\n",
|
|
|
4eb2a4 |
- (req->typecode == TYPE_CODE_ARRAY) ? "TYPE_CODE_ARRAY" : "other");
|
|
|
4eb2a4 |
- fprintf(fp, " target_typecode: %s\n",
|
|
|
4eb2a4 |
- req->target_typecode == TYPE_CODE_INT ? "TYPE_CODE_INT" : "other");
|
|
|
4eb2a4 |
- fprintf(fp, " target_length: %ld\n", req->target_length);
|
|
|
4eb2a4 |
- fprintf(fp, " length: %ld\n", req->length);
|
|
|
4eb2a4 |
- }
|
|
|
4eb2a4 |
-
|
|
|
4eb2a4 |
- ms->irq_stack_size = req->length;
|
|
|
4eb2a4 |
- if (!(ms->irq_stacks = (ulong *)malloc((size_t)(kt->cpus * sizeof(ulong)))))
|
|
|
4eb2a4 |
- error(FATAL, "cannot malloc irq_stack addresses\n");
|
|
|
4eb2a4 |
+ if (symbol_exists("irq_stack") &&
|
|
|
4eb2a4 |
+ (sp = per_cpu_symbol_search("irq_stack")) &&
|
|
|
4eb2a4 |
+ get_symbol_type("irq_stack", NULL, req)) {
|
|
|
4eb2a4 |
+ /* before v4.14 or CONFIG_VMAP_STACK disabled */
|
|
|
4eb2a4 |
+ if (CRASHDEBUG(1)) {
|
|
|
4eb2a4 |
+ fprintf(fp, "irq_stack: \n");
|
|
|
4eb2a4 |
+ fprintf(fp, " type: %s\n",
|
|
|
4eb2a4 |
+ (req->typecode == TYPE_CODE_ARRAY) ?
|
|
|
4eb2a4 |
+ "TYPE_CODE_ARRAY" : "other");
|
|
|
4eb2a4 |
+ fprintf(fp, " target_typecode: %s\n",
|
|
|
4eb2a4 |
+ req->target_typecode == TYPE_CODE_INT ?
|
|
|
4eb2a4 |
+ "TYPE_CODE_INT" : "other");
|
|
|
4eb2a4 |
+ fprintf(fp, " target_length: %ld\n",
|
|
|
4eb2a4 |
+ req->target_length);
|
|
|
4eb2a4 |
+ fprintf(fp, " length: %ld\n", req->length);
|
|
|
4eb2a4 |
+ }
|
|
|
4eb2a4 |
+
|
|
|
4eb2a4 |
+ if (!(ms->irq_stacks = (ulong *)malloc((size_t)(kt->cpus * sizeof(ulong)))))
|
|
|
4eb2a4 |
+ error(FATAL, "cannot malloc irq_stack addresses\n");
|
|
|
4eb2a4 |
+ ms->irq_stack_size = req->length;
|
|
|
4eb2a4 |
+ machdep->flags |= IRQ_STACKS;
|
|
|
4eb2a4 |
|
|
|
4eb2a4 |
- for (i = 0; i < kt->cpus; i++)
|
|
|
4eb2a4 |
- ms->irq_stacks[i] = kt->__per_cpu_offset[i] + sp->value;
|
|
|
4eb2a4 |
+ for (i = 0; i < kt->cpus; i++)
|
|
|
4eb2a4 |
+ ms->irq_stacks[i] = kt->__per_cpu_offset[i] + sp->value;
|
|
|
4eb2a4 |
+ } else if (symbol_exists("irq_stack_ptr") &&
|
|
|
4eb2a4 |
+ (sp = per_cpu_symbol_search("irq_stack_ptr")) &&
|
|
|
4eb2a4 |
+ get_symbol_type("irq_stack_ptr", NULL, req)) {
|
|
|
4eb2a4 |
+ /* v4.14 and later with CONFIG_VMAP_STACK enabled */
|
|
|
4eb2a4 |
+ if (CRASHDEBUG(1)) {
|
|
|
4eb2a4 |
+ fprintf(fp, "irq_stack_ptr: \n");
|
|
|
4eb2a4 |
+ fprintf(fp, " type: %x, %s\n",
|
|
|
4eb2a4 |
+ (int)req->typecode,
|
|
|
4eb2a4 |
+ (req->typecode == TYPE_CODE_PTR) ?
|
|
|
4eb2a4 |
+ "TYPE_CODE_PTR" : "other");
|
|
|
4eb2a4 |
+ fprintf(fp, " target_typecode: %x, %s\n",
|
|
|
4eb2a4 |
+ (int)req->target_typecode,
|
|
|
4eb2a4 |
+ req->target_typecode == TYPE_CODE_INT ?
|
|
|
4eb2a4 |
+ "TYPE_CODE_INT" : "other");
|
|
|
4eb2a4 |
+ fprintf(fp, " target_length: %ld\n",
|
|
|
4eb2a4 |
+ req->target_length);
|
|
|
4eb2a4 |
+ fprintf(fp, " length: %ld\n", req->length);
|
|
|
4eb2a4 |
+ }
|
|
|
4eb2a4 |
+
|
|
|
4eb2a4 |
+ if (!(ms->irq_stacks = (ulong *)malloc((size_t)(kt->cpus * sizeof(ulong)))))
|
|
|
4eb2a4 |
+ error(FATAL, "cannot malloc irq_stack addresses\n");
|
|
|
4eb2a4 |
+ ms->irq_stack_size = 16384;
|
|
|
4eb2a4 |
+ machdep->flags |= IRQ_STACKS;
|
|
|
4eb2a4 |
|
|
|
4eb2a4 |
- machdep->flags |= IRQ_STACKS;
|
|
|
4eb2a4 |
+ for (i = 0; i < kt->cpus; i++) {
|
|
|
4eb2a4 |
+ p = kt->__per_cpu_offset[i] + sp->value;
|
|
|
4eb2a4 |
+ readmem(p, KVADDR, &(ms->irq_stacks[i]), sizeof(ulong),
|
|
|
4eb2a4 |
+ "IRQ stack pointer", RETURN_ON_ERROR);
|
|
|
4eb2a4 |
+ }
|
|
|
4eb2a4 |
+ }
|
|
|
4eb2a4 |
}
|
|
|
4eb2a4 |
|
|
|
4eb2a4 |
/*
|
|
|
4eb2a4 |
@@ -1750,11 +1781,20 @@ arm64_display_full_frame(struct bt_info *bt, ulong sp)
|
|
|
4eb2a4 |
if (bt->frameptr == sp)
|
|
|
4eb2a4 |
return;
|
|
|
4eb2a4 |
|
|
|
4eb2a4 |
- if (!INSTACK(sp, bt) || !INSTACK(bt->frameptr, bt)) {
|
|
|
4eb2a4 |
- if (sp == 0)
|
|
|
4eb2a4 |
- sp = bt->stacktop - USER_EFRAME_OFFSET;
|
|
|
4eb2a4 |
- else
|
|
|
4eb2a4 |
- return;
|
|
|
4eb2a4 |
+ if (INSTACK(bt->frameptr, bt)) {
|
|
|
4eb2a4 |
+ if (INSTACK(sp, bt)) {
|
|
|
4eb2a4 |
+ ; /* normal case */
|
|
|
4eb2a4 |
+ } else {
|
|
|
4eb2a4 |
+ if (sp == 0)
|
|
|
4eb2a4 |
+ /* interrupt in user mode */
|
|
|
4eb2a4 |
+ sp = bt->stacktop - USER_EFRAME_OFFSET;
|
|
|
4eb2a4 |
+ else
|
|
|
4eb2a4 |
+ /* interrupt in kernel mode */
|
|
|
4eb2a4 |
+ sp = bt->stacktop;
|
|
|
4eb2a4 |
+ }
|
|
|
4eb2a4 |
+ } else {
|
|
|
4eb2a4 |
+ /* IRQ exception frame */
|
|
|
4eb2a4 |
+ return;
|
|
|
4eb2a4 |
}
|
|
|
4eb2a4 |
|
|
|
4eb2a4 |
words = (sp - bt->frameptr) / sizeof(ulong);
|
|
|
4eb2a4 |
@@ -1860,6 +1900,9 @@ arm64_unwind_frame(struct bt_info *bt, struct arm64_stackframe *frame)
|
|
|
4eb2a4 |
if ((frame->fp == 0) && (frame->pc == 0))
|
|
|
4eb2a4 |
return FALSE;
|
|
|
4eb2a4 |
|
|
|
4eb2a4 |
+ if (!(machdep->flags & IRQ_STACKS))
|
|
|
4eb2a4 |
+ return TRUE;
|
|
|
4eb2a4 |
+
|
|
|
4eb2a4 |
/*
|
|
|
4eb2a4 |
* The kernel's manner of determining the end of the IRQ stack:
|
|
|
4eb2a4 |
*
|
|
|
4eb2a4 |
@@ -1872,7 +1915,25 @@ arm64_unwind_frame(struct bt_info *bt, struct arm64_stackframe *frame)
|
|
|
4eb2a4 |
* irq_stack_ptr = IRQ_STACK_PTR(raw_smp_processor_id());
|
|
|
4eb2a4 |
* orig_sp = IRQ_STACK_TO_TASK_STACK(irq_stack_ptr); (pt_regs pointer on process stack)
|
|
|
4eb2a4 |
*/
|
|
|
4eb2a4 |
- if (machdep->flags & IRQ_STACKS) {
|
|
|
4eb2a4 |
+ if (machdep->flags & UNW_4_14) {
|
|
|
4eb2a4 |
+ if ((bt->flags & BT_IRQSTACK) &&
|
|
|
4eb2a4 |
+ !arm64_on_irq_stack(bt->tc->processor, frame->fp)) {
|
|
|
4eb2a4 |
+ if (arm64_on_process_stack(bt, frame->fp)) {
|
|
|
4eb2a4 |
+ arm64_set_process_stack(bt);
|
|
|
4eb2a4 |
+
|
|
|
4eb2a4 |
+ frame->sp = frame->fp - SIZE(pt_regs) + 16;
|
|
|
4eb2a4 |
+ /* for switch_stack */
|
|
|
4eb2a4 |
+ /* fp still points to irq stack */
|
|
|
4eb2a4 |
+ bt->bptr = fp;
|
|
|
4eb2a4 |
+ /* for display_full_frame */
|
|
|
4eb2a4 |
+ /* sp points to process stack */
|
|
|
4eb2a4 |
+ bt->frameptr = frame->sp;
|
|
|
4eb2a4 |
+ } else {
|
|
|
4eb2a4 |
+ /* irq -> user */
|
|
|
4eb2a4 |
+ return FALSE;
|
|
|
4eb2a4 |
+ }
|
|
|
4eb2a4 |
+ }
|
|
|
4eb2a4 |
+ } else { /* !UNW_4_14 */
|
|
|
4eb2a4 |
ms = machdep->machspec;
|
|
|
4eb2a4 |
irq_stack_ptr = ms->irq_stacks[bt->tc->processor] + ms->irq_stack_size - 16;
|
|
|
4eb2a4 |
|
|
|
4eb2a4 |
@@ -1896,7 +1957,7 @@ arm64_unwind_frame(struct bt_info *bt, struct arm64_stackframe *frame)
|
|
|
4eb2a4 |
return FALSE;
|
|
|
4eb2a4 |
}
|
|
|
4eb2a4 |
}
|
|
|
4eb2a4 |
- }
|
|
|
4eb2a4 |
+ } /* UNW_4_14 */
|
|
|
4eb2a4 |
|
|
|
4eb2a4 |
return TRUE;
|
|
|
4eb2a4 |
}
|
|
|
4eb2a4 |
@@ -2086,10 +2147,17 @@ arm64_unwind_frame_v2(struct bt_info *bt, struct arm64_stackframe *frame,
|
|
|
4eb2a4 |
* We are on process stack. Just add a faked frame
|
|
|
4eb2a4 |
*/
|
|
|
4eb2a4 |
|
|
|
4eb2a4 |
- if (!arm64_on_irq_stack(bt->tc->processor, ext_frame.fp))
|
|
|
4eb2a4 |
- frame->sp = ext_frame.fp
|
|
|
4eb2a4 |
- - sizeof(struct arm64_pt_regs);
|
|
|
4eb2a4 |
- else {
|
|
|
4eb2a4 |
+ if (!arm64_on_irq_stack(bt->tc->processor, ext_frame.fp)) {
|
|
|
4eb2a4 |
+ if (MEMBER_EXISTS("pt_regs", "stackframe")) {
|
|
|
4eb2a4 |
+ frame->sp = ext_frame.fp
|
|
|
4eb2a4 |
+ - sizeof(struct arm64_pt_regs) - 16;
|
|
|
4eb2a4 |
+ frame->fp = ext_frame.fp;
|
|
|
4eb2a4 |
+ } else {
|
|
|
4eb2a4 |
+ frame->sp = ext_frame.fp
|
|
|
4eb2a4 |
+ - sizeof(struct arm64_pt_regs);
|
|
|
4eb2a4 |
+ frame->fp = frame->sp;
|
|
|
4eb2a4 |
+ }
|
|
|
4eb2a4 |
+ } else {
|
|
|
4eb2a4 |
/*
|
|
|
4eb2a4 |
* FIXME: very exceptional case
|
|
|
4eb2a4 |
* We are already back on process stack, but
|
|
|
4eb2a4 |
@@ -2109,10 +2177,10 @@ arm64_unwind_frame_v2(struct bt_info *bt, struct arm64_stackframe *frame,
|
|
|
4eb2a4 |
* Really ugly
|
|
|
4eb2a4 |
*/
|
|
|
4eb2a4 |
frame->sp = frame->fp + 0x20;
|
|
|
4eb2a4 |
+ frame->fp = frame->sp;
|
|
|
4eb2a4 |
fprintf(ofp, " (Next exception frame might be wrong)\n");
|
|
|
4eb2a4 |
}
|
|
|
4eb2a4 |
|
|
|
4eb2a4 |
- frame->fp = frame->sp;
|
|
|
4eb2a4 |
} else {
|
|
|
4eb2a4 |
/* We are on IRQ stack */
|
|
|
4eb2a4 |
|
|
|
4eb2a4 |
@@ -2122,9 +2190,15 @@ arm64_unwind_frame_v2(struct bt_info *bt, struct arm64_stackframe *frame,
|
|
|
4eb2a4 |
if (ext_frame.fp != irq_stack_ptr) {
|
|
|
4eb2a4 |
/* (2) Just add a faked frame */
|
|
|
4eb2a4 |
|
|
|
4eb2a4 |
- frame->sp = ext_frame.fp
|
|
|
4eb2a4 |
- - sizeof(struct arm64_pt_regs);
|
|
|
4eb2a4 |
- frame->fp = frame->sp;
|
|
|
4eb2a4 |
+ if (MEMBER_EXISTS("pt_regs", "stackframe")) {
|
|
|
4eb2a4 |
+ frame->sp = ext_frame.fp
|
|
|
4eb2a4 |
+ - sizeof(struct arm64_pt_regs);
|
|
|
4eb2a4 |
+ frame->fp = ext_frame.fp;
|
|
|
4eb2a4 |
+ } else {
|
|
|
4eb2a4 |
+ frame->sp = ext_frame.fp
|
|
|
4eb2a4 |
+ - sizeof(struct arm64_pt_regs) - 16;
|
|
|
4eb2a4 |
+ frame->fp = frame->sp;
|
|
|
4eb2a4 |
+ }
|
|
|
4eb2a4 |
} else {
|
|
|
4eb2a4 |
/*
|
|
|
4eb2a4 |
* (3)
|
|
|
4eb2a4 |
@@ -2303,12 +2377,17 @@ arm64_back_trace_cmd(struct bt_info *bt)
|
|
|
4eb2a4 |
|
|
|
4eb2a4 |
if (arm64_in_exception_text(bt->instptr) && INSTACK(stackframe.fp, bt)) {
|
|
|
4eb2a4 |
if (!(bt->flags & BT_IRQSTACK) ||
|
|
|
4eb2a4 |
- (((stackframe.sp + SIZE(pt_regs)) < bt->stacktop)))
|
|
|
4eb2a4 |
- exception_frame = stackframe.fp - SIZE(pt_regs);
|
|
|
4eb2a4 |
+ (((stackframe.sp + SIZE(pt_regs)) < bt->stacktop))) {
|
|
|
4eb2a4 |
+ if (MEMBER_EXISTS("pt_regs", "stackframe"))
|
|
|
4eb2a4 |
+ /* v4.14 or later */
|
|
|
4eb2a4 |
+ exception_frame = stackframe.fp - SIZE(pt_regs) + 16;
|
|
|
4eb2a4 |
+ else
|
|
|
4eb2a4 |
+ exception_frame = stackframe.fp - SIZE(pt_regs);
|
|
|
4eb2a4 |
+ }
|
|
|
4eb2a4 |
}
|
|
|
4eb2a4 |
|
|
|
4eb2a4 |
if ((bt->flags & BT_IRQSTACK) &&
|
|
|
4eb2a4 |
- !arm64_on_irq_stack(bt->tc->processor, stackframe.sp)) {
|
|
|
4eb2a4 |
+ !arm64_on_irq_stack(bt->tc->processor, stackframe.fp)) {
|
|
|
4eb2a4 |
bt->flags &= ~BT_IRQSTACK;
|
|
|
4eb2a4 |
if (arm64_switch_stack(bt, &stackframe, ofp) == USER_MODE)
|
|
|
4eb2a4 |
break;
|
|
|
4eb2a4 |
@@ -2424,6 +2503,8 @@ user_space:
|
|
|
4eb2a4 |
* otherwise show an exception frame.
|
|
|
4eb2a4 |
* Since exception entry code doesn't have a real
|
|
|
4eb2a4 |
* stackframe, we fake a dummy frame here.
|
|
|
4eb2a4 |
+ * Note: Since we have a real stack frame in pt_regs,
|
|
|
4eb2a4 |
+ * We no longer need a dummy frame on v4.14 or later.
|
|
|
4eb2a4 |
*/
|
|
|
4eb2a4 |
if (!arm64_in_exp_entry(stackframe.pc))
|
|
|
4eb2a4 |
continue;
|
|
|
4eb2a4 |
@@ -2669,7 +2750,9 @@ arm64_switch_stack(struct bt_info *bt, struct arm64_stackframe *frame, FILE *ofp
|
|
|
4eb2a4 |
if (frame->fp == 0)
|
|
|
4eb2a4 |
return USER_MODE;
|
|
|
4eb2a4 |
|
|
|
4eb2a4 |
- arm64_print_exception_frame(bt, frame->sp, KERNEL_MODE, ofp);
|
|
|
4eb2a4 |
+ if (!(machdep->flags & UNW_4_14))
|
|
|
4eb2a4 |
+ arm64_print_exception_frame(bt, frame->sp, KERNEL_MODE, ofp);
|
|
|
4eb2a4 |
+
|
|
|
4eb2a4 |
return KERNEL_MODE;
|
|
|
4eb2a4 |
}
|
|
|
4eb2a4 |
|
|
|
4eb2a4 |
@@ -3363,6 +3446,20 @@ arm64_clear_machdep_cache(void) {
|
|
|
4eb2a4 |
}
|
|
|
4eb2a4 |
|
|
|
4eb2a4 |
static int
|
|
|
4eb2a4 |
+arm64_on_process_stack(struct bt_info *bt, ulong stkptr)
|
|
|
4eb2a4 |
+{
|
|
|
4eb2a4 |
+ ulong stackbase, stacktop;
|
|
|
4eb2a4 |
+
|
|
|
4eb2a4 |
+ stackbase = GET_STACKBASE(bt->task);
|
|
|
4eb2a4 |
+ stacktop = GET_STACKTOP(bt->task);
|
|
|
4eb2a4 |
+
|
|
|
4eb2a4 |
+ if ((stkptr >= stackbase) && (stkptr < stacktop))
|
|
|
4eb2a4 |
+ return TRUE;
|
|
|
4eb2a4 |
+
|
|
|
4eb2a4 |
+ return FALSE;
|
|
|
4eb2a4 |
+}
|
|
|
4eb2a4 |
+
|
|
|
4eb2a4 |
+static int
|
|
|
4eb2a4 |
arm64_on_irq_stack(int cpu, ulong stkptr)
|
|
|
4eb2a4 |
{
|
|
|
4eb2a4 |
return arm64_in_alternate_stack(cpu, stkptr);
|
|
|
4eb2a4 |
|
|
|
4eb2a4 |
commit 30950ba8885fb39a1ed7b071cdb225e3ec38e7b3
|
|
|
4eb2a4 |
Author: Dave Anderson <anderson@redhat.com>
|
|
|
4eb2a4 |
Date: Tue Oct 17 16:20:19 2017 -0400
|
|
|
4eb2a4 |
|
|
|
4eb2a4 |
Implemented a new "search -T" option, which is identical to the
|
|
|
4eb2a4 |
"search -t" option, except that the search is restricted to the
|
|
|
4eb2a4 |
kernel stacks of active tasks.
|
|
|
4eb2a4 |
(atomlin@redhat.com)
|
|
|
4eb2a4 |
|
|
|
4eb2a4 |
diff --git a/help.c b/help.c
|
|
|
4eb2a4 |
index 2d80202..a9aab37 100644
|
|
|
4eb2a4 |
--- a/help.c
|
|
|
4eb2a4 |
+++ b/help.c
|
|
|
4eb2a4 |
@@ -2862,7 +2862,7 @@ NULL
|
|
|
4eb2a4 |
char *help_search[] = {
|
|
|
4eb2a4 |
"search",
|
|
|
4eb2a4 |
"search memory",
|
|
|
4eb2a4 |
-"[-s start] [ -[kKV] | -u | -p | -t ] [-e end | -l length] [-m mask]\n"
|
|
|
4eb2a4 |
+"[-s start] [ -[kKV] | -u | -p | -t | -T ] [-e end | -l length] [-m mask]\n"
|
|
|
4eb2a4 |
" [-x count] -[cwh] [value | (expression) | symbol | string] ...",
|
|
|
4eb2a4 |
" This command searches for a given value within a range of user virtual, kernel",
|
|
|
4eb2a4 |
" virtual, or physical memory space. If no end nor length value is entered, ",
|
|
|
4eb2a4 |
@@ -2893,6 +2893,7 @@ char *help_search[] = {
|
|
|
4eb2a4 |
" -t Search only the kernel stack pages of every task. If one or more",
|
|
|
4eb2a4 |
" matches are found in a task's kernel stack, precede the output",
|
|
|
4eb2a4 |
" with a task-identifying header.",
|
|
|
4eb2a4 |
+" -T Same as -t, except only the active task(s) are considered.",
|
|
|
4eb2a4 |
" -e end Stop the search at this hexadecimal user or kernel virtual",
|
|
|
4eb2a4 |
" address, kernel symbol, or physical address. The end address",
|
|
|
4eb2a4 |
" must be appropriate for the memory type specified.",
|
|
|
4eb2a4 |
diff --git a/memory.c b/memory.c
|
|
|
4eb2a4 |
index 9c9a40d..fb534e8 100644
|
|
|
4eb2a4 |
--- a/memory.c
|
|
|
4eb2a4 |
+++ b/memory.c
|
|
|
4eb2a4 |
@@ -13882,7 +13882,7 @@ cmd_search(void)
|
|
|
4eb2a4 |
ulong value, mask, len;
|
|
|
4eb2a4 |
ulong uvaddr_start, uvaddr_end;
|
|
|
4eb2a4 |
ulong kvaddr_start, kvaddr_end, range_end;
|
|
|
4eb2a4 |
- int sflag, Kflag, Vflag, pflag, tflag;
|
|
|
4eb2a4 |
+ int sflag, Kflag, Vflag, pflag, Tflag, tflag;
|
|
|
4eb2a4 |
struct searchinfo searchinfo;
|
|
|
4eb2a4 |
struct syment *sp;
|
|
|
4eb2a4 |
struct node_table *nt;
|
|
|
4eb2a4 |
@@ -13896,7 +13896,7 @@ cmd_search(void)
|
|
|
4eb2a4 |
|
|
|
4eb2a4 |
context = max = 0;
|
|
|
4eb2a4 |
start = end = 0;
|
|
|
4eb2a4 |
- value = mask = sflag = pflag = Kflag = Vflag = memtype = len = tflag = 0;
|
|
|
4eb2a4 |
+ value = mask = sflag = pflag = Kflag = Vflag = memtype = len = Tflag = tflag = 0;
|
|
|
4eb2a4 |
kvaddr_start = kvaddr_end = 0;
|
|
|
4eb2a4 |
uvaddr_start = UNINITIALIZED;
|
|
|
4eb2a4 |
uvaddr_end = COMMON_VADDR_SPACE() ? (ulong)(-1) : machdep->kvbase;
|
|
|
4eb2a4 |
@@ -13933,7 +13933,7 @@ cmd_search(void)
|
|
|
4eb2a4 |
|
|
|
4eb2a4 |
searchinfo.mode = SEARCH_ULONG; /* default search */
|
|
|
4eb2a4 |
|
|
|
4eb2a4 |
- while ((c = getopt(argcnt, args, "tl:ukKVps:e:v:m:hwcx:")) != EOF) {
|
|
|
4eb2a4 |
+ while ((c = getopt(argcnt, args, "Ttl:ukKVps:e:v:m:hwcx:")) != EOF) {
|
|
|
4eb2a4 |
switch(c)
|
|
|
4eb2a4 |
{
|
|
|
4eb2a4 |
case 'u':
|
|
|
4eb2a4 |
@@ -14038,12 +14038,19 @@ cmd_search(void)
|
|
|
4eb2a4 |
context = dtoi(optarg, FAULT_ON_ERROR, NULL);
|
|
|
4eb2a4 |
break;
|
|
|
4eb2a4 |
|
|
|
4eb2a4 |
+ case 'T':
|
|
|
4eb2a4 |
case 't':
|
|
|
4eb2a4 |
if (XEN_HYPER_MODE())
|
|
|
4eb2a4 |
error(FATAL,
|
|
|
4eb2a4 |
- "-t option is not applicable to the "
|
|
|
4eb2a4 |
- "Xen hypervisor\n");
|
|
|
4eb2a4 |
- tflag++;
|
|
|
4eb2a4 |
+ "-%c option is not applicable to the "
|
|
|
4eb2a4 |
+ "Xen hypervisor\n", c);
|
|
|
4eb2a4 |
+ if (c == 'T')
|
|
|
4eb2a4 |
+ Tflag++;
|
|
|
4eb2a4 |
+ else if (c == 't')
|
|
|
4eb2a4 |
+ tflag++;
|
|
|
4eb2a4 |
+ if (tflag && Tflag)
|
|
|
4eb2a4 |
+ error(FATAL,
|
|
|
4eb2a4 |
+ "-t and -T options are mutually exclusive\n");
|
|
|
4eb2a4 |
break;
|
|
|
4eb2a4 |
|
|
|
4eb2a4 |
default:
|
|
|
4eb2a4 |
@@ -14052,10 +14059,11 @@ cmd_search(void)
|
|
|
4eb2a4 |
}
|
|
|
4eb2a4 |
}
|
|
|
4eb2a4 |
|
|
|
4eb2a4 |
- if (tflag && (memtype || start || end || len))
|
|
|
4eb2a4 |
+ if ((tflag || Tflag) && (memtype || start || end || len))
|
|
|
4eb2a4 |
error(FATAL,
|
|
|
4eb2a4 |
- "-t option cannot be used with other "
|
|
|
4eb2a4 |
- "memory-selection options\n");
|
|
|
4eb2a4 |
+ "-%c option cannot be used with other "
|
|
|
4eb2a4 |
+ "memory-selection options\n",
|
|
|
4eb2a4 |
+ tflag ? 't' : 'T');
|
|
|
4eb2a4 |
|
|
|
4eb2a4 |
if (XEN_HYPER_MODE()) {
|
|
|
4eb2a4 |
memtype = KVADDR;
|
|
|
4eb2a4 |
@@ -14328,10 +14336,12 @@ cmd_search(void)
|
|
|
4eb2a4 |
break;
|
|
|
4eb2a4 |
}
|
|
|
4eb2a4 |
|
|
|
4eb2a4 |
- if (tflag) {
|
|
|
4eb2a4 |
+ if (tflag || Tflag) {
|
|
|
4eb2a4 |
searchinfo.tasks_found = 0;
|
|
|
4eb2a4 |
tc = FIRST_CONTEXT();
|
|
|
4eb2a4 |
for (i = 0; i < RUNNING_TASKS(); i++, tc++) {
|
|
|
4eb2a4 |
+ if (Tflag && !is_task_active(tc->task))
|
|
|
4eb2a4 |
+ continue;
|
|
|
4eb2a4 |
searchinfo.vaddr_start = GET_STACKBASE(tc->task);
|
|
|
4eb2a4 |
searchinfo.vaddr_end = GET_STACKTOP(tc->task);
|
|
|
4eb2a4 |
searchinfo.task_context = tc;
|
|
|
4eb2a4 |
|
|
|
4eb2a4 |
commit 090bf28907782549ba980c588979372061764aa7
|
|
|
4eb2a4 |
Author: Dave Anderson <anderson@redhat.com>
|
|
|
4eb2a4 |
Date: Fri Oct 20 14:23:36 2017 -0400
|
|
|
4eb2a4 |
|
|
|
4eb2a4 |
Removal of the ARM64 "bt -o" option for Linux 4.14 and later kernels,
|
|
|
4eb2a4 |
along with several cleanups/readability improvements.
|
|
|
4eb2a4 |
(takahiro.akashi@linaro.org)
|
|
|
4eb2a4 |
|
|
|
4eb2a4 |
diff --git a/arm64.c b/arm64.c
|
|
|
4eb2a4 |
index c75669b..7904f65 100644
|
|
|
4eb2a4 |
--- a/arm64.c
|
|
|
4eb2a4 |
+++ b/arm64.c
|
|
|
4eb2a4 |
@@ -612,6 +612,7 @@ arm64_dump_machdep_table(ulong arg)
|
|
|
4eb2a4 |
fprintf(fp, " exp_entry2_end: %lx\n", ms->exp_entry2_end);
|
|
|
4eb2a4 |
fprintf(fp, " panic_task_regs: %lx\n", (ulong)ms->panic_task_regs);
|
|
|
4eb2a4 |
fprintf(fp, " user_eframe_offset: %ld\n", ms->user_eframe_offset);
|
|
|
4eb2a4 |
+ fprintf(fp, " kern_eframe_offset: %ld\n", ms->kern_eframe_offset);
|
|
|
4eb2a4 |
fprintf(fp, " PTE_PROT_NONE: %lx\n", ms->PTE_PROT_NONE);
|
|
|
4eb2a4 |
fprintf(fp, " PTE_FILE: ");
|
|
|
4eb2a4 |
if (ms->PTE_FILE)
|
|
|
4eb2a4 |
@@ -1383,7 +1384,7 @@ arm64_irq_stack_init(void)
|
|
|
4eb2a4 |
|
|
|
4eb2a4 |
if (!(ms->irq_stacks = (ulong *)malloc((size_t)(kt->cpus * sizeof(ulong)))))
|
|
|
4eb2a4 |
error(FATAL, "cannot malloc irq_stack addresses\n");
|
|
|
4eb2a4 |
- ms->irq_stack_size = 16384;
|
|
|
4eb2a4 |
+ ms->irq_stack_size = ARM64_IRQ_STACK_SIZE;
|
|
|
4eb2a4 |
machdep->flags |= IRQ_STACKS;
|
|
|
4eb2a4 |
|
|
|
4eb2a4 |
for (i = 0; i < kt->cpus; i++) {
|
|
|
4eb2a4 |
@@ -1410,10 +1411,13 @@ arm64_stackframe_init(void)
|
|
|
4eb2a4 |
MEMBER_OFFSET_INIT(elf_prstatus_pr_pid, "elf_prstatus", "pr_pid");
|
|
|
4eb2a4 |
MEMBER_OFFSET_INIT(elf_prstatus_pr_reg, "elf_prstatus", "pr_reg");
|
|
|
4eb2a4 |
|
|
|
4eb2a4 |
- if (MEMBER_EXISTS("pt_regs", "stackframe"))
|
|
|
4eb2a4 |
+ if (MEMBER_EXISTS("pt_regs", "stackframe")) {
|
|
|
4eb2a4 |
machdep->machspec->user_eframe_offset = SIZE(pt_regs);
|
|
|
4eb2a4 |
- else
|
|
|
4eb2a4 |
+ machdep->machspec->kern_eframe_offset = SIZE(pt_regs) - 16;
|
|
|
4eb2a4 |
+ } else {
|
|
|
4eb2a4 |
machdep->machspec->user_eframe_offset = SIZE(pt_regs) + 16;
|
|
|
4eb2a4 |
+ machdep->machspec->kern_eframe_offset = SIZE(pt_regs);
|
|
|
4eb2a4 |
+ }
|
|
|
4eb2a4 |
|
|
|
4eb2a4 |
machdep->machspec->__exception_text_start =
|
|
|
4eb2a4 |
symbol_value("__exception_text_start");
|
|
|
4eb2a4 |
@@ -1503,6 +1507,7 @@ arm64_stackframe_init(void)
|
|
|
4eb2a4 |
#define USER_MODE (2)
|
|
|
4eb2a4 |
|
|
|
4eb2a4 |
#define USER_EFRAME_OFFSET (machdep->machspec->user_eframe_offset)
|
|
|
4eb2a4 |
+#define KERN_EFRAME_OFFSET (machdep->machspec->kern_eframe_offset)
|
|
|
4eb2a4 |
|
|
|
4eb2a4 |
/*
|
|
|
4eb2a4 |
* PSR bits
|
|
|
4eb2a4 |
@@ -1793,7 +1798,7 @@ arm64_display_full_frame(struct bt_info *bt, ulong sp)
|
|
|
4eb2a4 |
sp = bt->stacktop;
|
|
|
4eb2a4 |
}
|
|
|
4eb2a4 |
} else {
|
|
|
4eb2a4 |
- /* IRQ exception frame */
|
|
|
4eb2a4 |
+ /* This is a transition case from irq to process stack. */
|
|
|
4eb2a4 |
return;
|
|
|
4eb2a4 |
}
|
|
|
4eb2a4 |
|
|
|
4eb2a4 |
@@ -1903,61 +1908,73 @@ arm64_unwind_frame(struct bt_info *bt, struct arm64_stackframe *frame)
|
|
|
4eb2a4 |
if (!(machdep->flags & IRQ_STACKS))
|
|
|
4eb2a4 |
return TRUE;
|
|
|
4eb2a4 |
|
|
|
4eb2a4 |
- /*
|
|
|
4eb2a4 |
- * The kernel's manner of determining the end of the IRQ stack:
|
|
|
4eb2a4 |
- *
|
|
|
4eb2a4 |
- * #define THREAD_SIZE 16384
|
|
|
4eb2a4 |
- * #define THREAD_START_SP (THREAD_SIZE - 16)
|
|
|
4eb2a4 |
- * #define IRQ_STACK_START_SP THREAD_START_SP
|
|
|
4eb2a4 |
- * #define IRQ_STACK_PTR(cpu) ((unsigned long)per_cpu(irq_stack, cpu) + IRQ_STACK_START_SP)
|
|
|
4eb2a4 |
- * #define IRQ_STACK_TO_TASK_STACK(ptr) (*((unsigned long *)((ptr) - 0x08)))
|
|
|
4eb2a4 |
- *
|
|
|
4eb2a4 |
- * irq_stack_ptr = IRQ_STACK_PTR(raw_smp_processor_id());
|
|
|
4eb2a4 |
- * orig_sp = IRQ_STACK_TO_TASK_STACK(irq_stack_ptr); (pt_regs pointer on process stack)
|
|
|
4eb2a4 |
- */
|
|
|
4eb2a4 |
+ if (!(machdep->flags & IRQ_STACKS))
|
|
|
4eb2a4 |
+ return TRUE;
|
|
|
4eb2a4 |
+
|
|
|
4eb2a4 |
if (machdep->flags & UNW_4_14) {
|
|
|
4eb2a4 |
if ((bt->flags & BT_IRQSTACK) &&
|
|
|
4eb2a4 |
!arm64_on_irq_stack(bt->tc->processor, frame->fp)) {
|
|
|
4eb2a4 |
if (arm64_on_process_stack(bt, frame->fp)) {
|
|
|
4eb2a4 |
arm64_set_process_stack(bt);
|
|
|
4eb2a4 |
|
|
|
4eb2a4 |
- frame->sp = frame->fp - SIZE(pt_regs) + 16;
|
|
|
4eb2a4 |
- /* for switch_stack */
|
|
|
4eb2a4 |
- /* fp still points to irq stack */
|
|
|
4eb2a4 |
+ frame->sp = frame->fp - KERN_EFRAME_OFFSET;
|
|
|
4eb2a4 |
+ /*
|
|
|
4eb2a4 |
+ * for switch_stack
|
|
|
4eb2a4 |
+ * fp still points to irq stack
|
|
|
4eb2a4 |
+ */
|
|
|
4eb2a4 |
bt->bptr = fp;
|
|
|
4eb2a4 |
- /* for display_full_frame */
|
|
|
4eb2a4 |
- /* sp points to process stack */
|
|
|
4eb2a4 |
- bt->frameptr = frame->sp;
|
|
|
4eb2a4 |
+ /*
|
|
|
4eb2a4 |
+ * for display_full_frame
|
|
|
4eb2a4 |
+ * sp points to process stack
|
|
|
4eb2a4 |
+ *
|
|
|
4eb2a4 |
+ * If we want to see pt_regs,
|
|
|
4eb2a4 |
+ * comment out the below.
|
|
|
4eb2a4 |
+ * bt->frameptr = frame->sp;
|
|
|
4eb2a4 |
+ */
|
|
|
4eb2a4 |
} else {
|
|
|
4eb2a4 |
/* irq -> user */
|
|
|
4eb2a4 |
return FALSE;
|
|
|
4eb2a4 |
}
|
|
|
4eb2a4 |
}
|
|
|
4eb2a4 |
- } else { /* !UNW_4_14 */
|
|
|
4eb2a4 |
- ms = machdep->machspec;
|
|
|
4eb2a4 |
- irq_stack_ptr = ms->irq_stacks[bt->tc->processor] + ms->irq_stack_size - 16;
|
|
|
4eb2a4 |
-
|
|
|
4eb2a4 |
- if (frame->sp == irq_stack_ptr) {
|
|
|
4eb2a4 |
- orig_sp = GET_STACK_ULONG(irq_stack_ptr - 8);
|
|
|
4eb2a4 |
- arm64_set_process_stack(bt);
|
|
|
4eb2a4 |
- if (INSTACK(orig_sp, bt) && (INSTACK(frame->fp, bt) || (frame->fp == 0))) {
|
|
|
4eb2a4 |
- ptregs = (struct arm64_pt_regs *)&bt->stackbuf[(ulong)(STACK_OFFSET_TYPE(orig_sp))];
|
|
|
4eb2a4 |
- frame->sp = orig_sp;
|
|
|
4eb2a4 |
- frame->pc = ptregs->pc;
|
|
|
4eb2a4 |
- bt->bptr = fp;
|
|
|
4eb2a4 |
- if (CRASHDEBUG(1))
|
|
|
4eb2a4 |
- error(INFO,
|
|
|
4eb2a4 |
- "arm64_unwind_frame: switch stacks: fp: %lx sp: %lx pc: %lx\n",
|
|
|
4eb2a4 |
- frame->fp, frame->sp, frame->pc);
|
|
|
4eb2a4 |
- } else {
|
|
|
4eb2a4 |
- error(WARNING,
|
|
|
4eb2a4 |
- "arm64_unwind_frame: on IRQ stack: oriq_sp: %lx%s fp: %lx%s\n",
|
|
|
4eb2a4 |
- orig_sp, INSTACK(orig_sp, bt) ? "" : " (?)",
|
|
|
4eb2a4 |
- frame->fp, INSTACK(frame->fp, bt) ? "" : " (?)");
|
|
|
4eb2a4 |
- return FALSE;
|
|
|
4eb2a4 |
- }
|
|
|
4eb2a4 |
+
|
|
|
4eb2a4 |
+ return TRUE;
|
|
|
4eb2a4 |
+ }
|
|
|
4eb2a4 |
+
|
|
|
4eb2a4 |
+ /*
|
|
|
4eb2a4 |
+ * The kernel's manner of determining the end of the IRQ stack:
|
|
|
4eb2a4 |
+ *
|
|
|
4eb2a4 |
+ * #define THREAD_SIZE 16384
|
|
|
4eb2a4 |
+ * #define THREAD_START_SP (THREAD_SIZE - 16)
|
|
|
4eb2a4 |
+ * #define IRQ_STACK_START_SP THREAD_START_SP
|
|
|
4eb2a4 |
+ * #define IRQ_STACK_PTR(cpu) ((unsigned long)per_cpu(irq_stack, cpu) + IRQ_STACK_START_SP)
|
|
|
4eb2a4 |
+ * #define IRQ_STACK_TO_TASK_STACK(ptr) (*((unsigned long *)((ptr) - 0x08)))
|
|
|
4eb2a4 |
+ *
|
|
|
4eb2a4 |
+ * irq_stack_ptr = IRQ_STACK_PTR(raw_smp_processor_id());
|
|
|
4eb2a4 |
+ * orig_sp = IRQ_STACK_TO_TASK_STACK(irq_stack_ptr); (pt_regs pointer on process stack)
|
|
|
4eb2a4 |
+ */
|
|
|
4eb2a4 |
+ ms = machdep->machspec;
|
|
|
4eb2a4 |
+ irq_stack_ptr = ms->irq_stacks[bt->tc->processor] + ms->irq_stack_size - 16;
|
|
|
4eb2a4 |
+
|
|
|
4eb2a4 |
+ if (frame->sp == irq_stack_ptr) {
|
|
|
4eb2a4 |
+ orig_sp = GET_STACK_ULONG(irq_stack_ptr - 8);
|
|
|
4eb2a4 |
+ arm64_set_process_stack(bt);
|
|
|
4eb2a4 |
+ if (INSTACK(orig_sp, bt) && (INSTACK(frame->fp, bt) || (frame->fp == 0))) {
|
|
|
4eb2a4 |
+ ptregs = (struct arm64_pt_regs *)&bt->stackbuf[(ulong)(STACK_OFFSET_TYPE(orig_sp))];
|
|
|
4eb2a4 |
+ frame->sp = orig_sp;
|
|
|
4eb2a4 |
+ frame->pc = ptregs->pc;
|
|
|
4eb2a4 |
+ bt->bptr = fp;
|
|
|
4eb2a4 |
+ if (CRASHDEBUG(1))
|
|
|
4eb2a4 |
+ error(INFO,
|
|
|
4eb2a4 |
+ "arm64_unwind_frame: switch stacks: fp: %lx sp: %lx pc: %lx\n",
|
|
|
4eb2a4 |
+ frame->fp, frame->sp, frame->pc);
|
|
|
4eb2a4 |
+ } else {
|
|
|
4eb2a4 |
+ error(WARNING,
|
|
|
4eb2a4 |
+ "arm64_unwind_frame: on IRQ stack: oriq_sp: %lx%s fp: %lx%s\n",
|
|
|
4eb2a4 |
+ orig_sp, INSTACK(orig_sp, bt) ? "" : " (?)",
|
|
|
4eb2a4 |
+ frame->fp, INSTACK(frame->fp, bt) ? "" : " (?)");
|
|
|
4eb2a4 |
+ return FALSE;
|
|
|
4eb2a4 |
}
|
|
|
4eb2a4 |
- } /* UNW_4_14 */
|
|
|
4eb2a4 |
+ }
|
|
|
4eb2a4 |
|
|
|
4eb2a4 |
return TRUE;
|
|
|
4eb2a4 |
}
|
|
|
4eb2a4 |
@@ -2147,17 +2164,10 @@ arm64_unwind_frame_v2(struct bt_info *bt, struct arm64_stackframe *frame,
|
|
|
4eb2a4 |
* We are on process stack. Just add a faked frame
|
|
|
4eb2a4 |
*/
|
|
|
4eb2a4 |
|
|
|
4eb2a4 |
- if (!arm64_on_irq_stack(bt->tc->processor, ext_frame.fp)) {
|
|
|
4eb2a4 |
- if (MEMBER_EXISTS("pt_regs", "stackframe")) {
|
|
|
4eb2a4 |
- frame->sp = ext_frame.fp
|
|
|
4eb2a4 |
- - sizeof(struct arm64_pt_regs) - 16;
|
|
|
4eb2a4 |
- frame->fp = ext_frame.fp;
|
|
|
4eb2a4 |
- } else {
|
|
|
4eb2a4 |
- frame->sp = ext_frame.fp
|
|
|
4eb2a4 |
- - sizeof(struct arm64_pt_regs);
|
|
|
4eb2a4 |
- frame->fp = frame->sp;
|
|
|
4eb2a4 |
- }
|
|
|
4eb2a4 |
- } else {
|
|
|
4eb2a4 |
+ if (!arm64_on_irq_stack(bt->tc->processor, ext_frame.fp))
|
|
|
4eb2a4 |
+ frame->sp = ext_frame.fp
|
|
|
4eb2a4 |
+ - sizeof(struct arm64_pt_regs);
|
|
|
4eb2a4 |
+ else {
|
|
|
4eb2a4 |
/*
|
|
|
4eb2a4 |
* FIXME: very exceptional case
|
|
|
4eb2a4 |
* We are already back on process stack, but
|
|
|
4eb2a4 |
@@ -2177,10 +2187,10 @@ arm64_unwind_frame_v2(struct bt_info *bt, struct arm64_stackframe *frame,
|
|
|
4eb2a4 |
* Really ugly
|
|
|
4eb2a4 |
*/
|
|
|
4eb2a4 |
frame->sp = frame->fp + 0x20;
|
|
|
4eb2a4 |
- frame->fp = frame->sp;
|
|
|
4eb2a4 |
fprintf(ofp, " (Next exception frame might be wrong)\n");
|
|
|
4eb2a4 |
}
|
|
|
4eb2a4 |
|
|
|
4eb2a4 |
+ frame->fp = frame->sp;
|
|
|
4eb2a4 |
} else {
|
|
|
4eb2a4 |
/* We are on IRQ stack */
|
|
|
4eb2a4 |
|
|
|
4eb2a4 |
@@ -2190,15 +2200,9 @@ arm64_unwind_frame_v2(struct bt_info *bt, struct arm64_stackframe *frame,
|
|
|
4eb2a4 |
if (ext_frame.fp != irq_stack_ptr) {
|
|
|
4eb2a4 |
/* (2) Just add a faked frame */
|
|
|
4eb2a4 |
|
|
|
4eb2a4 |
- if (MEMBER_EXISTS("pt_regs", "stackframe")) {
|
|
|
4eb2a4 |
- frame->sp = ext_frame.fp
|
|
|
4eb2a4 |
- - sizeof(struct arm64_pt_regs);
|
|
|
4eb2a4 |
- frame->fp = ext_frame.fp;
|
|
|
4eb2a4 |
- } else {
|
|
|
4eb2a4 |
- frame->sp = ext_frame.fp
|
|
|
4eb2a4 |
- - sizeof(struct arm64_pt_regs) - 16;
|
|
|
4eb2a4 |
- frame->fp = frame->sp;
|
|
|
4eb2a4 |
- }
|
|
|
4eb2a4 |
+ frame->sp = ext_frame.fp
|
|
|
4eb2a4 |
+ - sizeof(struct arm64_pt_regs);
|
|
|
4eb2a4 |
+ frame->fp = frame->sp;
|
|
|
4eb2a4 |
} else {
|
|
|
4eb2a4 |
/*
|
|
|
4eb2a4 |
* (3)
|
|
|
4eb2a4 |
@@ -2285,6 +2289,11 @@ arm64_back_trace_cmd(struct bt_info *bt)
|
|
|
4eb2a4 |
FILE *ofp;
|
|
|
4eb2a4 |
|
|
|
4eb2a4 |
if (bt->flags & BT_OPT_BACK_TRACE) {
|
|
|
4eb2a4 |
+ if (machdep->flags & UNW_4_14) {
|
|
|
4eb2a4 |
+ option_not_supported('o');
|
|
|
4eb2a4 |
+ return;
|
|
|
4eb2a4 |
+ }
|
|
|
4eb2a4 |
+
|
|
|
4eb2a4 |
arm64_back_trace_cmd_v2(bt);
|
|
|
4eb2a4 |
return;
|
|
|
4eb2a4 |
}
|
|
|
4eb2a4 |
@@ -2346,7 +2355,7 @@ arm64_back_trace_cmd(struct bt_info *bt)
|
|
|
4eb2a4 |
goto complete_user;
|
|
|
4eb2a4 |
|
|
|
4eb2a4 |
if (DUMPFILE() && is_task_active(bt->task)) {
|
|
|
4eb2a4 |
- exception_frame = stackframe.fp - SIZE(pt_regs);
|
|
|
4eb2a4 |
+ exception_frame = stackframe.fp - KERN_EFRAME_OFFSET;
|
|
|
4eb2a4 |
if (arm64_is_kernel_exception_frame(bt, exception_frame))
|
|
|
4eb2a4 |
arm64_print_exception_frame(bt, exception_frame,
|
|
|
4eb2a4 |
KERNEL_MODE, ofp);
|
|
|
4eb2a4 |
@@ -2377,13 +2386,8 @@ arm64_back_trace_cmd(struct bt_info *bt)
|
|
|
4eb2a4 |
|
|
|
4eb2a4 |
if (arm64_in_exception_text(bt->instptr) && INSTACK(stackframe.fp, bt)) {
|
|
|
4eb2a4 |
if (!(bt->flags & BT_IRQSTACK) ||
|
|
|
4eb2a4 |
- (((stackframe.sp + SIZE(pt_regs)) < bt->stacktop))) {
|
|
|
4eb2a4 |
- if (MEMBER_EXISTS("pt_regs", "stackframe"))
|
|
|
4eb2a4 |
- /* v4.14 or later */
|
|
|
4eb2a4 |
- exception_frame = stackframe.fp - SIZE(pt_regs) + 16;
|
|
|
4eb2a4 |
- else
|
|
|
4eb2a4 |
- exception_frame = stackframe.fp - SIZE(pt_regs);
|
|
|
4eb2a4 |
- }
|
|
|
4eb2a4 |
+ (((stackframe.sp + SIZE(pt_regs)) < bt->stacktop)))
|
|
|
4eb2a4 |
+ exception_frame = stackframe.fp - KERN_EFRAME_OFFSET;
|
|
|
4eb2a4 |
}
|
|
|
4eb2a4 |
|
|
|
4eb2a4 |
if ((bt->flags & BT_IRQSTACK) &&
|
|
|
4eb2a4 |
@@ -2503,8 +2507,6 @@ user_space:
|
|
|
4eb2a4 |
* otherwise show an exception frame.
|
|
|
4eb2a4 |
* Since exception entry code doesn't have a real
|
|
|
4eb2a4 |
* stackframe, we fake a dummy frame here.
|
|
|
4eb2a4 |
- * Note: Since we have a real stack frame in pt_regs,
|
|
|
4eb2a4 |
- * We no longer need a dummy frame on v4.14 or later.
|
|
|
4eb2a4 |
*/
|
|
|
4eb2a4 |
if (!arm64_in_exp_entry(stackframe.pc))
|
|
|
4eb2a4 |
continue;
|
|
|
4eb2a4 |
diff --git a/defs.h b/defs.h
|
|
|
4eb2a4 |
index 7768895..a694a66 100644
|
|
|
4eb2a4 |
--- a/defs.h
|
|
|
4eb2a4 |
+++ b/defs.h
|
|
|
4eb2a4 |
@@ -3038,6 +3038,7 @@ typedef signed int s32;
|
|
|
4eb2a4 |
#define ARM64_VMEMMAP_END (ARM64_VMEMMAP_VADDR + GIGABYTES(8UL) - 1)
|
|
|
4eb2a4 |
|
|
|
4eb2a4 |
#define ARM64_STACK_SIZE (16384)
|
|
|
4eb2a4 |
+#define ARM64_IRQ_STACK_SIZE ARM64_STACK_SIZE
|
|
|
4eb2a4 |
|
|
|
4eb2a4 |
#define _SECTION_SIZE_BITS 30
|
|
|
4eb2a4 |
#define _MAX_PHYSMEM_BITS 40
|
|
|
4eb2a4 |
@@ -3117,6 +3118,8 @@ struct machine_specific {
|
|
|
4eb2a4 |
ulong kimage_text;
|
|
|
4eb2a4 |
ulong kimage_end;
|
|
|
4eb2a4 |
ulong user_eframe_offset;
|
|
|
4eb2a4 |
+ /* for v4.14 or later */
|
|
|
4eb2a4 |
+ ulong kern_eframe_offset;
|
|
|
4eb2a4 |
};
|
|
|
4eb2a4 |
|
|
|
4eb2a4 |
struct arm64_stackframe {
|
|
|
4eb2a4 |
diff --git a/help.c b/help.c
|
|
|
4eb2a4 |
index a9aab37..f9c5792 100644
|
|
|
4eb2a4 |
--- a/help.c
|
|
|
4eb2a4 |
+++ b/help.c
|
|
|
4eb2a4 |
@@ -1799,7 +1799,8 @@ char *help_bt[] = {
|
|
|
4eb2a4 |
" It does so by verifying the thread_info.task pointer, ensuring that",
|
|
|
4eb2a4 |
" the thread_info.cpu is a valid cpu number, and checking the end of ",
|
|
|
4eb2a4 |
" the stack for the STACK_END_MAGIC value.",
|
|
|
4eb2a4 |
-" -o arm64: use optional backtrace method.",
|
|
|
4eb2a4 |
+" -o arm64: use optional backtrace method; not supported on Linux 4.14 or",
|
|
|
4eb2a4 |
+" later kernels.",
|
|
|
4eb2a4 |
" x86: use old backtrace method, permissible only on kernels that were",
|
|
|
4eb2a4 |
" compiled without the -fomit-frame_pointer.",
|
|
|
4eb2a4 |
" x86_64: use old backtrace method, which dumps potentially stale",
|
|
|
4eb2a4 |
diff --git a/task.c b/task.c
|
|
|
4eb2a4 |
index 2b12af0..362822c 100644
|
|
|
4eb2a4 |
--- a/task.c
|
|
|
4eb2a4 |
+++ b/task.c
|
|
|
4eb2a4 |
@@ -6750,6 +6750,8 @@ panic_search(void)
|
|
|
4eb2a4 |
fd->keyword_array[0] = FOREACH_BT;
|
|
|
4eb2a4 |
if (machine_type("S390X"))
|
|
|
4eb2a4 |
fd->flags |= FOREACH_o_FLAG;
|
|
|
4eb2a4 |
+ else if (machine_type("ARM64"))
|
|
|
4eb2a4 |
+ fd->flags |= FOREACH_t_FLAG;
|
|
|
4eb2a4 |
else
|
|
|
4eb2a4 |
fd->flags |= (FOREACH_t_FLAG|FOREACH_o_FLAG);
|
|
|
4eb2a4 |
|
|
|
4eb2a4 |
|
|
|
4eb2a4 |
commit 45b74b89530d611b3fa95a1041e158fbb865fa84
|
|
|
4eb2a4 |
Author: Dave Anderson <anderson@redhat.com>
|
|
|
4eb2a4 |
Date: Mon Oct 23 11:15:39 2017 -0400
|
|
|
4eb2a4 |
|
|
|
4eb2a4 |
Fix for support of KASLR enabled kernels captured by the SADUMP
|
|
|
4eb2a4 |
dumpfile facility. SADUMP dumpfile headers do not contain phys_base
|
|
|
4eb2a4 |
or VMCOREINFO notes, so without this patch, the crash session fails
|
|
|
4eb2a4 |
during initialization with the message "crash: seek error: kernel
|
|
|
4eb2a4 |
virtual address: <address> type: "page_offset_base". This patch
|
|
|
4eb2a4 |
calculates the phys_base value and the KASLR offset using the IDTR
|
|
|
4eb2a4 |
and CR3 registers from the dumpfile header.
|
|
|
4eb2a4 |
(indou.takao@jp.fujitsu.com)
|
|
|
4eb2a4 |
|
|
|
4eb2a4 |
diff --git a/defs.h b/defs.h
|
|
|
4eb2a4 |
index a694a66..76e5512 100644
|
|
|
4eb2a4 |
--- a/defs.h
|
|
|
4eb2a4 |
+++ b/defs.h
|
|
|
4eb2a4 |
@@ -2591,6 +2591,9 @@ struct symbol_table_data {
|
|
|
4eb2a4 |
ulong last_section_end;
|
|
|
4eb2a4 |
ulong _stext_vmlinux;
|
|
|
4eb2a4 |
struct downsized downsized;
|
|
|
4eb2a4 |
+ ulong divide_error_vmlinux;
|
|
|
4eb2a4 |
+ ulong idt_table_vmlinux;
|
|
|
4eb2a4 |
+ ulong saved_command_line_vmlinux;
|
|
|
4eb2a4 |
};
|
|
|
4eb2a4 |
|
|
|
4eb2a4 |
/* flags for st */
|
|
|
4eb2a4 |
@@ -6312,6 +6315,7 @@ void sadump_set_zero_excluded(void);
|
|
|
4eb2a4 |
void sadump_unset_zero_excluded(void);
|
|
|
4eb2a4 |
struct sadump_data;
|
|
|
4eb2a4 |
struct sadump_data *get_sadump_data(void);
|
|
|
4eb2a4 |
+int sadump_calc_kaslr_offset(ulong *);
|
|
|
4eb2a4 |
|
|
|
4eb2a4 |
/*
|
|
|
4eb2a4 |
* qemu.c
|
|
|
4eb2a4 |
diff --git a/sadump.c b/sadump.c
|
|
|
4eb2a4 |
index a96ba9c..2ccfa82 100644
|
|
|
4eb2a4 |
--- a/sadump.c
|
|
|
4eb2a4 |
+++ b/sadump.c
|
|
|
4eb2a4 |
@@ -1558,12 +1558,17 @@ sadump_display_regs(int cpu, FILE *ofp)
|
|
|
4eb2a4 |
*/
|
|
|
4eb2a4 |
int sadump_phys_base(ulong *phys_base)
|
|
|
4eb2a4 |
{
|
|
|
4eb2a4 |
- if (SADUMP_VALID()) {
|
|
|
4eb2a4 |
+ if (SADUMP_VALID() && !sd->phys_base) {
|
|
|
4eb2a4 |
if (CRASHDEBUG(1))
|
|
|
4eb2a4 |
error(NOTE, "sadump: does not save phys_base.\n");
|
|
|
4eb2a4 |
return FALSE;
|
|
|
4eb2a4 |
}
|
|
|
4eb2a4 |
|
|
|
4eb2a4 |
+ if (sd->phys_base) {
|
|
|
4eb2a4 |
+ *phys_base = sd->phys_base;
|
|
|
4eb2a4 |
+ return TRUE;
|
|
|
4eb2a4 |
+ }
|
|
|
4eb2a4 |
+
|
|
|
4eb2a4 |
return FALSE;
|
|
|
4eb2a4 |
}
|
|
|
4eb2a4 |
|
|
|
4eb2a4 |
@@ -1649,3 +1654,461 @@ get_sadump_data(void)
|
|
|
4eb2a4 |
{
|
|
|
4eb2a4 |
return sd;
|
|
|
4eb2a4 |
}
|
|
|
4eb2a4 |
+
|
|
|
4eb2a4 |
+#ifdef X86_64
|
|
|
4eb2a4 |
+static int
|
|
|
4eb2a4 |
+get_sadump_smram_cpu_state_any(struct sadump_smram_cpu_state *smram)
|
|
|
4eb2a4 |
+{
|
|
|
4eb2a4 |
+ ulong offset;
|
|
|
4eb2a4 |
+ struct sadump_header *sh = sd->dump_header;
|
|
|
4eb2a4 |
+ int apicid;
|
|
|
4eb2a4 |
+ struct sadump_smram_cpu_state scs, zero;
|
|
|
4eb2a4 |
+
|
|
|
4eb2a4 |
+ offset = sd->sub_hdr_offset + sizeof(uint32_t) +
|
|
|
4eb2a4 |
+ sd->dump_header->nr_cpus * sizeof(struct sadump_apic_state);
|
|
|
4eb2a4 |
+
|
|
|
4eb2a4 |
+ memset(&zero, 0, sizeof(zero));
|
|
|
4eb2a4 |
+
|
|
|
4eb2a4 |
+ for (apicid = 0; apicid < sh->nr_cpus; ++apicid) {
|
|
|
4eb2a4 |
+ if (!read_device(&scs, sizeof(scs), &offset)) {
|
|
|
4eb2a4 |
+ error(INFO, "sadump: cannot read sub header "
|
|
|
4eb2a4 |
+ "cpu_state\n");
|
|
|
4eb2a4 |
+ return FALSE;
|
|
|
4eb2a4 |
+ }
|
|
|
4eb2a4 |
+ if (memcmp(&scs, &zero, sizeof(scs)) != 0) {
|
|
|
4eb2a4 |
+ *smram = scs;
|
|
|
4eb2a4 |
+ return TRUE;
|
|
|
4eb2a4 |
+ }
|
|
|
4eb2a4 |
+ }
|
|
|
4eb2a4 |
+
|
|
|
4eb2a4 |
+ return FALSE;
|
|
|
4eb2a4 |
+}
|
|
|
4eb2a4 |
+
|
|
|
4eb2a4 |
+/*
|
|
|
4eb2a4 |
+ * Get address of vector0 interrupt handler (Devide Error) from Interrupt
|
|
|
4eb2a4 |
+ * Descriptor Table.
|
|
|
4eb2a4 |
+ */
|
|
|
4eb2a4 |
+static ulong
|
|
|
4eb2a4 |
+get_vec0_addr(ulong idtr)
|
|
|
4eb2a4 |
+{
|
|
|
4eb2a4 |
+ struct gate_struct64 {
|
|
|
4eb2a4 |
+ uint16_t offset_low;
|
|
|
4eb2a4 |
+ uint16_t segment;
|
|
|
4eb2a4 |
+ uint32_t ist : 3, zero0 : 5, type : 5, dpl : 2, p : 1;
|
|
|
4eb2a4 |
+ uint16_t offset_middle;
|
|
|
4eb2a4 |
+ uint32_t offset_high;
|
|
|
4eb2a4 |
+ uint32_t zero1;
|
|
|
4eb2a4 |
+ } __attribute__((packed)) gate;
|
|
|
4eb2a4 |
+
|
|
|
4eb2a4 |
+ readmem(idtr, PHYSADDR, &gate, sizeof(gate), "idt_table", FAULT_ON_ERROR);
|
|
|
4eb2a4 |
+
|
|
|
4eb2a4 |
+ return ((ulong)gate.offset_high << 32)
|
|
|
4eb2a4 |
+ + ((ulong)gate.offset_middle << 16)
|
|
|
4eb2a4 |
+ + gate.offset_low;
|
|
|
4eb2a4 |
+}
|
|
|
4eb2a4 |
+
|
|
|
4eb2a4 |
+/*
|
|
|
4eb2a4 |
+ * Parse a string of [size[KMG] ]offset[KMG]
|
|
|
4eb2a4 |
+ * Import from Linux kernel(lib/cmdline.c)
|
|
|
4eb2a4 |
+ */
|
|
|
4eb2a4 |
+static ulong memparse(char *ptr, char **retptr)
|
|
|
4eb2a4 |
+{
|
|
|
4eb2a4 |
+ char *endptr;
|
|
|
4eb2a4 |
+
|
|
|
4eb2a4 |
+ unsigned long long ret = strtoull(ptr, &endptr, 0);
|
|
|
4eb2a4 |
+
|
|
|
4eb2a4 |
+ switch (*endptr) {
|
|
|
4eb2a4 |
+ case 'E':
|
|
|
4eb2a4 |
+ case 'e':
|
|
|
4eb2a4 |
+ ret <<= 10;
|
|
|
4eb2a4 |
+ case 'P':
|
|
|
4eb2a4 |
+ case 'p':
|
|
|
4eb2a4 |
+ ret <<= 10;
|
|
|
4eb2a4 |
+ case 'T':
|
|
|
4eb2a4 |
+ case 't':
|
|
|
4eb2a4 |
+ ret <<= 10;
|
|
|
4eb2a4 |
+ case 'G':
|
|
|
4eb2a4 |
+ case 'g':
|
|
|
4eb2a4 |
+ ret <<= 10;
|
|
|
4eb2a4 |
+ case 'M':
|
|
|
4eb2a4 |
+ case 'm':
|
|
|
4eb2a4 |
+ ret <<= 10;
|
|
|
4eb2a4 |
+ case 'K':
|
|
|
4eb2a4 |
+ case 'k':
|
|
|
4eb2a4 |
+ ret <<= 10;
|
|
|
4eb2a4 |
+ endptr++;
|
|
|
4eb2a4 |
+ default:
|
|
|
4eb2a4 |
+ break;
|
|
|
4eb2a4 |
+ }
|
|
|
4eb2a4 |
+
|
|
|
4eb2a4 |
+ if (retptr)
|
|
|
4eb2a4 |
+ *retptr = endptr;
|
|
|
4eb2a4 |
+
|
|
|
4eb2a4 |
+ return ret;
|
|
|
4eb2a4 |
+}
|
|
|
4eb2a4 |
+
|
|
|
4eb2a4 |
+/*
|
|
|
4eb2a4 |
+ * Find "elfcorehdr=" in the boot parameter of kernel and return the address
|
|
|
4eb2a4 |
+ * of elfcorehdr.
|
|
|
4eb2a4 |
+ */
|
|
|
4eb2a4 |
+static ulong
|
|
|
4eb2a4 |
+get_elfcorehdr(ulong cr3, ulong kaslr_offset)
|
|
|
4eb2a4 |
+{
|
|
|
4eb2a4 |
+ char cmdline[BUFSIZE], *ptr;
|
|
|
4eb2a4 |
+ ulong cmdline_vaddr;
|
|
|
4eb2a4 |
+ ulong cmdline_paddr;
|
|
|
4eb2a4 |
+ ulong buf_vaddr, buf_paddr;
|
|
|
4eb2a4 |
+ char *end;
|
|
|
4eb2a4 |
+ ulong elfcorehdr_addr = 0, elfcorehdr_size = 0;
|
|
|
4eb2a4 |
+ int verbose = CRASHDEBUG(1)? 1: 0;
|
|
|
4eb2a4 |
+
|
|
|
4eb2a4 |
+ cmdline_vaddr = st->saved_command_line_vmlinux + kaslr_offset;
|
|
|
4eb2a4 |
+ if (!kvtop(NULL, cmdline_vaddr, &cmdline_paddr, verbose))
|
|
|
4eb2a4 |
+ return 0;
|
|
|
4eb2a4 |
+
|
|
|
4eb2a4 |
+ if (CRASHDEBUG(1)) {
|
|
|
4eb2a4 |
+ fprintf(fp, "cmdline vaddr=%lx\n", cmdline_vaddr);
|
|
|
4eb2a4 |
+ fprintf(fp, "cmdline paddr=%lx\n", cmdline_paddr);
|
|
|
4eb2a4 |
+ }
|
|
|
4eb2a4 |
+
|
|
|
4eb2a4 |
+ if (!readmem(cmdline_paddr, PHYSADDR, &buf_vaddr, sizeof(ulong),
|
|
|
4eb2a4 |
+ "saved_command_line", RETURN_ON_ERROR))
|
|
|
4eb2a4 |
+ return 0;
|
|
|
4eb2a4 |
+
|
|
|
4eb2a4 |
+ if (!kvtop(NULL, buf_vaddr, &buf_paddr, verbose))
|
|
|
4eb2a4 |
+ return 0;
|
|
|
4eb2a4 |
+
|
|
|
4eb2a4 |
+ if (CRASHDEBUG(1)) {
|
|
|
4eb2a4 |
+ fprintf(fp, "cmdline buffer vaddr=%lx\n", buf_vaddr);
|
|
|
4eb2a4 |
+ fprintf(fp, "cmdline buffer paddr=%lx\n", buf_paddr);
|
|
|
4eb2a4 |
+ }
|
|
|
4eb2a4 |
+
|
|
|
4eb2a4 |
+ memset(cmdline, 0, BUFSIZE);
|
|
|
4eb2a4 |
+ if (!readmem(buf_paddr, PHYSADDR, cmdline, BUFSIZE,
|
|
|
4eb2a4 |
+ "saved_command_line", RETURN_ON_ERROR))
|
|
|
4eb2a4 |
+ return 0;
|
|
|
4eb2a4 |
+
|
|
|
4eb2a4 |
+ ptr = strstr(cmdline, "elfcorehdr=");
|
|
|
4eb2a4 |
+ if (!ptr)
|
|
|
4eb2a4 |
+ return 0;
|
|
|
4eb2a4 |
+
|
|
|
4eb2a4 |
+ if (CRASHDEBUG(1))
|
|
|
4eb2a4 |
+ fprintf(fp, "2nd kernel detected\n");
|
|
|
4eb2a4 |
+
|
|
|
4eb2a4 |
+ ptr += strlen("elfcorehdr=");
|
|
|
4eb2a4 |
+ elfcorehdr_addr = memparse(ptr, &end;;
|
|
|
4eb2a4 |
+ if (*end == '@') {
|
|
|
4eb2a4 |
+ elfcorehdr_size = elfcorehdr_addr;
|
|
|
4eb2a4 |
+ elfcorehdr_addr = memparse(end + 1, &end;;
|
|
|
4eb2a4 |
+ }
|
|
|
4eb2a4 |
+
|
|
|
4eb2a4 |
+ if (CRASHDEBUG(1)) {
|
|
|
4eb2a4 |
+ fprintf(fp, "elfcorehdr_addr=%lx\n", elfcorehdr_addr);
|
|
|
4eb2a4 |
+ fprintf(fp, "elfcorehdr_size=%lx\n", elfcorehdr_size);
|
|
|
4eb2a4 |
+ }
|
|
|
4eb2a4 |
+
|
|
|
4eb2a4 |
+ return elfcorehdr_addr;
|
|
|
4eb2a4 |
+}
|
|
|
4eb2a4 |
+
|
|
|
4eb2a4 |
+ /*
|
|
|
4eb2a4 |
+ * Get vmcoreinfo from elfcorehdr.
|
|
|
4eb2a4 |
+ * Some codes are imported from Linux kernel(fs/proc/vmcore.c)
|
|
|
4eb2a4 |
+ */
|
|
|
4eb2a4 |
+static int
|
|
|
4eb2a4 |
+get_vmcoreinfo(ulong elfcorehdr, ulong *addr, int *len)
|
|
|
4eb2a4 |
+{
|
|
|
4eb2a4 |
+ unsigned char e_ident[EI_NIDENT];
|
|
|
4eb2a4 |
+ Elf64_Ehdr ehdr;
|
|
|
4eb2a4 |
+ Elf64_Phdr phdr;
|
|
|
4eb2a4 |
+ Elf64_Nhdr nhdr;
|
|
|
4eb2a4 |
+ ulong ptr;
|
|
|
4eb2a4 |
+ ulong nhdr_offset = 0;
|
|
|
4eb2a4 |
+ int i;
|
|
|
4eb2a4 |
+
|
|
|
4eb2a4 |
+ if (!readmem(elfcorehdr, PHYSADDR, e_ident, EI_NIDENT,
|
|
|
4eb2a4 |
+ "EI_NIDENT", RETURN_ON_ERROR))
|
|
|
4eb2a4 |
+ return FALSE;
|
|
|
4eb2a4 |
+
|
|
|
4eb2a4 |
+ if (e_ident[EI_CLASS] != ELFCLASS64) {
|
|
|
4eb2a4 |
+ error(INFO, "Only ELFCLASS64 is supportd\n");
|
|
|
4eb2a4 |
+ return FALSE;
|
|
|
4eb2a4 |
+ }
|
|
|
4eb2a4 |
+
|
|
|
4eb2a4 |
+ if (!readmem(elfcorehdr, PHYSADDR, &ehdr, sizeof(ehdr),
|
|
|
4eb2a4 |
+ "Elf64_Ehdr", RETURN_ON_ERROR))
|
|
|
4eb2a4 |
+ return FALSE;
|
|
|
4eb2a4 |
+
|
|
|
4eb2a4 |
+ /* Sanity Check */
|
|
|
4eb2a4 |
+ if (memcmp(ehdr.e_ident, ELFMAG, SELFMAG) != 0 ||
|
|
|
4eb2a4 |
+ (ehdr.e_type != ET_CORE) ||
|
|
|
4eb2a4 |
+ ehdr.e_ident[EI_CLASS] != ELFCLASS64 ||
|
|
|
4eb2a4 |
+ ehdr.e_ident[EI_VERSION] != EV_CURRENT ||
|
|
|
4eb2a4 |
+ ehdr.e_version != EV_CURRENT ||
|
|
|
4eb2a4 |
+ ehdr.e_ehsize != sizeof(Elf64_Ehdr) ||
|
|
|
4eb2a4 |
+ ehdr.e_phentsize != sizeof(Elf64_Phdr) ||
|
|
|
4eb2a4 |
+ ehdr.e_phnum == 0) {
|
|
|
4eb2a4 |
+ error(INFO, "Invalid elf header\n");
|
|
|
4eb2a4 |
+ return FALSE;
|
|
|
4eb2a4 |
+ }
|
|
|
4eb2a4 |
+
|
|
|
4eb2a4 |
+ ptr = elfcorehdr + ehdr.e_phoff;
|
|
|
4eb2a4 |
+ for (i = 0; i < ehdr.e_phnum; i++) {
|
|
|
4eb2a4 |
+ ulong offset;
|
|
|
4eb2a4 |
+ char name[16];
|
|
|
4eb2a4 |
+
|
|
|
4eb2a4 |
+ if (!readmem(ptr, PHYSADDR, &phdr, sizeof(phdr),
|
|
|
4eb2a4 |
+ "Elf64_Phdr", RETURN_ON_ERROR))
|
|
|
4eb2a4 |
+ return FALSE;
|
|
|
4eb2a4 |
+
|
|
|
4eb2a4 |
+ ptr += sizeof(phdr);
|
|
|
4eb2a4 |
+ if (phdr.p_type != PT_NOTE)
|
|
|
4eb2a4 |
+ continue;
|
|
|
4eb2a4 |
+
|
|
|
4eb2a4 |
+ offset = phdr.p_offset;
|
|
|
4eb2a4 |
+ if (!readmem(offset, PHYSADDR, &nhdr, sizeof(nhdr),
|
|
|
4eb2a4 |
+ "Elf64_Nhdr", RETURN_ON_ERROR))
|
|
|
4eb2a4 |
+ return FALSE;
|
|
|
4eb2a4 |
+
|
|
|
4eb2a4 |
+ offset += DIV_ROUND_UP(sizeof(Elf64_Nhdr), sizeof(Elf64_Word))*
|
|
|
4eb2a4 |
+ sizeof(Elf64_Word);
|
|
|
4eb2a4 |
+ memset(name, 0, sizeof(name));
|
|
|
4eb2a4 |
+ if (!readmem(offset, PHYSADDR, name, sizeof(name),
|
|
|
4eb2a4 |
+ "Elf64_Nhdr name", RETURN_ON_ERROR))
|
|
|
4eb2a4 |
+ return FALSE;
|
|
|
4eb2a4 |
+
|
|
|
4eb2a4 |
+ if(!strcmp(name, "VMCOREINFO")) {
|
|
|
4eb2a4 |
+ nhdr_offset = offset;
|
|
|
4eb2a4 |
+ break;
|
|
|
4eb2a4 |
+ }
|
|
|
4eb2a4 |
+ }
|
|
|
4eb2a4 |
+
|
|
|
4eb2a4 |
+ if (!nhdr_offset)
|
|
|
4eb2a4 |
+ return FALSE;
|
|
|
4eb2a4 |
+
|
|
|
4eb2a4 |
+ *addr = nhdr_offset +
|
|
|
4eb2a4 |
+ DIV_ROUND_UP(nhdr.n_namesz, sizeof(Elf64_Word))*
|
|
|
4eb2a4 |
+ sizeof(Elf64_Word);
|
|
|
4eb2a4 |
+ *len = nhdr.n_descsz;
|
|
|
4eb2a4 |
+
|
|
|
4eb2a4 |
+ if (CRASHDEBUG(1)) {
|
|
|
4eb2a4 |
+ fprintf(fp, "vmcoreinfo addr=%lx\n", *addr);
|
|
|
4eb2a4 |
+ fprintf(fp, "vmcoreinfo len=%d\n", *len);
|
|
|
4eb2a4 |
+ }
|
|
|
4eb2a4 |
+
|
|
|
4eb2a4 |
+ return TRUE;
|
|
|
4eb2a4 |
+}
|
|
|
4eb2a4 |
+
|
|
|
4eb2a4 |
+/*
|
|
|
4eb2a4 |
+ * Check if current kaslr_offset/phys_base is for 1st kernel or 2nd kernel.
|
|
|
4eb2a4 |
+ * If we are in 2nd kernel, get kaslr_offset/phys_base from vmcoreinfo.
|
|
|
4eb2a4 |
+ *
|
|
|
4eb2a4 |
+ * 1. Get command line and try to retrieve "elfcorehdr=" boot parameter
|
|
|
4eb2a4 |
+ * 2. If "elfcorehdr=" is not found in command line, we are in 1st kernel.
|
|
|
4eb2a4 |
+ * There is nothing to do.
|
|
|
4eb2a4 |
+ * 3. If "elfcorehdr=" is found, we are in 2nd kernel. Find vmcoreinfo
|
|
|
4eb2a4 |
+ * using "elfcorehdr=" and retrieve kaslr_offset/phys_base from vmcoreinfo.
|
|
|
4eb2a4 |
+ */
|
|
|
4eb2a4 |
+static int
|
|
|
4eb2a4 |
+get_kaslr_offset_from_vmcoreinfo(ulong cr3, ulong orig_kaslr_offset,
|
|
|
4eb2a4 |
+ ulong *kaslr_offset, ulong *phys_base)
|
|
|
4eb2a4 |
+{
|
|
|
4eb2a4 |
+ ulong elfcorehdr_addr = 0;
|
|
|
4eb2a4 |
+ ulong vmcoreinfo_addr;
|
|
|
4eb2a4 |
+ int vmcoreinfo_len;
|
|
|
4eb2a4 |
+ char *buf, *pos;
|
|
|
4eb2a4 |
+ int ret = FALSE;
|
|
|
4eb2a4 |
+
|
|
|
4eb2a4 |
+ /* Find "elfcorehdr=" in the kernel boot parameter */
|
|
|
4eb2a4 |
+ elfcorehdr_addr = get_elfcorehdr(cr3, orig_kaslr_offset);
|
|
|
4eb2a4 |
+ if (!elfcorehdr_addr)
|
|
|
4eb2a4 |
+ return FALSE;
|
|
|
4eb2a4 |
+
|
|
|
4eb2a4 |
+ /* Get vmcoreinfo from the address of "elfcorehdr=" */
|
|
|
4eb2a4 |
+ if (!get_vmcoreinfo(elfcorehdr_addr, &vmcoreinfo_addr, &vmcoreinfo_len))
|
|
|
4eb2a4 |
+ return FALSE;
|
|
|
4eb2a4 |
+
|
|
|
4eb2a4 |
+ if (!vmcoreinfo_len)
|
|
|
4eb2a4 |
+ return FALSE;
|
|
|
4eb2a4 |
+
|
|
|
4eb2a4 |
+ if (CRASHDEBUG(1))
|
|
|
4eb2a4 |
+ fprintf(fp, "Find vmcoreinfo in kdump memory\n");
|
|
|
4eb2a4 |
+
|
|
|
4eb2a4 |
+ buf = GETBUF(vmcoreinfo_len);
|
|
|
4eb2a4 |
+ if (!readmem(vmcoreinfo_addr, PHYSADDR, buf, vmcoreinfo_len,
|
|
|
4eb2a4 |
+ "vmcoreinfo", RETURN_ON_ERROR))
|
|
|
4eb2a4 |
+ goto quit;
|
|
|
4eb2a4 |
+
|
|
|
4eb2a4 |
+ /* Get phys_base form vmcoreinfo */
|
|
|
4eb2a4 |
+ pos = strstr(buf, "NUMBER(phys_base)=");
|
|
|
4eb2a4 |
+ if (!pos)
|
|
|
4eb2a4 |
+ goto quit;
|
|
|
4eb2a4 |
+ *phys_base = strtoull(pos + strlen("NUMBER(phys_base)="), NULL, 0);
|
|
|
4eb2a4 |
+
|
|
|
4eb2a4 |
+ /* Get kaslr_offset form vmcoreinfo */
|
|
|
4eb2a4 |
+ pos = strstr(buf, "KERNELOFFSET=");
|
|
|
4eb2a4 |
+ if (!pos)
|
|
|
4eb2a4 |
+ goto quit;
|
|
|
4eb2a4 |
+ *kaslr_offset = strtoull(pos + strlen("KERNELOFFSET="), NULL, 16);
|
|
|
4eb2a4 |
+
|
|
|
4eb2a4 |
+ ret = TRUE;
|
|
|
4eb2a4 |
+
|
|
|
4eb2a4 |
+quit:
|
|
|
4eb2a4 |
+ FREEBUF(buf);
|
|
|
4eb2a4 |
+ return ret;
|
|
|
4eb2a4 |
+}
|
|
|
4eb2a4 |
+
|
|
|
4eb2a4 |
+/*
|
|
|
4eb2a4 |
+ * Calculate kaslr_offset and phys_base
|
|
|
4eb2a4 |
+ *
|
|
|
4eb2a4 |
+ * kaslr_offset:
|
|
|
4eb2a4 |
+ * The difference between original address in System.map or vmlinux and
|
|
|
4eb2a4 |
+ * actual address placed randomly by kaslr feature. To be more accurate,
|
|
|
4eb2a4 |
+ * kaslr_offset = actual address - original address
|
|
|
4eb2a4 |
+ *
|
|
|
4eb2a4 |
+ * phys_base:
|
|
|
4eb2a4 |
+ * Physical address where the kerenel is placed. In other words, it's a
|
|
|
4eb2a4 |
+ * physical address of __START_KERNEL_map. This is also decided randomly by
|
|
|
4eb2a4 |
+ * kaslr.
|
|
|
4eb2a4 |
+ *
|
|
|
4eb2a4 |
+ * kaslr offset and phys_base are calculated as follows:
|
|
|
4eb2a4 |
+ *
|
|
|
4eb2a4 |
+ * kaslr_offset:
|
|
|
4eb2a4 |
+ * 1) Get IDTR and CR3 value from the dump header.
|
|
|
4eb2a4 |
+ * 2) Get a virtual address of IDT from IDTR value
|
|
|
4eb2a4 |
+ * --- (A)
|
|
|
4eb2a4 |
+ * 3) Translate (A) to physical address using CR3, which points a top of
|
|
|
4eb2a4 |
+ * page table.
|
|
|
4eb2a4 |
+ * --- (B)
|
|
|
4eb2a4 |
+ * 4) Get an address of vector0 (Devide Error) interrupt handler from
|
|
|
4eb2a4 |
+ * IDT, which are pointed by (B).
|
|
|
4eb2a4 |
+ * --- (C)
|
|
|
4eb2a4 |
+ * 5) Get an address of symbol "divide_error" form vmlinux
|
|
|
4eb2a4 |
+ * --- (D)
|
|
|
4eb2a4 |
+ *
|
|
|
4eb2a4 |
+ * Now we have two addresses:
|
|
|
4eb2a4 |
+ * (C)-> Actual address of "divide_error"
|
|
|
4eb2a4 |
+ * (D)-> Original address of "divide_error" in the vmlinux
|
|
|
4eb2a4 |
+ *
|
|
|
4eb2a4 |
+ * kaslr_offset can be calculated by the difference between these two
|
|
|
4eb2a4 |
+ * value.
|
|
|
4eb2a4 |
+ *
|
|
|
4eb2a4 |
+ * phys_base;
|
|
|
4eb2a4 |
+ * 1) Get IDT virtual address from vmlinux
|
|
|
4eb2a4 |
+ * --- (E)
|
|
|
4eb2a4 |
+ *
|
|
|
4eb2a4 |
+ * So phys_base can be calculated using relationship of directly mapped
|
|
|
4eb2a4 |
+ * address.
|
|
|
4eb2a4 |
+ *
|
|
|
4eb2a4 |
+ * phys_base =
|
|
|
4eb2a4 |
+ * Physical address(B) -
|
|
|
4eb2a4 |
+ * (Virtual address(E) + kaslr_offset - __START_KERNEL_map)
|
|
|
4eb2a4 |
+ *
|
|
|
4eb2a4 |
+ * Note that the address (A) cannot be used instead of (E) because (A) is
|
|
|
4eb2a4 |
+ * not direct map address, it's a fixed map address.
|
|
|
4eb2a4 |
+ *
|
|
|
4eb2a4 |
+ * This solution works in most every case, but does not work in the
|
|
|
4eb2a4 |
+ * following case.
|
|
|
4eb2a4 |
+ *
|
|
|
4eb2a4 |
+ * 1) If the dump is captured on early stage of kernel boot, IDTR points
|
|
|
4eb2a4 |
+ * early IDT table(early_idts) instead of normal IDT(idt_table).
|
|
|
4eb2a4 |
+ * 2) If the dump is captured whle kdump is working, IDTR points
|
|
|
4eb2a4 |
+ * IDT table of 2nd kernel, not 1st kernel.
|
|
|
4eb2a4 |
+ *
|
|
|
4eb2a4 |
+ * Current implementation does not support the case 1), need
|
|
|
4eb2a4 |
+ * enhancement in the future. For the case 2), get kaslr_offset and
|
|
|
4eb2a4 |
+ * phys_base as follows.
|
|
|
4eb2a4 |
+ *
|
|
|
4eb2a4 |
+ * 1) Get kaslr_offset and phys_base using the above solution.
|
|
|
4eb2a4 |
+ * 2) Get kernel boot parameter from "saved_command_line"
|
|
|
4eb2a4 |
+ * 3) If "elfcorehdr=" is not included in boot parameter, we are in the
|
|
|
4eb2a4 |
+ * first kernel, nothing to do any more.
|
|
|
4eb2a4 |
+ * 4) If "elfcorehdr=" is included in boot parameter, we are in the 2nd
|
|
|
4eb2a4 |
+ * kernel. Retrieve vmcoreinfo from address of "elfcorehdr=" and
|
|
|
4eb2a4 |
+ * get kaslr_offset and phys_base from vmcoreinfo.
|
|
|
4eb2a4 |
+ */
|
|
|
4eb2a4 |
+int
|
|
|
4eb2a4 |
+sadump_calc_kaslr_offset(ulong *kaslr_offset)
|
|
|
4eb2a4 |
+{
|
|
|
4eb2a4 |
+ ulong phys_base = 0;
|
|
|
4eb2a4 |
+ struct sadump_smram_cpu_state scs;
|
|
|
4eb2a4 |
+ uint64_t idtr = 0, cr3 = 0, idtr_paddr;
|
|
|
4eb2a4 |
+ ulong divide_error_vmcore;
|
|
|
4eb2a4 |
+ ulong kaslr_offset_kdump, phys_base_kdump;
|
|
|
4eb2a4 |
+ int ret = FALSE;
|
|
|
4eb2a4 |
+ int verbose = CRASHDEBUG(1)? 1: 0;
|
|
|
4eb2a4 |
+
|
|
|
4eb2a4 |
+ if (!machine_type("X86_64"))
|
|
|
4eb2a4 |
+ return FALSE;
|
|
|
4eb2a4 |
+
|
|
|
4eb2a4 |
+ memset(&scs, 0, sizeof(scs));
|
|
|
4eb2a4 |
+ get_sadump_smram_cpu_state_any(&scs);
|
|
|
4eb2a4 |
+ cr3 = scs.Cr3;
|
|
|
4eb2a4 |
+ idtr = ((uint64_t)scs.IdtUpper)<<32 | (uint64_t)scs.IdtLower;
|
|
|
4eb2a4 |
+
|
|
|
4eb2a4 |
+ /*
|
|
|
4eb2a4 |
+ * Set up for kvtop.
|
|
|
4eb2a4 |
+ *
|
|
|
4eb2a4 |
+ * calc_kaslr_offset() is called before machdep_init(PRE_GDB), so some
|
|
|
4eb2a4 |
+ * variables are not initialized yet. Set up them here to call kvtop().
|
|
|
4eb2a4 |
+ *
|
|
|
4eb2a4 |
+ * TODO: XEN and 5-level is not supported
|
|
|
4eb2a4 |
+ */
|
|
|
4eb2a4 |
+ vt->kernel_pgd[0] = cr3;
|
|
|
4eb2a4 |
+ machdep->machspec->last_pml4_read = vt->kernel_pgd[0];
|
|
|
4eb2a4 |
+ machdep->machspec->physical_mask_shift = __PHYSICAL_MASK_SHIFT_2_6;
|
|
|
4eb2a4 |
+ machdep->machspec->pgdir_shift = PGDIR_SHIFT;
|
|
|
4eb2a4 |
+ if (!readmem(cr3, PHYSADDR, machdep->machspec->pml4, PAGESIZE(),
|
|
|
4eb2a4 |
+ "cr3", RETURN_ON_ERROR))
|
|
|
4eb2a4 |
+ goto quit;
|
|
|
4eb2a4 |
+
|
|
|
4eb2a4 |
+ /* Convert virtual address of IDT table to physical address */
|
|
|
4eb2a4 |
+ if (!kvtop(NULL, idtr, &idtr_paddr, verbose))
|
|
|
4eb2a4 |
+ goto quit;
|
|
|
4eb2a4 |
+
|
|
|
4eb2a4 |
+ /* Now we can calculate kaslr_offset and phys_base */
|
|
|
4eb2a4 |
+ divide_error_vmcore = get_vec0_addr(idtr_paddr);
|
|
|
4eb2a4 |
+ *kaslr_offset = divide_error_vmcore - st->divide_error_vmlinux;
|
|
|
4eb2a4 |
+ phys_base = idtr_paddr -
|
|
|
4eb2a4 |
+ (st->idt_table_vmlinux + *kaslr_offset - __START_KERNEL_map);
|
|
|
4eb2a4 |
+
|
|
|
4eb2a4 |
+ if (CRASHDEBUG(1)) {
|
|
|
4eb2a4 |
+ fprintf(fp, "calc_kaslr_offset: idtr=%lx\n", idtr);
|
|
|
4eb2a4 |
+ fprintf(fp, "calc_kaslr_offset: cr3=%lx\n", cr3);
|
|
|
4eb2a4 |
+ fprintf(fp, "calc_kaslr_offset: idtr(phys)=%lx\n", idtr_paddr);
|
|
|
4eb2a4 |
+ fprintf(fp, "calc_kaslr_offset: divide_error(vmlinux): %lx\n",
|
|
|
4eb2a4 |
+ st->divide_error_vmlinux);
|
|
|
4eb2a4 |
+ fprintf(fp, "calc_kaslr_offset: divide_error(vmcore): %lx\n",
|
|
|
4eb2a4 |
+ divide_error_vmcore);
|
|
|
4eb2a4 |
+ }
|
|
|
4eb2a4 |
+
|
|
|
4eb2a4 |
+ /*
|
|
|
4eb2a4 |
+ * Check if current kaslr_offset/phys_base is for 1st kernel or 2nd
|
|
|
4eb2a4 |
+ * kernel. If we are in 2nd kernel, get kaslr_offset/phys_base
|
|
|
4eb2a4 |
+ * from vmcoreinfo
|
|
|
4eb2a4 |
+ */
|
|
|
4eb2a4 |
+ if (get_kaslr_offset_from_vmcoreinfo(
|
|
|
4eb2a4 |
+ cr3, *kaslr_offset, &kaslr_offset_kdump, &phys_base_kdump)) {
|
|
|
4eb2a4 |
+ *kaslr_offset = kaslr_offset_kdump;
|
|
|
4eb2a4 |
+ phys_base = phys_base_kdump;
|
|
|
4eb2a4 |
+ }
|
|
|
4eb2a4 |
+
|
|
|
4eb2a4 |
+ if (CRASHDEBUG(1)) {
|
|
|
4eb2a4 |
+ fprintf(fp, "calc_kaslr_offset: kaslr_offset=%lx\n",
|
|
|
4eb2a4 |
+ *kaslr_offset);
|
|
|
4eb2a4 |
+ fprintf(fp, "calc_kaslr_offset: phys_base=%lx\n", phys_base);
|
|
|
4eb2a4 |
+ }
|
|
|
4eb2a4 |
+
|
|
|
4eb2a4 |
+ sd->phys_base = phys_base;
|
|
|
4eb2a4 |
+ ret = TRUE;
|
|
|
4eb2a4 |
+quit:
|
|
|
4eb2a4 |
+ vt->kernel_pgd[0] = 0;
|
|
|
4eb2a4 |
+ machdep->machspec->last_pml4_read = 0;
|
|
|
4eb2a4 |
+ return ret;
|
|
|
4eb2a4 |
+}
|
|
|
4eb2a4 |
+#else
|
|
|
4eb2a4 |
+int
|
|
|
4eb2a4 |
+sadump_calc_kaslr_offset(ulong *kaslr_offset)
|
|
|
4eb2a4 |
+{
|
|
|
4eb2a4 |
+ return FALSE;
|
|
|
4eb2a4 |
+}
|
|
|
4eb2a4 |
+#endif /* X86_64 */
|
|
|
4eb2a4 |
diff --git a/sadump.h b/sadump.h
|
|
|
4eb2a4 |
index 7f8e384..681f5e4 100644
|
|
|
4eb2a4 |
--- a/sadump.h
|
|
|
4eb2a4 |
+++ b/sadump.h
|
|
|
4eb2a4 |
@@ -219,6 +219,7 @@ struct sadump_data {
|
|
|
4eb2a4 |
ulonglong backup_offset;
|
|
|
4eb2a4 |
|
|
|
4eb2a4 |
uint64_t max_mapnr;
|
|
|
4eb2a4 |
+ ulong phys_base;
|
|
|
4eb2a4 |
};
|
|
|
4eb2a4 |
|
|
|
4eb2a4 |
struct sadump_data *sadump_get_sadump_data(void);
|
|
|
4eb2a4 |
diff --git a/symbols.c b/symbols.c
|
|
|
4eb2a4 |
index 02cb34e..b2f2796 100644
|
|
|
4eb2a4 |
--- a/symbols.c
|
|
|
4eb2a4 |
+++ b/symbols.c
|
|
|
4eb2a4 |
@@ -624,6 +624,9 @@ kaslr_init(void)
|
|
|
4eb2a4 |
st->_stext_vmlinux = UNINITIALIZED;
|
|
|
4eb2a4 |
}
|
|
|
4eb2a4 |
}
|
|
|
4eb2a4 |
+
|
|
|
4eb2a4 |
+ if (SADUMP_DUMPFILE())
|
|
|
4eb2a4 |
+ kt->flags2 |= KASLR_CHECK;
|
|
|
4eb2a4 |
}
|
|
|
4eb2a4 |
|
|
|
4eb2a4 |
/*
|
|
|
4eb2a4 |
@@ -637,6 +640,19 @@ derive_kaslr_offset(bfd *abfd, int dynamic, bfd_byte *start, bfd_byte *end,
|
|
|
4eb2a4 |
unsigned long relocate;
|
|
|
4eb2a4 |
ulong _stext_relocated;
|
|
|
4eb2a4 |
|
|
|
4eb2a4 |
+ if (SADUMP_DUMPFILE()) {
|
|
|
4eb2a4 |
+ ulong kaslr_offset = 0;
|
|
|
4eb2a4 |
+
|
|
|
4eb2a4 |
+ sadump_calc_kaslr_offset(&kaslr_offset);
|
|
|
4eb2a4 |
+
|
|
|
4eb2a4 |
+ if (kaslr_offset) {
|
|
|
4eb2a4 |
+ kt->relocate = kaslr_offset * -1;
|
|
|
4eb2a4 |
+ kt->flags |= RELOC_SET;
|
|
|
4eb2a4 |
+ }
|
|
|
4eb2a4 |
+
|
|
|
4eb2a4 |
+ return;
|
|
|
4eb2a4 |
+ }
|
|
|
4eb2a4 |
+
|
|
|
4eb2a4 |
if (ACTIVE()) {
|
|
|
4eb2a4 |
_stext_relocated = symbol_value_from_proc_kallsyms("_stext");
|
|
|
4eb2a4 |
if (_stext_relocated == BADVAL)
|
|
|
4eb2a4 |
@@ -3052,6 +3068,16 @@ dump_symbol_table(void)
|
|
|
4eb2a4 |
else
|
|
|
4eb2a4 |
fprintf(fp, "\n");
|
|
|
4eb2a4 |
|
|
|
4eb2a4 |
+ if (SADUMP_DUMPFILE()) {
|
|
|
4eb2a4 |
+ fprintf(fp, "divide_error_vmlinux: %lx\n", st->divide_error_vmlinux);
|
|
|
4eb2a4 |
+ fprintf(fp, " idt_table_vmlinux: %lx\n", st->idt_table_vmlinux);
|
|
|
4eb2a4 |
+ fprintf(fp, "saved_command_line_vmlinux: %lx\n", st->saved_command_line_vmlinux);
|
|
|
4eb2a4 |
+ } else {
|
|
|
4eb2a4 |
+ fprintf(fp, "divide_error_vmlinux: (unused)\n");
|
|
|
4eb2a4 |
+ fprintf(fp, " idt_table_vmlinux: (unused)\n");
|
|
|
4eb2a4 |
+ fprintf(fp, "saved_command_line_vmlinux: (unused)\n");
|
|
|
4eb2a4 |
+ }
|
|
|
4eb2a4 |
+
|
|
|
4eb2a4 |
fprintf(fp, " symval_hash[%d]: %lx\n", SYMVAL_HASH,
|
|
|
4eb2a4 |
(ulong)&st->symval_hash[0]);
|
|
|
4eb2a4 |
|
|
|
4eb2a4 |
@@ -12246,6 +12272,24 @@ numeric_forward(const void *P_x, const void *P_y)
|
|
|
4eb2a4 |
}
|
|
|
4eb2a4 |
}
|
|
|
4eb2a4 |
|
|
|
4eb2a4 |
+ if (SADUMP_DUMPFILE()) {
|
|
|
4eb2a4 |
+ /* Need for kaslr_offset and phys_base */
|
|
|
4eb2a4 |
+ if (STREQ(x->name, "divide_error"))
|
|
|
4eb2a4 |
+ st->divide_error_vmlinux = valueof(x);
|
|
|
4eb2a4 |
+ else if (STREQ(y->name, "divide_error"))
|
|
|
4eb2a4 |
+ st->divide_error_vmlinux = valueof(y);
|
|
|
4eb2a4 |
+
|
|
|
4eb2a4 |
+ if (STREQ(x->name, "idt_table"))
|
|
|
4eb2a4 |
+ st->idt_table_vmlinux = valueof(x);
|
|
|
4eb2a4 |
+ else if (STREQ(y->name, "idt_table"))
|
|
|
4eb2a4 |
+ st->idt_table_vmlinux = valueof(y);
|
|
|
4eb2a4 |
+
|
|
|
4eb2a4 |
+ if (STREQ(x->name, "saved_command_line"))
|
|
|
4eb2a4 |
+ st->saved_command_line_vmlinux = valueof(x);
|
|
|
4eb2a4 |
+ else if (STREQ(y->name, "saved_command_line"))
|
|
|
4eb2a4 |
+ st->saved_command_line_vmlinux = valueof(y);
|
|
|
4eb2a4 |
+ }
|
|
|
4eb2a4 |
+
|
|
|
4eb2a4 |
xs = bfd_get_section(x);
|
|
|
4eb2a4 |
ys = bfd_get_section(y);
|
|
|
4eb2a4 |
|
|
|
4eb2a4 |
diff --git a/x86_64.c b/x86_64.c
|
|
|
4eb2a4 |
index 6e60dda..2f9e6db 100644
|
|
|
4eb2a4 |
--- a/x86_64.c
|
|
|
4eb2a4 |
+++ b/x86_64.c
|
|
|
4eb2a4 |
@@ -194,6 +194,9 @@ x86_64_init(int when)
|
|
|
4eb2a4 |
machdep->machspec->kernel_image_size = dtol(string, QUIET, NULL);
|
|
|
4eb2a4 |
free(string);
|
|
|
4eb2a4 |
}
|
|
|
4eb2a4 |
+ if (SADUMP_DUMPFILE())
|
|
|
4eb2a4 |
+ /* Need for calculation of kaslr_offset and phys_base */
|
|
|
4eb2a4 |
+ machdep->kvtop = x86_64_kvtop;
|
|
|
4eb2a4 |
break;
|
|
|
4eb2a4 |
|
|
|
4eb2a4 |
case PRE_GDB:
|
|
|
4eb2a4 |
@@ -2019,6 +2022,22 @@ x86_64_kvtop(struct task_context *tc, ulong kvaddr, physaddr_t *paddr, int verbo
|
|
|
4eb2a4 |
ulong pte;
|
|
|
4eb2a4 |
physaddr_t physpage;
|
|
|
4eb2a4 |
|
|
|
4eb2a4 |
+ if (SADUMP_DUMPFILE() && !(machdep->flags & KSYMS_START)) {
|
|
|
4eb2a4 |
+ /*
|
|
|
4eb2a4 |
+ * In the case of sadump, to calculate kaslr_offset and
|
|
|
4eb2a4 |
+ * phys_base, kvtop is called during symtab_init(). In this
|
|
|
4eb2a4 |
+ * stage phys_base is not initialized yet and x86_64_VTOP()
|
|
|
4eb2a4 |
+ * does not work. Jump to the code of pagetable translation.
|
|
|
4eb2a4 |
+ */
|
|
|
4eb2a4 |
+ FILL_PML4();
|
|
|
4eb2a4 |
+ pml4 = ((ulong *)machdep->machspec->pml4) + pml4_index(kvaddr);
|
|
|
4eb2a4 |
+ if (verbose) {
|
|
|
4eb2a4 |
+ fprintf(fp, "PML4 DIRECTORY: %lx\n", vt->kernel_pgd[0]);
|
|
|
4eb2a4 |
+ fprintf(fp, "PAGE DIRECTORY: %lx\n", *pml4);
|
|
|
4eb2a4 |
+ }
|
|
|
4eb2a4 |
+ goto start_vtop_with_pagetable;
|
|
|
4eb2a4 |
+ }
|
|
|
4eb2a4 |
+
|
|
|
4eb2a4 |
if (!IS_KVADDR(kvaddr))
|
|
|
4eb2a4 |
return FALSE;
|
|
|
4eb2a4 |
|
|
|
4eb2a4 |
@@ -2065,6 +2084,8 @@ x86_64_kvtop(struct task_context *tc, ulong kvaddr, physaddr_t *paddr, int verbo
|
|
|
4eb2a4 |
fprintf(fp, "PAGE DIRECTORY: %lx\n", *pml4);
|
|
|
4eb2a4 |
}
|
|
|
4eb2a4 |
}
|
|
|
4eb2a4 |
+
|
|
|
4eb2a4 |
+start_vtop_with_pagetable:
|
|
|
4eb2a4 |
if (!(*pml4) & _PAGE_PRESENT)
|
|
|
4eb2a4 |
goto no_kpage;
|
|
|
4eb2a4 |
pgd_paddr = (*pml4) & PHYSICAL_PAGE_MASK;
|
|
|
4eb2a4 |
|
|
|
4eb2a4 |
commit 4550bf32a5ec1d9b7b6d5099aaee6e8e363a7827
|
|
|
4eb2a4 |
Author: Dave Anderson <anderson@redhat.com>
|
|
|
4eb2a4 |
Date: Wed Oct 25 11:04:53 2017 -0400
|
|
|
4eb2a4 |
|
|
|
4eb2a4 |
Implemented a new "ps -y policy" option to filter the task display
|
|
|
4eb2a4 |
by scheduling policy. Applicable to both standalone ps invocation
|
|
|
4eb2a4 |
as well as via foreach.
|
|
|
4eb2a4 |
(oleksandr@redhat.com)
|
|
|
4eb2a4 |
|
|
|
4eb2a4 |
diff --git a/defs.h b/defs.h
|
|
|
4eb2a4 |
index 76e5512..4b4e331 100644
|
|
|
4eb2a4 |
--- a/defs.h
|
|
|
4eb2a4 |
+++ b/defs.h
|
|
|
4eb2a4 |
@@ -1139,6 +1139,7 @@ extern struct machdep_table *machdep;
|
|
|
4eb2a4 |
#define FOREACH_a_FLAG (0x4000000)
|
|
|
4eb2a4 |
#define FOREACH_G_FLAG (0x8000000)
|
|
|
4eb2a4 |
#define FOREACH_F_FLAG2 (0x10000000)
|
|
|
4eb2a4 |
+#define FOREACH_y_FLAG (0x20000000)
|
|
|
4eb2a4 |
|
|
|
4eb2a4 |
#define FOREACH_PS_EXCLUSIVE \
|
|
|
4eb2a4 |
(FOREACH_g_FLAG|FOREACH_a_FLAG|FOREACH_t_FLAG|FOREACH_c_FLAG|FOREACH_p_FLAG|FOREACH_l_FLAG|FOREACH_r_FLAG|FOREACH_m_FLAG)
|
|
|
4eb2a4 |
@@ -1162,6 +1163,7 @@ struct foreach_data {
|
|
|
4eb2a4 |
int comms;
|
|
|
4eb2a4 |
int args;
|
|
|
4eb2a4 |
int regexs;
|
|
|
4eb2a4 |
+ int policy;
|
|
|
4eb2a4 |
};
|
|
|
4eb2a4 |
|
|
|
4eb2a4 |
struct reference {
|
|
|
4eb2a4 |
@@ -1992,6 +1994,7 @@ struct offset_table { /* stash of commonly-used offsets */
|
|
|
4eb2a4 |
long mod_arch_specific_num_orcs;
|
|
|
4eb2a4 |
long mod_arch_specific_orc_unwind_ip;
|
|
|
4eb2a4 |
long mod_arch_specific_orc_unwind;
|
|
|
4eb2a4 |
+ long task_struct_policy;
|
|
|
4eb2a4 |
};
|
|
|
4eb2a4 |
|
|
|
4eb2a4 |
struct size_table { /* stash of commonly-used sizes */
|
|
|
4eb2a4 |
@@ -2141,6 +2144,7 @@ struct size_table { /* stash of commonly-used sizes */
|
|
|
4eb2a4 |
long sk_buff_head_qlen;
|
|
|
4eb2a4 |
long sk_buff_len;
|
|
|
4eb2a4 |
long orc_entry;
|
|
|
4eb2a4 |
+ long task_struct_policy;
|
|
|
4eb2a4 |
};
|
|
|
4eb2a4 |
|
|
|
4eb2a4 |
struct array_table {
|
|
|
4eb2a4 |
@@ -4576,6 +4580,13 @@ enum type_code {
|
|
|
4eb2a4 |
*/
|
|
|
4eb2a4 |
#define PF_EXITING 0x00000004 /* getting shut down */
|
|
|
4eb2a4 |
#define PF_KTHREAD 0x00200000 /* I am a kernel thread */
|
|
|
4eb2a4 |
+#define SCHED_NORMAL 0
|
|
|
4eb2a4 |
+#define SCHED_FIFO 1
|
|
|
4eb2a4 |
+#define SCHED_RR 2
|
|
|
4eb2a4 |
+#define SCHED_BATCH 3
|
|
|
4eb2a4 |
+#define SCHED_ISO 4
|
|
|
4eb2a4 |
+#define SCHED_IDLE 5
|
|
|
4eb2a4 |
+#define SCHED_DEADLINE 6
|
|
|
4eb2a4 |
|
|
|
4eb2a4 |
extern long _ZOMBIE_;
|
|
|
4eb2a4 |
#define IS_ZOMBIE(task) (task_state(task) & _ZOMBIE_)
|
|
|
4eb2a4 |
@@ -4603,6 +4614,7 @@ extern long _ZOMBIE_;
|
|
|
4eb2a4 |
#define PS_NO_HEADER (0x10000)
|
|
|
4eb2a4 |
#define PS_MSECS (0x20000)
|
|
|
4eb2a4 |
#define PS_SUMMARY (0x40000)
|
|
|
4eb2a4 |
+#define PS_POLICY (0x80000)
|
|
|
4eb2a4 |
|
|
|
4eb2a4 |
#define PS_EXCLUSIVE (PS_TGID_LIST|PS_ARGV_ENVP|PS_TIMES|PS_CHILD_LIST|PS_PPID_LIST|PS_LAST_RUN|PS_RLIMIT|PS_MSECS|PS_SUMMARY)
|
|
|
4eb2a4 |
|
|
|
4eb2a4 |
@@ -4620,6 +4632,7 @@ struct psinfo {
|
|
|
4eb2a4 |
} regex_data[MAX_PS_ARGS];
|
|
|
4eb2a4 |
int regexs;
|
|
|
4eb2a4 |
ulong *cpus;
|
|
|
4eb2a4 |
+ int policy;
|
|
|
4eb2a4 |
};
|
|
|
4eb2a4 |
|
|
|
4eb2a4 |
#define IS_A_NUMBER(X) (decimal(X, 0) || hexadecimal(X, 0))
|
|
|
4eb2a4 |
@@ -4823,7 +4836,7 @@ char *strip_ending_char(char *, char);
|
|
|
4eb2a4 |
char *strip_beginning_char(char *, char);
|
|
|
4eb2a4 |
char *strip_comma(char *);
|
|
|
4eb2a4 |
char *strip_hex(char *);
|
|
|
4eb2a4 |
-char *upper_case(char *, char *);
|
|
|
4eb2a4 |
+char *upper_case(const char *, char *);
|
|
|
4eb2a4 |
char *first_nonspace(char *);
|
|
|
4eb2a4 |
char *first_space(char *);
|
|
|
4eb2a4 |
char *replace_string(char *, char *, char);
|
|
|
4eb2a4 |
diff --git a/help.c b/help.c
|
|
|
4eb2a4 |
index f9c5792..efa55e0 100644
|
|
|
4eb2a4 |
--- a/help.c
|
|
|
4eb2a4 |
+++ b/help.c
|
|
|
4eb2a4 |
@@ -844,7 +844,7 @@ char *help_foreach[] = {
|
|
|
4eb2a4 |
" net run the \"net\" command (optional flags: -s -S -R -d -x)",
|
|
|
4eb2a4 |
" set run the \"set\" command",
|
|
|
4eb2a4 |
" ps run the \"ps\" command (optional flags: -G -s -p -c -t -l -a",
|
|
|
4eb2a4 |
-" -g -r)",
|
|
|
4eb2a4 |
+" -g -r -y)",
|
|
|
4eb2a4 |
" sig run the \"sig\" command (optional flag: -g)",
|
|
|
4eb2a4 |
" vtop run the \"vtop\" command (optional flags: -c -u -k)\n",
|
|
|
4eb2a4 |
" flag Pass this optional flag to the command selected.",
|
|
|
4eb2a4 |
@@ -1250,7 +1250,7 @@ NULL
|
|
|
4eb2a4 |
char *help_ps[] = {
|
|
|
4eb2a4 |
"ps",
|
|
|
4eb2a4 |
"display process status information",
|
|
|
4eb2a4 |
-"[-k|-u|-G] [-s] [-p|-c|-t|-[l|m][-C cpu]|-a|-g|-r|-S]\n [pid | task | command] ...",
|
|
|
4eb2a4 |
+"[-k|-u|-G|-y policy] [-s] [-p|-c|-t|-[l|m][-C cpu]|-a|-g|-r|-S]\n [pid | task | command] ...",
|
|
|
4eb2a4 |
" This command displays process status for selected, or all, processes" ,
|
|
|
4eb2a4 |
" in the system. If no arguments are entered, the process data is",
|
|
|
4eb2a4 |
" is displayed for all processes. Specific processes may be selected",
|
|
|
4eb2a4 |
@@ -1267,6 +1267,16 @@ char *help_ps[] = {
|
|
|
4eb2a4 |
" -k restrict the output to only kernel threads.",
|
|
|
4eb2a4 |
" -u restrict the output to only user tasks.",
|
|
|
4eb2a4 |
" -G display only the thread group leader in a thread group.",
|
|
|
4eb2a4 |
+" -y policy restrict the output to tasks having a specified scheduling policy",
|
|
|
4eb2a4 |
+" expressed by its integer value or by its (case-insensitive) name;",
|
|
|
4eb2a4 |
+" multiple policies may be entered in a comma-separated list:",
|
|
|
4eb2a4 |
+" 0 or NORMAL",
|
|
|
4eb2a4 |
+" 1 or FIFO",
|
|
|
4eb2a4 |
+" 2 or RR",
|
|
|
4eb2a4 |
+" 3 or BATCH",
|
|
|
4eb2a4 |
+" 4 or ISO",
|
|
|
4eb2a4 |
+" 5 or IDLE",
|
|
|
4eb2a4 |
+" 6 or DEADLINE",
|
|
|
4eb2a4 |
" ",
|
|
|
4eb2a4 |
" The process identifier types may be mixed. For each task, the following",
|
|
|
4eb2a4 |
" items are displayed:",
|
|
|
4eb2a4 |
diff --git a/symbols.c b/symbols.c
|
|
|
4eb2a4 |
index b2f2796..f7599e8 100644
|
|
|
4eb2a4 |
--- a/symbols.c
|
|
|
4eb2a4 |
+++ b/symbols.c
|
|
|
4eb2a4 |
@@ -8584,6 +8584,8 @@ dump_offset_table(char *spec, ulong makestruct)
|
|
|
4eb2a4 |
OFFSET(task_struct_prio));
|
|
|
4eb2a4 |
fprintf(fp, " task_struct_on_rq: %ld\n",
|
|
|
4eb2a4 |
OFFSET(task_struct_on_rq));
|
|
|
4eb2a4 |
+ fprintf(fp, " task_struct_policy: %ld\n",
|
|
|
4eb2a4 |
+ OFFSET(task_struct_policy));
|
|
|
4eb2a4 |
|
|
|
4eb2a4 |
fprintf(fp, " thread_info_task: %ld\n",
|
|
|
4eb2a4 |
OFFSET(thread_info_task));
|
|
|
4eb2a4 |
@@ -10211,6 +10213,7 @@ dump_offset_table(char *spec, ulong makestruct)
|
|
|
4eb2a4 |
fprintf(fp, " pt_regs: %ld\n", SIZE(pt_regs));
|
|
|
4eb2a4 |
fprintf(fp, " task_struct: %ld\n", SIZE(task_struct));
|
|
|
4eb2a4 |
fprintf(fp, " task_struct_flags: %ld\n", SIZE(task_struct_flags));
|
|
|
4eb2a4 |
+ fprintf(fp, " task_struct_policy: %ld\n", SIZE(task_struct_policy));
|
|
|
4eb2a4 |
fprintf(fp, " thread_info: %ld\n", SIZE(thread_info));
|
|
|
4eb2a4 |
fprintf(fp, " softirq_state: %ld\n",
|
|
|
4eb2a4 |
SIZE(softirq_state));
|
|
|
4eb2a4 |
diff --git a/task.c b/task.c
|
|
|
4eb2a4 |
index 362822c..5754159 100644
|
|
|
4eb2a4 |
--- a/task.c
|
|
|
4eb2a4 |
+++ b/task.c
|
|
|
4eb2a4 |
@@ -109,6 +109,24 @@ static void show_ps_summary(ulong);
|
|
|
4eb2a4 |
static void irqstacks_init(void);
|
|
|
4eb2a4 |
static void parse_task_thread(int argcnt, char *arglist[], struct task_context *);
|
|
|
4eb2a4 |
static void stack_overflow_check_init(void);
|
|
|
4eb2a4 |
+static int has_sched_policy(ulong, ulong);
|
|
|
4eb2a4 |
+static ulong task_policy(ulong);
|
|
|
4eb2a4 |
+static ulong sched_policy_bit_from_str(const char *);
|
|
|
4eb2a4 |
+static ulong make_sched_policy(const char *);
|
|
|
4eb2a4 |
+
|
|
|
4eb2a4 |
+static struct sched_policy_info {
|
|
|
4eb2a4 |
+ ulong value;
|
|
|
4eb2a4 |
+ char *name;
|
|
|
4eb2a4 |
+} sched_policy_info[] = {
|
|
|
4eb2a4 |
+ { SCHED_NORMAL, "NORMAL" },
|
|
|
4eb2a4 |
+ { SCHED_FIFO, "FIFO" },
|
|
|
4eb2a4 |
+ { SCHED_RR, "RR" },
|
|
|
4eb2a4 |
+ { SCHED_BATCH, "BATCH" },
|
|
|
4eb2a4 |
+ { SCHED_ISO, "ISO" },
|
|
|
4eb2a4 |
+ { SCHED_IDLE, "IDLE" },
|
|
|
4eb2a4 |
+ { SCHED_DEADLINE, "DEADLINE" },
|
|
|
4eb2a4 |
+ { ULONG_MAX, NULL }
|
|
|
4eb2a4 |
+};
|
|
|
4eb2a4 |
|
|
|
4eb2a4 |
/*
|
|
|
4eb2a4 |
* Figure out how much space will be required to hold the task context
|
|
|
4eb2a4 |
@@ -273,6 +291,8 @@ task_init(void)
|
|
|
4eb2a4 |
MEMBER_OFFSET_INIT(task_struct_next_run, "task_struct", "next_run");
|
|
|
4eb2a4 |
MEMBER_OFFSET_INIT(task_struct_flags, "task_struct", "flags");
|
|
|
4eb2a4 |
MEMBER_SIZE_INIT(task_struct_flags, "task_struct", "flags");
|
|
|
4eb2a4 |
+ MEMBER_OFFSET_INIT(task_struct_policy, "task_struct", "policy");
|
|
|
4eb2a4 |
+ MEMBER_SIZE_INIT(task_struct_policy, "task_struct", "policy");
|
|
|
4eb2a4 |
MEMBER_OFFSET_INIT(task_struct_pidhash_next,
|
|
|
4eb2a4 |
"task_struct", "pidhash_next");
|
|
|
4eb2a4 |
MEMBER_OFFSET_INIT(task_struct_pgrp, "task_struct", "pgrp");
|
|
|
4eb2a4 |
@@ -2974,7 +2994,7 @@ cmd_ps(void)
|
|
|
4eb2a4 |
cpuspec = NULL;
|
|
|
4eb2a4 |
flag = 0;
|
|
|
4eb2a4 |
|
|
|
4eb2a4 |
- while ((c = getopt(argcnt, args, "SgstcpkuGlmarC:")) != EOF) {
|
|
|
4eb2a4 |
+ while ((c = getopt(argcnt, args, "SgstcpkuGlmarC:y:")) != EOF) {
|
|
|
4eb2a4 |
switch(c)
|
|
|
4eb2a4 |
{
|
|
|
4eb2a4 |
case 'k':
|
|
|
4eb2a4 |
@@ -3075,6 +3095,11 @@ cmd_ps(void)
|
|
|
4eb2a4 |
make_cpumask(cpuspec, psinfo.cpus, FAULT_ON_ERROR, NULL);
|
|
|
4eb2a4 |
break;
|
|
|
4eb2a4 |
|
|
|
4eb2a4 |
+ case 'y':
|
|
|
4eb2a4 |
+ flag |= PS_POLICY;
|
|
|
4eb2a4 |
+ psinfo.policy = make_sched_policy(optarg);
|
|
|
4eb2a4 |
+ break;
|
|
|
4eb2a4 |
+
|
|
|
4eb2a4 |
default:
|
|
|
4eb2a4 |
argerrs++;
|
|
|
4eb2a4 |
break;
|
|
|
4eb2a4 |
@@ -3218,6 +3243,8 @@ show_ps_data(ulong flag, struct task_context *tc, struct psinfo *psi)
|
|
|
4eb2a4 |
return;
|
|
|
4eb2a4 |
if ((flag & PS_KERNEL) && !is_kernel_thread(tc->task))
|
|
|
4eb2a4 |
return;
|
|
|
4eb2a4 |
+ if ((flag & PS_POLICY) && !has_sched_policy(tc->task, psi->policy))
|
|
|
4eb2a4 |
+ return;
|
|
|
4eb2a4 |
if (flag & PS_GROUP) {
|
|
|
4eb2a4 |
if (flag & (PS_LAST_RUN|PS_MSECS))
|
|
|
4eb2a4 |
error(FATAL, "-G not supported with -%c option\n",
|
|
|
4eb2a4 |
@@ -3336,7 +3363,7 @@ show_ps(ulong flag, struct psinfo *psi)
|
|
|
4eb2a4 |
|
|
|
4eb2a4 |
tc = FIRST_CONTEXT();
|
|
|
4eb2a4 |
for (i = 0; i < RUNNING_TASKS(); i++, tc++)
|
|
|
4eb2a4 |
- show_ps_data(flag, tc, NULL);
|
|
|
4eb2a4 |
+ show_ps_data(flag, tc, psi);
|
|
|
4eb2a4 |
|
|
|
4eb2a4 |
return;
|
|
|
4eb2a4 |
}
|
|
|
4eb2a4 |
@@ -3391,7 +3418,7 @@ show_ps(ulong flag, struct psinfo *psi)
|
|
|
4eb2a4 |
if (flag & PS_TIMES)
|
|
|
4eb2a4 |
show_task_times(tc, flag);
|
|
|
4eb2a4 |
else
|
|
|
4eb2a4 |
- show_ps_data(flag, tc, NULL);
|
|
|
4eb2a4 |
+ show_ps_data(flag, tc, psi);
|
|
|
4eb2a4 |
}
|
|
|
4eb2a4 |
}
|
|
|
4eb2a4 |
}
|
|
|
4eb2a4 |
@@ -3546,7 +3573,7 @@ show_milliseconds(struct task_context *tc, struct psinfo *psi)
|
|
|
4eb2a4 |
sprintf(format, "[%c%dll%c] ", '%', c,
|
|
|
4eb2a4 |
pc->output_radix == 10 ? 'u' : 'x');
|
|
|
4eb2a4 |
|
|
|
4eb2a4 |
- if (psi) {
|
|
|
4eb2a4 |
+ if (psi && psi->cpus) {
|
|
|
4eb2a4 |
for (c = others = 0; c < kt->cpus; c++) {
|
|
|
4eb2a4 |
if (!NUM_IN_BITMAP(psi->cpus, c))
|
|
|
4eb2a4 |
continue;
|
|
|
4eb2a4 |
@@ -5366,6 +5393,27 @@ task_flags(ulong task)
|
|
|
4eb2a4 |
}
|
|
|
4eb2a4 |
|
|
|
4eb2a4 |
/*
|
|
|
4eb2a4 |
+ * Return task's policy as bitmask bit.
|
|
|
4eb2a4 |
+ */
|
|
|
4eb2a4 |
+static ulong
|
|
|
4eb2a4 |
+task_policy(ulong task)
|
|
|
4eb2a4 |
+{
|
|
|
4eb2a4 |
+ ulong policy = 0;
|
|
|
4eb2a4 |
+
|
|
|
4eb2a4 |
+ fill_task_struct(task);
|
|
|
4eb2a4 |
+
|
|
|
4eb2a4 |
+ if (!tt->last_task_read)
|
|
|
4eb2a4 |
+ return policy;
|
|
|
4eb2a4 |
+
|
|
|
4eb2a4 |
+ if (SIZE(task_struct_policy) == sizeof(unsigned int))
|
|
|
4eb2a4 |
+ policy = 1 << UINT(tt->task_struct + OFFSET(task_struct_policy));
|
|
|
4eb2a4 |
+ else
|
|
|
4eb2a4 |
+ policy = 1 << ULONG(tt->task_struct + OFFSET(task_struct_policy));
|
|
|
4eb2a4 |
+
|
|
|
4eb2a4 |
+ return policy;
|
|
|
4eb2a4 |
+}
|
|
|
4eb2a4 |
+
|
|
|
4eb2a4 |
+/*
|
|
|
4eb2a4 |
* Return a task's tgid.
|
|
|
4eb2a4 |
*/
|
|
|
4eb2a4 |
ulong
|
|
|
4eb2a4 |
@@ -5797,7 +5845,7 @@ cmd_foreach(void)
|
|
|
4eb2a4 |
BZERO(&foreach_data, sizeof(struct foreach_data));
|
|
|
4eb2a4 |
fd = &foreach_data;
|
|
|
4eb2a4 |
|
|
|
4eb2a4 |
- while ((c = getopt(argcnt, args, "R:vomlgersStTpukcfFxhdaG")) != EOF) {
|
|
|
4eb2a4 |
+ while ((c = getopt(argcnt, args, "R:vomlgersStTpukcfFxhdaGy:")) != EOF) {
|
|
|
4eb2a4 |
switch(c)
|
|
|
4eb2a4 |
{
|
|
|
4eb2a4 |
case 'R':
|
|
|
4eb2a4 |
@@ -5892,6 +5940,11 @@ cmd_foreach(void)
|
|
|
4eb2a4 |
fd->flags |= FOREACH_G_FLAG;
|
|
|
4eb2a4 |
break;
|
|
|
4eb2a4 |
|
|
|
4eb2a4 |
+ case 'y':
|
|
|
4eb2a4 |
+ fd->flags |= FOREACH_y_FLAG;
|
|
|
4eb2a4 |
+ fd->policy = make_sched_policy(optarg);
|
|
|
4eb2a4 |
+ break;
|
|
|
4eb2a4 |
+
|
|
|
4eb2a4 |
default:
|
|
|
4eb2a4 |
argerrs++;
|
|
|
4eb2a4 |
break;
|
|
|
4eb2a4 |
@@ -6554,6 +6607,10 @@ foreach(struct foreach_data *fd)
|
|
|
4eb2a4 |
cmdflags |= PS_GROUP;
|
|
|
4eb2a4 |
if (fd->flags & FOREACH_s_FLAG)
|
|
|
4eb2a4 |
cmdflags |= PS_KSTACKP;
|
|
|
4eb2a4 |
+ if (fd->flags & FOREACH_y_FLAG) {
|
|
|
4eb2a4 |
+ cmdflags |= PS_POLICY;
|
|
|
4eb2a4 |
+ psinfo.policy = fd->policy;
|
|
|
4eb2a4 |
+ }
|
|
|
4eb2a4 |
/*
|
|
|
4eb2a4 |
* mutually exclusive flags
|
|
|
4eb2a4 |
*/
|
|
|
4eb2a4 |
@@ -7389,6 +7446,82 @@ is_kernel_thread(ulong task)
|
|
|
4eb2a4 |
}
|
|
|
4eb2a4 |
|
|
|
4eb2a4 |
/*
|
|
|
4eb2a4 |
+ * Checks if task policy corresponds to given mask.
|
|
|
4eb2a4 |
+ */
|
|
|
4eb2a4 |
+static int
|
|
|
4eb2a4 |
+has_sched_policy(ulong task, ulong policy)
|
|
|
4eb2a4 |
+{
|
|
|
4eb2a4 |
+ return !!(task_policy(task) & policy);
|
|
|
4eb2a4 |
+}
|
|
|
4eb2a4 |
+
|
|
|
4eb2a4 |
+/*
|
|
|
4eb2a4 |
+ * Converts sched policy name into mask bit.
|
|
|
4eb2a4 |
+ */
|
|
|
4eb2a4 |
+static ulong
|
|
|
4eb2a4 |
+sched_policy_bit_from_str(const char *policy_str)
|
|
|
4eb2a4 |
+{
|
|
|
4eb2a4 |
+ struct sched_policy_info *info = NULL;
|
|
|
4eb2a4 |
+ ulong policy = 0;
|
|
|
4eb2a4 |
+ int found = 0;
|
|
|
4eb2a4 |
+ char *upper = NULL;
|
|
|
4eb2a4 |
+ /*
|
|
|
4eb2a4 |
+ * Once kernel gets more than 10 scheduling policies,
|
|
|
4eb2a4 |
+ * sizes of these arrays should be adjusted
|
|
|
4eb2a4 |
+ */
|
|
|
4eb2a4 |
+ char digit[2] = { 0, 0 };
|
|
|
4eb2a4 |
+ char hex[4] = { 0, 0, 0, 0 };
|
|
|
4eb2a4 |
+
|
|
|
4eb2a4 |
+ upper = GETBUF(strlen(policy_str) + 1);
|
|
|
4eb2a4 |
+ upper_case(policy_str, upper);
|
|
|
4eb2a4 |
+
|
|
|
4eb2a4 |
+ for (info = sched_policy_info; info->name; info++) {
|
|
|
4eb2a4 |
+ snprintf(digit, sizeof digit, "%lu", info->value);
|
|
|
4eb2a4 |
+ /*
|
|
|
4eb2a4 |
+ * Not using %#lX format here since "0X" prefix
|
|
|
4eb2a4 |
+ * is not prepended if 0 value is given
|
|
|
4eb2a4 |
+ */
|
|
|
4eb2a4 |
+ snprintf(hex, sizeof hex, "0X%lX", info->value);
|
|
|
4eb2a4 |
+ if (strncmp(upper, info->name, strlen(info->name)) == 0 ||
|
|
|
4eb2a4 |
+ strncmp(upper, digit, sizeof digit) == 0 ||
|
|
|
4eb2a4 |
+ strncmp(upper, hex, sizeof hex) == 0) {
|
|
|
4eb2a4 |
+ policy = 1 << info->value;
|
|
|
4eb2a4 |
+ found = 1;
|
|
|
4eb2a4 |
+ break;
|
|
|
4eb2a4 |
+ }
|
|
|
4eb2a4 |
+ }
|
|
|
4eb2a4 |
+
|
|
|
4eb2a4 |
+ FREEBUF(upper);
|
|
|
4eb2a4 |
+
|
|
|
4eb2a4 |
+ if (!found)
|
|
|
4eb2a4 |
+ error(FATAL,
|
|
|
4eb2a4 |
+ "%s: invalid scheduling policy\n", policy_str);
|
|
|
4eb2a4 |
+
|
|
|
4eb2a4 |
+ return policy;
|
|
|
4eb2a4 |
+}
|
|
|
4eb2a4 |
+
|
|
|
4eb2a4 |
+/*
|
|
|
4eb2a4 |
+ * Converts sched policy string set into bitmask.
|
|
|
4eb2a4 |
+ */
|
|
|
4eb2a4 |
+static ulong
|
|
|
4eb2a4 |
+make_sched_policy(const char *policy_str)
|
|
|
4eb2a4 |
+{
|
|
|
4eb2a4 |
+ ulong policy = 0;
|
|
|
4eb2a4 |
+ char *iter = NULL;
|
|
|
4eb2a4 |
+ char *orig = NULL;
|
|
|
4eb2a4 |
+ char *cur = NULL;
|
|
|
4eb2a4 |
+
|
|
|
4eb2a4 |
+ iter = STRDUPBUF(policy_str);
|
|
|
4eb2a4 |
+ orig = iter;
|
|
|
4eb2a4 |
+
|
|
|
4eb2a4 |
+ while ((cur = strsep(&iter, ",")))
|
|
|
4eb2a4 |
+ policy |= sched_policy_bit_from_str(cur);
|
|
|
4eb2a4 |
+
|
|
|
4eb2a4 |
+ FREEBUF(orig);
|
|
|
4eb2a4 |
+
|
|
|
4eb2a4 |
+ return policy;
|
|
|
4eb2a4 |
+}
|
|
|
4eb2a4 |
+
|
|
|
4eb2a4 |
+/*
|
|
|
4eb2a4 |
* Gather an arry of pointers to the per-cpu idle tasks. The tasklist
|
|
|
4eb2a4 |
* argument must be at least the size of ulong[NR_CPUS]. There may be
|
|
|
4eb2a4 |
* junk in everything after the first entry on a single CPU box, so the
|
|
|
4eb2a4 |
diff --git a/tools.c b/tools.c
|
|
|
4eb2a4 |
index 886d7fb..186b703 100644
|
|
|
4eb2a4 |
--- a/tools.c
|
|
|
4eb2a4 |
+++ b/tools.c
|
|
|
4eb2a4 |
@@ -423,9 +423,10 @@ strip_hex(char *line)
|
|
|
4eb2a4 |
* Turn a string into upper-case.
|
|
|
4eb2a4 |
*/
|
|
|
4eb2a4 |
char *
|
|
|
4eb2a4 |
-upper_case(char *s, char *buf)
|
|
|
4eb2a4 |
+upper_case(const char *s, char *buf)
|
|
|
4eb2a4 |
{
|
|
|
4eb2a4 |
- char *p1, *p2;
|
|
|
4eb2a4 |
+ const char *p1;
|
|
|
4eb2a4 |
+ char *p2;
|
|
|
4eb2a4 |
|
|
|
4eb2a4 |
p1 = s;
|
|
|
4eb2a4 |
p2 = buf;
|
|
|
4eb2a4 |
|
|
|
4eb2a4 |
commit d3909692e9f64e4a1ac440afa81e9efd6e9ea0b4
|
|
|
4eb2a4 |
Author: Dave Anderson <anderson@redhat.com>
|
|
|
4eb2a4 |
Date: Thu Oct 26 16:54:28 2017 -0400
|
|
|
4eb2a4 |
|
|
|
4eb2a4 |
Fix for the "kmem -[sS]" options on Linux 4.14 and later kernels that
|
|
|
4eb2a4 |
contain commit 2482ddec670fb83717d129012bc558777cb159f7, titled
|
|
|
4eb2a4 |
"mm: add SLUB free list pointer obfuscation". Without the patch,
|
|
|
4eb2a4 |
there will numerous error messages of the type "kmem: <cache name>
|
|
|
4eb2a4 |
slab: <address> invalid freepointer: <obfuscated address>".
|
|
|
4eb2a4 |
(anderson@redhat.com)
|
|
|
4eb2a4 |
|
|
|
4eb2a4 |
diff --git a/defs.h b/defs.h
|
|
|
4eb2a4 |
index 4b4e331..967fce0 100644
|
|
|
4eb2a4 |
--- a/defs.h
|
|
|
4eb2a4 |
+++ b/defs.h
|
|
|
4eb2a4 |
@@ -1995,6 +1995,7 @@ struct offset_table { /* stash of commonly-used offsets */
|
|
|
4eb2a4 |
long mod_arch_specific_orc_unwind_ip;
|
|
|
4eb2a4 |
long mod_arch_specific_orc_unwind;
|
|
|
4eb2a4 |
long task_struct_policy;
|
|
|
4eb2a4 |
+ long kmem_cache_random;
|
|
|
4eb2a4 |
};
|
|
|
4eb2a4 |
|
|
|
4eb2a4 |
struct size_table { /* stash of commonly-used sizes */
|
|
|
4eb2a4 |
diff --git a/memory.c b/memory.c
|
|
|
4eb2a4 |
index fb534e8..9926199 100644
|
|
|
4eb2a4 |
--- a/memory.c
|
|
|
4eb2a4 |
+++ b/memory.c
|
|
|
4eb2a4 |
@@ -75,7 +75,7 @@ struct meminfo { /* general purpose memory information structure */
|
|
|
4eb2a4 |
ulong container;
|
|
|
4eb2a4 |
int *freelist;
|
|
|
4eb2a4 |
int freelist_index_size;
|
|
|
4eb2a4 |
-
|
|
|
4eb2a4 |
+ ulong random;
|
|
|
4eb2a4 |
};
|
|
|
4eb2a4 |
|
|
|
4eb2a4 |
/*
|
|
|
4eb2a4 |
@@ -293,6 +293,7 @@ static void dump_per_cpu_offsets(void);
|
|
|
4eb2a4 |
static void dump_page_flags(ulonglong);
|
|
|
4eb2a4 |
static ulong kmem_cache_nodelists(ulong);
|
|
|
4eb2a4 |
static void dump_hstates(void);
|
|
|
4eb2a4 |
+static ulong freelist_ptr(struct meminfo *, ulong, ulong);
|
|
|
4eb2a4 |
|
|
|
4eb2a4 |
/*
|
|
|
4eb2a4 |
* Memory display modes specific to this file.
|
|
|
4eb2a4 |
@@ -726,6 +727,7 @@ vm_init(void)
|
|
|
4eb2a4 |
MEMBER_OFFSET_INIT(kmem_cache_red_left_pad, "kmem_cache", "red_left_pad");
|
|
|
4eb2a4 |
MEMBER_OFFSET_INIT(kmem_cache_name, "kmem_cache", "name");
|
|
|
4eb2a4 |
MEMBER_OFFSET_INIT(kmem_cache_flags, "kmem_cache", "flags");
|
|
|
4eb2a4 |
+ MEMBER_OFFSET_INIT(kmem_cache_random, "kmem_cache", "random");
|
|
|
4eb2a4 |
MEMBER_OFFSET_INIT(kmem_cache_cpu_freelist, "kmem_cache_cpu", "freelist");
|
|
|
4eb2a4 |
MEMBER_OFFSET_INIT(kmem_cache_cpu_page, "kmem_cache_cpu", "page");
|
|
|
4eb2a4 |
MEMBER_OFFSET_INIT(kmem_cache_cpu_node, "kmem_cache_cpu", "node");
|
|
|
4eb2a4 |
@@ -18000,6 +18002,9 @@ dump_kmem_cache_slub(struct meminfo *si)
|
|
|
4eb2a4 |
si->slabsize = (PAGESIZE() << order);
|
|
|
4eb2a4 |
si->inuse = si->num_slabs = 0;
|
|
|
4eb2a4 |
si->slab_offset = offset;
|
|
|
4eb2a4 |
+ si->random = VALID_MEMBER(kmem_cache_random) ?
|
|
|
4eb2a4 |
+ ULONG(si->cache_buf + OFFSET(kmem_cache_random)) : 0;
|
|
|
4eb2a4 |
+
|
|
|
4eb2a4 |
if (!get_kmem_cache_slub_data(GET_SLUB_SLABS, si) ||
|
|
|
4eb2a4 |
!get_kmem_cache_slub_data(GET_SLUB_OBJECTS, si))
|
|
|
4eb2a4 |
si->flags |= SLAB_GATHER_FAILURE;
|
|
|
4eb2a4 |
@@ -18587,6 +18592,15 @@ count_free_objects(struct meminfo *si, ulong freelist)
|
|
|
4eb2a4 |
return c;
|
|
|
4eb2a4 |
}
|
|
|
4eb2a4 |
|
|
|
4eb2a4 |
+static ulong
|
|
|
4eb2a4 |
+freelist_ptr(struct meminfo *si, ulong ptr, ulong ptr_addr)
|
|
|
4eb2a4 |
+{
|
|
|
4eb2a4 |
+ if (si->random)
|
|
|
4eb2a4 |
+ /* CONFIG_SLAB_FREELIST_HARDENED */
|
|
|
4eb2a4 |
+ return (ptr ^ si->random ^ ptr_addr);
|
|
|
4eb2a4 |
+ else
|
|
|
4eb2a4 |
+ return ptr;
|
|
|
4eb2a4 |
+}
|
|
|
4eb2a4 |
|
|
|
4eb2a4 |
static ulong
|
|
|
4eb2a4 |
get_freepointer(struct meminfo *si, void *object)
|
|
|
4eb2a4 |
@@ -18601,7 +18615,7 @@ get_freepointer(struct meminfo *si, void *object)
|
|
|
4eb2a4 |
return BADADDR;
|
|
|
4eb2a4 |
}
|
|
|
4eb2a4 |
|
|
|
4eb2a4 |
- return nextfree;
|
|
|
4eb2a4 |
+ return (freelist_ptr(si, nextfree, vaddr));
|
|
|
4eb2a4 |
}
|
|
|
4eb2a4 |
|
|
|
4eb2a4 |
static void
|
|
|
4eb2a4 |
diff --git a/symbols.c b/symbols.c
|
|
|
4eb2a4 |
index f7599e8..8a4c878 100644
|
|
|
4eb2a4 |
--- a/symbols.c
|
|
|
4eb2a4 |
+++ b/symbols.c
|
|
|
4eb2a4 |
@@ -9378,6 +9378,8 @@ dump_offset_table(char *spec, ulong makestruct)
|
|
|
4eb2a4 |
OFFSET(kmem_cache_cpu_cache));
|
|
|
4eb2a4 |
fprintf(fp, " kmem_cache_oo: %ld\n",
|
|
|
4eb2a4 |
OFFSET(kmem_cache_oo));
|
|
|
4eb2a4 |
+ fprintf(fp, " kmem_cache_random: %ld\n",
|
|
|
4eb2a4 |
+ OFFSET(kmem_cache_random));
|
|
|
4eb2a4 |
|
|
|
4eb2a4 |
fprintf(fp, " kmem_cache_node_nr_partial: %ld\n",
|
|
|
4eb2a4 |
OFFSET(kmem_cache_node_nr_partial));
|
|
|
4eb2a4 |
|
|
|
4eb2a4 |
commit e81db08bc69fb1a7a7e48f892c2038d992a71f6d
|
|
|
4eb2a4 |
Author: Dave Anderson <anderson@redhat.com>
|
|
|
4eb2a4 |
Date: Fri Oct 27 14:10:43 2017 -0400
|
|
|
4eb2a4 |
|
|
|
4eb2a4 |
Fix for the validation of the bits located in the least signficant
|
|
|
4eb2a4 |
bits of mem_section.section_mem_map pointers. Without the patch,
|
|
|
4eb2a4 |
the validation functions always returned valid, due to a coding
|
|
|
4eb2a4 |
error found by clang. However, it was never really a problem
|
|
|
4eb2a4 |
because it is extremely unlikely that an existing mem_section would
|
|
|
4eb2a4 |
ever be invalid.
|
|
|
4eb2a4 |
(oleksandr@redhat.com, anderson@redhat.com)
|
|
|
4eb2a4 |
|
|
|
4eb2a4 |
diff --git a/memory.c b/memory.c
|
|
|
4eb2a4 |
index 9926199..60594a4 100644
|
|
|
4eb2a4 |
--- a/memory.c
|
|
|
4eb2a4 |
+++ b/memory.c
|
|
|
4eb2a4 |
@@ -17003,8 +17003,8 @@ valid_section(ulong addr)
|
|
|
4eb2a4 |
|
|
|
4eb2a4 |
if ((mem_section = read_mem_section(addr)))
|
|
|
4eb2a4 |
return (ULONG(mem_section +
|
|
|
4eb2a4 |
- OFFSET(mem_section_section_mem_map)) &&
|
|
|
4eb2a4 |
- SECTION_MARKED_PRESENT);
|
|
|
4eb2a4 |
+ OFFSET(mem_section_section_mem_map))
|
|
|
4eb2a4 |
+ & SECTION_MARKED_PRESENT);
|
|
|
4eb2a4 |
return 0;
|
|
|
4eb2a4 |
}
|
|
|
4eb2a4 |
|
|
|
4eb2a4 |
@@ -17012,11 +17012,17 @@ int
|
|
|
4eb2a4 |
section_has_mem_map(ulong addr)
|
|
|
4eb2a4 |
{
|
|
|
4eb2a4 |
char *mem_section;
|
|
|
4eb2a4 |
+ ulong kernel_version_bit;
|
|
|
4eb2a4 |
+
|
|
|
4eb2a4 |
+ if (THIS_KERNEL_VERSION >= LINUX(2,6,24))
|
|
|
4eb2a4 |
+ kernel_version_bit = SECTION_HAS_MEM_MAP;
|
|
|
4eb2a4 |
+ else
|
|
|
4eb2a4 |
+ kernel_version_bit = SECTION_MARKED_PRESENT;
|
|
|
4eb2a4 |
|
|
|
4eb2a4 |
if ((mem_section = read_mem_section(addr)))
|
|
|
4eb2a4 |
return (ULONG(mem_section +
|
|
|
4eb2a4 |
OFFSET(mem_section_section_mem_map))
|
|
|
4eb2a4 |
- && SECTION_HAS_MEM_MAP);
|
|
|
4eb2a4 |
+ & kernel_version_bit);
|
|
|
4eb2a4 |
return 0;
|
|
|
4eb2a4 |
}
|
|
|
4eb2a4 |
|
|
|
4eb2a4 |
|
|
|
4eb2a4 |
commit 0f40db8fbac538ea448bbb2beb44912e4c43a54a
|
|
|
4eb2a4 |
Author: Dave Anderson <anderson@redhat.com>
|
|
|
4eb2a4 |
Date: Mon Oct 30 14:20:41 2017 -0400
|
|
|
4eb2a4 |
|
|
|
4eb2a4 |
Fix for the x86_64 kernel virtual address to physical address
|
|
|
4eb2a4 |
translation mechanism. Without the patch, when verifying that the
|
|
|
4eb2a4 |
PAGE_PRESENT bit is set in the top-level page table, it would always
|
|
|
4eb2a4 |
test positively, and the translation would continue parsing the
|
|
|
4eb2a4 |
remainder of the page tables. This would virtually never be a
|
|
|
4eb2a4 |
problem in practice because if the top-level page table entry
|
|
|
4eb2a4 |
existed, its PAGE_PRESENT bit would be set.
|
|
|
4eb2a4 |
(oleksandr@redhat.com, anderson@redhat.com)
|
|
|
4eb2a4 |
|
|
|
4eb2a4 |
diff --git a/x86_64.c b/x86_64.c
|
|
|
4eb2a4 |
index 2f9e6db..7d01140 100644
|
|
|
4eb2a4 |
--- a/x86_64.c
|
|
|
4eb2a4 |
+++ b/x86_64.c
|
|
|
4eb2a4 |
@@ -2086,7 +2086,7 @@ x86_64_kvtop(struct task_context *tc, ulong kvaddr, physaddr_t *paddr, int verbo
|
|
|
4eb2a4 |
}
|
|
|
4eb2a4 |
|
|
|
4eb2a4 |
start_vtop_with_pagetable:
|
|
|
4eb2a4 |
- if (!(*pml4) & _PAGE_PRESENT)
|
|
|
4eb2a4 |
+ if (!(*pml4 & _PAGE_PRESENT))
|
|
|
4eb2a4 |
goto no_kpage;
|
|
|
4eb2a4 |
pgd_paddr = (*pml4) & PHYSICAL_PAGE_MASK;
|
|
|
4eb2a4 |
FILL_PGD(pgd_paddr, PHYSADDR, PAGESIZE());
|
|
|
4eb2a4 |
@@ -2187,7 +2187,7 @@ x86_64_kvtop_xen_wpt(struct task_context *tc, ulong kvaddr, physaddr_t *paddr, i
|
|
|
4eb2a4 |
fprintf(fp, "PML4 DIRECTORY: %lx\n", vt->kernel_pgd[0]);
|
|
|
4eb2a4 |
fprintf(fp, "PAGE DIRECTORY: %lx [machine]\n", *pml4);
|
|
|
4eb2a4 |
}
|
|
|
4eb2a4 |
- if (!(*pml4) & _PAGE_PRESENT)
|
|
|
4eb2a4 |
+ if (!(*pml4 & _PAGE_PRESENT))
|
|
|
4eb2a4 |
goto no_kpage;
|
|
|
4eb2a4 |
pgd_paddr = (*pml4) & PHYSICAL_PAGE_MASK;
|
|
|
4eb2a4 |
pgd_paddr = xen_m2p(pgd_paddr);
|
|
|
4eb2a4 |
|
|
|
4eb2a4 |
commit 9339874f3764fe99a408aec1a814b19c77f5dfe1
|
|
|
4eb2a4 |
Author: Dave Anderson <anderson@redhat.com>
|
|
|
4eb2a4 |
Date: Mon Oct 30 14:33:15 2017 -0400
|
|
|
4eb2a4 |
|
|
|
4eb2a4 |
Removed a check for a negative block_size value which is always a
|
|
|
4eb2a4 |
non-negative unsigned value in the SADUMP header parsing function.
|
|
|
4eb2a4 |
(oleksandr@redhat.com)
|
|
|
4eb2a4 |
|
|
|
4eb2a4 |
diff --git a/sadump.c b/sadump.c
|
|
|
4eb2a4 |
index 2ccfa82..6b912d4 100644
|
|
|
4eb2a4 |
--- a/sadump.c
|
|
|
4eb2a4 |
+++ b/sadump.c
|
|
|
4eb2a4 |
@@ -157,9 +157,6 @@ read_dump_header(char *file)
|
|
|
4eb2a4 |
}
|
|
|
4eb2a4 |
|
|
|
4eb2a4 |
restart:
|
|
|
4eb2a4 |
- if (block_size < 0)
|
|
|
4eb2a4 |
- return FALSE;
|
|
|
4eb2a4 |
-
|
|
|
4eb2a4 |
if (!read_device(sph, block_size, &offset)) {
|
|
|
4eb2a4 |
error(INFO, "sadump: cannot read partition header\n");
|
|
|
4eb2a4 |
goto err;
|
|
|
4eb2a4 |
|
|
|
4eb2a4 |
commit b2d1bba766118fddf43235f0bed483dff32ac6e0
|
|
|
4eb2a4 |
Author: Dave Anderson <anderson@redhat.com>
|
|
|
4eb2a4 |
Date: Mon Oct 30 14:46:32 2017 -0400
|
|
|
4eb2a4 |
|
|
|
4eb2a4 |
Removed a check for an impossible negative value when calculating
|
|
|
4eb2a4 |
the beginning address when applying the context value specified by
|
|
|
4eb2a4 |
the "search -x <count>" option.
|
|
|
4eb2a4 |
(oleksandr@redhat.com)
|
|
|
4eb2a4 |
|
|
|
4eb2a4 |
diff --git a/memory.c b/memory.c
|
|
|
4eb2a4 |
index 60594a4..ebd671a 100644
|
|
|
4eb2a4 |
--- a/memory.c
|
|
|
4eb2a4 |
+++ b/memory.c
|
|
|
4eb2a4 |
@@ -14467,7 +14467,7 @@ display_with_pre_and_post(void *bufptr, ulonglong addr, struct searchinfo *si)
|
|
|
4eb2a4 |
}
|
|
|
4eb2a4 |
|
|
|
4eb2a4 |
amount = ctx * t;
|
|
|
4eb2a4 |
- addr_d = addr - amount < 0 ? 0 : addr - amount;
|
|
|
4eb2a4 |
+ addr_d = addr - amount;
|
|
|
4eb2a4 |
|
|
|
4eb2a4 |
display_memory(addr_d, ctx, flag, memtype, NULL);
|
|
|
4eb2a4 |
|
|
|
4eb2a4 |
|
|
|
4eb2a4 |
commit e2efacdd9b7b229747a78c743b2acc6d15280a8a
|
|
|
4eb2a4 |
Author: Dave Anderson <anderson@redhat.com>
|
|
|
4eb2a4 |
Date: Mon Oct 30 16:49:48 2017 -0400
|
|
|
4eb2a4 |
|
|
|
4eb2a4 |
Implemented a new "timer -C <cpu-specifier>" option that restricts
|
|
|
4eb2a4 |
the timer or hrtimer output to the timer queue data associated with
|
|
|
4eb2a4 |
one or more cpus. For multiple cpus, the cpu-specifier uses the
|
|
|
4eb2a4 |
standard comma or dash separated list format.
|
|
|
4eb2a4 |
(oleksandr@redhat.com)
|
|
|
4eb2a4 |
|
|
|
4eb2a4 |
diff --git a/help.c b/help.c
|
|
|
4eb2a4 |
index efa55e0..f7f61a1 100644
|
|
|
4eb2a4 |
--- a/help.c
|
|
|
4eb2a4 |
+++ b/help.c
|
|
|
4eb2a4 |
@@ -2387,7 +2387,7 @@ NULL
|
|
|
4eb2a4 |
char *help_timer[] = {
|
|
|
4eb2a4 |
"timer",
|
|
|
4eb2a4 |
"timer queue data",
|
|
|
4eb2a4 |
-"[-r]",
|
|
|
4eb2a4 |
+"[-r][-C cpu]",
|
|
|
4eb2a4 |
" This command displays the timer queue entries, both old- and new-style,",
|
|
|
4eb2a4 |
" in chronological order. In the case of the old-style timers, the",
|
|
|
4eb2a4 |
" timer_table array index is shown; in the case of the new-style timers, ",
|
|
|
4eb2a4 |
@@ -2397,6 +2397,8 @@ char *help_timer[] = {
|
|
|
4eb2a4 |
" chronological order. In the case of the old-style hrtimers, the",
|
|
|
4eb2a4 |
" expiration time is a single value; in the new-style hrtimers, the",
|
|
|
4eb2a4 |
" expiration time is a range.",
|
|
|
4eb2a4 |
+" -C cpu Restrict the output to one or more CPUs, where multiple cpu[s] can",
|
|
|
4eb2a4 |
+" be specified, for example, as \"1,3,5\", \"1-3\", or \"1,3,5-7,10\".",
|
|
|
4eb2a4 |
"\nEXAMPLES",
|
|
|
4eb2a4 |
" %s> timer",
|
|
|
4eb2a4 |
" JIFFIES",
|
|
|
4eb2a4 |
diff --git a/kernel.c b/kernel.c
|
|
|
4eb2a4 |
index 8e95573..4638495 100644
|
|
|
4eb2a4 |
--- a/kernel.c
|
|
|
4eb2a4 |
+++ b/kernel.c
|
|
|
4eb2a4 |
@@ -38,18 +38,18 @@ static void display_bh_1(void);
|
|
|
4eb2a4 |
static void display_bh_2(void);
|
|
|
4eb2a4 |
static void display_bh_3(void);
|
|
|
4eb2a4 |
static void display_bh_4(void);
|
|
|
4eb2a4 |
-static void dump_hrtimer_data(void);
|
|
|
4eb2a4 |
+static void dump_hrtimer_data(const ulong *cpus);
|
|
|
4eb2a4 |
static void dump_hrtimer_clock_base(const void *, const int);
|
|
|
4eb2a4 |
static void dump_hrtimer_base(const void *, const int);
|
|
|
4eb2a4 |
static void dump_active_timers(const void *, ulonglong);
|
|
|
4eb2a4 |
static int get_expires_len(const int, const ulong *, const int);
|
|
|
4eb2a4 |
static void print_timer(const void *);
|
|
|
4eb2a4 |
static ulonglong ktime_to_ns(const void *);
|
|
|
4eb2a4 |
-static void dump_timer_data(void);
|
|
|
4eb2a4 |
-static void dump_timer_data_tvec_bases_v1(void);
|
|
|
4eb2a4 |
-static void dump_timer_data_tvec_bases_v2(void);
|
|
|
4eb2a4 |
-static void dump_timer_data_tvec_bases_v3(void);
|
|
|
4eb2a4 |
-static void dump_timer_data_timer_bases(void);
|
|
|
4eb2a4 |
+static void dump_timer_data(const ulong *cpus);
|
|
|
4eb2a4 |
+static void dump_timer_data_tvec_bases_v1(const ulong *cpus);
|
|
|
4eb2a4 |
+static void dump_timer_data_tvec_bases_v2(const ulong *cpus);
|
|
|
4eb2a4 |
+static void dump_timer_data_tvec_bases_v3(const ulong *cpus);
|
|
|
4eb2a4 |
+static void dump_timer_data_timer_bases(const ulong *cpus);
|
|
|
4eb2a4 |
struct tv_range;
|
|
|
4eb2a4 |
static void init_tv_ranges(struct tv_range *, int, int, int);
|
|
|
4eb2a4 |
static int do_timer_list(ulong,int, ulong *, void *,ulong *,struct tv_range *);
|
|
|
4eb2a4 |
@@ -7353,16 +7353,24 @@ cmd_timer(void)
|
|
|
4eb2a4 |
{
|
|
|
4eb2a4 |
int c;
|
|
|
4eb2a4 |
int rflag;
|
|
|
4eb2a4 |
+ char *cpuspec;
|
|
|
4eb2a4 |
+ ulong *cpus = NULL;
|
|
|
4eb2a4 |
|
|
|
4eb2a4 |
rflag = 0;
|
|
|
4eb2a4 |
|
|
|
4eb2a4 |
- while ((c = getopt(argcnt, args, "r")) != EOF) {
|
|
|
4eb2a4 |
+ while ((c = getopt(argcnt, args, "rC:")) != EOF) {
|
|
|
4eb2a4 |
switch(c)
|
|
|
4eb2a4 |
{
|
|
|
4eb2a4 |
case 'r':
|
|
|
4eb2a4 |
rflag = 1;
|
|
|
4eb2a4 |
break;
|
|
|
4eb2a4 |
|
|
|
4eb2a4 |
+ case 'C':
|
|
|
4eb2a4 |
+ cpuspec = optarg;
|
|
|
4eb2a4 |
+ cpus = get_cpumask_buf();
|
|
|
4eb2a4 |
+ make_cpumask(cpuspec, cpus, FAULT_ON_ERROR, NULL);
|
|
|
4eb2a4 |
+ break;
|
|
|
4eb2a4 |
+
|
|
|
4eb2a4 |
default:
|
|
|
4eb2a4 |
argerrs++;
|
|
|
4eb2a4 |
break;
|
|
|
4eb2a4 |
@@ -7373,15 +7381,18 @@ cmd_timer(void)
|
|
|
4eb2a4 |
cmd_usage(pc->curcmd, SYNOPSIS);
|
|
|
4eb2a4 |
|
|
|
4eb2a4 |
if (rflag)
|
|
|
4eb2a4 |
- dump_hrtimer_data();
|
|
|
4eb2a4 |
+ dump_hrtimer_data(cpus);
|
|
|
4eb2a4 |
else
|
|
|
4eb2a4 |
- dump_timer_data();
|
|
|
4eb2a4 |
+ dump_timer_data(cpus);
|
|
|
4eb2a4 |
+
|
|
|
4eb2a4 |
+ if (cpus)
|
|
|
4eb2a4 |
+ FREEBUF(cpus);
|
|
|
4eb2a4 |
}
|
|
|
4eb2a4 |
|
|
|
4eb2a4 |
static void
|
|
|
4eb2a4 |
-dump_hrtimer_data(void)
|
|
|
4eb2a4 |
+dump_hrtimer_data(const ulong *cpus)
|
|
|
4eb2a4 |
{
|
|
|
4eb2a4 |
- int i, j;
|
|
|
4eb2a4 |
+ int i, j, k = 0;
|
|
|
4eb2a4 |
int hrtimer_max_clock_bases, max_hrtimer_bases;
|
|
|
4eb2a4 |
struct syment * hrtimer_bases;
|
|
|
4eb2a4 |
|
|
|
4eb2a4 |
@@ -7405,7 +7416,10 @@ dump_hrtimer_data(void)
|
|
|
4eb2a4 |
hrtimer_bases = per_cpu_symbol_search("hrtimer_bases");
|
|
|
4eb2a4 |
|
|
|
4eb2a4 |
for (i = 0; i < kt->cpus; i++) {
|
|
|
4eb2a4 |
- if (i)
|
|
|
4eb2a4 |
+ if (cpus && !NUM_IN_BITMAP(cpus, i))
|
|
|
4eb2a4 |
+ continue;
|
|
|
4eb2a4 |
+
|
|
|
4eb2a4 |
+ if (k++)
|
|
|
4eb2a4 |
fprintf(fp, "\n");
|
|
|
4eb2a4 |
|
|
|
4eb2a4 |
if (hide_offline_cpu(i)) {
|
|
|
4eb2a4 |
@@ -7752,7 +7766,7 @@ struct tv_range {
|
|
|
4eb2a4 |
#define TVN (6)
|
|
|
4eb2a4 |
|
|
|
4eb2a4 |
static void
|
|
|
4eb2a4 |
-dump_timer_data(void)
|
|
|
4eb2a4 |
+dump_timer_data(const ulong *cpus)
|
|
|
4eb2a4 |
{
|
|
|
4eb2a4 |
int i;
|
|
|
4eb2a4 |
ulong timer_active;
|
|
|
4eb2a4 |
@@ -7773,16 +7787,16 @@ dump_timer_data(void)
|
|
|
4eb2a4 |
struct tv_range tv[TVN];
|
|
|
4eb2a4 |
|
|
|
4eb2a4 |
if (kt->flags2 & TIMER_BASES) {
|
|
|
4eb2a4 |
- dump_timer_data_timer_bases();
|
|
|
4eb2a4 |
+ dump_timer_data_timer_bases(cpus);
|
|
|
4eb2a4 |
return;
|
|
|
4eb2a4 |
} else if (kt->flags2 & TVEC_BASES_V3) {
|
|
|
4eb2a4 |
- dump_timer_data_tvec_bases_v3();
|
|
|
4eb2a4 |
+ dump_timer_data_tvec_bases_v3(cpus);
|
|
|
4eb2a4 |
return;
|
|
|
4eb2a4 |
} else if (kt->flags & TVEC_BASES_V2) {
|
|
|
4eb2a4 |
- dump_timer_data_tvec_bases_v2();
|
|
|
4eb2a4 |
+ dump_timer_data_tvec_bases_v2(cpus);
|
|
|
4eb2a4 |
return;
|
|
|
4eb2a4 |
} else if (kt->flags & TVEC_BASES_V1) {
|
|
|
4eb2a4 |
- dump_timer_data_tvec_bases_v1();
|
|
|
4eb2a4 |
+ dump_timer_data_tvec_bases_v1(cpus);
|
|
|
4eb2a4 |
return;
|
|
|
4eb2a4 |
}
|
|
|
4eb2a4 |
|
|
|
4eb2a4 |
@@ -7924,7 +7938,7 @@ dump_timer_data(void)
|
|
|
4eb2a4 |
*/
|
|
|
4eb2a4 |
|
|
|
4eb2a4 |
static void
|
|
|
4eb2a4 |
-dump_timer_data_tvec_bases_v1(void)
|
|
|
4eb2a4 |
+dump_timer_data_tvec_bases_v1(const ulong *cpus)
|
|
|
4eb2a4 |
{
|
|
|
4eb2a4 |
int i, cpu, tdx, flen;
|
|
|
4eb2a4 |
struct timer_data *td;
|
|
|
4eb2a4 |
@@ -7947,6 +7961,11 @@ dump_timer_data_tvec_bases_v1(void)
|
|
|
4eb2a4 |
cpu = 0;
|
|
|
4eb2a4 |
|
|
|
4eb2a4 |
next_cpu:
|
|
|
4eb2a4 |
+ if (cpus && !NUM_IN_BITMAP(cpus, cpu)) {
|
|
|
4eb2a4 |
+ if (++cpu < kt->cpus)
|
|
|
4eb2a4 |
+ goto next_cpu;
|
|
|
4eb2a4 |
+ return;
|
|
|
4eb2a4 |
+ }
|
|
|
4eb2a4 |
|
|
|
4eb2a4 |
count = 0;
|
|
|
4eb2a4 |
td = (struct timer_data *)NULL;
|
|
|
4eb2a4 |
@@ -8039,7 +8058,7 @@ next_cpu:
|
|
|
4eb2a4 |
*/
|
|
|
4eb2a4 |
|
|
|
4eb2a4 |
static void
|
|
|
4eb2a4 |
-dump_timer_data_tvec_bases_v2(void)
|
|
|
4eb2a4 |
+dump_timer_data_tvec_bases_v2(const ulong *cpus)
|
|
|
4eb2a4 |
{
|
|
|
4eb2a4 |
int i, cpu, tdx, flen;
|
|
|
4eb2a4 |
struct timer_data *td;
|
|
|
4eb2a4 |
@@ -8073,6 +8092,11 @@ dump_timer_data_tvec_bases_v2(void)
|
|
|
4eb2a4 |
cpu = 0;
|
|
|
4eb2a4 |
|
|
|
4eb2a4 |
next_cpu:
|
|
|
4eb2a4 |
+ if (cpus && !NUM_IN_BITMAP(cpus, cpu)) {
|
|
|
4eb2a4 |
+ if (++cpu < kt->cpus)
|
|
|
4eb2a4 |
+ goto next_cpu;
|
|
|
4eb2a4 |
+ return;
|
|
|
4eb2a4 |
+ }
|
|
|
4eb2a4 |
/*
|
|
|
4eb2a4 |
* hide data of offline cpu and goto next cpu
|
|
|
4eb2a4 |
*/
|
|
|
4eb2a4 |
@@ -8185,7 +8209,7 @@ next_cpu:
|
|
|
4eb2a4 |
* Linux 4.2 timers use new tvec_root, tvec and timer_list structures
|
|
|
4eb2a4 |
*/
|
|
|
4eb2a4 |
static void
|
|
|
4eb2a4 |
-dump_timer_data_tvec_bases_v3(void)
|
|
|
4eb2a4 |
+dump_timer_data_tvec_bases_v3(const ulong *cpus)
|
|
|
4eb2a4 |
{
|
|
|
4eb2a4 |
int i, cpu, tdx, flen;
|
|
|
4eb2a4 |
struct timer_data *td;
|
|
|
4eb2a4 |
@@ -8216,6 +8240,11 @@ dump_timer_data_tvec_bases_v3(void)
|
|
|
4eb2a4 |
cpu = 0;
|
|
|
4eb2a4 |
|
|
|
4eb2a4 |
next_cpu:
|
|
|
4eb2a4 |
+ if (cpus && !NUM_IN_BITMAP(cpus, cpu)) {
|
|
|
4eb2a4 |
+ if (++cpu < kt->cpus)
|
|
|
4eb2a4 |
+ goto next_cpu;
|
|
|
4eb2a4 |
+ return;
|
|
|
4eb2a4 |
+ }
|
|
|
4eb2a4 |
/*
|
|
|
4eb2a4 |
* hide data of offline cpu and goto next cpu
|
|
|
4eb2a4 |
*/
|
|
|
4eb2a4 |
@@ -8758,9 +8787,9 @@ do_timer_list_v4(struct timer_bases_data *data)
|
|
|
4eb2a4 |
* Linux 4.8 timers use new timer_bases[][]
|
|
|
4eb2a4 |
*/
|
|
|
4eb2a4 |
static void
|
|
|
4eb2a4 |
-dump_timer_data_timer_bases(void)
|
|
|
4eb2a4 |
+dump_timer_data_timer_bases(const ulong *cpus)
|
|
|
4eb2a4 |
{
|
|
|
4eb2a4 |
- int i, cpu, flen, base, nr_bases, found, display;
|
|
|
4eb2a4 |
+ int i, cpu, flen, base, nr_bases, found, display, j = 0;
|
|
|
4eb2a4 |
struct syment *sp;
|
|
|
4eb2a4 |
ulong timer_base, jiffies, function;
|
|
|
4eb2a4 |
struct timer_bases_data data;
|
|
|
4eb2a4 |
@@ -8785,6 +8814,11 @@ dump_timer_data_timer_bases(void)
|
|
|
4eb2a4 |
RJUST|LONG_DEC,MKSTR(jiffies)));
|
|
|
4eb2a4 |
|
|
|
4eb2a4 |
next_cpu:
|
|
|
4eb2a4 |
+ if (cpus && !NUM_IN_BITMAP(cpus, cpu)) {
|
|
|
4eb2a4 |
+ if (++cpu < kt->cpus)
|
|
|
4eb2a4 |
+ goto next_cpu;
|
|
|
4eb2a4 |
+ goto done;
|
|
|
4eb2a4 |
+ }
|
|
|
4eb2a4 |
/*
|
|
|
4eb2a4 |
* hide data of offline cpu and goto next cpu
|
|
|
4eb2a4 |
*/
|
|
|
4eb2a4 |
@@ -8803,7 +8837,7 @@ next_cpu:
|
|
|
4eb2a4 |
else
|
|
|
4eb2a4 |
timer_base = sp->value;
|
|
|
4eb2a4 |
|
|
|
4eb2a4 |
- if (cpu)
|
|
|
4eb2a4 |
+ if (j++)
|
|
|
4eb2a4 |
fprintf(fp, "\n");
|
|
|
4eb2a4 |
next_base:
|
|
|
4eb2a4 |
|