diff options
author | Samuel Thibault <samuel.thibault@ens-lyon.org> | 2023-10-01 03:03:13 +0200 |
---|---|---|
committer | Samuel Thibault <samuel.thibault@ens-lyon.org> | 2023-10-01 04:27:00 +0200 |
commit | 42bdb9e4fea494b85b394dd99d1686e812eb8a28 (patch) | |
tree | e4cbc60130c81c94043f603ef8a826d0a896e842 | |
parent | 511536317e810a5d204530ed8513f645acf67d9c (diff) | |
download | gnumach-42bdb9e4fea494b85b394dd99d1686e812eb8a28.tar.gz gnumach-42bdb9e4fea494b85b394dd99d1686e812eb8a28.tar.bz2 gnumach-42bdb9e4fea494b85b394dd99d1686e812eb8a28.zip |
ddb: Add whatis command
This is convenient when tracking buffer overflows
-rw-r--r-- | ddb/db_command.c | 1 | ||||
-rw-r--r-- | ddb/db_examine.c | 154 | ||||
-rw-r--r-- | ddb/db_examine.h | 6 | ||||
-rw-r--r-- | ddb/db_print.c | 2 | ||||
-rw-r--r-- | ddb/db_print.h | 5 | ||||
-rw-r--r-- | doc/mach.texi | 4 | ||||
-rw-r--r-- | i386/intel/pmap.c | 100 | ||||
-rw-r--r-- | kern/slab.c | 40 | ||||
-rw-r--r-- | kern/slab.h | 1 | ||||
-rw-r--r-- | vm/pmap.h | 4 |
10 files changed, 315 insertions, 2 deletions
diff --git a/ddb/db_command.c b/ddb/db_command.c index 2fae61b0..4671fe8d 100644 --- a/ddb/db_command.c +++ b/ddb/db_command.c @@ -362,6 +362,7 @@ struct db_command db_command_table[] = { { "x", db_examine_cmd, CS_MORE|CS_SET_DOT, 0 }, { "xf", db_examine_forward, CS_SET_DOT, 0 }, { "xb", db_examine_backward, CS_SET_DOT, 0 }, + { "whatis", db_whatis_cmd, CS_MORE, 0 }, { "search", db_search_cmd, CS_OWN|CS_SET_DOT, 0 }, { "set", (db_command_fun_t)db_set_cmd, CS_OWN, 0 }, { "write", db_write_cmd, CS_MORE|CS_SET_DOT, 0 }, diff --git a/ddb/db_examine.c b/ddb/db_examine.c index 30799360..4e7f8d15 100644 --- a/ddb/db_examine.c +++ b/ddb/db_examine.c @@ -42,8 +42,10 @@ #include <ddb/db_task_thread.h> #include <ddb/db_examine.h> #include <ddb/db_expr.h> +#include <ddb/db_print.h> #include <kern/thread.h> #include <kern/task.h> +#include <kern/smp.h> #include <mach/vm_param.h> #define db_thread_to_task(thread) ((thread)? thread->task: TASK_NULL) @@ -253,6 +255,158 @@ db_examine( } /* + * Find out what this address may be + */ +/*ARGSUSED*/ +void +db_whatis_cmd( + db_expr_t addr, + int have_addr, + db_expr_t count, + const char * modif) +{ + /* TODO: Add whatever you can think of */ + + int i; + + { + /* tasks */ + + task_t task; + int task_id = 0; + processor_set_t pset; + thread_t thread; + int thread_id; + vm_map_entry_t entry; + + queue_iterate(&all_psets, pset, processor_set_t, all_psets) + queue_iterate(&pset->tasks, task, task_t, pset_tasks) { + if (addr >= (vm_offset_t) task + && addr < (vm_offset_t) task + sizeof(*task)) + db_printf("%3d %0*X %s [%d]\n", + task_id, + 2*sizeof(vm_offset_t), + task, + task->name, + task->thread_count); + + if (addr >= (vm_offset_t) task->map + && addr < (vm_offset_t) task->map + sizeof(*(task->map))) + db_printf("map %X for task%d %s\n", (vm_offset_t) task->map, task_id, task->name); + + for (entry = vm_map_first_entry(task->map); + entry != vm_map_to_entry(task->map); + entry = entry->vme_next) + if (addr >= (vm_offset_t) entry + && addr < (vm_offset_t) entry + sizeof(*entry)) + db_printf("map %X for task%d %s entry 0x%X: ", + (vm_offset_t) task->map, task_id, task->name, + (vm_offset_t) entry); + + if (pmap_whatis(task->map->pmap, addr)) + db_printf(" in task%d %s\n", task_id, task->name); + + if ((task == current_task() || task == kernel_task) + && addr >= vm_map_min(task->map) + && addr < vm_map_max(task->map)) { + db_printf("inside map of task%d %s\n", task_id, task->name); + + for (entry = vm_map_first_entry(task->map); + entry != vm_map_to_entry(task->map); + entry = entry->vme_next) + if (addr >= entry->vme_start + && addr < entry->vme_end) { + db_printf(" entry 0x%X: ", (vm_offset_t) entry); + if (entry->is_sub_map) + db_printf("submap=0x%X, offset=0x%X\n", + (vm_offset_t) entry->object.sub_map, + (vm_offset_t) entry->offset); + else + db_printf("object=0x%X, offset=0x%X\n", + (vm_offset_t) entry->object.vm_object, + (vm_offset_t) entry->offset); + } + } + + thread_id = 0; + queue_iterate(&task->thread_list, thread, thread_t, thread_list) { + if (addr >= (vm_offset_t) thread + && addr < (vm_offset_t) thread + sizeof(*thread)) { + db_printf("In task%d %s\n", task_id, task->name); + db_print_thread(thread, thread_id, 0); + } + if (addr >= thread->kernel_stack + && addr < thread->kernel_stack + KERNEL_STACK_SIZE) { + db_printf("In task%d %s\n", task_id, task->name); + db_printf(" on stack of\n"); + db_print_thread(thread, thread_id, 0); + } + thread_id++; + } + task_id++; + } + } + + pmap_whatis(kernel_pmap, addr); + + { + /* runqs */ + if (addr >= (vm_offset_t) &default_pset.runq + && addr < (vm_offset_t) &default_pset.runq + sizeof(default_pset.runq)) + db_printf("default runq %p\n", &default_pset.runq); + for (i = 0; i < smp_get_numcpus(); i++) { + processor_t proc = cpu_to_processor(i); + if (addr >= (vm_offset_t) &proc->runq + && addr < (vm_offset_t) &proc->runq + sizeof(proc->runq)) + db_printf("Processor #%d runq %p\n", &proc->runq); + } + } + + { + /* stacks */ + for (i = 0; i < smp_get_numcpus(); i++) { + if (addr >= percpu_array[i].active_stack + && addr < percpu_array[i].active_stack + KERNEL_STACK_SIZE) + db_printf("Processor #%d active stack\n", i); + } + } + + db_whatis_slab(addr); + + { + /* page */ + phys_addr_t pa; + if (DB_VALID_KERN_ADDR(addr)) + pa = kvtophys(addr); + else + pa = pmap_extract(current_task()->map->pmap, addr); + + if (pa) { + struct vm_page *page = vm_page_lookup_pa(pa); + db_printf("phys %llx, page %p\n", (unsigned long long) pa, page); + if (page) { + const char *types[] = { + [VM_PT_FREE] = "free", + [VM_PT_RESERVED] = "reserved", + [VM_PT_TABLE] = "table", + [VM_PT_KERNEL] = "kernel", + }; + db_printf(" %s\n", types[page->type]); + db_printf(" free %u\n", page->free); + db_printf(" external %u\n", page->external); + db_printf(" busy %u\n", page->busy); + db_printf(" private %u\n", page->private); + db_printf(" object %lx\n", page->object); + db_printf(" offset %lx\n", page->offset); + db_printf(" wired %u\n", page->wire_count); + db_printf(" segment %u\n", page->seg_index); + db_printf(" order %u\n", page->order); + } + } + } +} + +/* * Print value. */ char db_print_format = 'x'; diff --git a/ddb/db_examine.h b/ddb/db_examine.h index 56a1a346..c76fa2a2 100644 --- a/ddb/db_examine.h +++ b/ddb/db_examine.h @@ -61,6 +61,12 @@ int db_xcdump( int count, task_t task); +extern void db_whatis_cmd ( + db_expr_t addr, + int have_addr, + db_expr_t count, + const char *modif); + void db_print_cmd(void); void db_search_cmd( diff --git a/ddb/db_print.c b/ddb/db_print.c index 89250f7b..028cb887 100644 --- a/ddb/db_print.c +++ b/ddb/db_print.c @@ -148,7 +148,7 @@ db_thread_stat( return(status); } -static void +void db_print_thread( thread_t thread, int thread_id, diff --git a/ddb/db_print.h b/ddb/db_print.h index 27b3990a..b86c6966 100644 --- a/ddb/db_print.h +++ b/ddb/db_print.h @@ -60,4 +60,9 @@ db_addr_t db_task_from_space( ipc_space_t space, int *task_id); +void db_print_thread( + thread_t thread, + int thread_id, + int flag); + #endif /* !_DDB_DB_PRINT_H_ */ diff --git a/doc/mach.texi b/doc/mach.texi index 7eb5baa1..76bf68f7 100644 --- a/doc/mach.texi +++ b/doc/mach.texi @@ -6918,6 +6918,10 @@ Examine backward. It executes an examine command with the last specified parameters to it except that the last start address subtracted by the size displayed by it is used as the start address. +@item whatis @var{addr} +Try to find what this address is. This looks up in the various tasks, threads, +maps, caches etc. to give an idea what is behind this address. + @item print[/axzodurc] @var{addr1} [ @var{addr2} @dots{} ] Print @var{addr}'s according to the modifier character. Valid formats are: @code{a} @code{x} @code{z} @code{o} @code{d} @code{u} @code{r} diff --git a/i386/intel/pmap.c b/i386/intel/pmap.c index 5e60141e..7d0ec6c8 100644 --- a/i386/intel/pmap.c +++ b/i386/intel/pmap.c @@ -91,6 +91,9 @@ #include <i386/mp_desc.h> #endif +#include <ddb/db_output.h> +#include <machine/db_machdep.h> + #ifdef MACH_PSEUDO_PHYS #define WRITE_PTE(pte_p, pte_entry) *(pte_p) = pte_entry?pa_to_ma(pte_entry):0; #else /* MACH_PSEUDO_PHYS */ @@ -2577,6 +2580,103 @@ void pmap_collect(pmap_t p) } +#if MACH_KDB +/* + * Routine: pmap_whatis + * Function: + * Check whether this address is within a pmap + * Usage: + * Called from debugger + */ +int pmap_whatis(pmap_t p, vm_offset_t a) +{ + pt_entry_t *ptp; + phys_addr_t pa; + int spl; + int ret = 0; + + if (p == PMAP_NULL) + return 0; + + PMAP_READ_LOCK(p, spl); +#if PAE +#ifdef __x86_64__ + if (a >= (vm_offset_t) p->l4base && a < (vm_offset_t) (&p->l4base[NPTES])) { + db_printf("L4 for pmap %p\n", p); + ret = 1; + } + for (int l4i = 0; l4i < NPTES; l4i++) { + pt_entry_t pdp = (pt_entry_t) p->l4base[l4i]; + if (!(pdp & INTEL_PTE_VALID)) + continue; + pt_entry_t *pdpbase = (pt_entry_t*) ptetokv(pdp); +#else /* __x86_64__ */ + int l4i = 0; + pt_entry_t *pdpbase = p->pdpbase; +#endif /* __x86_64__ */ + if (a >= (vm_offset_t) pdpbase && a < (vm_offset_t) (&pdpbase[NPTES])) { + db_printf("PDP %d for pmap %p\n", l4i, p); + ret = 1; + } + for (int l3i = 0; l3i < NPTES; l3i++) + { + pt_entry_t pde = (pt_entry_t ) pdpbase[l3i]; + if (!(pde & INTEL_PTE_VALID)) + continue; + pt_entry_t *pdebase = (pt_entry_t*) ptetokv(pde); +#else /* PAE */ + int l3i = 0; + pt_entry_t *pdebase = p->dirbase; +#endif /* PAE */ + if (a >= (vm_offset_t) pdebase && a < (vm_offset_t) (&pdebase[NPTES])) { + db_printf("PDE %d %d for pmap %p\n", l4i, l3i, p); + ret = 1; + } + for (int l2i = 0; l2i < NPTES; l2i++) + { + pt_entry_t pte = (pt_entry_t) pdebase[l2i]; + if (!(pte & INTEL_PTE_VALID)) + continue; + + pa = pte_to_pa(pte); + ptp = (pt_entry_t *)phystokv(pa); + + if (a >= (vm_offset_t) ptp && a < (vm_offset_t) (&ptp[NPTES*ptes_per_vm_page])) { + db_printf("PTP %d %d %d for pmap %p\n", l4i, l3i, l2i, p); + ret = 1; + } + } +#if PAE + } +#ifdef __x86_64__ + } +#endif /* __x86_64__ */ +#endif /* PAE */ + PMAP_READ_UNLOCK(p, spl); + + if (p == kernel_pmap) { + phys_addr_t pa; + if (DB_VALID_KERN_ADDR(a)) + pa = kvtophys(a); + else + pa = pmap_extract(current_task()->map->pmap, a); + + if (valid_page(pa)) { + unsigned long pai; + pv_entry_t pv_h; + + pai = pa_index(pa); + for (pv_h = pai_to_pvh(pai); + pv_h && pv_h->pmap; + pv_h = pv_h->next) + db_printf("pmap %p at %llx\n", pv_h->pmap, pv_h->va); + } + } + + return ret; +} +#endif /* MACH_KDB */ + /* * Routine: pmap_activate * Function: diff --git a/kern/slab.c b/kern/slab.c index 545c7019..3264ebba 100644 --- a/kern/slab.c +++ b/kern/slab.c @@ -1496,11 +1496,49 @@ void slab_info(void) #if MACH_KDB #include <ddb/db_output.h> - void db_show_slab_info(void) +void db_show_slab_info(void) { _slab_info(db_printf); } +void db_whatis_slab(vm_offset_t a) +{ + struct kmem_cache *cache; + +#ifndef SLAB_VERIFY + db_printf("enabling SLAB_VERIFY is recommended\n"); +#endif + + simple_lock(&kmem_cache_list_lock); + + list_for_each_entry(&kmem_cache_list, cache, node) { + if (a >= (vm_offset_t) cache + && a < (vm_offset_t) cache + sizeof(*cache)) + db_printf("Cache %s\n", cache->name); + + simple_lock(&cache->lock); + + if (cache->flags & KMEM_CF_USE_TREE) { + struct rbtree_node *node; + + node = rbtree_lookup_nearest(&cache->active_slabs, (void*) a, + kmem_slab_cmp_lookup, RBTREE_LEFT); + if (node) { + struct kmem_slab *slab; + slab = rbtree_entry(node, struct kmem_slab, tree_node); + if (a >= (vm_offset_t) slab->addr + && a < (vm_offset_t) slab->addr + cache->slab_size) + db_printf("In cache %s\n", cache->name); + } + } + + simple_unlock(&cache->lock); + } + + simple_unlock(&kmem_cache_list_lock); + +} + #endif /* MACH_KDB */ #if MACH_DEBUG diff --git a/kern/slab.h b/kern/slab.h index 1e916872..4d51755a 100644 --- a/kern/slab.h +++ b/kern/slab.h @@ -237,6 +237,7 @@ void slab_info(void); #if MACH_KDB void db_show_slab_info(void); +void db_whatis_slab(vm_offset_t addr); #endif /* MACH_KDB */ #endif /* _KERN_SLAB_H */ @@ -157,6 +157,10 @@ boolean_t pmap_is_modified(phys_addr_t pa); extern phys_addr_t pmap_extract(pmap_t, vm_offset_t); /* Perform garbage collection, if any. */ extern void pmap_collect(pmap_t); + +/* Lookup an address. */ +int pmap_whatis(pmap_t, vm_offset_t); + /* Specify pageability. */ extern void pmap_change_wiring(pmap_t, vm_offset_t, boolean_t); |