1124 lines
38 KiB
Diff
1124 lines
38 KiB
Diff
commit 105a3e13167665dde5d3c12bf76ef9c916e82d0e
|
|
Author: Dave Anderson <anderson@redhat.com>
|
|
Date: Thu Oct 10 14:07:22 2019 -0400
|
|
|
|
Fix for Linux 5.4-rc1 and later kernels that contain commit
|
|
688fcbfc06e4fdfbb7e1d5a942a1460fe6379d2d, titled "mm/vmalloc:
|
|
modify struct vmap_area to reduce its size". Without the
|
|
patch "kmem -v" will display nothing; other architectures
|
|
that utilize the vmap_area_list to determine the base of
|
|
mapped/vmalloc address space will fail.
|
|
(anderson@redhat.com)
|
|
|
|
diff --git a/memory.c b/memory.c
|
|
index 3a8b998..fe82fac 100644
|
|
--- a/memory.c
|
|
+++ b/memory.c
|
|
@@ -401,9 +401,10 @@ vm_init(void)
|
|
STRUCT_SIZE_INIT(vmap_area, "vmap_area");
|
|
if (VALID_MEMBER(vmap_area_va_start) &&
|
|
VALID_MEMBER(vmap_area_va_end) &&
|
|
- VALID_MEMBER(vmap_area_flags) &&
|
|
VALID_MEMBER(vmap_area_list) &&
|
|
VALID_MEMBER(vmap_area_vm) &&
|
|
+ (VALID_MEMBER(vmap_area_flags) ||
|
|
+ (OFFSET(vmap_area_vm) == MEMBER_OFFSET("vmap_area", "purge_list"))) &&
|
|
kernel_symbol_exists("vmap_area_list"))
|
|
vt->flags |= USE_VMAP_AREA;
|
|
|
|
@@ -8742,7 +8743,7 @@ static void
|
|
dump_vmap_area(struct meminfo *vi)
|
|
{
|
|
int i, cnt;
|
|
- ulong start, end, vm_struct, flags;
|
|
+ ulong start, end, vm_struct, flags, vm;
|
|
struct list_data list_data, *ld;
|
|
char *vmap_area_buf;
|
|
ulong size, pcheck, count, verified;
|
|
@@ -8790,9 +8791,15 @@ dump_vmap_area(struct meminfo *vi)
|
|
readmem(ld->list_ptr[i], KVADDR, vmap_area_buf,
|
|
SIZE(vmap_area), "vmap_area struct", FAULT_ON_ERROR);
|
|
|
|
- flags = ULONG(vmap_area_buf + OFFSET(vmap_area_flags));
|
|
- if (flags != VM_VM_AREA)
|
|
- continue;
|
|
+ if (VALID_MEMBER(vmap_area_flags)) {
|
|
+ flags = ULONG(vmap_area_buf + OFFSET(vmap_area_flags));
|
|
+ if (flags != VM_VM_AREA)
|
|
+ continue;
|
|
+ } else {
|
|
+ vm = ULONG(vmap_area_buf + OFFSET(vmap_area_vm));
|
|
+ if (!vm)
|
|
+ continue;
|
|
+ }
|
|
start = ULONG(vmap_area_buf + OFFSET(vmap_area_va_start));
|
|
end = ULONG(vmap_area_buf + OFFSET(vmap_area_va_end));
|
|
vm_struct = ULONG(vmap_area_buf + OFFSET(vmap_area_vm));
|
|
|
|
commit 82ce13bceb1082a7c53c1bda71e17ca9c2a5cbc4
|
|
Author: Dave Anderson <anderson@redhat.com>
|
|
Date: Fri Oct 11 11:14:28 2019 -0400
|
|
|
|
Fix for Linux 5.4-rc1 and later kernels that contain commit/merge
|
|
e0703556644a531e50b5dc61b9f6ea83af5f6604, titled "Merge tag 'modules-
|
|
for-v5.4' of git://git.kernel.org/pub/scm/linux/kernel/git/jeyu/linux
|
|
which introduces symbol namespaces. Without the patch, and depending
|
|
upon the architecture:
|
|
(1) the kernel module symbol list will contain garbage entries
|
|
(2) the session fails during session initialization with a dump of
|
|
the internal buffer allocation stats followed by the message
|
|
"crash: cannot allocate any more memory!"
|
|
(3) the session fails during session initialization with a
|
|
segmentation violation.
|
|
(anderson@redhat.com)
|
|
|
|
diff --git a/defs.h b/defs.h
|
|
index 32bd147..502e7c2 100644
|
|
--- a/defs.h
|
|
+++ b/defs.h
|
|
@@ -2694,6 +2694,7 @@ struct symbol_table_data {
|
|
ulong saved_command_line_vmlinux;
|
|
ulong pti_init_vmlinux;
|
|
ulong kaiser_init_vmlinux;
|
|
+ int kernel_symbol_type;
|
|
};
|
|
|
|
/* flags for st */
|
|
diff --git a/symbols.c b/symbols.c
|
|
index 3ce8692..7af5e69 100644
|
|
--- a/symbols.c
|
|
+++ b/symbols.c
|
|
@@ -1607,39 +1607,100 @@ union kernel_symbol {
|
|
unsigned long value;
|
|
const char *name;
|
|
} v1;
|
|
- /* kernel 4.19 introduced relative symbol positionning */
|
|
+ /* kernel 4.19 introduced relative symbol positioning */
|
|
struct kernel_symbol_v2 {
|
|
int value_offset;
|
|
int name_offset;
|
|
} v2;
|
|
+ /* kernel 5.4 introduced symbol namespaces */
|
|
+ struct kernel_symbol_v3 {
|
|
+ int value_offset;
|
|
+ int name_offset;
|
|
+ int namespace_offset;
|
|
+ } v3;
|
|
+ struct kernel_symbol_v4 {
|
|
+ unsigned long value;
|
|
+ const char *name;
|
|
+ const char *namespace;
|
|
+ } v4;
|
|
};
|
|
|
|
+static size_t
|
|
+kernel_symbol_type_init(void)
|
|
+{
|
|
+ if (MEMBER_EXISTS("kernel_symbol", "value") &&
|
|
+ MEMBER_EXISTS("kernel_symbol", "name")) {
|
|
+ if (MEMBER_EXISTS("kernel_symbol", "namespace")) {
|
|
+ st->kernel_symbol_type = 4;
|
|
+ return (sizeof(struct kernel_symbol_v4));
|
|
+ } else {
|
|
+ st->kernel_symbol_type = 1;
|
|
+ return (sizeof(struct kernel_symbol_v1));
|
|
+ }
|
|
+ }
|
|
+ if (MEMBER_EXISTS("kernel_symbol", "value_offset") &&
|
|
+ MEMBER_EXISTS("kernel_symbol", "name_offset")) {
|
|
+ if (MEMBER_EXISTS("kernel_symbol", "namespace_offset")) {
|
|
+ st->kernel_symbol_type = 3;
|
|
+ return (sizeof(struct kernel_symbol_v3));
|
|
+ } else {
|
|
+ st->kernel_symbol_type = 2;
|
|
+ return (sizeof(struct kernel_symbol_v2));
|
|
+ }
|
|
+ }
|
|
+
|
|
+ error(FATAL, "kernel_symbol data structure has changed\n");
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
static ulong
|
|
modsym_name(ulong syms, union kernel_symbol *modsym, int i)
|
|
{
|
|
- if (VALID_MEMBER(kernel_symbol_value))
|
|
+ switch (st->kernel_symbol_type)
|
|
+ {
|
|
+ case 1:
|
|
return (ulong)modsym->v1.name;
|
|
+ case 2:
|
|
+ return (syms + i * sizeof(struct kernel_symbol_v2) +
|
|
+ offsetof(struct kernel_symbol_v2, name_offset) +
|
|
+ modsym->v2.name_offset);
|
|
+ case 3:
|
|
+ return (syms + i * sizeof(struct kernel_symbol_v3) +
|
|
+ offsetof(struct kernel_symbol_v3, name_offset) +
|
|
+ modsym->v3.name_offset);
|
|
+ case 4:
|
|
+ return (ulong)modsym->v4.name;
|
|
+ }
|
|
|
|
- return syms + i * sizeof(struct kernel_symbol_v2) +
|
|
- offsetof(struct kernel_symbol_v2, name_offset) +
|
|
- modsym->v2.name_offset;
|
|
+ return 0;
|
|
}
|
|
|
|
static ulong
|
|
modsym_value(ulong syms, union kernel_symbol *modsym, int i)
|
|
{
|
|
- if (VALID_MEMBER(kernel_symbol_value))
|
|
+ switch (st->kernel_symbol_type)
|
|
+ {
|
|
+ case 1:
|
|
return (ulong)modsym->v1.value;
|
|
+ case 2:
|
|
+ return (syms + i * sizeof(struct kernel_symbol_v2) +
|
|
+ offsetof(struct kernel_symbol_v2, value_offset) +
|
|
+ modsym->v2.value_offset);
|
|
+ case 3:
|
|
+ return (syms + i * sizeof(struct kernel_symbol_v3) +
|
|
+ offsetof(struct kernel_symbol_v3, value_offset) +
|
|
+ modsym->v3.value_offset);
|
|
+ case 4:
|
|
+ return (ulong)modsym->v4.value;
|
|
+ }
|
|
|
|
- return syms + i * sizeof(struct kernel_symbol_v2) +
|
|
- offsetof(struct kernel_symbol_v2, value_offset) +
|
|
- modsym->v2.value_offset;
|
|
+ return 0;
|
|
}
|
|
|
|
void
|
|
store_module_symbols_v2(ulong total, int mods_installed)
|
|
{
|
|
-
|
|
int i, m;
|
|
ulong mod, mod_next;
|
|
char *mod_name;
|
|
@@ -1675,12 +1736,7 @@ store_module_symbols_v2(ulong total, int mods_installed)
|
|
"re-initialization of module symbols not implemented yet!\n");
|
|
}
|
|
|
|
- MEMBER_OFFSET_INIT(kernel_symbol_value, "kernel_symbol", "value");
|
|
- if (VALID_MEMBER(kernel_symbol_value)) {
|
|
- kernel_symbol_size = sizeof(struct kernel_symbol_v1);
|
|
- } else {
|
|
- kernel_symbol_size = sizeof(struct kernel_symbol_v2);
|
|
- }
|
|
+ kernel_symbol_size = kernel_symbol_type_init();
|
|
|
|
if ((st->ext_module_symtable = (struct syment *)
|
|
calloc(total, sizeof(struct syment))) == NULL)
|
|
@@ -3418,6 +3474,8 @@ dump_symbol_table(void)
|
|
fprintf(fp, "\n");
|
|
} else
|
|
fprintf(fp, "(none)\n");
|
|
+
|
|
+ fprintf(fp, " kernel_symbol_type: v%d\n", st->kernel_symbol_type);
|
|
}
|
|
|
|
|
|
|
|
commit c1ac656508ad064ef0ef222acb73621ae0bf4f00
|
|
Author: Dave Anderson <anderson@redhat.com>
|
|
Date: Tue Oct 15 11:21:55 2019 -0400
|
|
|
|
Fix for the "timer -r" option on Linux 5.4-rc1 and later kernels
|
|
that contain commit 511885d7061eda3eb1faf3f57dcc936ff75863f1, titled
|
|
"lib/timerqueue: Rely on rbtree semantics for next timer". Without
|
|
the patch, the option fails with the following error "timer: invalid
|
|
structure member offset: timerqueue_head_next".
|
|
(k-hagio@ab.jp.nec.com)
|
|
|
|
diff --git a/defs.h b/defs.h
|
|
index 502e7c2..efa40b9 100644
|
|
--- a/defs.h
|
|
+++ b/defs.h
|
|
@@ -2073,6 +2073,8 @@ struct offset_table { /* stash of commonly-used offsets */
|
|
long cpu_context_save_r7;
|
|
long dentry_d_sb;
|
|
long device_private_knode_class;
|
|
+ long timerqueue_head_rb_root;
|
|
+ long rb_root_cached_rb_leftmost;
|
|
};
|
|
|
|
struct size_table { /* stash of commonly-used sizes */
|
|
diff --git a/kernel.c b/kernel.c
|
|
index 375e1b4..c4cb001 100644
|
|
--- a/kernel.c
|
|
+++ b/kernel.c
|
|
@@ -783,7 +783,13 @@ kernel_init()
|
|
MEMBER_OFFSET_INIT(timerqueue_node_expires,
|
|
"timerqueue_node", "expires");
|
|
MEMBER_OFFSET_INIT(timerqueue_node_node,
|
|
- "timerqueue_node_node", "node");
|
|
+ "timerqueue_node", "node");
|
|
+ if (INVALID_MEMBER(timerqueue_head_next)) {
|
|
+ MEMBER_OFFSET_INIT(timerqueue_head_rb_root,
|
|
+ "timerqueue_head", "rb_root");
|
|
+ MEMBER_OFFSET_INIT(rb_root_cached_rb_leftmost,
|
|
+ "rb_root_cached", "rb_leftmost");
|
|
+ }
|
|
}
|
|
MEMBER_OFFSET_INIT(hrtimer_softexpires, "hrtimer", "_softexpires");
|
|
MEMBER_OFFSET_INIT(hrtimer_function, "hrtimer", "function");
|
|
@@ -7647,11 +7653,17 @@ next_one:
|
|
readmem((ulong)(base + OFFSET(hrtimer_clock_base_first)),
|
|
KVADDR, &curr, sizeof(curr), "hrtimer_clock_base first",
|
|
FAULT_ON_ERROR);
|
|
- else
|
|
+ else if (VALID_MEMBER(timerqueue_head_next))
|
|
readmem((ulong)(base + OFFSET(hrtimer_clock_base_active) +
|
|
OFFSET(timerqueue_head_next)),
|
|
KVADDR, &curr, sizeof(curr), "hrtimer_clock base",
|
|
FAULT_ON_ERROR);
|
|
+ else
|
|
+ readmem((ulong)(base + OFFSET(hrtimer_clock_base_active) +
|
|
+ OFFSET(timerqueue_head_rb_root) +
|
|
+ OFFSET(rb_root_cached_rb_leftmost)),
|
|
+ KVADDR, &curr, sizeof(curr),
|
|
+ "hrtimer_clock_base active", FAULT_ON_ERROR);
|
|
|
|
while (curr && i < next) {
|
|
curr = rb_next(curr);
|
|
diff --git a/symbols.c b/symbols.c
|
|
index 7af5e69..eb88ca1 100644
|
|
--- a/symbols.c
|
|
+++ b/symbols.c
|
|
@@ -10032,6 +10032,8 @@ dump_offset_table(char *spec, ulong makestruct)
|
|
OFFSET(rb_node_rb_left));
|
|
fprintf(fp, " rb_node_rb_right: %ld\n",
|
|
OFFSET(rb_node_rb_right));
|
|
+ fprintf(fp, " rb_root_cached_rb_leftmost: %ld\n",
|
|
+ OFFSET(rb_root_cached_rb_leftmost));
|
|
|
|
fprintf(fp, " x8664_pda_pcurrent: %ld\n",
|
|
OFFSET(x8664_pda_pcurrent));
|
|
@@ -10388,6 +10390,8 @@ dump_offset_table(char *spec, ulong makestruct)
|
|
OFFSET(hrtimer_function));
|
|
fprintf(fp, " timerqueue_head_next: %ld\n",
|
|
OFFSET(timerqueue_head_next));
|
|
+ fprintf(fp, " timerqueue_head_rb_root: %ld\n",
|
|
+ OFFSET(timerqueue_head_rb_root));
|
|
fprintf(fp, " timerqueue_node_expires: %ld\n",
|
|
OFFSET(timerqueue_node_expires));
|
|
fprintf(fp, " timerqueue_node_node: %ld\n",
|
|
|
|
commit e13fe8ba5a0b9c54edea103a309e9879784d9b94
|
|
Author: Dave Anderson <anderson@redhat.com>
|
|
Date: Tue Oct 15 16:29:30 2019 -0400
|
|
|
|
Fix for a "[-Wstringop-truncation]" compiler warning emitted when
|
|
symbols.c is built in a Fedora Rawhide environment with gcc-9.0.1
|
|
or later.
|
|
(anderson@redhat.com)
|
|
|
|
diff --git a/symbols.c b/symbols.c
|
|
index eb88ca1..55199fc 100644
|
|
--- a/symbols.c
|
|
+++ b/symbols.c
|
|
@@ -8174,8 +8174,10 @@ parse_for_member_extended(struct datatype_member *dm,
|
|
*/
|
|
|
|
if (current && p && (p - p1 < BUFSIZE)) {
|
|
- strncpy(current->field_name, p1, p - p1);
|
|
+// strncpy(current->field_name, p1, p - p1); (NOTE: gcc-9.0.1 emits [-Wstringop-truncation] warning)
|
|
current->field_len = p - p1;
|
|
+ memcpy(current->field_name, p1, current->field_len);
|
|
+ current->field_name[current->field_len] = '\0';
|
|
}
|
|
|
|
if ( p && (*s_e != '{' || (*s_e == '{' && buf[len] == '}') )) {
|
|
|
|
commit 9937878cce2fc049283d833685cb939caca462ca
|
|
Author: Dave Anderson <anderson@redhat.com>
|
|
Date: Thu Oct 17 12:00:23 2019 -0400
|
|
|
|
Fix for the "kmem -n" option on Linux-5.4-rc1 and later kernels that
|
|
contain commit b6c88d3b9d38f9448e0fcf44847a075ea81d5ca2, titled
|
|
"drivers/base/memory.c: don't store end_section_nr in memory blocks".
|
|
Without the patch, the command option fails with the error message
|
|
"kmem: invalid structure member offset: memory_block_end_section_nr".
|
|
(msys.mizuma@gmail.com)
|
|
|
|
diff --git a/help.c b/help.c
|
|
index a5218a7..cfd46c3 100644
|
|
--- a/help.c
|
|
+++ b/help.c
|
|
@@ -7177,7 +7177,7 @@ char *help_kmem[] = {
|
|
" 6 ffff88003d4d90c0 ffffea0000000000 ffffea0000c00000 PM 196608",
|
|
" 7 ffff88003d4d90e0 ffffea0000000000 ffffea0000e00000 PM 229376",
|
|
" ",
|
|
-" MEM_BLOCK NAME PHYSICAL RANGE STATE SECTIONS",
|
|
+" MEM_BLOCK NAME PHYSICAL RANGE STATE START_SECTION_NO",
|
|
" ffff88003a707c00 memory0 0 - 7ffffff ONLINE 0",
|
|
" ffff88003a6e0000 memory1 8000000 - fffffff ONLINE 1",
|
|
" ffff88003a6e1000 memory2 10000000 - 17ffffff ONLINE 2",
|
|
diff --git a/memory.c b/memory.c
|
|
index fe82fac..0a79838 100644
|
|
--- a/memory.c
|
|
+++ b/memory.c
|
|
@@ -17402,20 +17402,18 @@ fill_memory_block_name(ulong memblock, char *name)
|
|
}
|
|
|
|
static void
|
|
-fill_memory_block_srange(ulong start_sec, ulong end_sec, char *srange)
|
|
+fill_memory_block_srange(ulong start_sec, char *srange)
|
|
{
|
|
memset(srange, 0, sizeof(*srange) * BUFSIZE);
|
|
|
|
- if (start_sec == end_sec)
|
|
- sprintf(srange, "%lu", start_sec);
|
|
- else
|
|
- sprintf(srange, "%lu-%lu", start_sec, end_sec);
|
|
+ sprintf(srange, "%lu", start_sec);
|
|
}
|
|
|
|
static void
|
|
print_memory_block(ulong memory_block)
|
|
{
|
|
- ulong start_sec, end_sec, start_pfn, end_pfn, nid;
|
|
+ ulong start_sec, end_sec, nid;
|
|
+ ulong memblock_size, mbs, start_addr, end_addr;
|
|
char statebuf[BUFSIZE];
|
|
char srangebuf[BUFSIZE];
|
|
char name[BUFSIZE];
|
|
@@ -17430,15 +17428,25 @@ print_memory_block(ulong memory_block)
|
|
readmem(memory_block + OFFSET(memory_block_start_section_nr), KVADDR,
|
|
&start_sec, sizeof(void *), "memory_block start_section_nr",
|
|
FAULT_ON_ERROR);
|
|
- readmem(memory_block + OFFSET(memory_block_end_section_nr), KVADDR,
|
|
- &end_sec, sizeof(void *), "memory_block end_section_nr",
|
|
- FAULT_ON_ERROR);
|
|
|
|
- start_pfn = section_nr_to_pfn(start_sec);
|
|
- end_pfn = section_nr_to_pfn(end_sec + 1);
|
|
+ start_addr = pfn_to_phys(section_nr_to_pfn(start_sec));
|
|
+
|
|
+ if (symbol_exists("memory_block_size_probed")) {
|
|
+ memblock_size = symbol_value("memory_block_size_probed");
|
|
+ readmem(memblock_size, KVADDR,
|
|
+ &mbs, sizeof(ulong), "memory_block_size_probed",
|
|
+ FAULT_ON_ERROR);
|
|
+ end_addr = start_addr + mbs - 1;
|
|
+ } else {
|
|
+ readmem(memory_block + OFFSET(memory_block_end_section_nr), KVADDR,
|
|
+ &end_sec, sizeof(void *), "memory_block end_section_nr",
|
|
+ FAULT_ON_ERROR);
|
|
+ end_addr = pfn_to_phys(section_nr_to_pfn(end_sec + 1)) - 1;
|
|
+ }
|
|
+
|
|
fill_memory_block_state(memory_block, statebuf);
|
|
fill_memory_block_name(memory_block, name);
|
|
- fill_memory_block_srange(start_sec, end_sec, srangebuf);
|
|
+ fill_memory_block_srange(start_sec, srangebuf);
|
|
|
|
if (MEMBER_EXISTS("memory_block", "nid")) {
|
|
readmem(memory_block + OFFSET(memory_block_nid), KVADDR, &nid,
|
|
@@ -17448,9 +17456,9 @@ print_memory_block(ulong memory_block)
|
|
MKSTR(memory_block)),
|
|
mkstring(buf2, 12, CENTER, name),
|
|
mkstring(buf3, PADDR_PRLEN, RJUST|LONG_HEX,
|
|
- MKSTR(pfn_to_phys(start_pfn))),
|
|
+ MKSTR(start_addr)),
|
|
mkstring(buf4, PADDR_PRLEN, LJUST|LONG_HEX,
|
|
- MKSTR(pfn_to_phys(end_pfn) - 1)),
|
|
+ MKSTR(end_addr)),
|
|
mkstring(buf5, strlen("NODE"), CENTER|LONG_DEC,
|
|
MKSTR(nid)),
|
|
mkstring(buf6, strlen("CANCEL_OFFLINE"), LJUST,
|
|
@@ -17462,9 +17470,9 @@ print_memory_block(ulong memory_block)
|
|
MKSTR(memory_block)),
|
|
mkstring(buf2, 10, CENTER, name),
|
|
mkstring(buf3, PADDR_PRLEN, RJUST|LONG_HEX,
|
|
- MKSTR(pfn_to_phys(start_pfn))),
|
|
+ MKSTR(start_addr)),
|
|
mkstring(buf4, PADDR_PRLEN, LJUST|LONG_HEX,
|
|
- MKSTR(pfn_to_phys(end_pfn) - 1)),
|
|
+ MKSTR(end_addr)),
|
|
mkstring(buf5, strlen("CANCEL_OFFLINE"), LJUST,
|
|
statebuf),
|
|
mkstring(buf6, 12, LJUST, srangebuf));
|
|
@@ -17552,14 +17560,14 @@ dump_memory_blocks(int initialize)
|
|
mkstring(buf3, PADDR_PRLEN*2 + 2, CENTER, "PHYSICAL RANGE"),
|
|
mkstring(buf4, strlen("NODE"), CENTER, "NODE"),
|
|
mkstring(buf5, strlen("CANCEL_OFFLINE"), LJUST, "STATE"),
|
|
- mkstring(buf6, 12, LJUST, "SECTIONS"));
|
|
+ mkstring(buf6, 12, LJUST, "START_SECTION_NO"));
|
|
else
|
|
sprintf(mb_hdr, "\n%s %s %s %s %s\n",
|
|
mkstring(buf1, VADDR_PRLEN, CENTER|LJUST, "MEM_BLOCK"),
|
|
mkstring(buf2, 10, CENTER, "NAME"),
|
|
mkstring(buf3, PADDR_PRLEN*2, CENTER, "PHYSICAL RANGE"),
|
|
mkstring(buf4, strlen("CANCEL_OFFLINE"), LJUST, "STATE"),
|
|
- mkstring(buf5, 12, LJUST, "SECTIONS"));
|
|
+ mkstring(buf5, 12, LJUST, "START_SECTION_NO"));
|
|
fprintf(fp, "%s", mb_hdr);
|
|
|
|
for (i = 0; i < klistcnt; i++) {
|
|
|
|
commit 1f9e0ac5d0b43004639e304f718177ff4c82343b
|
|
Author: Dave Anderson <anderson@redhat.com>
|
|
Date: Sat Oct 19 16:43:16 2019 -0400
|
|
|
|
Fix for Linux 4.19.5 and later 4.19-based x86_64 kernels which
|
|
are NOT configured with CONFIG_RANDOMIZE_BASE and have backported
|
|
kernel commit d52888aa2753e3063a9d3a0c9f72f94aa9809c15, titled
|
|
"x86/mm: Move LDT remap out of KASLR region on 5-level paging",
|
|
which modified the 4-level and 5-level paging PAGE_OFFSET values.
|
|
Without this patch, the crash session fails during initialization
|
|
with the error message "crash: seek error: kernel virtual address:
|
|
<address> type: "tss_struct ist array".
|
|
(anderson@redhat.com)
|
|
|
|
diff --git a/x86_64.c b/x86_64.c
|
|
index d57b602..c7967bd 100644
|
|
--- a/x86_64.c
|
|
+++ b/x86_64.c
|
|
@@ -382,7 +382,7 @@ x86_64_init(int when)
|
|
|
|
case POST_GDB:
|
|
if (!(machdep->flags & RANDOMIZED) &&
|
|
- ((THIS_KERNEL_VERSION >= LINUX(4,20,0)) ||
|
|
+ ((THIS_KERNEL_VERSION >= LINUX(4,19,5)) ||
|
|
((THIS_KERNEL_VERSION >= LINUX(4,14,84)) &&
|
|
(THIS_KERNEL_VERSION < LINUX(4,15,0))))) {
|
|
machdep->machspec->page_offset = machdep->flags & VM_5LEVEL ?
|
|
|
|
commit 1d2bc0c65792d15f94ebfd97c22da620b74634fa
|
|
Author: Dave Anderson <anderson@redhat.com>
|
|
Date: Mon Oct 21 11:46:01 2019 -0400
|
|
|
|
Additional fix for the "kmem -n" option on Linux-5.4-rc1 and later
|
|
kernels that contain commit b6c88d3b9d38f9448e0fcf44847a075ea81d5ca2,
|
|
titled "drivers/base/memory.c: don't store end_section_nr in memory
|
|
blocks". The initial fix only addressed the x86_64 architecture;
|
|
this incremental patch addresses the other architectures.
|
|
(msys.mizuma@gmail.com)
|
|
|
|
diff --git a/help.c b/help.c
|
|
index cfd46c3..2b2285b 100644
|
|
--- a/help.c
|
|
+++ b/help.c
|
|
@@ -7177,15 +7177,15 @@ char *help_kmem[] = {
|
|
" 6 ffff88003d4d90c0 ffffea0000000000 ffffea0000c00000 PM 196608",
|
|
" 7 ffff88003d4d90e0 ffffea0000000000 ffffea0000e00000 PM 229376",
|
|
" ",
|
|
-" MEM_BLOCK NAME PHYSICAL RANGE STATE START_SECTION_NO",
|
|
-" ffff88003a707c00 memory0 0 - 7ffffff ONLINE 0",
|
|
-" ffff88003a6e0000 memory1 8000000 - fffffff ONLINE 1",
|
|
-" ffff88003a6e1000 memory2 10000000 - 17ffffff ONLINE 2",
|
|
-" ffff88003a6e1400 memory3 18000000 - 1fffffff ONLINE 3",
|
|
-" ffff88003a6e1800 memory4 20000000 - 27ffffff ONLINE 4",
|
|
-" ffff88003a6e0400 memory5 28000000 - 2fffffff ONLINE 5",
|
|
-" ffff88003a6e0800 memory6 30000000 - 37ffffff ONLINE 6",
|
|
-" ffff88003a6e0c00 memory7 38000000 - 3fffffff ONLINE 7",
|
|
+" MEM_BLOCK NAME PHYSICAL RANGE STATE START_SECTION_NO",
|
|
+" ffff88003a707c00 memory0 0 - 7ffffff ONLINE 0",
|
|
+" ffff88003a6e0000 memory1 8000000 - fffffff ONLINE 1",
|
|
+" ffff88003a6e1000 memory2 10000000 - 17ffffff ONLINE 2",
|
|
+" ffff88003a6e1400 memory3 18000000 - 1fffffff ONLINE 3",
|
|
+" ffff88003a6e1800 memory4 20000000 - 27ffffff ONLINE 4",
|
|
+" ffff88003a6e0400 memory5 28000000 - 2fffffff ONLINE 5",
|
|
+" ffff88003a6e0800 memory6 30000000 - 37ffffff ONLINE 6",
|
|
+" ffff88003a6e0c00 memory7 38000000 - 3fffffff ONLINE 7",
|
|
|
|
"\n Translate a page structure's flags field contents:\n",
|
|
" %s> kmem -g 4080",
|
|
diff --git a/memory.c b/memory.c
|
|
index 0a79838..f36685b 100644
|
|
--- a/memory.c
|
|
+++ b/memory.c
|
|
@@ -17401,6 +17401,23 @@ fill_memory_block_name(ulong memblock, char *name)
|
|
read_string(value, name, BUFSIZE-1);
|
|
}
|
|
|
|
+static void
|
|
+fill_memory_block_parange(ulong saddr, ulong eaddr, char *parange)
|
|
+{
|
|
+ char buf1[BUFSIZE];
|
|
+ char buf2[BUFSIZE];
|
|
+
|
|
+ memset(parange, 0, sizeof(*parange) * BUFSIZE);
|
|
+
|
|
+ if (eaddr == ULLONG_MAX)
|
|
+ sprintf(parange, "%s",
|
|
+ mkstring(buf1, PADDR_PRLEN*2 + 3, CENTER|LONG_HEX, MKSTR(saddr)));
|
|
+ else
|
|
+ sprintf(parange, "%s - %s",
|
|
+ mkstring(buf1, PADDR_PRLEN, RJUST|LONG_HEX, MKSTR(saddr)),
|
|
+ mkstring(buf2, PADDR_PRLEN, RJUST|LONG_HEX, MKSTR(eaddr)));
|
|
+}
|
|
+
|
|
static void
|
|
fill_memory_block_srange(ulong start_sec, char *srange)
|
|
{
|
|
@@ -17413,14 +17430,13 @@ static void
|
|
print_memory_block(ulong memory_block)
|
|
{
|
|
ulong start_sec, end_sec, nid;
|
|
- ulong memblock_size, mbs, start_addr, end_addr;
|
|
+ ulong memblock_size, mbs, start_addr, end_addr = ULLONG_MAX;
|
|
char statebuf[BUFSIZE];
|
|
char srangebuf[BUFSIZE];
|
|
+ char parangebuf[BUFSIZE];
|
|
char name[BUFSIZE];
|
|
char buf1[BUFSIZE];
|
|
char buf2[BUFSIZE];
|
|
- char buf3[BUFSIZE];
|
|
- char buf4[BUFSIZE];
|
|
char buf5[BUFSIZE];
|
|
char buf6[BUFSIZE];
|
|
char buf7[BUFSIZE];
|
|
@@ -17437,7 +17453,7 @@ print_memory_block(ulong memory_block)
|
|
&mbs, sizeof(ulong), "memory_block_size_probed",
|
|
FAULT_ON_ERROR);
|
|
end_addr = start_addr + mbs - 1;
|
|
- } else {
|
|
+ } else if (MEMBER_EXISTS("memory_block", "end_section_nr")) {
|
|
readmem(memory_block + OFFSET(memory_block_end_section_nr), KVADDR,
|
|
&end_sec, sizeof(void *), "memory_block end_section_nr",
|
|
FAULT_ON_ERROR);
|
|
@@ -17446,34 +17462,29 @@ print_memory_block(ulong memory_block)
|
|
|
|
fill_memory_block_state(memory_block, statebuf);
|
|
fill_memory_block_name(memory_block, name);
|
|
+ fill_memory_block_parange(start_addr, end_addr, parangebuf);
|
|
fill_memory_block_srange(start_sec, srangebuf);
|
|
|
|
if (MEMBER_EXISTS("memory_block", "nid")) {
|
|
readmem(memory_block + OFFSET(memory_block_nid), KVADDR, &nid,
|
|
sizeof(void *), "memory_block nid", FAULT_ON_ERROR);
|
|
- fprintf(fp, " %s %s %s - %s %s %s %s\n",
|
|
+ fprintf(fp, " %s %s %s %s %s %s\n",
|
|
mkstring(buf1, VADDR_PRLEN, LJUST|LONG_HEX,
|
|
MKSTR(memory_block)),
|
|
mkstring(buf2, 12, CENTER, name),
|
|
- mkstring(buf3, PADDR_PRLEN, RJUST|LONG_HEX,
|
|
- MKSTR(start_addr)),
|
|
- mkstring(buf4, PADDR_PRLEN, LJUST|LONG_HEX,
|
|
- MKSTR(end_addr)),
|
|
+ parangebuf,
|
|
mkstring(buf5, strlen("NODE"), CENTER|LONG_DEC,
|
|
MKSTR(nid)),
|
|
- mkstring(buf6, strlen("CANCEL_OFFLINE"), LJUST,
|
|
+ mkstring(buf6, strlen("OFFLINE"), LJUST,
|
|
statebuf),
|
|
mkstring(buf7, 12, LJUST, srangebuf));
|
|
} else
|
|
- fprintf(fp, " %s %s %s - %s %s %s\n",
|
|
+ fprintf(fp, " %s %s %s %s %s\n",
|
|
mkstring(buf1, VADDR_PRLEN, LJUST|LONG_HEX,
|
|
MKSTR(memory_block)),
|
|
mkstring(buf2, 10, CENTER, name),
|
|
- mkstring(buf3, PADDR_PRLEN, RJUST|LONG_HEX,
|
|
- MKSTR(start_addr)),
|
|
- mkstring(buf4, PADDR_PRLEN, LJUST|LONG_HEX,
|
|
- MKSTR(end_addr)),
|
|
- mkstring(buf5, strlen("CANCEL_OFFLINE"), LJUST,
|
|
+ parangebuf,
|
|
+ mkstring(buf5, strlen("OFFLINE"), LJUST,
|
|
statebuf),
|
|
mkstring(buf6, 12, LJUST, srangebuf));
|
|
}
|
|
@@ -17537,6 +17548,7 @@ dump_memory_blocks(int initialize)
|
|
int klistcnt, i;
|
|
struct list_data list_data;
|
|
char mb_hdr[BUFSIZE];
|
|
+ char paddr_hdr[BUFSIZE];
|
|
char buf1[BUFSIZE];
|
|
char buf2[BUFSIZE];
|
|
char buf3[BUFSIZE];
|
|
@@ -17553,20 +17565,26 @@ dump_memory_blocks(int initialize)
|
|
|
|
init_memory_block(&list_data, &klistcnt, &klistbuf);
|
|
|
|
+ if ((symbol_exists("memory_block_size_probed")) ||
|
|
+ (MEMBER_EXISTS("memory_block", "end_section_nr")))
|
|
+ sprintf(paddr_hdr, "%s", "PHYSICAL RANGE");
|
|
+ else
|
|
+ sprintf(paddr_hdr, "%s", "PHYSICAL START");
|
|
+
|
|
if (MEMBER_EXISTS("memory_block", "nid"))
|
|
- sprintf(mb_hdr, "\n%s %s %s %s %s %s\n",
|
|
+ sprintf(mb_hdr, "\n%s %s %s %s %s %s\n",
|
|
mkstring(buf1, VADDR_PRLEN, CENTER|LJUST, "MEM_BLOCK"),
|
|
mkstring(buf2, 10, CENTER, "NAME"),
|
|
- mkstring(buf3, PADDR_PRLEN*2 + 2, CENTER, "PHYSICAL RANGE"),
|
|
+ mkstring(buf3, PADDR_PRLEN*2 + 2, CENTER, paddr_hdr),
|
|
mkstring(buf4, strlen("NODE"), CENTER, "NODE"),
|
|
- mkstring(buf5, strlen("CANCEL_OFFLINE"), LJUST, "STATE"),
|
|
+ mkstring(buf5, strlen("OFFLINE"), LJUST, "STATE"),
|
|
mkstring(buf6, 12, LJUST, "START_SECTION_NO"));
|
|
else
|
|
- sprintf(mb_hdr, "\n%s %s %s %s %s\n",
|
|
+ sprintf(mb_hdr, "\n%s %s %s %s %s\n",
|
|
mkstring(buf1, VADDR_PRLEN, CENTER|LJUST, "MEM_BLOCK"),
|
|
mkstring(buf2, 10, CENTER, "NAME"),
|
|
- mkstring(buf3, PADDR_PRLEN*2, CENTER, "PHYSICAL RANGE"),
|
|
- mkstring(buf4, strlen("CANCEL_OFFLINE"), LJUST, "STATE"),
|
|
+ mkstring(buf3, PADDR_PRLEN*2, CENTER, paddr_hdr),
|
|
+ mkstring(buf4, strlen("OFFLINE"), LJUST, "STATE"),
|
|
mkstring(buf5, 12, LJUST, "START_SECTION_NO"));
|
|
fprintf(fp, "%s", mb_hdr);
|
|
|
|
|
|
commit 869f3b24fc3f1dd236b58e1cff86fb4e68da76cf
|
|
Author: Dave Anderson <anderson@redhat.com>
|
|
Date: Tue Oct 22 16:42:57 2019 -0400
|
|
|
|
In the unlikely event that the panic task in a dumpfile cannot be
|
|
determined by the normal means, scan the kernel log buffer for panic
|
|
keywords, and if found, generate the panic task from the CPU number
|
|
that is specified following the panic message.
|
|
(chenqiwu@xiaomi.com)
|
|
|
|
diff --git a/task.c b/task.c
|
|
index 829c794..8dd2b96 100644
|
|
--- a/task.c
|
|
+++ b/task.c
|
|
@@ -48,6 +48,9 @@ static void show_tgid_list(ulong);
|
|
static int compare_start_time(const void *, const void *);
|
|
static int start_time_timespec(void);
|
|
static ulonglong convert_start_time(ulonglong, ulonglong);
|
|
+static ulong search_panic_task_by_cpu(char *);
|
|
+static ulong search_panic_task_by_keywords(char *, int *);
|
|
+static ulong get_log_panic_task(void);
|
|
static ulong get_dumpfile_panic_task(void);
|
|
static ulong get_active_set_panic_task(void);
|
|
static void populate_panic_threads(void);
|
|
@@ -132,6 +135,23 @@ static struct sched_policy_info {
|
|
{ ULONG_MAX, NULL }
|
|
};
|
|
|
|
+enum PANIC_TASK_FOUND_RESULT {
|
|
+ FOUND_NO_PANIC_KEYWORD,
|
|
+ FOUND_PANIC_KEYWORD,
|
|
+ FOUND_PANIC_TASK
|
|
+};
|
|
+
|
|
+const char *panic_keywords[] = {
|
|
+ "Unable to handle kernel",
|
|
+ "BUG: unable to handle kernel",
|
|
+ "Kernel BUG at",
|
|
+ "kernel BUG at",
|
|
+ "Bad mode in",
|
|
+ "Oops",
|
|
+ "Kernel panic",
|
|
+ NULL,
|
|
+};
|
|
+
|
|
/*
|
|
* Figure out how much space will be required to hold the task context
|
|
* data, malloc() it, and call refresh_task_table() to fill it up.
|
|
@@ -6116,8 +6136,8 @@ get_panic_ksp(struct bt_info *bt, ulong *ksp)
|
|
|
|
/*
|
|
* Look for kcore's storage information for the system's panic state.
|
|
- * If it's not there (somebody else's dump format?), look through all the
|
|
- * stack traces for evidence of panic.
|
|
+ * If it's not there (somebody else's dump format?), look through all
|
|
+ * the stack traces or the log buffer for evidence of panic.
|
|
*/
|
|
static ulong
|
|
get_panic_context(void)
|
|
@@ -6321,6 +6341,13 @@ get_panicmsg(char *buf)
|
|
break;
|
|
}
|
|
}
|
|
+ rewind(pc->tmpfile);
|
|
+ while (!msg_found && fgets(buf, BUFSIZE, pc->tmpfile)) {
|
|
+ if (strstr(buf, "Bad mode in ")) {
|
|
+ msg_found = TRUE;
|
|
+ break;
|
|
+ }
|
|
+ }
|
|
|
|
close_tmpfile();
|
|
|
|
@@ -7401,6 +7428,8 @@ panic_search(void)
|
|
|
|
close_tmpfile();
|
|
|
|
+ pc->curcmd = pc->program_name;
|
|
+
|
|
if (!found && (dietask > (NO_TASK+1)) && task_has_cpu(dietask, NULL)) {
|
|
lasttask = dietask;
|
|
found = TRUE;
|
|
@@ -7410,9 +7439,16 @@ panic_search(void)
|
|
error(WARNING, "multiple active tasks have called die\n\n");
|
|
|
|
if (CRASHDEBUG(1) && found)
|
|
- error(INFO, "panic_search: %lx (via foreach bt)\n",
|
|
+ error(INFO, "panic_search: %lx (via foreach bt)\n",
|
|
lasttask);
|
|
|
|
+ if (!found) {
|
|
+ if (CRASHDEBUG(1))
|
|
+ error(INFO, "panic_search: failed (via foreach bt)\n");
|
|
+ if ((lasttask = get_log_panic_task()))
|
|
+ found = TRUE;
|
|
+ }
|
|
+
|
|
found_panic_task:
|
|
populate_panic_threads();
|
|
|
|
@@ -7430,11 +7466,114 @@ found_panic_task:
|
|
}
|
|
|
|
if (CRASHDEBUG(1))
|
|
- error(INFO, "panic_search: failed (via foreach bt)\n");
|
|
+ error(INFO, "panic_search: failed\n");
|
|
|
|
return NULL;
|
|
}
|
|
|
|
+static ulong
|
|
+search_panic_task_by_cpu(char *buf)
|
|
+{
|
|
+ int crashing_cpu;
|
|
+ char *p1, *p2;
|
|
+ ulong task = NO_TASK;
|
|
+
|
|
+ p1 = NULL;
|
|
+
|
|
+ if ((p1 = strstr(buf, "CPU: ")))
|
|
+ p1 += strlen("CPU: ");
|
|
+ else if (STRNEQ(buf, "CPU "))
|
|
+ p1 = buf + strlen("CPU ");
|
|
+
|
|
+ if (p1) {
|
|
+ p2 = p1;
|
|
+ while (!whitespace(*p2) && (*p2 != '\n'))
|
|
+ p2++;
|
|
+ *p2 = NULLCHAR;
|
|
+ crashing_cpu = dtol(p1, RETURN_ON_ERROR, NULL);
|
|
+ if ((crashing_cpu >= 0) && in_cpu_map(ONLINE_MAP, crashing_cpu)) {
|
|
+ task = tt->active_set[crashing_cpu];
|
|
+ if (CRASHDEBUG(1))
|
|
+ error(WARNING,
|
|
+ "get_log_panic_task: active_set[%d]: %lx\n",
|
|
+ crashing_cpu, tt->active_set[crashing_cpu]);
|
|
+ }
|
|
+ }
|
|
+ return task;
|
|
+}
|
|
+
|
|
+static ulong
|
|
+search_panic_task_by_keywords(char *buf, int *found_flag)
|
|
+{
|
|
+ char *p;
|
|
+ int i = 0;
|
|
+ ulong task;
|
|
+
|
|
+ while (panic_keywords[i]) {
|
|
+ if ((p = strstr(buf, panic_keywords[i]))) {
|
|
+ if ((task = search_panic_task_by_cpu(p))) {
|
|
+ *found_flag = FOUND_PANIC_TASK;
|
|
+ return task;
|
|
+ } else {
|
|
+ *found_flag = FOUND_PANIC_KEYWORD;
|
|
+ return NO_TASK;
|
|
+ }
|
|
+ }
|
|
+ i++;
|
|
+ }
|
|
+ *found_flag = FOUND_NO_PANIC_KEYWORD;
|
|
+ return NO_TASK;
|
|
+}
|
|
+
|
|
+/*
|
|
+ * Search for the panic task by seeking panic keywords from kernel log buffer.
|
|
+ * The panic keyword is generally followed by printing out the stack trace info
|
|
+ * of the panicking task. We can determine the panic task by finding the first
|
|
+ * instance of "CPU: " or "CPU " following the panic keywords.
|
|
+ */
|
|
+static ulong
|
|
+get_log_panic_task(void)
|
|
+{
|
|
+ int found_flag = FOUND_NO_PANIC_KEYWORD;
|
|
+ int found_panic_keyword = FALSE;
|
|
+ ulong task = NO_TASK;
|
|
+ char buf[BUFSIZE];
|
|
+
|
|
+ if (!get_active_set())
|
|
+ goto fail;
|
|
+
|
|
+ BZERO(buf, BUFSIZE);
|
|
+ open_tmpfile();
|
|
+ dump_log(SHOW_LOG_TEXT);
|
|
+ rewind(pc->tmpfile);
|
|
+ while (fgets(buf, BUFSIZE, pc->tmpfile)) {
|
|
+ if (!found_panic_keyword) {
|
|
+ task = search_panic_task_by_keywords(buf, &found_flag);
|
|
+ switch (found_flag) {
|
|
+ case FOUND_PANIC_TASK:
|
|
+ goto found_panic_task;
|
|
+ case FOUND_PANIC_KEYWORD:
|
|
+ found_panic_keyword = TRUE;
|
|
+ continue;
|
|
+ default:
|
|
+ continue;
|
|
+ }
|
|
+ } else {
|
|
+ task = search_panic_task_by_cpu(buf);
|
|
+ if (task)
|
|
+ goto found_panic_task;
|
|
+ }
|
|
+ }
|
|
+
|
|
+found_panic_task:
|
|
+ close_tmpfile();
|
|
+fail:
|
|
+ if (CRASHDEBUG(1) && !task)
|
|
+ error(WARNING, "cannot determine the panic task from kernel log buffer\n");
|
|
+
|
|
+ return task;
|
|
+}
|
|
+
|
|
/*
|
|
* Get the panic task from the appropriate dumpfile handler.
|
|
*/
|
|
|
|
commit 6a466f8afbb0dcdf4ddc5ef37aec6d343c2636c6
|
|
Author: Dave Anderson <anderson@redhat.com>
|
|
Date: Mon Nov 4 11:56:28 2019 -0500
|
|
|
|
Adjust a crash-7.1.8 patch for support of /proc/kcore as the live
|
|
memory source in Linux 4.8 and later x86_64 kernels configured with
|
|
CONFIG_RANDOMIZE_BASE, which randomizes the unity-mapping PAGE_OFFSET
|
|
value. Since the problem only arises before the determination of the
|
|
randomized PAGE_OFFSET value, restrict the patch such that it only
|
|
takes effect during session initialization.
|
|
(anderson@redhat.com)
|
|
|
|
diff --git a/netdump.c b/netdump.c
|
|
index 55b64e6..fdaecf3 100644
|
|
--- a/netdump.c
|
|
+++ b/netdump.c
|
|
@@ -4269,7 +4269,8 @@ read_proc_kcore(int fd, void *bufptr, int cnt, ulong addr, physaddr_t paddr)
|
|
* If KASLR, the PAGE_OFFSET may be unknown early on, so try
|
|
* the (hopefully) mapped kernel address first.
|
|
*/
|
|
- if ((pc->curcmd_flags & MEMTYPE_KVADDR) && (kvaddr != addr)) {
|
|
+ if (!(pc->flags & RUNTIME) &&
|
|
+ (pc->curcmd_flags & MEMTYPE_KVADDR) && (kvaddr != addr)) {
|
|
pc->curcmd_flags &= ~MEMTYPE_KVADDR;
|
|
for (i = 0; i < pkd->segments; i++) {
|
|
lp64 = pkd->load64 + i;
|
|
|
|
commit c0bbd8fae4271159aee9e643350781909484c92f
|
|
Author: Dave Anderson <anderson@redhat.com>
|
|
Date: Fri Nov 8 14:00:56 2019 -0500
|
|
|
|
Add support for extended numbering support in ELF dumpfiles to handle
|
|
more than PN_XNUM (0xffff) program headers. If the real number of
|
|
program header table entries is equal to or greater than PN_XNUM, the
|
|
e_phnum field of the ELF header is set to PN_XNUM, and the actual
|
|
number is set in the sh_info field of the section header at index 0.
|
|
(k-hagio@ab.jp.nec.com)
|
|
|
|
diff --git a/netdump.c b/netdump.c
|
|
index fdaecf3..3ced87c 100644
|
|
--- a/netdump.c
|
|
+++ b/netdump.c
|
|
@@ -28,12 +28,13 @@ static struct vmcore_data *nd = &vmcore_data;
|
|
static struct proc_kcore_data proc_kcore_data = { 0 };
|
|
static struct proc_kcore_data *pkd = &proc_kcore_data;
|
|
static void netdump_print(char *, ...);
|
|
-static size_t resize_elf_header(int, char *, char **, ulong);
|
|
+static size_t resize_elf_header(int, char *, char **, char **, ulong);
|
|
static void dump_Elf32_Ehdr(Elf32_Ehdr *);
|
|
static void dump_Elf32_Phdr(Elf32_Phdr *, int);
|
|
static size_t dump_Elf32_Nhdr(Elf32_Off offset, int);
|
|
static void dump_Elf64_Ehdr(Elf64_Ehdr *);
|
|
static void dump_Elf64_Phdr(Elf64_Phdr *, int);
|
|
+static void dump_Elf64_Shdr(Elf64_Shdr *shdr);
|
|
static size_t dump_Elf64_Nhdr(Elf64_Off offset, int);
|
|
static void get_netdump_regs_32(struct bt_info *, ulong *, ulong *);
|
|
static void get_netdump_regs_ppc(struct bt_info *, ulong *, ulong *);
|
|
@@ -116,7 +117,7 @@ is_netdump(char *file, ulong source_query)
|
|
Elf32_Phdr *load32;
|
|
Elf64_Ehdr *elf64;
|
|
Elf64_Phdr *load64;
|
|
- char *eheader;
|
|
+ char *eheader, *sect0;
|
|
char buf[BUFSIZE];
|
|
size_t size, len, tot;
|
|
Elf32_Off offset32;
|
|
@@ -330,7 +331,8 @@ is_netdump(char *file, ulong source_query)
|
|
goto bailout;
|
|
}
|
|
|
|
- if (!(size = resize_elf_header(fd, file, &eheader, format)))
|
|
+ sect0 = NULL;
|
|
+ if (!(size = resize_elf_header(fd, file, &eheader, §0, format)))
|
|
goto bailout;
|
|
|
|
nd->ndfd = fd;
|
|
@@ -372,7 +374,17 @@ is_netdump(char *file, ulong source_query)
|
|
case KDUMP_ELF64:
|
|
nd->header_size = size;
|
|
nd->elf64 = (Elf64_Ehdr *)&nd->elf_header[0];
|
|
- nd->num_pt_load_segments = nd->elf64->e_phnum - 1;
|
|
+
|
|
+ /*
|
|
+ * Extended Numbering support
|
|
+ * See include/uapi/linux/elf.h and elf(5) for more information
|
|
+ */
|
|
+ if (nd->elf64->e_phnum == PN_XNUM) {
|
|
+ nd->sect0_64 = (Elf64_Shdr *)sect0;
|
|
+ nd->num_pt_load_segments = nd->sect0_64->sh_info - 1;
|
|
+ } else
|
|
+ nd->num_pt_load_segments = nd->elf64->e_phnum - 1;
|
|
+
|
|
if ((nd->pt_load_segments = (struct pt_load_segment *)
|
|
malloc(sizeof(struct pt_load_segment) *
|
|
nd->num_pt_load_segments)) == NULL) {
|
|
@@ -432,7 +444,8 @@ bailout:
|
|
*/
|
|
|
|
static size_t
|
|
-resize_elf_header(int fd, char *file, char **eheader_ptr, ulong format)
|
|
+resize_elf_header(int fd, char *file, char **eheader_ptr, char **sect0_ptr,
|
|
+ ulong format)
|
|
{
|
|
int i;
|
|
char buf[BUFSIZE];
|
|
@@ -462,7 +475,44 @@ resize_elf_header(int fd, char *file, char **eheader_ptr, ulong format)
|
|
|
|
case NETDUMP_ELF64:
|
|
case KDUMP_ELF64:
|
|
- num_pt_load_segments = elf64->e_phnum - 1;
|
|
+ /*
|
|
+ * Extended Numbering support
|
|
+ * See include/uapi/linux/elf.h and elf(5) for more information
|
|
+ */
|
|
+ if (elf64->e_phnum == PN_XNUM) {
|
|
+ Elf64_Shdr *shdr64;
|
|
+
|
|
+ shdr64 = (Elf64_Shdr *)malloc(sizeof(*shdr64));
|
|
+ if (!shdr64) {
|
|
+ fprintf(stderr,
|
|
+ "cannot malloc a section header buffer\n");
|
|
+ return 0;
|
|
+ }
|
|
+ if (FLAT_FORMAT()) {
|
|
+ if (!read_flattened_format(fd, elf64->e_shoff,
|
|
+ shdr64, elf64->e_shentsize))
|
|
+ return 0;
|
|
+ } else {
|
|
+ if (lseek(fd, elf64->e_shoff, SEEK_SET) !=
|
|
+ elf64->e_shoff) {
|
|
+ sprintf(buf, "%s: section header lseek",
|
|
+ file);
|
|
+ perror(buf);
|
|
+ return 0;
|
|
+ }
|
|
+ if (read(fd, shdr64, elf64->e_shentsize) !=
|
|
+ elf64->e_shentsize) {
|
|
+ sprintf(buf, "%s: section header read",
|
|
+ file);
|
|
+ perror(buf);
|
|
+ return 0;
|
|
+ }
|
|
+ }
|
|
+ num_pt_load_segments = shdr64->sh_info - 1;
|
|
+ *sect0_ptr = (char *)shdr64;
|
|
+ } else
|
|
+ num_pt_load_segments = elf64->e_phnum - 1;
|
|
+
|
|
header_size = sizeof(Elf64_Ehdr) + sizeof(Elf64_Phdr) +
|
|
(sizeof(Elf64_Phdr) * num_pt_load_segments);
|
|
break;
|
|
@@ -1168,6 +1218,7 @@ netdump_memory_dump(FILE *fp)
|
|
netdump_print(" elf64: %lx\n", nd->elf64);
|
|
netdump_print(" notes64: %lx\n", nd->notes64);
|
|
netdump_print(" load64: %lx\n", nd->load64);
|
|
+ netdump_print(" sect0_64: %lx\n", nd->sect0_64);
|
|
netdump_print(" nt_prstatus: %lx\n", nd->nt_prstatus);
|
|
netdump_print(" nt_prpsinfo: %lx\n", nd->nt_prpsinfo);
|
|
netdump_print(" nt_taskstruct: %lx\n", nd->nt_taskstruct);
|
|
@@ -1252,6 +1303,8 @@ netdump_memory_dump(FILE *fp)
|
|
dump_Elf64_Phdr(nd->notes64, ELFREAD);
|
|
for (i = 0; i < nd->num_pt_load_segments; i++)
|
|
dump_Elf64_Phdr(nd->load64 + i, ELFREAD);
|
|
+ if (nd->sect0_64)
|
|
+ dump_Elf64_Shdr(nd->sect0_64);
|
|
offset64 = nd->notes64->p_offset;
|
|
for (tot = 0; tot < nd->notes64->p_filesz; tot += len) {
|
|
if (!(len = dump_Elf64_Nhdr(offset64, ELFREAD)))
|
|
@@ -1763,6 +1816,32 @@ dump_Elf64_Phdr(Elf64_Phdr *prog, int store_pt_load_data)
|
|
netdump_print(" p_align: %lld\n", prog->p_align);
|
|
}
|
|
|
|
+static void
|
|
+dump_Elf64_Shdr(Elf64_Shdr *shdr)
|
|
+{
|
|
+ netdump_print("Elf64_Shdr:\n");
|
|
+ netdump_print(" sh_name: %x\n", shdr->sh_name);
|
|
+ netdump_print(" sh_type: %x ", shdr->sh_type);
|
|
+ switch (shdr->sh_type)
|
|
+ {
|
|
+ case SHT_NULL:
|
|
+ netdump_print("(SHT_NULL)\n");
|
|
+ break;
|
|
+ default:
|
|
+ netdump_print("\n");
|
|
+ break;
|
|
+ }
|
|
+ netdump_print(" sh_flags: %lx\n", shdr->sh_flags);
|
|
+ netdump_print(" sh_addr: %lx\n", shdr->sh_addr);
|
|
+ netdump_print(" sh_offset: %lx\n", shdr->sh_offset);
|
|
+ netdump_print(" sh_size: %lx\n", shdr->sh_size);
|
|
+ netdump_print(" sh_link: %x\n", shdr->sh_link);
|
|
+ netdump_print(" sh_info: %x (%u)\n", shdr->sh_info,
|
|
+ shdr->sh_info);
|
|
+ netdump_print(" sh_addralign: %lx\n", shdr->sh_addralign);
|
|
+ netdump_print(" sh_entsize: %lx\n", shdr->sh_entsize);
|
|
+}
|
|
+
|
|
/*
|
|
* VMCOREINFO
|
|
*
|
|
diff --git a/netdump.h b/netdump.h
|
|
index ad1fc77..7fa04f7 100644
|
|
--- a/netdump.h
|
|
+++ b/netdump.h
|
|
@@ -61,6 +61,7 @@ struct vmcore_data {
|
|
Elf64_Ehdr *elf64;
|
|
Elf64_Phdr *notes64;
|
|
Elf64_Phdr *load64;
|
|
+ Elf64_Shdr *sect0_64;
|
|
void *nt_prstatus;
|
|
void *nt_prpsinfo;
|
|
void *nt_taskstruct;
|
|
|
|
commit b5c2359f9f7347a2efa4896fa134dbf128601ca8
|
|
Author: Dave Anderson <anderson@redhat.com>
|
|
Date: Fri Nov 8 14:32:53 2019 -0500
|
|
|
|
Fix for a "warning: large integer implicitly truncated to unsigned
|
|
type [-Woverflow]" compiler message generated on 32-bit architectures
|
|
as a result of the "Additional fix for the kmem -n option" patch
|
|
above.
|
|
(anderson@redhat.com)
|
|
|
|
diff --git a/memory.c b/memory.c
|
|
index f36685b..4f7b6a0 100644
|
|
--- a/memory.c
|
|
+++ b/memory.c
|
|
@@ -17430,7 +17430,7 @@ static void
|
|
print_memory_block(ulong memory_block)
|
|
{
|
|
ulong start_sec, end_sec, nid;
|
|
- ulong memblock_size, mbs, start_addr, end_addr = ULLONG_MAX;
|
|
+ ulong memblock_size, mbs, start_addr, end_addr = (ulong)ULLONG_MAX;
|
|
char statebuf[BUFSIZE];
|
|
char srangebuf[BUFSIZE];
|
|
char parangebuf[BUFSIZE];
|