Command search walks through all pages in identity mapping (i.e. virtual
address space starting at PAGE_OFFSET and ending at high_memory) when
it's used to search kernel memory. The new option -f allows the command
to skip some uninteresting pages (e.g. LRU pages) to speed up the search.
---
help.c | 11 +++++-
memory.c | 123 +++++++++++++++++++++++++++++++++++++++++++++++++--------------
2 files changed, 107 insertions(+), 27 deletions(-)
diff --git a/help.c b/help.c
index b2f4d21..8d45667 100644
--- a/help.c
+++ b/help.c
@@ -2814,7 +2814,8 @@ char *help_search[] = {
"search",
"search memory",
"[-s start] [ -[kKV] | -u | -p | -t ] [-e end | -l length] [-m mask]\n"
-" [-x count] -[cwh] [value | (expression) | symbol | string] ...",
+" [-f struct-page.flags-mask] [-x count] -[cwh] "
+" [value | (expression) | symbol | string] ...",
" This command searches for a given value within a range of user virtual,
kernel",
" virtual, or physical memory space. If no end nor length value is entered,
",
" then the search stops at the end of user virtual, kernel virtual, or
physical",
@@ -2849,6 +2850,11 @@ char *help_search[] = {
" must be appropriate for the memory type specified.",
" -l length Length in bytes of address range to search.",
" -m mask Ignore the bits that are set in the hexadecimal mask value.",
+" -f struct-page.flags-mask",
+" Only search pages when page.flags & mask is true, or not true
when",
+" the mask is preceded by a letter n. When used multiple times,
only",
+" pages that meet all conditions will be searched. Only works
for",
+" virtual address space (either user or kernel).",
" -c Search for character string values instead of unsigned longs.
If",
" the string contains any space(s), it must be encompassed by
double",
" quotes.",
@@ -2986,6 +2992,9 @@ char *help_search[] = {
" ffff8100399565a8: ffffffff80493d60 (anon_inode_inode)",
" ffff81003a278cd0: ffffffff800649d6 (__down_interruptible+191)",
" ffff81003cc23e08: ffffffff800649d6 (__down_interruptible+191)",
+"\n Search kernel virtual address space for all instances of 0xdeadbeef",
+" within compound (PG_head|tail) pages that are not LRU pages:\n",
+" %s> search deadbeef -f c000 -f n20",
NULL
};
diff --git a/memory.c b/memory.c
index 2208553..70649a2 100644
--- a/memory.c
+++ b/memory.c
@@ -77,6 +77,16 @@ struct meminfo { /* general purpose memory information
structure */
};
/*
+ * Memory cache for struct page within range
+ * of kernel virtual address start and end.
+ */
+struct mem_map_cache {
+ ulong start;
+ ulong end;
+ char *cache;
+};
+
+/*
* Search modes
*/
@@ -100,6 +110,9 @@ struct searchinfo {
ulong vaddr_end;
ulonglong paddr_start;
ulonglong paddr_end;
+ int pg_nmasks;
+ char pg_mask_neg[MAXARGS];
+ ulong pg_mask[MAXARGS];
union {
/* default ulong search */
struct {
@@ -136,7 +149,7 @@ static char *memtype_string(int, int);
static char *error_handle_string(ulong);
static void dump_mem_map(struct meminfo *);
static void dump_mem_map_SPARSEMEM(struct meminfo *);
-static void fill_mem_map_cache(ulong, ulong, char *);
+static void fill_mem_map_cache(struct mem_map_cache *);
static void page_flags_init(void);
static int page_flags_init_from_pageflag_names(void);
static int page_flags_init_from_pageflags_enum(void);
@@ -4956,7 +4969,7 @@ dump_mem_map_SPARSEMEM(struct meminfo *mi)
ulong i;
long total_pages;
int others, page_not_mapped, phys_not_mapped, page_mapping;
- ulong pp, ppend;
+ ulong pp;
physaddr_t phys, physend;
ulong tmp, reserved, shared, slabs;
ulong PG_reserved_flag;
@@ -4970,12 +4983,12 @@ dump_mem_map_SPARSEMEM(struct meminfo *mi)
char buf2[BUFSIZE];
char buf3[BUFSIZE];
char buf4[BUFSIZE];
- char *page_cache;
char *pcache;
ulong section, section_nr, nr_mem_sections, section_size;
long buffersize;
char *outputbuffer;
int bufferindex;
+ struct mem_map_cache mmc;
buffersize = 1024 * 1024;
outputbuffer = GETBUF(buffersize + 512);
@@ -5101,7 +5114,7 @@ dump_mem_map_SPARSEMEM(struct meminfo *mi)
break;
}
- page_cache = GETBUF(SIZE(page) * PGMM_CACHED);
+ mmc.cache = GETBUF(SIZE(page) * PGMM_CACHED);
done = FALSE;
total_pages = 0;
@@ -5166,23 +5179,23 @@ dump_mem_map_SPARSEMEM(struct meminfo *mi)
i++, pp += SIZE(page), phys += PAGESIZE()) {
if ((i % PGMM_CACHED) == 0) {
-
- ppend = pp + ((PGMM_CACHED-1) * SIZE(page));
+ mmc.start = pp;
+ mmc.end = pp + ((PGMM_CACHED-1) * SIZE(page));
physend = phys + ((PGMM_CACHED-1) * PAGESIZE());
- if ((pg_spec && (mi->spec_addr > ppend)) ||
+ if ((pg_spec && (mi->spec_addr > mmc.end)) ||
(phys_spec &&
(PHYSPAGEBASE(mi->spec_addr) > physend))) {
i += (PGMM_CACHED-1);
- pp = ppend;
+ pp = mmc.end;
phys = physend;
continue;
}
- fill_mem_map_cache(pp, ppend, page_cache);
+ fill_mem_map_cache(&mmc);
}
- pcache = page_cache + ((i%PGMM_CACHED) * SIZE(page));
+ pcache = mmc.cache + ((i%PGMM_CACHED) * SIZE(page));
if (received_SIGINT())
restart(0);
@@ -5417,7 +5430,7 @@ dump_mem_map_SPARSEMEM(struct meminfo *mi)
}
FREEBUF(outputbuffer);
- FREEBUF(page_cache);
+ FREEBUF(mmc.cache);
}
static void
@@ -5426,7 +5439,7 @@ dump_mem_map(struct meminfo *mi)
long i, n;
long total_pages;
int others, page_not_mapped, phys_not_mapped, page_mapping;
- ulong pp, ppend;
+ ulong pp;
physaddr_t phys, physend;
ulong tmp, reserved, shared, slabs;
ulong PG_reserved_flag;
@@ -5442,11 +5455,11 @@ dump_mem_map(struct meminfo *mi)
char buf2[BUFSIZE];
char buf3[BUFSIZE];
char buf4[BUFSIZE];
- char *page_cache;
char *pcache;
long buffersize;
char *outputbuffer;
int bufferindex;
+ struct mem_map_cache mmc;
buffersize = 1024 * 1024;
outputbuffer = GETBUF(buffersize + 512);
@@ -5577,7 +5590,7 @@ dump_mem_map(struct meminfo *mi)
break;
}
- page_cache = GETBUF(SIZE(page) * PGMM_CACHED);
+ mmc.cache = GETBUF(SIZE(page) * PGMM_CACHED);
done = FALSE;
total_pages = 0;
@@ -5604,22 +5617,23 @@ dump_mem_map(struct meminfo *mi)
i++, pp += SIZE(page), phys += PAGESIZE()) {
if ((i % PGMM_CACHED) == 0) {
- ppend = pp + ((PGMM_CACHED-1) * SIZE(page));
+ mmc.start = pp;
+ mmc.end = pp + ((PGMM_CACHED-1) * SIZE(page));
physend = phys + ((PGMM_CACHED-1) * PAGESIZE());
- if ((pg_spec && (mi->spec_addr > ppend)) ||
+ if ((pg_spec && (mi->spec_addr > mmc.end)) ||
(phys_spec &&
(PHYSPAGEBASE(mi->spec_addr) > physend))) {
i += (PGMM_CACHED-1);
- pp = ppend;
+ pp = mmc.end;
phys = physend;
continue;
}
- fill_mem_map_cache(pp, ppend, page_cache);
+ fill_mem_map_cache(&mmc);
}
- pcache = page_cache + ((i%PGMM_CACHED) * SIZE(page));
+ pcache = mmc.cache + ((i%PGMM_CACHED) * SIZE(page));
if (received_SIGINT())
restart(0);
@@ -5855,7 +5869,7 @@ dump_mem_map(struct meminfo *mi)
}
FREEBUF(outputbuffer);
- FREEBUF(page_cache);
+ FREEBUF(mmc.cache);
}
/*
@@ -5866,7 +5880,7 @@ dump_mem_map(struct meminfo *mi)
* that are currently mapped, leaving the unmapped ones just zeroed out.
*/
static void
-fill_mem_map_cache(ulong pp, ulong ppend, char *page_cache)
+fill_mem_map_cache(struct mem_map_cache *mmc)
{
long size, cnt;
ulong addr;
@@ -5875,7 +5889,7 @@ fill_mem_map_cache(ulong pp, ulong ppend, char *page_cache)
/*
* Try to read it in one fell swoop.
*/
- if (readmem(pp, KVADDR, page_cache, SIZE(page) * PGMM_CACHED,
+ if (readmem(mmc->start, KVADDR, mmc->cache, SIZE(page) * PGMM_CACHED,
"page struct cache", RETURN_ON_ERROR|QUIET))
return;
@@ -5884,8 +5898,8 @@ fill_mem_map_cache(ulong pp, ulong ppend, char *page_cache)
* not a virtual mem_map.
*/
size = SIZE(page) * PGMM_CACHED;
- addr = pp;
- bufptr = page_cache;
+ addr = mmc->start;
+ bufptr = mmc->cache;
while (size > 0) {
/*
@@ -5899,7 +5913,7 @@ fill_mem_map_cache(ulong pp, ulong ppend, char *page_cache)
if (!readmem(addr, KVADDR, bufptr, size,
"virtual page struct cache", RETURN_ON_ERROR|QUIET)) {
BZERO(bufptr, size);
- if (!(vt->flags & V_MEM_MAP) && ((addr+size) < ppend))
+ if (!(vt->flags & V_MEM_MAP) && ((addr+size) < mmc->end))
error(WARNING,
"mem_map[] from %lx to %lx not accessible\n",
addr, addr+size);
@@ -13500,7 +13514,7 @@ cmd_search(void)
searchinfo.mode = SEARCH_ULONG; /* default search */
- while ((c = getopt(argcnt, args, "tl:ukKVps:e:v:m:hwcx:")) != EOF) {
+ while ((c = getopt(argcnt, args, "tl:ukKVps:e:v:m:f:hwcx:")) != EOF) {
switch(c)
{
case 'u':
@@ -13572,6 +13586,17 @@ cmd_search(void)
error(FATAL, "invalid ending address: 0\n");
break;
+ case 'f':
+ if (searchinfo.pg_nmasks == MAXARGS)
+ break;
+
+ c = *optarg == 'n';
+ searchinfo.pg_mask_neg[searchinfo.pg_nmasks] = c;
+ searchinfo.pg_mask[searchinfo.pg_nmasks] =
+ htol(optarg + c, FAULT_ON_ERROR, NULL);
+ searchinfo.pg_nmasks++;
+ break;
+
case 'l':
len = stol(optarg, FAULT_ON_ERROR, NULL);
break;
@@ -14409,6 +14434,42 @@ search_chars_p(ulong *bufptr, ulonglong addr_p, int longcnt,
struct searchinfo *
return addr_p;
}
+static int
+skip_pages(struct searchinfo *si, struct mem_map_cache *mmc, ulong page, ulong *pp)
+{
+ int i;
+ ulong flags;
+
+ if (page < mmc->start || page > mmc->end) {
+ mmc->start = page;
+ mmc->end = page + SIZE(page) * (PGMM_CACHED - 1);
+ fill_mem_map_cache(mmc);
+ }
+
+ flags = ULONG(mmc->cache + page - mmc->start + OFFSET(page_flags));
+
+ for (i = 0; i < si->pg_nmasks; i++) {
+ if ((si->pg_mask_neg[i] && si->pg_mask[i] & flags) ||
+ (!si->pg_mask_neg[i] && !(si->pg_mask[i] & flags)))
+ goto skip;
+ }
+
+ if (CRASHDEBUG(4))
+ fprintf(fp, "search page: struct %lx, vaddr %lx, flags %lx\n",
+ page, *pp, flags);
+
+ return 0;
+
+skip:
+ if (CRASHDEBUG(5))
+ fprintf(fp, "ignore page: struct %lx, vaddr %lx, flags %lx\n",
+ page, *pp, flags);
+
+ *pp += PAGESIZE();
+
+ return 1;
+}
+
static void
search_virtual(struct searchinfo *si)
{
@@ -14420,6 +14481,7 @@ search_virtual(struct searchinfo *si)
char *pagebuf;
ulong pct, pages_read, pages_checked;
time_t begin, finish;
+ struct mem_map_cache mmc;
start = si->vaddr_start;
end = si->vaddr_end;
@@ -14427,6 +14489,10 @@ search_virtual(struct searchinfo *si)
begin = finish = 0;
pagebuf = GETBUF(PAGESIZE());
+ if (si->pg_nmasks) {
+ mmc.start = mmc.end = 0;
+ mmc.cache = GETBUF(SIZE(page) * PGMM_CACHED);
+ }
if (start & (sizeof(long)-1)) {
start &= ~(sizeof(long)-1);
@@ -14482,6 +14548,9 @@ search_virtual(struct searchinfo *si)
break;
}
+ if (si->pg_nmasks && skip_pages(si, &mmc, page, &pp))
+ continue;
+
if (!readmem(paddr, PHYSADDR, pagebuf, PAGESIZE(),
"search page", RETURN_ON_ERROR|QUIET)) {
pp += PAGESIZE();
@@ -14536,6 +14605,8 @@ done:
}
FREEBUF(pagebuf);
+ if (si->pg_nmasks)
+ FREEBUF(mmc.cache);
}
--
2.2.0.rc0.207.ga3a616c