[PATCH] extensions: use -m32 for target=MIPS build of eppic
by Rabin Vincent
Force -m32 in eppic.mk, similiar to how it's already done for ARM and
X86.
---
extensions/eppic.mk | 3 +++
1 file changed, 3 insertions(+)
diff --git a/extensions/eppic.mk b/extensions/eppic.mk
index 7421ebc..de3ff4f 100644
--- a/extensions/eppic.mk
+++ b/extensions/eppic.mk
@@ -16,6 +16,9 @@ endif
ifeq ($(TARGET), ARM)
TARGET_FLAGS += -m32
endif
+ifeq ($(TARGET), MIPS)
+ TARGET_FLAGS += -m32
+endif
ifeq ($(TARGET), X86)
TARGET_FLAGS += -m32
endif
--
1.7.10.4
9 years, 4 months
[PATCH] address compiler warning for extensions/trace.c
by Dave Anderson
Hello Qiao,
With more recent versions of gcc, extensions/trace.c generates this warning:
$ make extensions
...
gcc -Wall -g -shared -rdynamic -o trace.so trace.c -fPIC -DX86_64 -DLZO -DSNAPPY -DGDB_7_6
/tmp/ccSOIphT.o: In function 'ftrace_show':
/root/crash.git/extensions/trace.c:1560: warning: the use of 'mktemp' is dangerous, better use 'mkstemp'
...
$
I've attached an untested patch that replaces the mktemp() call with mkstemp().
I believe the only behavioral difference is that mkstemp() will create the file
automatically with permissions 600 and open flags of O_EXCL, whereas it is
currently being opened with permissions 644 and flags (O_WRONLY | O_CREAT | O_TRUNC).
Can you either ACK the patch, or address the warning as you would prefer?
Thanks,
Dave
9 years, 4 months
task: recursive temporary file usage
by Rabin Vincent
Hi,
If I try to print a non-existing member of task_struct with foreach, I get
expected error messages:
crash> foreach task -R invalid
PID: 0 TASK: 806d9d30 CPU: 0 COMMAND: "swapper/0"
task: invalid: not a task_struct or thread_info member
PID: 0 TASK: 8fce2808 CPU: 1 COMMAND: "swapper/1"
task: invalid: not a task_struct or thread_info member
PID: 1 TASK: 8fc9c768 CPU: 0 COMMAND: "systemd"
task: invalid: not a task_struct or thread_info member
But, if I try to do this with a non-existing submember of an existing
member, I get 'recursive temporary file usage':
crash> foreach task -R se.invalid
PID: 0 TASK: 806d9d30 CPU: 0 COMMAND: "swapper/0"
task: invalid data structure member reference: se.invalid
task: recursive temporary file usage
task: recursive temporary file usage
task: recursive temporary file usage
task: recursive temporary file usage
This is with the the latest crash from git. I think this started from
the patches which introduced the deep-printing of structures. I haven't
investigated further yet, though.
Thanks.
/Rabin
9 years, 4 months
Re: [Crash-utility] [PATCH] read physical memory layout from device tree (32-bit ARM)
by Arseniy Krasnov
Sorry for patch mistakes...
> Looking at the kernel sources, I can't understand exactly how it works
with multiple physical base addresses?
> There is another __virt_to_phys() that is constrained to
CONFIG_PATCH_ARM_PHYS_VIRT, but it seems to depend
> on !SPARSEMEM? Can you explain how the kernel does it?
Exactly!, i've found another __virt_to_phys() in our kernel, which works in
same way as vtop_sparse() in my patch.
> Your dumpfile is an ELF vmcore. Can you show me the output of "readelf
-a"
> on your vmcore?
Program Headers:
Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align
NOTE 0x0000d4 0x00000000 0x00000000 0x00850 0x00850 0
LOAD 0x000924 0xc0000000 0x20000000 0xf800000 0xf800000 RWE 0
LOAD 0xf800924 0xe0000000 0x40000000 0x00000 0x00000 RWE 0
LOAD 0xf800924 0xe1000000 0x41000000 0x2b000000 0x2b000000 RWE 0
LOAD 0x3a800924 0x24800000 0x84800000 0x2b000000 0x2b000000 RWE
0
Yes it reflects memory regions of board, but not precisely(I don't know
why). As you can see third PT_LOAD has
PhysAddr more for 0x1000000 than needed, may be previous PT_LOAD with
0x40000000 and size 0 must be considered.
> I don't know what "provided device tree" file means. Where does the file
come from?
It is just binary file with information about hardware which used by kernel
during boot. Also there is information
about memory regions.
> Worse case, it seems that you should be able to create something like a
"--machdep phys_base=<addr:size,addr:size,addr:size>"
> option string that describes the multiple physical bases/sizes.
I think you are right, it will be more simple way than always carrying file
with information of memory regions.
So now I understood that issue is in another virt_to_phys() for my board, I
also found another sparse virt_to_phys()
in arch/arm/mach-realview/include/mach/memory.h and finally I think problem
is that crash doesn't support "not flat"
virt_to_phys() cases. Of course it is very rare case, but maybe it will be
useful to handle such situations...
----- Original Message -----
> Hello Dave,
> here is patch mentioned in bug
> https://bugzilla.redhat.com/show_bug.cgi?id=1238151.
> It adds new option "--dtbmem" which reads physical memory layout from
> provided device tree and use it for kernel virtual to physical memory
> address translation. This is needed because some unusual boards have
> sparse memory and it is impossible to translate address using offset
> cause memory "holes" must be considered.
> Fail occurs during read of "mem_section" symbol.
> With this patch everything works ok. I use device tree parser based on
> 'fdtdump' utility from device tree compiler.
>
> Of course it is just basic concept and code doesn't look good, but if
> this idea will be useful i'll improve it.
Hello Arseniy,
Just so the 32-bit ARM developers on this list can understand what this is
all about, here is the description from the bugzilla you filed:
Description of problem: crash failed reading 'memory_section' symbol with
sparse mem.
How reproducible:
I have board with sparse memory. When i'm trying to load coredump of this
board,
i get the following message:
crash: read error: kernel virtual address: dc98f400 type: "memory
section"
This happens because 'arm_kvtop' translates virtual to physical just using
offset,
while mentioned board has the following physical memory layout(from,
size):
0x20000000, 0xf800000
0x40000000, 0x2c000000
0x84800000, 0x2b000000
So when crash substracts offset from 0xdc98f400 it gets 0x3c98f400, which
is
out of physical addresses of coredump program segments. I've prepared
simple
patch which parses device tree in order to read these memory regions and
use
them instead of offset substraction during virtual to physical address
translation.
So the problem is not with the CONFIG_SPARSEMEM per se, but rather with the
the crash utility's VTOP() macro for 32-bit ARM, which is this:
#define PTOV(X) \
((unsigned
long)(X)-(machdep->machspec->phys_base)+(machdep->kvbase))
#define VTOP(X) \
((unsigned
long)(X)-(machdep->kvbase)+(machdep->machspec->phys_base))
and where the machdep->machspec->phys_base value is determined during
initialization like so:
(1) on live systems, by parsing /proc/iomem
(2) in ELF kdump dumpfiles, from parsing the PT_LOAD segments, and selects
the lowest "PhysAddr" value.
(3) in compressed kdump dumpfiles, from the dumpile header
(4) or the user must pass the offset with "--machdep phys_base=<addr>"
The crash utility's VTOP() is a direct reflection of how the 32-bit ARM
kernel does it, at least if the kernel is configured with CONFIG_FLATMEM:
static inline phys_addr_t __virt_to_phys(unsigned long x)
{
return (phys_addr_t)x - PAGE_OFFSET + PHYS_OFFSET;
}
Looking at the kernel sources, I can't understand exactly how it works with
multiple physical base addresses? There is another __virt_to_phys() that is
constrained to CONFIG_PATCH_ARM_PHYS_VIRT, but it seems to depend on
!SPARSEMEM? Can you explain how the kernel does it?
So anyway, the problem is that crash does not support 32-bit ARM kernels
configured with CONFIG_SPARSEMEM which have *multiple* phys_base values.
Your patch adds a "--dtbmem <file>" option which reads the physical memory
layout from a
"provided device tree". It parses that file, and creates an array of
structures containing a physical-base-address/size pairs for each memory
segment.
I don't know what "provided device tree" file means. Where does the file
come from?
Regardless of that, I have to believe that this cannot be accomplished in a
much simpler manner.
Your dumpfile is an ELF vmcore. Can you show me the output of "readelf -a"
on your vmcore? It should reflect the physical address ranges you showed
above:
> 0x20000000, 0xf800000
> 0x40000000, 0x2c000000
> 0x84800000, 0x2b000000
I guessing that the PT_LOAD segments will precisely reflect the regions
above. If that's true, why can't the information be gathered from the
vmcore header as it does now?
Worse case, it seems that you should be able to create something like a
"--machdep phys_base=<addr:size,addr:size,addr:size>" option string that
describes the multiple physical bases/sizes.
In any case, I have some initial comments about the patch.
First, can you please post your patches as attachments to your email?
It seems that it has been line-wrapped somewhere along the line. I started
fixing each complaint, but I give up:
$ patch -p1 --dry-run < dtb.patch
patching file Makefile
patch: **** malformed patch at line 39: help.c task.c \
$ vi +39 $dl/dtc.patch
< fix line 39 >
$ patch -p1 --dry-run < dtb.patch
patching file Makefile
patch: **** malformed patch at line 43: \
$ vi +43 $dl/dtc.patch
< fix line 43 >
$ patch -p1 --dry-run < dtb.patch
patching file Makefile
Hunk #1 succeeded at 69 with fuzz 2 (offset -1 lines).
patching file arm.c
patch: **** malformed patch at line 77: PMD_TYPE_TABLE 1 #define
PMD_TYPE_SECT_LPAE 1
$
Your patch replaces the two VTOP() calls in arm.c with a new vtop_sparse()
function if this feature has been used:
+ if (dyn_mems == NULL)
+ *paddr = VTOP(kvaddr);
+ else
+ *paddr = vtop_sparse(kvaddr);
But the patch does not handle the cases where VTOP() is used by generic
crash code outside of arm.c. And it doesn't handle PTOV() at all.
So what would have to be done is to change the ARM VTOP() and PTOV() macros
in "defs.h" so that all callers will do the right thing.
The Makefile has declared mem_dtb.c and mem_dtb.o, but then compiles it
based upon "parse.o"?:
+ ramdump.c vmware_vmss.c mem_dtb.c
+ ramdump.o vmware_vmss.o mem_dtb.o
+parse.o: ${GENERIC_HFILES} mem_dtb.c
+ ${CC} -c ${CRASH_CFLAGS} mem_dtb.c ${WARNING_OPTIONS}
${WARNING_ERROR}
+
I note this at the end of the new mem_dtb.c file:
+#ifdef ARM
... [ cut ] ...
+}
+#else
+int read_dtb_sparse_mem(const char *dtb_file_name) {
+ error(INFO, "Sparse mem supported only for arm!\n");
+ return 0;
+}
+#endif
--
Kind of misleading -- it's not a problem with sparsemem, but rather this
device tree file business.
But again, I appreciate the work you put into this, but please let's try to
avoid this additional file requirement.
Thanks,
Dave
>
> >From a634cf95aadff1a4372f066cca009332bcec2fc6 Mon Sep 17 00:00:00
> >2001
> From: Arseniy Krasnov <a.krasnov(a)samsung.com>
> Date: Wed, 1 Jul 2015 10:26:34 +0300
> Subject: [PATCH] crashtool: phys memory layout from device tree.
>
> ---
> Makefile | 7 +-
> arm.c | 39 +++++++-
> defs.h | 9 ++
> main.c | 8 +-
> mem_dtb.c | 299
> ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
> 5 files changed, 354 insertions(+), 8 deletions(-) create mode
> 100644 mem_dtb.c
>
> diff --git a/Makefile b/Makefile
> index 3c38ff5..e2188a5 100644
> --- a/Makefile
> +++ b/Makefile
> @@ -70,7 +70,7 @@ CFILES=main.c tools.c global_data.c memory.c
> filesys.c help.c task.c \
> unwind_x86_32_64.c unwind_arm.c \
> xen_hyper.c xen_hyper_command.c xen_hyper_global_data.c \
> xen_hyper_dump_tables.c kvmdump.c qemu.c qemu-load.c sadump.c ipcs.c
> \
> - ramdump.c vmware_vmss.c
> + ramdump.c vmware_vmss.c mem_dtb.c
>
> SOURCE_FILES=${CFILES} ${GENERIC_HFILES} ${MCORE_HFILES} \
> ${REDHAT_CFILES} ${REDHAT_HFILES} ${UNWIND_HFILES} \ @@ -88,7 +88,7
> @@ OBJECT_FILES=main.o tools.o global_data.o memory.o filesys.o help.o
> task.o \
> unwind_x86_32_64.o unwind_arm.o \
> xen_hyper.o xen_hyper_command.o xen_hyper_global_data.o \
> xen_hyper_dump_tables.o kvmdump.o qemu.o qemu-load.o sadump.o ipcs.o
> \
> - ramdump.o vmware_vmss.o
> + ramdump.o vmware_vmss.o mem_dtb.o
>
> MEMORY_DRIVER_FILES=memory_driver/Makefile memory_driver/crash.c
> memory_driver/README
>
> @@ -345,6 +345,9 @@ help.o: ${GENERIC_HFILES} help.c
> memory.o: ${GENERIC_HFILES} memory.c
> ${CC} -c ${CRASH_CFLAGS} memory.c ${WARNING_OPTIONS}
> ${WARNING_ERROR}
>
> +parse.o: ${GENERIC_HFILES} mem_dtb.c
> + ${CC} -c ${CRASH_CFLAGS} mem_dtb.c ${WARNING_OPTIONS}
> ${WARNING_ERROR}
> +
> test.o: ${GENERIC_HFILES} test.c
> ${CC} -c ${CRASH_CFLAGS} test.c ${WARNING_OPTIONS} ${WARNING_ERROR}
>
> diff --git a/arm.c b/arm.c
> index 534c501..c31e6a1 100644
> --- a/arm.c
> +++ b/arm.c
> @@ -85,6 +85,10 @@ static struct arm_pt_regs *panic_task_regs;
> #define PMD_TYPE_TABLE 1 #define PMD_TYPE_SECT_LPAE 1
>
> +/* number of memory areas and its array */ int mems_num; struct
> +mem_area *dyn_mems;
> +
> static inline ulong *
> pmd_page_addr(ulong pmd)
> {
> @@ -1264,6 +1268,30 @@ arm_uvtop(struct task_context *tc, ulong
> uvaddr, physaddr_t *paddr, int verbose)
> return arm_vtop(uvaddr, pgd, paddr, verbose); }
>
> +static physaddr_t vtop_sparse(unsigned int vaddr) {
> + physaddr_t ret;
> + physaddr_t cur;
> + int i;
> +
> + ret = vaddr - machdep->kvbase;
> +
> + cur = 0;
> + for(i = 0;i < mems_num;i++) {
> + if (ret < cur + dyn_mems[i].size) {
> + if (i == 0)
> + ret += dyn_mems[0].base;
> + else
> + ret = dyn_mems[i].base + (ret - cur);
> + break;
> + }
> +
> + cur += dyn_mems[i].size;
> + }
> +
> + return ret;
> +}
> +
> /*
> * Translates a kernel virtual address to its physical address.
> cmd_vtop() sets
> * the verbose flag so that the pte translation gets displayed; all
> other @@ -1279,14 +1307,19 @@ arm_kvtop(struct task_context *tc, ulong
> kvaddr, physaddr_t *paddr, int verbose)
> return arm_lpae_vtop(kvaddr, (ulong *)vt->kernel_pgd[0],
> paddr, verbose);
>
> -
> if (!vt->vmalloc_start) {
> - *paddr = VTOP(kvaddr);
> + if (dyn_mems == NULL)
> + *paddr = VTOP(kvaddr);
> + else
> + *paddr = vtop_sparse(kvaddr);
> return TRUE;
> }
>
> if (!IS_VMALLOC_ADDR(kvaddr)) {
> - *paddr = VTOP(kvaddr);
> + if (dyn_mems == NULL)
> + *paddr = VTOP(kvaddr);
> + else
> + *paddr = vtop_sparse(kvaddr);
> if (!verbose)
> return TRUE;
> }
> diff --git a/defs.h b/defs.h
> index ecadc29..94e5509 100644
> --- a/defs.h
> +++ b/defs.h
> @@ -6281,4 +6281,13 @@ extern int have_full_symbols(void); #define
> XEN_HYPERVISOR_ARCH #endif
>
> +#ifdef ARM
> +/* describes memory area for sparse memory systems */ struct mem_area {
> + physaddr_t base;
> + unsigned int size;
> +};
> +int read_dtb_sparse_mem(const char *filename); #endif
> +
> #endif /* !GDB_COMMON */
> diff --git a/main.c b/main.c
> index fd7f7a8..eeccd68 100644
> --- a/main.c
> +++ b/main.c
> @@ -72,6 +72,7 @@ static struct option long_options[] = {
> {"no_strip", 0, 0, 0},
> {"hash", required_argument, 0, 0},
> {"offline", required_argument, 0, 0},
> + {"dtbmem", required_argument, 0, 0},
> {0, 0, 0, 0}
> };
>
> @@ -291,9 +292,10 @@ main(int argc, char **argv)
> error(INFO, "invalid --offline
> argument: %s\n", optarg);
> program_usage(SHORT_FORM);
> }
> - }
> -
> - else {
> + } else if (STREQ(long_options[option_index].name,
> "dtbmem")) {
> + if (read_dtb_sparse_mem(optarg) == 0)
> + error(INFO, "Failed to read sparse
> mem config!\n");
> + } else {
> error(INFO, "internal error: option %s
unhandled\n",
> long_options[option_index].name);
> program_usage(SHORT_FORM);
> diff --git a/mem_dtb.c b/mem_dtb.c
> new file mode 100644
> index 0000000..23526bc
> --- /dev/null
> +++ b/mem_dtb.c
> @@ -0,0 +1,299 @@
> +/*
> + * Tiny device tree parser from 'fdtdump' application of device tree
> compiler.
> + * http://www.devicetree.org/Device_Tree_Compiler
> + * https://git.kernel.org/cgit/utils/dtc/dtc.git
> + */
> +#include <stdio.h>
> +#include <sys/mman.h>
> +#include <stdint.h>
> +#include <fcntl.h>
> +#include <stdlib.h>
> +#include <byteswap.h>
> +#include <sys/stat.h>
> +#include <sys/types.h>
> +#include <unistd.h>
> +#include <assert.h>
> +#include <string.h>
> +#include <ctype.h>
> +#include "defs.h"
> +
> +typedef uint32_t fdt32_t;
> +typedef uint64_t fdt64_t;
> +
> +#define FDT_BEGIN_NODE 0x1 /* Start node: full name */
> +#define FDT_END_NODE 0x2 /* End node */
> +#define FDT_PROP 0x3 /* Property: name off,
> + size, content */
> +#define FDT_NOP 0x4 /* nop */
> +#define FDT_END 0x9
> +
> +#define EXTRACT_BYTE(x, n) ((unsigned long long)((uint8_t *)&x)[n])
> +#define CPU_TO_FDT32(x) ((EXTRACT_BYTE(x, 0) << 24) |
> +(EXTRACT_BYTE(x, 1)
> << 16) | \
> + (EXTRACT_BYTE(x, 2) << 8) | EXTRACT_BYTE(x, 3))
> #define
> +CPU_TO_FDT64(x) ((EXTRACT_BYTE(x, 0) << 56) | (EXTRACT_BYTE(x, 1) <<
> +48) |
> \
> + (EXTRACT_BYTE(x, 2) << 40) | (EXTRACT_BYTE(x, 3) <<
> 32) | \
> + (EXTRACT_BYTE(x, 4) << 24) | (EXTRACT_BYTE(x, 5) <<
> 16) | \
> + (EXTRACT_BYTE(x, 6) << 8) | EXTRACT_BYTE(x, 7))
> +
> +#define ALIGN(x, a) (((x) + ((a) - 1)) & ~((a) - 1))
> +#define PALIGN(p, a) ((void *)(ALIGN((unsigned long)(p), (a))))
> +#define GET_CELL(p) (p += 4, *((const uint32_t *)(p-4)))
> +
> +#ifdef ARM
> +int memory_found;
> +int memory_node_found;
> +
> +extern struct mem_area *dyn_mems;
> +extern int mems_num;
> +
> +static inline uint32_t fdt32_to_cpu(fdt32_t x) {
> + return (uint32_t)CPU_TO_FDT32(x);
> +}
> +
> +static inline uint64_t fdt64_to_cpu(fdt64_t x) {
> + return (uint64_t)CPU_TO_FDT64(x);
> +}
> +
> +struct fdt_header {
> + fdt32_t magic; /* magic word FDT_MAGIC */
> + fdt32_t totalsize; /* total size of DT block */
> + fdt32_t off_dt_struct; /* offset to structure */
> + fdt32_t off_dt_strings; /* offset to strings */
> + fdt32_t off_mem_rsvmap; /* offset to memory reserve map */
> + fdt32_t version; /* format version */
> + fdt32_t last_comp_version; /* last compatible version */
> +
> + /* version 2 fields below */
> + fdt32_t boot_cpuid_phys; /* Which physical CPU id we're
> + booting on */
> + /* version 3 fields below */
> + fdt32_t size_dt_strings; /* size of the strings block */
> +
> + /* version 17 fields below */
> + fdt32_t size_dt_struct; /* size of the structure block */
> +};
> +
> +struct fdt_reserve_entry {
> + fdt64_t address;
> + fdt64_t size;
> +};
> +
> +struct fdt_node_header {
> + fdt32_t tag;
> + char name[0];
> +};
> +
> +struct fdt_property {
> + fdt32_t tag;
> + fdt32_t len;
> + fdt32_t nameoff;
> + char data[0];
> +};
> +
> +static int util_is_printable_string(const void *data, int len) {
> + const char *s = data;
> + const char *ss, *se;
> +
> + /* zero length is not */
> + if (len == 0)
> + return 0;
> +
> + /* must terminate with zero */
> + if (s[len - 1] != '\0')
> + return 0;
> +
> + se = s + len;
> +
> + while (s < se) {
> + ss = s;
> + while (s < se && *s && isprint((unsigned char)*s))
> + s++;
> +
> + /* not zero, or not done yet */
> + if (*s != '\0' || s == ss)
> + return 0;
> +
> + s++;
> + }
> +
> + return 1;
> +}
> +
> +static int utilfdt_print_data(const char *data, int len) {
> + int i;
> + const char *s;
> +
> + /* no data, don't print */
> + if (len == 0)
> + return;
> +
> + if (util_is_printable_string(data, len)) {
> + s = data;
> +
> + if (strcmp(s, "memory") == 0) {
> + if (memory_node_found == 1)
> + memory_found = 1;
> + } else
> + memory_found = 0;
> +
> + do {
> + s += strlen(s) + 1;
> + } while (s < data + len);
> +
> + } else if ((len % 4) == 0) {
> + const uint32_t *cell = (const uint32_t *)data;
> +
> + len /= 4;
> +
> + if (memory_found == 1) {
> + int k;
> +
> + /* we are on property with memory regions */
> + dyn_mems = malloc((len / 2) * (sizeof *dyn_mems));
> +
> + if (dyn_mems == NULL)
> + return -1;
> +
> + for (k = 0, i = 0; i < len; k++, i += 2) {
> + physaddr_t from;
> + unsigned int size;
> +
> + from = fdt32_to_cpu(cell[i]);
> + size = fdt32_to_cpu(cell[i + 1]);
> + dyn_mems[k].base = from;
> + dyn_mems[k].size = size;
> + printf("adding memregion: %08llX sz:
> %08X\n",
> + dyn_mems[k].base, dyn_mems[k].size);
> + }
> +
> + mems_num = k;
> +
> + return 1;
> + }
> + }
> +
> + return 0;
> +}
> +
> +static int parse_dt(void *blob)
> +{
> + struct fdt_header *bph = blob;
> + uint32_t off_mem_rsvmap = fdt32_to_cpu(bph->off_mem_rsvmap);
> + uint32_t off_dt = fdt32_to_cpu(bph->off_dt_struct);
> + uint32_t off_str = fdt32_to_cpu(bph->off_dt_strings);
> + struct fdt_reserve_entry *p_rsvmap =
> + (struct fdt_reserve_entry *)((char *)blob + off_mem_rsvmap);
> + const char *p_struct = (const char *)blob + off_dt;
> + const char *p_strings = (const char *)blob + off_str;
> + uint32_t version = fdt32_to_cpu(bph->version);
> + uint32_t tag;
> + const char *p, *s, *t;
> + int depth, sz;
> + int i;
> + uint64_t addr, size;
> +
> + depth = 0;
> +
> + for (i = 0; ; i++) {
> + addr = fdt64_to_cpu(p_rsvmap[i].address);
> + size = fdt64_to_cpu(p_rsvmap[i].size);
> +
> + if (addr == 0 && size == 0)
> + break;
> + }
> +
> + p = p_struct;
> +
> + while ((tag = fdt32_to_cpu(GET_CELL(p))) != FDT_END) {
> + int res;
> +
> + if (tag == FDT_BEGIN_NODE) {
> + s = p;
> + p = PALIGN(p + strlen(s) + 1, 4);
> +
> + if (*s == '\0')
> + s = "/";
> +
> + if (!strcmp(s, "memory"))
> + memory_node_found = 1;
> +
> + depth++;
> + continue;
> + }
> +
> + if (tag == FDT_END_NODE) {
> + depth--;
> + continue;
> + }
> +
> + if (tag == FDT_NOP)
> + continue;
> +
> + if (tag != FDT_PROP)
> + break;
> +
> + sz = fdt32_to_cpu(GET_CELL(p));
> + s = p_strings + fdt32_to_cpu(GET_CELL(p));
> +
> + if (version < 16 && sz >= 8)
> + p = PALIGN(p, 8);
> +
> + t = p;
> +
> + p = PALIGN(p + sz, 4);
> +
> + res = utilfdt_print_data(t, sz);
> +
> + /* error occured */
> + if (res == -1)
> + return 0;
> +
> + /* memory region parsed, exit */
> + if (res == 1)
> + return 1;
> +
> + /* again */
> + }
> +
> + return 0;
> +}
> +
> +int read_dtb_sparse_mem(const char *dtb_file_name) {
> + int dt_fd;
> + unsigned char *p;
> + struct stat si;
> + int res;
> +
> + res = 0;
> + dt_fd = open(dtb_file_name, O_RDONLY);
> +
> + if (dt_fd == -1)
> + goto out;
> +
> + if (fstat(dt_fd, &si))
> + goto out_close;
> +
> + p = mmap(NULL, si.st_size, PROT_READ | PROT_WRITE,
> + MAP_PRIVATE, dt_fd, 0);
> +
> + if (p == MAP_FAILED)
> + goto out_close;
> +
> + res = parse_dt(p);
> +out_close:
> + close(dt_fd);
> +out:
> + return res;
> +}
> +#else
> +int read_dtb_sparse_mem(const char *dtb_file_name) {
> + error(INFO, "Sparse mem supported only for arm!\n");
> + return 0;
> +}
> +#endif
> --
> 1.9.1
>
>
> --
> Crash-utility mailing list
> Crash-utility(a)redhat.com
> https://www.redhat.com/mailman/listinfo/crash-utility
>
--
Crash-utility mailing list
Crash-utility(a)redhat.com
https://www.redhat.com/mailman/listinfo/crash-utility
End of Crash-utility Digest, Vol 118, Issue 3
*********************************************
9 years, 4 months
[PATCH] Make runq -g work without RT_GROUP_SCHED
by Rabin Vincent
CONFIG_FAIR_GROUP_SCHED (which provides task_group.cfs_rq) and
CONFIG_RT_GROUP_SCHED (which provides task_group.rt_rq) need not be both
enabled in a kernel. Let's support runq -g even if only one of them is
enabled.
---
task.c | 46 ++++++++++++++++++++++++++++------------------
1 file changed, 28 insertions(+), 18 deletions(-)
diff --git a/task.c b/task.c
index 3a88d68..3e6aff4 100644
--- a/task.c
+++ b/task.c
@@ -7747,8 +7747,8 @@ cmd_runq(void)
dump_milliseconds_flag = 1;
break;
case 'g':
- if (INVALID_MEMBER(task_group_cfs_rq) ||
- INVALID_MEMBER(task_group_rt_rq) ||
+ if ((INVALID_MEMBER(task_group_cfs_rq) &&
+ INVALID_MEMBER(task_group_rt_rq)) ||
INVALID_MEMBER(task_group_parent))
option_not_supported(c);
dump_task_group_flag = 1;
@@ -9134,8 +9134,8 @@ static void
dump_tasks_by_task_group(void)
{
int cpu, displayed;
- ulong root_task_group, cfs_rq, cfs_rq_p;
- ulong rt_rq, rt_rq_p;
+ ulong root_task_group, cfs_rq = 0, cfs_rq_p;
+ ulong rt_rq = 0, rt_rq_p;
char *buf;
struct task_context *tc;
char *task_group_name;
@@ -9161,8 +9161,10 @@ dump_tasks_by_task_group(void)
buf = GETBUF(SIZE(task_group));
readmem(root_task_group, KVADDR, buf, SIZE(task_group),
"task_group", FAULT_ON_ERROR);
- rt_rq = ULONG(buf + OFFSET(task_group_rt_rq));
- cfs_rq = ULONG(buf + OFFSET(task_group_cfs_rq));
+ if (VALID_MEMBER(task_group_rt_rq))
+ rt_rq = ULONG(buf + OFFSET(task_group_rt_rq));
+ if (VALID_MEMBER(task_group_cfs_rq))
+ cfs_rq = ULONG(buf + OFFSET(task_group_cfs_rq));
fill_task_group_info_array(0, root_task_group, buf, -1);
sort_task_group_info_array();
@@ -9178,10 +9180,14 @@ dump_tasks_by_task_group(void)
if (cpus && !NUM_IN_BITMAP(cpus, cpu))
continue;
- readmem(rt_rq + cpu * sizeof(ulong), KVADDR, &rt_rq_p,
- sizeof(ulong), "task_group rt_rq", FAULT_ON_ERROR);
- readmem(cfs_rq + cpu * sizeof(ulong), KVADDR, &cfs_rq_p,
- sizeof(ulong), "task_group cfs_rq", FAULT_ON_ERROR);
+ if (rt_rq)
+ readmem(rt_rq + cpu * sizeof(ulong), KVADDR,
+ &rt_rq_p, sizeof(ulong), "task_group rt_rq",
+ FAULT_ON_ERROR);
+ if (cfs_rq)
+ readmem(cfs_rq + cpu * sizeof(ulong), KVADDR,
+ &cfs_rq_p, sizeof(ulong), "task_group cfs_rq",
+ FAULT_ON_ERROR);
fprintf(fp, "%sCPU %d", displayed++ ? "\n" : "", cpu);
if (hide_offline_cpu(cpu)) {
@@ -9197,15 +9203,19 @@ dump_tasks_by_task_group(void)
else
fprintf(fp, "%lx\n", tt->active_set[cpu]);
- fprintf(fp, " %s_TASK_GROUP: %lx RT_RQ: %lx\n",
- task_group_name, root_task_group, rt_rq_p);
- reuse_task_group_info_array();
- dump_tasks_in_task_group_rt_rq(0, rt_rq_p, cpu);
+ if (rt_rq) {
+ fprintf(fp, " %s_TASK_GROUP: %lx RT_RQ: %lx\n",
+ task_group_name, root_task_group, rt_rq_p);
+ reuse_task_group_info_array();
+ dump_tasks_in_task_group_rt_rq(0, rt_rq_p, cpu);
+ }
- fprintf(fp, " %s_TASK_GROUP: %lx CFS_RQ: %lx\n",
- task_group_name, root_task_group, cfs_rq_p);
- reuse_task_group_info_array();
- dump_tasks_in_task_group_cfs_rq(0, cfs_rq_p, cpu, tc);
+ if (cfs_rq) {
+ fprintf(fp, " %s_TASK_GROUP: %lx CFS_RQ: %lx\n",
+ task_group_name, root_task_group, cfs_rq_p);
+ reuse_task_group_info_array();
+ dump_tasks_in_task_group_cfs_rq(0, cfs_rq_p, cpu, tc);
+ }
}
FREEBUF(buf);
--
1.7.10.4
9 years, 4 months
[PATCH v4] files: support dump file memory mapping
by yangoliver
Hi Dave,
This is v4 patch for files memory mapping dump support.
The major changes in this version are,
1. Your alignment patch for NRPAGES
2. Changed files -a to files -p
Changed output and displayed INODE, ADDRESS_SPACE, NRPAGES
at beginning.
3. Updated help.c and added exmaple outputs for new options.
4. Some minor code cleanup, for function name defined in defs.h
Here is my patch,
Added two options in files command,
1. -m option, which allows dump file mapping and
page count for each files
2. -p option, which could dump each pages within
the mapping for given inode address
The foreach command also could work with -m, so
that we can easily find which processes/files hold
biggest page cache within the system.
Signed-off-by: Yong Yang <yangoliver(a)gmail.com>
---
defs.h | 6 +++
filesys.c | 166 +++++++++++++++++++++++++++++++++++++++++++++++++++++++-------
help.c | 39 ++++++++++++++-
memory.c | 61 +++++++++++++++++++++++
symbols.c | 2 +
task.c | 19 +++++--
6 files changed, 271 insertions(+), 22 deletions(-)
diff --git a/defs.h b/defs.h
index b25b505..ba4e0d8 100644
--- a/defs.h
+++ b/defs.h
@@ -1940,6 +1940,7 @@ struct offset_table { /* stash of commonly-used offsets */
long task_struct_thread_reg31;
long pt_regs_regs;
long pt_regs_cp0_badvaddr;
+ long address_space_page_tree;
};
struct size_table { /* stash of commonly-used sizes */
@@ -2598,6 +2599,7 @@ struct load_module {
#define PRINT_SINGLE_VMA (0x80)
#define PRINT_RADIX_10 (0x100)
#define PRINT_RADIX_16 (0x200)
+#define PRINT_PAGES (0x400)
#define MIN_PAGE_SIZE (4096)
@@ -4707,6 +4709,8 @@ void alter_stackbuf(struct bt_info *);
int vaddr_type(ulong, struct task_context *);
char *format_stack_entry(struct bt_info *bt, char *, ulong, ulong);
int in_user_stack(ulong, ulong);
+void dump_file_addr_mapping(ulong);
+long get_file_mapping_nrpages(ulong);
/*
* filesys.c
@@ -4743,6 +4747,7 @@ int is_readable(char *);
#define RADIX_TREE_SEARCH (2)
#define RADIX_TREE_DUMP (3)
#define RADIX_TREE_GATHER (4)
+#define RADIX_TREE_DUMP_CB (5)
struct radix_tree_pair {
ulong index;
void *value;
@@ -4753,6 +4758,7 @@ int file_dump(ulong, ulong, ulong, int, int);
#define DUMP_INODE_ONLY 2
#define DUMP_DENTRY_ONLY 4
#define DUMP_EMPTY_FILE 8
+#define DUMP_FILE_PAGE 16
#endif /* !GDB_COMMON */
int same_file(char *, char *);
#ifndef GDB_COMMON
diff --git a/filesys.c b/filesys.c
index 0573fe6..a54576f 100644
--- a/filesys.c
+++ b/filesys.c
@@ -49,7 +49,7 @@ static void *radix_tree_lookup(ulong, ulong, int);
static int match_file_string(char *, char *, char *);
static ulong get_root_vfsmount(char *);
static void check_live_arch_mismatch(void);
-
+static void dump_file_addr_space(ulong);
#define DENTRY_CACHE (20)
#define INODE_CACHE (20)
@@ -2167,6 +2167,50 @@ show_hit_rates:
}
}
+static void
+dump_file_addr_space(ulong inode)
+{
+ char *inode_buf;
+ ulong i_mapping;
+ ulong nrpages;
+ char header[BUFSIZE];
+ char buf1[BUFSIZE];
+ char buf2[BUFSIZE];
+ char buf3[BUFSIZE];
+
+ inode_buf = GETBUF(SIZE(inode));
+ readmem(inode, KVADDR, inode_buf, SIZE(inode), "inode buffer",
+ FAULT_ON_ERROR);
+
+ i_mapping = ULONG(inode_buf + OFFSET(inode_i_mapping));
+ nrpages = get_file_mapping_nrpages(i_mapping);
+
+ sprintf(header, "%s%s%s%sNRPAGES\n",
+ mkstring(buf1, VADDR_PRLEN, CENTER|LJUST, "INODE"),
+ space(MINSPACE),
+ mkstring(buf2, VADDR_PRLEN, CENTER|LJUST, "MAPPING"),
+ space(MINSPACE));
+ fprintf(fp, "%s", header);
+
+ fprintf(fp, "%s%s%s%s%s\n\n",
+ mkstring(buf1, VADDR_PRLEN,
+ CENTER|RJUST|LONG_HEX,
+ MKSTR(inode)),
+ space(MINSPACE),
+ mkstring(buf2, VADDR_PRLEN,
+ CENTER|RJUST|LONG_HEX,
+ MKSTR(i_mapping)),
+ space(MINSPACE),
+ mkstring(buf3, strlen("NRPAGES"),
+ RJUST|LONG_DEC,
+ MKSTR(nrpages)));
+
+ dump_file_addr_mapping(i_mapping);
+
+ FREEBUF(inode_buf);
+ return;
+}
+
/*
* This command displays information about the open files of a context.
* For each open file descriptor the file descriptor number, a pointer
@@ -2187,11 +2231,12 @@ cmd_files(void)
int subsequent;
struct reference reference, *ref;
char *refarg;
+ int open_flags = 0;
ref = NULL;
refarg = NULL;
- while ((c = getopt(argcnt, args, "d:R:")) != EOF) {
+ while ((c = getopt(argcnt, args, "d:R:p:m")) != EOF) {
switch(c)
{
case 'R':
@@ -2210,6 +2255,24 @@ cmd_files(void)
display_dentry_info(value);
return;
+ case 'p':
+ if (VALID_MEMBER(address_space_page_tree) &&
+ VALID_MEMBER(inode_i_mapping)) {
+ value = htol(optarg, FAULT_ON_ERROR, NULL);
+ dump_file_addr_space(value);
+ } else {
+ option_not_supported('p');
+ }
+ return;
+
+ case 'm':
+ if (VALID_MEMBER(address_space_page_tree) &&
+ VALID_MEMBER(inode_i_mapping))
+ open_flags |= PRINT_PAGES;
+ else
+ option_not_supported('m');
+ break;
+
default:
argerrs++;
break;
@@ -2222,7 +2285,9 @@ cmd_files(void)
if (!args[optind]) {
if (!ref)
print_task_header(fp, CURRENT_CONTEXT(), 0);
- open_files_dump(CURRENT_TASK(), 0, ref);
+
+ open_files_dump(CURRENT_TASK(), open_flags, ref);
+
return;
}
@@ -2241,7 +2306,7 @@ cmd_files(void)
for (tc = pid_to_context(value); tc; tc = tc->tc_next) {
if (!ref)
print_task_header(fp, tc, subsequent);
- open_files_dump(tc->task, 0, ref);
+ open_files_dump(tc->task, open_flags, ref);
fprintf(fp, "\n");
}
break;
@@ -2249,7 +2314,7 @@ cmd_files(void)
case STR_TASK:
if (!ref)
print_task_header(fp, tc, subsequent);
- open_files_dump(tc->task, 0, ref);
+ open_files_dump(tc->task, open_flags, ref);
break;
case STR_INVALID:
@@ -2321,6 +2386,7 @@ open_files_dump(ulong task, int flags, struct reference *ref)
char buf4[BUFSIZE];
char root_pwd[BUFSIZE];
int root_pwd_printed = 0;
+ int file_dump_flags = 0;
BZERO(root_pathname, BUFSIZE);
BZERO(pwd_pathname, BUFSIZE);
@@ -2329,15 +2395,26 @@ open_files_dump(ulong task, int flags, struct reference *ref)
fdtable_buf = GETBUF(SIZE(fdtable));
fill_task_struct(task);
- sprintf(files_header, " FD%s%s%s%s%s%s%sTYPE%sPATH\n",
- space(MINSPACE),
- mkstring(buf1, VADDR_PRLEN, CENTER|LJUST, "FILE"),
- space(MINSPACE),
- mkstring(buf2, VADDR_PRLEN, CENTER|LJUST, "DENTRY"),
- space(MINSPACE),
- mkstring(buf3, VADDR_PRLEN, CENTER|LJUST, "INODE"),
- space(MINSPACE),
- space(MINSPACE));
+ if (flags & PRINT_PAGES) {
+ sprintf(files_header, " FD%s%s%s%s%sNRPAGES%sTYPE%sPATH\n",
+ space(MINSPACE),
+ mkstring(buf1, VADDR_PRLEN, CENTER|LJUST, "INODE"),
+ space(MINSPACE),
+ mkstring(buf2, VADDR_PRLEN, CENTER|LJUST, "MAPPING"),
+ space(MINSPACE),
+ space(MINSPACE),
+ space(MINSPACE));
+ } else {
+ sprintf(files_header, " FD%s%s%s%s%s%s%sTYPE%sPATH\n",
+ space(MINSPACE),
+ mkstring(buf1, VADDR_PRLEN, CENTER|LJUST, "FILE"),
+ space(MINSPACE),
+ mkstring(buf2, VADDR_PRLEN, CENTER|LJUST, "DENTRY"),
+ space(MINSPACE),
+ mkstring(buf3, VADDR_PRLEN, CENTER|LJUST, "INODE"),
+ space(MINSPACE),
+ space(MINSPACE));
+ }
tc = task_to_context(task);
@@ -2523,6 +2600,10 @@ open_files_dump(ulong task, int flags, struct reference *ref)
return;
}
+ file_dump_flags = DUMP_FULL_NAME | DUMP_EMPTY_FILE;
+ if (flags & PRINT_PAGES)
+ file_dump_flags |= DUMP_FILE_PAGE;
+
j = 0;
for (;;) {
unsigned long set;
@@ -2539,8 +2620,7 @@ open_files_dump(ulong task, int flags, struct reference *ref)
if (ref && file) {
open_tmpfile();
- if (file_dump(file, 0, 0, i,
- DUMP_FULL_NAME|DUMP_EMPTY_FILE)) {
+ if (file_dump(file, 0, 0, i, file_dump_flags)) {
BZERO(buf4, BUFSIZE);
rewind(pc->tmpfile);
ret = fgets(buf4, BUFSIZE,
@@ -2558,8 +2638,7 @@ open_files_dump(ulong task, int flags, struct reference *ref)
fprintf(fp, "%s", files_header);
header_printed = 1;
}
- file_dump(file, 0, 0, i,
- DUMP_FULL_NAME|DUMP_EMPTY_FILE);
+ file_dump(file, 0, 0, i, file_dump_flags);
}
}
i++;
@@ -2754,6 +2833,8 @@ file_dump(ulong file, ulong dentry, ulong inode, int fd, int flags)
char buf1[BUFSIZE];
char buf2[BUFSIZE];
char buf3[BUFSIZE];
+ ulong i_mapping = 0;
+ ulong nrpages = 0;
file_buf = NULL;
@@ -2863,6 +2944,28 @@ file_dump(ulong file, ulong dentry, ulong inode, int fd, int flags)
type,
space(MINSPACE),
pathname+1);
+ } else if (flags & DUMP_FILE_PAGE) {
+ i_mapping = ULONG(inode_buf + OFFSET(inode_i_mapping));
+ nrpages = get_file_mapping_nrpages(i_mapping);
+
+ fprintf(fp, "%3d%s%s%s%s%s%s%s%s%s%s\n",
+ fd,
+ space(MINSPACE),
+ mkstring(buf1, VADDR_PRLEN,
+ CENTER|RJUST|LONG_HEX,
+ MKSTR(inode)),
+ space(MINSPACE),
+ mkstring(buf2, VADDR_PRLEN,
+ CENTER|RJUST|LONG_HEX,
+ MKSTR(i_mapping)),
+ space(MINSPACE),
+ mkstring(buf3, strlen("NRPAGES"),
+ RJUST|LONG_DEC,
+ MKSTR(nrpages)),
+ space(MINSPACE),
+ type,
+ space(MINSPACE),
+ pathname);
} else {
fprintf(fp, "%3d%s%s%s%s%s%s%s%s%s%s\n",
fd,
@@ -3870,6 +3973,9 @@ ulong RADIX_TREE_MAP_MASK = UNINITIALIZED;
* limit the number of returned entries by putting the array size
* (max count) in the rtp->index field of the first structure
* in the passed-in array.
+ * RADIX_TREE_DUMP_CB - Similar with RADIX_TREE_DUMP, but for each
+ * radix tree entry, a user defined callback at rtp->value will
+ * be invoked.
*
* rtp: Unused by RADIX_TREE_COUNT and RADIX_TREE_DUMP.
* A pointer to a radix_tree_pair structure for RADIX_TREE_SEARCH.
@@ -3877,6 +3983,8 @@ ulong RADIX_TREE_MAP_MASK = UNINITIALIZED;
* RADIX_TREE_GATHER; the dimension (max count) of the array may
* be stored in the index field of the first structure to avoid
* any chance of an overrun.
+ * For RADIX_TREE_DUMP_CB, the rtp->value need to be initialized as
+ * callback function. The callback prototype must be int (*)(ulong);
*/
ulong
do_radix_tree(ulong root, int flag, struct radix_tree_pair *rtp)
@@ -3889,6 +3997,7 @@ do_radix_tree(ulong root, int flag, struct radix_tree_pair *rtp)
struct radix_tree_pair *r;
ulong root_rnode;
void *ret;
+ int (*cb)(ulong) = NULL;
count = 0;
@@ -3993,6 +4102,27 @@ do_radix_tree(ulong root, int flag, struct radix_tree_pair *rtp)
}
break;
+ case RADIX_TREE_DUMP_CB:
+ if (rtp->value == NULL) {
+ error(FATAL, "do_radix_tree: need set callback function");
+ return -EINVAL;
+ }
+ cb = (int (*)(ulong))rtp->value;
+ for (index = count = 0; index <= maxindex; index++) {
+ if ((ret =
+ radix_tree_lookup(root_rnode, index, height))) {
+ /* Caller defined operation */
+ if (cb((ulong)ret) != 0) {
+ error(FATAL, "do_radix_tree: dump "
+ "operation failed, count: %ld\n",
+ count);
+ return -EIO;
+ }
+ count++;
+ }
+ }
+ break;
+
default:
error(FATAL, "do_radix_tree: invalid flag: %lx\n", flag);
}
diff --git a/help.c b/help.c
index f36316f..25df6e5 100644
--- a/help.c
+++ b/help.c
@@ -6488,7 +6488,7 @@ NULL
char *help_files[] = {
"files",
"open files",
-"[-d dentry] | [-R reference] [pid | taskp] ... ",
+"[-d dentry] | [-p inode] | [-m] [-R reference] [pid | taskp] ... ",
" This command displays information about open files of a context.",
" It prints the context's current root directory and current working",
" directory, and then for each open file descriptor it prints a pointer",
@@ -6501,6 +6501,10 @@ char *help_files[] = {
" specific, and only shows the data requested.\n",
" -d dentry given a hexadecimal dentry address, display its inode,",
" super block, file type, and full pathname.",
+" -p inode given a hexadecimal inode address, dump all memory pages in",
+" its address space.",
+" -m show inode memory mapping information, including mapping",
+" address, page counts within the mapping.",
" -R reference search for references to this file descriptor number,",
" filename, or dentry, inode, or file structure address.",
" pid a process PID.",
@@ -6578,6 +6582,39 @@ char *help_files[] = {
" %s> files -d f745fd60",
" DENTRY INODE SUPERBLK TYPE PATH",
" f745fd60 f7284640 f73a3e00 REG /var/spool/lpd/lpd.lock",
+" ",
+" Show all tasks file mappings for REG file type:\n",
+" %s> foreach files -m -R REG",
+" PID: 1 TASK: f5c94000 CPU: 0 COMMAND: \"systemd\"",
+" ROOT: / CWD: /",
+" FD INODE MAPPING NRPAGES TYPE PATH",
+" 29 f5b7f338 f5b7f404 0 REG /proc/1/mountinfo",
+" 32 f5b728f0 f5b729bc 0 REG /proc/swaps",
+" ",
+" PID: 241 TASK: f5fcb020 CPU: 0 COMMAND: \"systemd-journal\"",
+" ROOT: / CWD: /",
+" FD INODE MAPPING NRPAGES TYPE PATH",
+" 16 f560a820 f560a8ec 1359 REG /var/log/journal/1f05.../system.journal",
+" 32 f3e42fb8 f3e43084 3 REG /var/log/journal/1f05.../user-42.journal",
+" 38 f577efb8 f577f084 438 REG /var/log/journal/1f05.../user-1000.journal",
+" <...snipped...>",
+" ",
+" PID: 280 TASK: f5d17020 CPU: 0 COMMAND: \"systemd-udevd\"",
+" ROOT: / CWD: /",
+" FD INODE MAPPING NRPAGES TYPE PATH",
+" 6 ea5adc0c ea5adcd8 1 REG /run/udev/queue.bin",
+" 11 f554efb8 f554f084 0 REG /etc/udev/hwdb.bin",
+" ",
+" Display file mapping and pages information about the inode at address f3e42fb8:\n",
+" %s> files -p f3e42fb8",
+" INODE MAPPING NRPAGES",
+" f3e42fb8 f3e43084 3",
+" ",
+" PAGE PHYSICAL MAPPING INDEX CNT FLAGS",
+" f71d4e60 1ebf3000 f3e43084 0 3 4002002c referenced,uptodate,lru,mappedtodisk",
+" f6eabf80 577c000 f3e43084 394 2 4002006c referenced,uptodate,lru,active,mappedtodisk",
+" f6e6fd60 396b000 f3e43084 396 2 4002006c referenced,uptodate,lru,active,mappedtodisk",
+" ",
NULL
};
diff --git a/memory.c b/memory.c
index 765732b..973d4eb 100644
--- a/memory.c
+++ b/memory.c
@@ -292,6 +292,7 @@ static void dump_per_cpu_offsets(void);
static void dump_page_flags(ulonglong);
static ulong kmem_cache_nodelists(ulong);
static void dump_hstates(void);
+static int dump_file_page(ulong);
/*
* Memory display modes specific to this file.
@@ -476,6 +477,7 @@ vm_init(void)
MEMBER_OFFSET_INIT(block_device_bd_list, "block_device", "bd_list");
MEMBER_OFFSET_INIT(block_device_bd_disk, "block_device", "bd_disk");
MEMBER_OFFSET_INIT(inode_i_mapping, "inode", "i_mapping");
+ MEMBER_OFFSET_INIT(address_space_page_tree, "address_space", "page_tree");
MEMBER_OFFSET_INIT(address_space_nrpages, "address_space", "nrpages");
if (INVALID_MEMBER(address_space_nrpages))
MEMBER_OFFSET_INIT(address_space_nrpages, "address_space", "__nrpages");
@@ -6465,6 +6467,65 @@ translate_page_flags(char *buffer, ulong flags)
}
/*
+ * Radix page tree dump callback.
+ */
+static int
+dump_file_page(ulong page)
+{
+ struct meminfo meminfo;
+
+ BZERO(&meminfo, sizeof(struct meminfo));
+ meminfo.spec_addr = page;
+ meminfo.memtype = KVADDR;
+ meminfo.flags = ADDRESS_SPECIFIED;
+ dump_mem_map(&meminfo);
+
+ return 0;
+}
+
+/*
+ * The address space file mapping radix tree walker.
+ */
+void
+dump_file_addr_mapping(ulong i_mapping)
+{
+ ulong root_rnode;
+ struct radix_tree_pair rtp;
+
+ root_rnode = i_mapping + OFFSET(address_space_page_tree);
+
+ rtp.index = 0;
+ rtp.value = (void *)&dump_file_page;
+
+ /* Dump each pages in radix tree */
+ (void) do_radix_tree(root_rnode, RADIX_TREE_DUMP_CB, &rtp);
+
+ return;
+}
+
+/*
+ * Get the page count for the specific mapping
+ */
+long
+get_file_mapping_nrpages(ulong i_mapping)
+{
+ ulong address_space = i_mapping;
+ char *address_space_buf;
+ ulong nrpages = 0;
+
+ address_space_buf = GETBUF(SIZE(address_space));
+
+ readmem(address_space, KVADDR, address_space_buf,
+ SIZE(address_space), "address_space buffer",
+ FAULT_ON_ERROR);
+ nrpages = ULONG(address_space_buf + OFFSET(address_space_nrpages));
+
+ FREEBUF(address_space_buf);
+
+ return nrpages;
+}
+
+/*
* dump_page_hash_table() displays the entries in each page_hash_table.
*/
diff --git a/symbols.c b/symbols.c
index 6acfcae..984cb55 100644
--- a/symbols.c
+++ b/symbols.c
@@ -8634,6 +8634,8 @@ dump_offset_table(char *spec, ulong makestruct)
OFFSET(block_device_bd_disk));
fprintf(fp, " address_space_nrpages: %ld\n",
OFFSET(address_space_nrpages));
+ fprintf(fp, " address_space_page_tree: %ld\n",
+ OFFSET(address_space_page_tree));
fprintf(fp, " gendisk_major: %ld\n",
OFFSET(gendisk_major));
fprintf(fp, " gendisk_fops: %ld\n",
diff --git a/task.c b/task.c
index 3a88d68..5fe650b 100644
--- a/task.c
+++ b/task.c
@@ -6234,6 +6234,13 @@ foreach(struct foreach_data *fd)
print_header = FALSE;
break;
+ case FOREACH_FILES:
+ if (fd->flags & FOREACH_p_FLAG)
+ error(FATAL,
+ "foreach files command does not "
+ "support -p option\n");
+ break;
+
case FOREACH_TEST:
break;
}
@@ -6460,9 +6467,15 @@ foreach(struct foreach_data *fd)
case FOREACH_FILES:
pc->curcmd = "files";
- open_files_dump(tc->task,
- fd->flags & FOREACH_i_FLAG ?
- PRINT_INODES : 0,
+ cmdflags = 0;
+
+ if (fd->flags & FOREACH_i_FLAG)
+ cmdflags |= PRINT_INODES;
+ if (fd->flags & FOREACH_m_FLAG)
+ cmdflags |= PRINT_PAGES;
+
+ open_files_dump(tc->task,
+ cmdflags,
fd->reference ? ref : NULL);
break;
--
2.4.0
9 years, 4 months
[PATCH] read physical memory layout from device tree
by Arseniy Krasnov
Sorry, forgot to set subject...
Hello Dave,
here is patch mentioned in bug
https://bugzilla.redhat.com/show_bug.cgi?id=1238151.
It adds new option "--dtbmem" which reads physical memory layout from
provided device tree and use it for kernel virtual
to physical memory address translation. This is needed because some unusual
boards have sparse memory and it is impossible
to translate address using offset cause memory "holes" must be considered.
Fail occurs during read of "mem_section" symbol.
With this patch everything works ok. I use device tree parser based on
'fdtdump' utility from device tree compiler.
Of course it is just basic concept and code doesn't look good, but if this
idea will be useful i'll improve it.
>From a634cf95aadff1a4372f066cca009332bcec2fc6 Mon Sep 17 00:00:00 2001
From: Arseniy Krasnov <a.krasnov(a)samsung.com>
Date: Wed, 1 Jul 2015 10:26:34 +0300
Subject: [PATCH] crashtool: phys memory layout from device tree.
---
Makefile | 7 +-
arm.c | 39 +++++++-
defs.h | 9 ++
main.c | 8 +-
mem_dtb.c | 299
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
5 files changed, 354 insertions(+), 8 deletions(-) create mode 100644
mem_dtb.c
diff --git a/Makefile b/Makefile
index 3c38ff5..e2188a5 100644
--- a/Makefile
+++ b/Makefile
@@ -70,7 +70,7 @@ CFILES=main.c tools.c global_data.c memory.c filesys.c
help.c task.c \
unwind_x86_32_64.c unwind_arm.c \
xen_hyper.c xen_hyper_command.c xen_hyper_global_data.c \
xen_hyper_dump_tables.c kvmdump.c qemu.c qemu-load.c sadump.c ipcs.c
\
- ramdump.c vmware_vmss.c
+ ramdump.c vmware_vmss.c mem_dtb.c
SOURCE_FILES=${CFILES} ${GENERIC_HFILES} ${MCORE_HFILES} \
${REDHAT_CFILES} ${REDHAT_HFILES} ${UNWIND_HFILES} \ @@ -88,7 +88,7
@@ OBJECT_FILES=main.o tools.o global_data.o memory.o filesys.o help.o
task.o \
unwind_x86_32_64.o unwind_arm.o \
xen_hyper.o xen_hyper_command.o xen_hyper_global_data.o \
xen_hyper_dump_tables.o kvmdump.o qemu.o qemu-load.o sadump.o ipcs.o
\
- ramdump.o vmware_vmss.o
+ ramdump.o vmware_vmss.o mem_dtb.o
MEMORY_DRIVER_FILES=memory_driver/Makefile memory_driver/crash.c
memory_driver/README
@@ -345,6 +345,9 @@ help.o: ${GENERIC_HFILES} help.c
memory.o: ${GENERIC_HFILES} memory.c
${CC} -c ${CRASH_CFLAGS} memory.c ${WARNING_OPTIONS}
${WARNING_ERROR}
+parse.o: ${GENERIC_HFILES} mem_dtb.c
+ ${CC} -c ${CRASH_CFLAGS} mem_dtb.c ${WARNING_OPTIONS}
${WARNING_ERROR}
+
test.o: ${GENERIC_HFILES} test.c
${CC} -c ${CRASH_CFLAGS} test.c ${WARNING_OPTIONS} ${WARNING_ERROR}
diff --git a/arm.c b/arm.c
index 534c501..c31e6a1 100644
--- a/arm.c
+++ b/arm.c
@@ -85,6 +85,10 @@ static struct arm_pt_regs *panic_task_regs; #define
PMD_TYPE_TABLE 1 #define PMD_TYPE_SECT_LPAE 1
+/* number of memory areas and its array */ int mems_num; struct
+mem_area *dyn_mems;
+
static inline ulong *
pmd_page_addr(ulong pmd)
{
@@ -1264,6 +1268,30 @@ arm_uvtop(struct task_context *tc, ulong uvaddr,
physaddr_t *paddr, int verbose)
return arm_vtop(uvaddr, pgd, paddr, verbose); }
+static physaddr_t vtop_sparse(unsigned int vaddr) {
+ physaddr_t ret;
+ physaddr_t cur;
+ int i;
+
+ ret = vaddr - machdep->kvbase;
+
+ cur = 0;
+ for(i = 0;i < mems_num;i++) {
+ if (ret < cur + dyn_mems[i].size) {
+ if (i == 0)
+ ret += dyn_mems[0].base;
+ else
+ ret = dyn_mems[i].base + (ret - cur);
+ break;
+ }
+
+ cur += dyn_mems[i].size;
+ }
+
+ return ret;
+}
+
/*
* Translates a kernel virtual address to its physical address. cmd_vtop()
sets
* the verbose flag so that the pte translation gets displayed; all other
@@ -1279,14 +1307,19 @@ arm_kvtop(struct task_context *tc, ulong kvaddr,
physaddr_t *paddr, int verbose)
return arm_lpae_vtop(kvaddr, (ulong *)vt->kernel_pgd[0],
paddr, verbose);
-
if (!vt->vmalloc_start) {
- *paddr = VTOP(kvaddr);
+ if (dyn_mems == NULL)
+ *paddr = VTOP(kvaddr);
+ else
+ *paddr = vtop_sparse(kvaddr);
return TRUE;
}
if (!IS_VMALLOC_ADDR(kvaddr)) {
- *paddr = VTOP(kvaddr);
+ if (dyn_mems == NULL)
+ *paddr = VTOP(kvaddr);
+ else
+ *paddr = vtop_sparse(kvaddr);
if (!verbose)
return TRUE;
}
diff --git a/defs.h b/defs.h
index ecadc29..94e5509 100644
--- a/defs.h
+++ b/defs.h
@@ -6281,4 +6281,13 @@ extern int have_full_symbols(void); #define
XEN_HYPERVISOR_ARCH #endif
+#ifdef ARM
+/* describes memory area for sparse memory systems */ struct mem_area {
+ physaddr_t base;
+ unsigned int size;
+};
+int read_dtb_sparse_mem(const char *filename); #endif
+
#endif /* !GDB_COMMON */
diff --git a/main.c b/main.c
index fd7f7a8..eeccd68 100644
--- a/main.c
+++ b/main.c
@@ -72,6 +72,7 @@ static struct option long_options[] = {
{"no_strip", 0, 0, 0},
{"hash", required_argument, 0, 0},
{"offline", required_argument, 0, 0},
+ {"dtbmem", required_argument, 0, 0},
{0, 0, 0, 0}
};
@@ -291,9 +292,10 @@ main(int argc, char **argv)
error(INFO, "invalid --offline
argument: %s\n", optarg);
program_usage(SHORT_FORM);
}
- }
-
- else {
+ } else if (STREQ(long_options[option_index].name,
"dtbmem")) {
+ if (read_dtb_sparse_mem(optarg) == 0)
+ error(INFO, "Failed to read sparse
mem config!\n");
+ } else {
error(INFO, "internal error: option %s
unhandled\n",
long_options[option_index].name);
program_usage(SHORT_FORM);
diff --git a/mem_dtb.c b/mem_dtb.c
new file mode 100644
index 0000000..23526bc
--- /dev/null
+++ b/mem_dtb.c
@@ -0,0 +1,299 @@
+/*
+ * Tiny device tree parser from 'fdtdump' application of device tree
compiler.
+ * http://www.devicetree.org/Device_Tree_Compiler
+ * https://git.kernel.org/cgit/utils/dtc/dtc.git
+ */
+#include <stdio.h>
+#include <sys/mman.h>
+#include <stdint.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <byteswap.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <assert.h>
+#include <string.h>
+#include <ctype.h>
+#include "defs.h"
+
+typedef uint32_t fdt32_t;
+typedef uint64_t fdt64_t;
+
+#define FDT_BEGIN_NODE 0x1 /* Start node: full name */
+#define FDT_END_NODE 0x2 /* End node */
+#define FDT_PROP 0x3 /* Property: name off,
+ size, content */
+#define FDT_NOP 0x4 /* nop */
+#define FDT_END 0x9
+
+#define EXTRACT_BYTE(x, n) ((unsigned long long)((uint8_t *)&x)[n])
+#define CPU_TO_FDT32(x) ((EXTRACT_BYTE(x, 0) << 24) | (EXTRACT_BYTE(x, 1)
<< 16) | \
+ (EXTRACT_BYTE(x, 2) << 8) | EXTRACT_BYTE(x, 3))
#define
+CPU_TO_FDT64(x) ((EXTRACT_BYTE(x, 0) << 56) | (EXTRACT_BYTE(x, 1) << 48) |
\
+ (EXTRACT_BYTE(x, 2) << 40) | (EXTRACT_BYTE(x, 3) <<
32) | \
+ (EXTRACT_BYTE(x, 4) << 24) | (EXTRACT_BYTE(x, 5) <<
16) | \
+ (EXTRACT_BYTE(x, 6) << 8) | EXTRACT_BYTE(x, 7))
+
+#define ALIGN(x, a) (((x) + ((a) - 1)) & ~((a) - 1))
+#define PALIGN(p, a) ((void *)(ALIGN((unsigned long)(p), (a))))
+#define GET_CELL(p) (p += 4, *((const uint32_t *)(p-4)))
+
+#ifdef ARM
+int memory_found;
+int memory_node_found;
+
+extern struct mem_area *dyn_mems;
+extern int mems_num;
+
+static inline uint32_t fdt32_to_cpu(fdt32_t x) {
+ return (uint32_t)CPU_TO_FDT32(x);
+}
+
+static inline uint64_t fdt64_to_cpu(fdt64_t x) {
+ return (uint64_t)CPU_TO_FDT64(x);
+}
+
+struct fdt_header {
+ fdt32_t magic; /* magic word FDT_MAGIC */
+ fdt32_t totalsize; /* total size of DT block */
+ fdt32_t off_dt_struct; /* offset to structure */
+ fdt32_t off_dt_strings; /* offset to strings */
+ fdt32_t off_mem_rsvmap; /* offset to memory reserve map */
+ fdt32_t version; /* format version */
+ fdt32_t last_comp_version; /* last compatible version */
+
+ /* version 2 fields below */
+ fdt32_t boot_cpuid_phys; /* Which physical CPU id we're
+ booting on */
+ /* version 3 fields below */
+ fdt32_t size_dt_strings; /* size of the strings block */
+
+ /* version 17 fields below */
+ fdt32_t size_dt_struct; /* size of the structure block */
+};
+
+struct fdt_reserve_entry {
+ fdt64_t address;
+ fdt64_t size;
+};
+
+struct fdt_node_header {
+ fdt32_t tag;
+ char name[0];
+};
+
+struct fdt_property {
+ fdt32_t tag;
+ fdt32_t len;
+ fdt32_t nameoff;
+ char data[0];
+};
+
+static int util_is_printable_string(const void *data, int len) {
+ const char *s = data;
+ const char *ss, *se;
+
+ /* zero length is not */
+ if (len == 0)
+ return 0;
+
+ /* must terminate with zero */
+ if (s[len - 1] != '\0')
+ return 0;
+
+ se = s + len;
+
+ while (s < se) {
+ ss = s;
+ while (s < se && *s && isprint((unsigned char)*s))
+ s++;
+
+ /* not zero, or not done yet */
+ if (*s != '\0' || s == ss)
+ return 0;
+
+ s++;
+ }
+
+ return 1;
+}
+
+static int utilfdt_print_data(const char *data, int len) {
+ int i;
+ const char *s;
+
+ /* no data, don't print */
+ if (len == 0)
+ return;
+
+ if (util_is_printable_string(data, len)) {
+ s = data;
+
+ if (strcmp(s, "memory") == 0) {
+ if (memory_node_found == 1)
+ memory_found = 1;
+ } else
+ memory_found = 0;
+
+ do {
+ s += strlen(s) + 1;
+ } while (s < data + len);
+
+ } else if ((len % 4) == 0) {
+ const uint32_t *cell = (const uint32_t *)data;
+
+ len /= 4;
+
+ if (memory_found == 1) {
+ int k;
+
+ /* we are on property with memory regions */
+ dyn_mems = malloc((len / 2) * (sizeof *dyn_mems));
+
+ if (dyn_mems == NULL)
+ return -1;
+
+ for (k = 0, i = 0; i < len; k++, i += 2) {
+ physaddr_t from;
+ unsigned int size;
+
+ from = fdt32_to_cpu(cell[i]);
+ size = fdt32_to_cpu(cell[i + 1]);
+ dyn_mems[k].base = from;
+ dyn_mems[k].size = size;
+ printf("adding memregion: %08llX sz:
%08X\n",
+ dyn_mems[k].base, dyn_mems[k].size);
+ }
+
+ mems_num = k;
+
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+static int parse_dt(void *blob)
+{
+ struct fdt_header *bph = blob;
+ uint32_t off_mem_rsvmap = fdt32_to_cpu(bph->off_mem_rsvmap);
+ uint32_t off_dt = fdt32_to_cpu(bph->off_dt_struct);
+ uint32_t off_str = fdt32_to_cpu(bph->off_dt_strings);
+ struct fdt_reserve_entry *p_rsvmap =
+ (struct fdt_reserve_entry *)((char *)blob + off_mem_rsvmap);
+ const char *p_struct = (const char *)blob + off_dt;
+ const char *p_strings = (const char *)blob + off_str;
+ uint32_t version = fdt32_to_cpu(bph->version);
+ uint32_t tag;
+ const char *p, *s, *t;
+ int depth, sz;
+ int i;
+ uint64_t addr, size;
+
+ depth = 0;
+
+ for (i = 0; ; i++) {
+ addr = fdt64_to_cpu(p_rsvmap[i].address);
+ size = fdt64_to_cpu(p_rsvmap[i].size);
+
+ if (addr == 0 && size == 0)
+ break;
+ }
+
+ p = p_struct;
+
+ while ((tag = fdt32_to_cpu(GET_CELL(p))) != FDT_END) {
+ int res;
+
+ if (tag == FDT_BEGIN_NODE) {
+ s = p;
+ p = PALIGN(p + strlen(s) + 1, 4);
+
+ if (*s == '\0')
+ s = "/";
+
+ if (!strcmp(s, "memory"))
+ memory_node_found = 1;
+
+ depth++;
+ continue;
+ }
+
+ if (tag == FDT_END_NODE) {
+ depth--;
+ continue;
+ }
+
+ if (tag == FDT_NOP)
+ continue;
+
+ if (tag != FDT_PROP)
+ break;
+
+ sz = fdt32_to_cpu(GET_CELL(p));
+ s = p_strings + fdt32_to_cpu(GET_CELL(p));
+
+ if (version < 16 && sz >= 8)
+ p = PALIGN(p, 8);
+
+ t = p;
+
+ p = PALIGN(p + sz, 4);
+
+ res = utilfdt_print_data(t, sz);
+
+ /* error occured */
+ if (res == -1)
+ return 0;
+
+ /* memory region parsed, exit */
+ if (res == 1)
+ return 1;
+
+ /* again */
+ }
+
+ return 0;
+}
+
+int read_dtb_sparse_mem(const char *dtb_file_name) {
+ int dt_fd;
+ unsigned char *p;
+ struct stat si;
+ int res;
+
+ res = 0;
+ dt_fd = open(dtb_file_name, O_RDONLY);
+
+ if (dt_fd == -1)
+ goto out;
+
+ if (fstat(dt_fd, &si))
+ goto out_close;
+
+ p = mmap(NULL, si.st_size, PROT_READ | PROT_WRITE,
+ MAP_PRIVATE, dt_fd, 0);
+
+ if (p == MAP_FAILED)
+ goto out_close;
+
+ res = parse_dt(p);
+out_close:
+ close(dt_fd);
+out:
+ return res;
+}
+#else
+int read_dtb_sparse_mem(const char *dtb_file_name) {
+ error(INFO, "Sparse mem supported only for arm!\n");
+ return 0;
+}
+#endif
--
1.9.1
9 years, 4 months
(no subject)
by Arseniy Krasnov
Hello Dave,
here is patch mentioned in bug
https://bugzilla.redhat.com/show_bug.cgi?id=1238151.
It adds new option "--dtbmem" which reads physical memory layout from
provided device tree and
use it for kernel virtual to physical memory address translation. This is
needed because some
unusual boards have sparse memory and it is impossible to translate address
using offset cause
memory "holes" must be considered. Fail occurs during read of "mem_section"
symbol. With this
patch everything works ok. I use device tree parser based on 'fdtdump'
utility from device tree
compiler.
Of course it is just basic concept and code doesn't look good, but if this
idea will be useful
i'll improve it.
>From a634cf95aadff1a4372f066cca009332bcec2fc6 Mon Sep 17 00:00:00 2001
From: Arseniy Krasnov <a.krasnov(a)samsung.com>
Date: Wed, 1 Jul 2015 10:26:34 +0300
Subject: [PATCH] crashtool: phys memory layout from device tree.
---
Makefile | 7 +-
arm.c | 39 +++++++-
defs.h | 9 ++
main.c | 8 +-
mem_dtb.c | 299
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
5 files changed, 354 insertions(+), 8 deletions(-)
create mode 100644 mem_dtb.c
diff --git a/Makefile b/Makefile
index 3c38ff5..e2188a5 100644
--- a/Makefile
+++ b/Makefile
@@ -70,7 +70,7 @@ CFILES=main.c tools.c global_data.c memory.c filesys.c
help.c task.c \
unwind_x86_32_64.c unwind_arm.c \
xen_hyper.c xen_hyper_command.c xen_hyper_global_data.c \
xen_hyper_dump_tables.c kvmdump.c qemu.c qemu-load.c sadump.c ipcs.c
\
- ramdump.c vmware_vmss.c
+ ramdump.c vmware_vmss.c mem_dtb.c
SOURCE_FILES=${CFILES} ${GENERIC_HFILES} ${MCORE_HFILES} \
${REDHAT_CFILES} ${REDHAT_HFILES} ${UNWIND_HFILES} \
@@ -88,7 +88,7 @@ OBJECT_FILES=main.o tools.o global_data.o memory.o
filesys.o help.o task.o \
unwind_x86_32_64.o unwind_arm.o \
xen_hyper.o xen_hyper_command.o xen_hyper_global_data.o \
xen_hyper_dump_tables.o kvmdump.o qemu.o qemu-load.o sadump.o ipcs.o
\
- ramdump.o vmware_vmss.o
+ ramdump.o vmware_vmss.o mem_dtb.o
MEMORY_DRIVER_FILES=memory_driver/Makefile memory_driver/crash.c
memory_driver/README
@@ -345,6 +345,9 @@ help.o: ${GENERIC_HFILES} help.c
memory.o: ${GENERIC_HFILES} memory.c
${CC} -c ${CRASH_CFLAGS} memory.c ${WARNING_OPTIONS}
${WARNING_ERROR}
+parse.o: ${GENERIC_HFILES} mem_dtb.c
+ ${CC} -c ${CRASH_CFLAGS} mem_dtb.c ${WARNING_OPTIONS}
${WARNING_ERROR}
+
test.o: ${GENERIC_HFILES} test.c
${CC} -c ${CRASH_CFLAGS} test.c ${WARNING_OPTIONS} ${WARNING_ERROR}
diff --git a/arm.c b/arm.c
index 534c501..c31e6a1 100644
--- a/arm.c
+++ b/arm.c
@@ -85,6 +85,10 @@ static struct arm_pt_regs *panic_task_regs;
#define PMD_TYPE_TABLE 1
#define PMD_TYPE_SECT_LPAE 1
+/* number of memory areas and its array */
+int mems_num;
+struct mem_area *dyn_mems;
+
static inline ulong *
pmd_page_addr(ulong pmd)
{
@@ -1264,6 +1268,30 @@ arm_uvtop(struct task_context *tc, ulong uvaddr,
physaddr_t *paddr, int verbose)
return arm_vtop(uvaddr, pgd, paddr, verbose);
}
+static physaddr_t vtop_sparse(unsigned int vaddr)
+{
+ physaddr_t ret;
+ physaddr_t cur;
+ int i;
+
+ ret = vaddr - machdep->kvbase;
+
+ cur = 0;
+ for(i = 0;i < mems_num;i++) {
+ if (ret < cur + dyn_mems[i].size) {
+ if (i == 0)
+ ret += dyn_mems[0].base;
+ else
+ ret = dyn_mems[i].base + (ret - cur);
+ break;
+ }
+
+ cur += dyn_mems[i].size;
+ }
+
+ return ret;
+}
+
/*
* Translates a kernel virtual address to its physical address. cmd_vtop()
sets
* the verbose flag so that the pte translation gets displayed; all other
@@ -1279,14 +1307,19 @@ arm_kvtop(struct task_context *tc, ulong kvaddr,
physaddr_t *paddr, int verbose)
return arm_lpae_vtop(kvaddr, (ulong *)vt->kernel_pgd[0],
paddr, verbose);
-
if (!vt->vmalloc_start) {
- *paddr = VTOP(kvaddr);
+ if (dyn_mems == NULL)
+ *paddr = VTOP(kvaddr);
+ else
+ *paddr = vtop_sparse(kvaddr);
return TRUE;
}
if (!IS_VMALLOC_ADDR(kvaddr)) {
- *paddr = VTOP(kvaddr);
+ if (dyn_mems == NULL)
+ *paddr = VTOP(kvaddr);
+ else
+ *paddr = vtop_sparse(kvaddr);
if (!verbose)
return TRUE;
}
diff --git a/defs.h b/defs.h
index ecadc29..94e5509 100644
--- a/defs.h
+++ b/defs.h
@@ -6281,4 +6281,13 @@ extern int have_full_symbols(void);
#define XEN_HYPERVISOR_ARCH
#endif
+#ifdef ARM
+/* describes memory area for sparse memory systems */
+struct mem_area {
+ physaddr_t base;
+ unsigned int size;
+};
+int read_dtb_sparse_mem(const char *filename);
+#endif
+
#endif /* !GDB_COMMON */
diff --git a/main.c b/main.c
index fd7f7a8..eeccd68 100644
--- a/main.c
+++ b/main.c
@@ -72,6 +72,7 @@ static struct option long_options[] = {
{"no_strip", 0, 0, 0},
{"hash", required_argument, 0, 0},
{"offline", required_argument, 0, 0},
+ {"dtbmem", required_argument, 0, 0},
{0, 0, 0, 0}
};
@@ -291,9 +292,10 @@ main(int argc, char **argv)
error(INFO, "invalid --offline
argument: %s\n", optarg);
program_usage(SHORT_FORM);
}
- }
-
- else {
+ } else if (STREQ(long_options[option_index].name,
"dtbmem")) {
+ if (read_dtb_sparse_mem(optarg) == 0)
+ error(INFO, "Failed to read sparse
mem config!\n");
+ } else {
error(INFO, "internal error: option %s
unhandled\n",
long_options[option_index].name);
program_usage(SHORT_FORM);
diff --git a/mem_dtb.c b/mem_dtb.c
new file mode 100644
index 0000000..23526bc
--- /dev/null
+++ b/mem_dtb.c
@@ -0,0 +1,299 @@
+/*
+ * Tiny device tree parser from 'fdtdump' application of device tree
compiler.
+ * http://www.devicetree.org/Device_Tree_Compiler
+ * https://git.kernel.org/cgit/utils/dtc/dtc.git
+ */
+#include <stdio.h>
+#include <sys/mman.h>
+#include <stdint.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <byteswap.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <assert.h>
+#include <string.h>
+#include <ctype.h>
+#include "defs.h"
+
+typedef uint32_t fdt32_t;
+typedef uint64_t fdt64_t;
+
+#define FDT_BEGIN_NODE 0x1 /* Start node: full name */
+#define FDT_END_NODE 0x2 /* End node */
+#define FDT_PROP 0x3 /* Property: name off,
+ size, content */
+#define FDT_NOP 0x4 /* nop */
+#define FDT_END 0x9
+
+#define EXTRACT_BYTE(x, n) ((unsigned long long)((uint8_t *)&x)[n])
+#define CPU_TO_FDT32(x) ((EXTRACT_BYTE(x, 0) << 24) | (EXTRACT_BYTE(x, 1)
<< 16) | \
+ (EXTRACT_BYTE(x, 2) << 8) | EXTRACT_BYTE(x, 3))
+#define CPU_TO_FDT64(x) ((EXTRACT_BYTE(x, 0) << 56) | (EXTRACT_BYTE(x, 1)
<< 48) | \
+ (EXTRACT_BYTE(x, 2) << 40) | (EXTRACT_BYTE(x, 3) <<
32) | \
+ (EXTRACT_BYTE(x, 4) << 24) | (EXTRACT_BYTE(x, 5) <<
16) | \
+ (EXTRACT_BYTE(x, 6) << 8) | EXTRACT_BYTE(x, 7))
+
+#define ALIGN(x, a) (((x) + ((a) - 1)) & ~((a) - 1))
+#define PALIGN(p, a) ((void *)(ALIGN((unsigned long)(p), (a))))
+#define GET_CELL(p) (p += 4, *((const uint32_t *)(p-4)))
+
+#ifdef ARM
+int memory_found;
+int memory_node_found;
+
+extern struct mem_area *dyn_mems;
+extern int mems_num;
+
+static inline uint32_t fdt32_to_cpu(fdt32_t x)
+{
+ return (uint32_t)CPU_TO_FDT32(x);
+}
+
+static inline uint64_t fdt64_to_cpu(fdt64_t x)
+{
+ return (uint64_t)CPU_TO_FDT64(x);
+}
+
+struct fdt_header {
+ fdt32_t magic; /* magic word FDT_MAGIC */
+ fdt32_t totalsize; /* total size of DT block */
+ fdt32_t off_dt_struct; /* offset to structure */
+ fdt32_t off_dt_strings; /* offset to strings */
+ fdt32_t off_mem_rsvmap; /* offset to memory reserve map */
+ fdt32_t version; /* format version */
+ fdt32_t last_comp_version; /* last compatible version */
+
+ /* version 2 fields below */
+ fdt32_t boot_cpuid_phys; /* Which physical CPU id we're
+ booting on */
+ /* version 3 fields below */
+ fdt32_t size_dt_strings; /* size of the strings block */
+
+ /* version 17 fields below */
+ fdt32_t size_dt_struct; /* size of the structure block */
+};
+
+struct fdt_reserve_entry {
+ fdt64_t address;
+ fdt64_t size;
+};
+
+struct fdt_node_header {
+ fdt32_t tag;
+ char name[0];
+};
+
+struct fdt_property {
+ fdt32_t tag;
+ fdt32_t len;
+ fdt32_t nameoff;
+ char data[0];
+};
+
+static int util_is_printable_string(const void *data, int len)
+{
+ const char *s = data;
+ const char *ss, *se;
+
+ /* zero length is not */
+ if (len == 0)
+ return 0;
+
+ /* must terminate with zero */
+ if (s[len - 1] != '\0')
+ return 0;
+
+ se = s + len;
+
+ while (s < se) {
+ ss = s;
+ while (s < se && *s && isprint((unsigned char)*s))
+ s++;
+
+ /* not zero, or not done yet */
+ if (*s != '\0' || s == ss)
+ return 0;
+
+ s++;
+ }
+
+ return 1;
+}
+
+static int utilfdt_print_data(const char *data, int len)
+{
+ int i;
+ const char *s;
+
+ /* no data, don't print */
+ if (len == 0)
+ return;
+
+ if (util_is_printable_string(data, len)) {
+ s = data;
+
+ if (strcmp(s, "memory") == 0) {
+ if (memory_node_found == 1)
+ memory_found = 1;
+ } else
+ memory_found = 0;
+
+ do {
+ s += strlen(s) + 1;
+ } while (s < data + len);
+
+ } else if ((len % 4) == 0) {
+ const uint32_t *cell = (const uint32_t *)data;
+
+ len /= 4;
+
+ if (memory_found == 1) {
+ int k;
+
+ /* we are on property with memory regions */
+ dyn_mems = malloc((len / 2) * (sizeof *dyn_mems));
+
+ if (dyn_mems == NULL)
+ return -1;
+
+ for (k = 0, i = 0; i < len; k++, i += 2) {
+ physaddr_t from;
+ unsigned int size;
+
+ from = fdt32_to_cpu(cell[i]);
+ size = fdt32_to_cpu(cell[i + 1]);
+ dyn_mems[k].base = from;
+ dyn_mems[k].size = size;
+ printf("adding memregion: %08llX sz:
%08X\n",
+ dyn_mems[k].base, dyn_mems[k].size);
+ }
+
+ mems_num = k;
+
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+static int parse_dt(void *blob)
+{
+ struct fdt_header *bph = blob;
+ uint32_t off_mem_rsvmap = fdt32_to_cpu(bph->off_mem_rsvmap);
+ uint32_t off_dt = fdt32_to_cpu(bph->off_dt_struct);
+ uint32_t off_str = fdt32_to_cpu(bph->off_dt_strings);
+ struct fdt_reserve_entry *p_rsvmap =
+ (struct fdt_reserve_entry *)((char *)blob + off_mem_rsvmap);
+ const char *p_struct = (const char *)blob + off_dt;
+ const char *p_strings = (const char *)blob + off_str;
+ uint32_t version = fdt32_to_cpu(bph->version);
+ uint32_t tag;
+ const char *p, *s, *t;
+ int depth, sz;
+ int i;
+ uint64_t addr, size;
+
+ depth = 0;
+
+ for (i = 0; ; i++) {
+ addr = fdt64_to_cpu(p_rsvmap[i].address);
+ size = fdt64_to_cpu(p_rsvmap[i].size);
+
+ if (addr == 0 && size == 0)
+ break;
+ }
+
+ p = p_struct;
+
+ while ((tag = fdt32_to_cpu(GET_CELL(p))) != FDT_END) {
+ int res;
+
+ if (tag == FDT_BEGIN_NODE) {
+ s = p;
+ p = PALIGN(p + strlen(s) + 1, 4);
+
+ if (*s == '\0')
+ s = "/";
+
+ if (!strcmp(s, "memory"))
+ memory_node_found = 1;
+
+ depth++;
+ continue;
+ }
+
+ if (tag == FDT_END_NODE) {
+ depth--;
+ continue;
+ }
+
+ if (tag == FDT_NOP)
+ continue;
+
+ if (tag != FDT_PROP)
+ break;
+
+ sz = fdt32_to_cpu(GET_CELL(p));
+ s = p_strings + fdt32_to_cpu(GET_CELL(p));
+
+ if (version < 16 && sz >= 8)
+ p = PALIGN(p, 8);
+
+ t = p;
+
+ p = PALIGN(p + sz, 4);
+
+ res = utilfdt_print_data(t, sz);
+
+ /* error occured */
+ if (res == -1)
+ return 0;
+
+ /* memory region parsed, exit */
+ if (res == 1)
+ return 1;
+
+ /* again */
+ }
+
+ return 0;
+}
+
+int read_dtb_sparse_mem(const char *dtb_file_name)
+{
+ int dt_fd;
+ unsigned char *p;
+ struct stat si;
+ int res;
+
+ res = 0;
+ dt_fd = open(dtb_file_name, O_RDONLY);
+
+ if (dt_fd == -1)
+ goto out;
+
+ if (fstat(dt_fd, &si))
+ goto out_close;
+
+ p = mmap(NULL, si.st_size, PROT_READ | PROT_WRITE,
+ MAP_PRIVATE, dt_fd, 0);
+
+ if (p == MAP_FAILED)
+ goto out_close;
+
+ res = parse_dt(p);
+out_close:
+ close(dt_fd);
+out:
+ return res;
+}
+#else
+int read_dtb_sparse_mem(const char *dtb_file_name)
+{
+ error(INFO, "Sparse mem supported only for arm!\n");
+ return 0;
+}
+#endif
--
1.9.1
9 years, 4 months