*** kdb.c.orig Sat Mar 18 11:27:13 2000 --- kdb.c Sun Mar 19 08:07:34 2000 *************** *** 26,31 **** --- 26,38 ---- #include "kdbsupport.h" #include "kdb_io.h" + /* For rmmod/lsmod */ + #include + #include + #include + extern struct module *module_list; + extern void vfree(void * addr); + volatile int kdb_active = 0; volatile int kdb_flags = 0; spinlock_t kdb_lock = SPIN_LOCK_UNLOCKED; *************** kdb(int reason, int error, struct pt_reg *** 723,729 **** } if (reason != KDB_REASON_DEBUG) { ! kdb_printf("Entering kdb "); #if defined(__SMP__) kdb_printf("on processor %d ", smp_processor_id()); #endif --- 730,736 ---- } if (reason != KDB_REASON_DEBUG) { ! kdb_printf("\nEntering kdb "); #if defined(__SMP__) kdb_printf("on processor %d ", smp_processor_id()); #endif *************** kdb(int reason, int error, struct pt_reg *** 737,743 **** */ diag = kdb_db_trap(regs); if (diag == 0) { ! kdb_printf("Entering kdb "); #if defined(__SMP__) kdb_printf("on processor %d ", smp_processor_id()); #endif --- 744,750 ---- */ diag = kdb_db_trap(regs); if (diag == 0) { ! kdb_printf("\nEntering kdb "); #if defined(__SMP__) kdb_printf("on processor %d ", smp_processor_id()); #endif *************** kdb_reboot(int argc, const char **argv, *** 1380,1385 **** --- 1387,1583 ---- return 0; } + + /* + * Taken directly from kernel/module.c + * + * Look for a module by name, ignoring modules marked for deletion. + */ + static struct module * + find_module(const char *name) + { + struct module *mod; + + for (mod = module_list; mod ; mod = mod->next) { + if (mod->flags & MOD_DELETED) + continue; + if (!strcmp(mod->name, name)) + break; + } + + return mod; + } + + /* + * Free the given module. + */ + static void + free_module(struct module *mod, int tag_freed) + { + struct module_ref *dep; + unsigned i; + #if defined(CONFIG_KDB) + struct module_symbol *s; + #endif + + /* Let the module clean up. */ + + mod->flags |= MOD_DELETED; + if (mod->flags & MOD_RUNNING) + { + if(mod->cleanup) + mod->cleanup(); + mod->flags &= ~MOD_RUNNING; + } + #if defined(CONFIG_KDB) + /* + * Remove symbols from kernel debugger + */ + for(i=0,s=mod->syms; insyms; i++, s++){ + kdbdelmodsym(s->name); + } + #endif + + /* Remove the module from the dependency lists. */ + for (i = 0, dep = mod->deps; i < mod->ndeps; ++i, ++dep) { + struct module_ref **pp; + for (pp = &dep->dep->refs; *pp != dep; pp = &(*pp)->next_ref) + continue; + *pp = dep->next_ref; + if (tag_freed && dep->dep->refs == NULL) + dep->dep->flags |= MOD_JUST_FREED; + } + + /* And from the main module list. */ + if (mod == module_list) { + module_list = mod->next; + } else { + struct module *p; + for (p = module_list; p->next != mod; p = p->next) + continue; + p->next = mod->next; + } + + /* And free the memory. */ + module_unmap(mod); + } + + /* + * kdb_lsmod + * + * This function implements the 'lsmod' command. Lists currently + * loaded kernel modules. + * + * Mostly taken from userland lsmod. + * + * Inputs: + * argc argument count + * argv argument vector + * envp environment vector + * regs registers at time kdb was entered. + * Outputs: + * None. + * Returns: + * zero for success, a kdb diagnostic if error + * Locking: + * none. + * Remarks: + * + */ + + int + kdb_lsmod(int argc, const char **argv, const char **envp, struct pt_regs *regs) + { + struct module *mod; + struct module_ref *mr; + + if (argc != 0) + return KDB_ARGCOUNT; + + kdb_printf("Module Size Used by\n"); + for (mod = module_list; mod && mod->next ;mod = mod->next) { + kdb_printf("%-20s%8lu%4ld ", mod->name, mod->size, mod->uc.usecount); + + if (mod->flags & MOD_DELETED) + kdb_printf(" (deleted)"); + else if (mod->flags & 64) + kdb_printf(" (initializing)"); + else if (!(mod->flags & MOD_RUNNING)) + kdb_printf(" (uninitialized)"); + else { + if (mod->flags & MOD_AUTOCLEAN) + kdb_printf(" (autoclean)"); + if (!(mod->flags & MOD_USED_ONCE)) + kdb_printf(" (unused)"); + } + + if (mod->refs) { + int i = 0; + + kdb_printf(" [ "); + + mr = mod->refs; + while (mr) { + kdb_printf("%s ", mr->ref->name); + mr = mr->next_ref; + } + + kdb_printf("]"); + } + + kdb_printf("\n"); + } + + return 0; + } + + /* + * kdb_rmmod + * + * This function implements the 'rmmod' command. Removes a given + * kernel module. + * + * Inputs: + * argc argument count + * argv argument vector + * envp environment vector + * regs registers at time kdb was entered. + * Outputs: + * None. + * Returns: + * zero for success, a kdb diagnostic if error + * Locking: + * none. + * Remarks: + * + */ + + int + kdb_rmmod(int argc, const char **argv, const char **envp, struct pt_regs *regs) + { + struct module *mod; + + + if (argc != 1) + return KDB_ARGCOUNT; + + kdb_printf("Attempting to remove module: [%s]\n", argv[1]); + if ((mod = find_module(argv[1])) == NULL) { + kdb_printf("Unable to find a module by that name\n"); + return 0; + } + + if (mod->refs != NULL || __MOD_IN_USE(mod)) { + kdb_printf("Module is in use, unable to unload\n"); + return 0; + } + + free_module(mod, 0); + kdb_printf("Module successfully unloaded\n"); + + return 0; + } + /* * kdb_env * *************** kdb_inittab(void) *** 1856,1861 **** --- 2054,2061 ---- #endif /* __SMP__ */ kdb_register("ps", kdb_ps, "", "Display active task list", 0); kdb_register("reboot", kdb_reboot, "", "Reboot the machine immediately", 0); + kdb_register("lsmod", kdb_lsmod, "", "List loaded kernel modules", 0); + kdb_register("rmmod", kdb_rmmod, "", "Remove given kernel module", 1); #if defined(CONFIG_MAGIC_SYSRQ) kdb_register("sr", kdb_sr, "", "Magic SysRq key", 0); #endif