Oops. A disclaimer: I have only tested on x86. I think it should work on sparc and amd64... but.... I haven't tried.
max [EMAIL PROTECTED] wrote: > Hi All, > > You can find a webrev for changes to mdb to allow ctf to be loaded > with raw targets at: > http://www.bruningsystems.com/webrev.rawctf. > > I'll say more about how this works in a later email. > > Usage looks like this: > > # mdb /dev/rdsk/c0d0s0 <-- should work with any file > > ::loadctf <-- currently no options, only > loads ctf for running kernel > > > > 2000::print struct fs <-- prints the superblock > > You can read my blog at http://mbruning.blogspot.com for some ideas > on how to use it. I have also written a dmod which has one dcmd and > one walker. > The dcmd takes an inumber and returns the disk location of the inode. > The walker takes an inode for a directory and walks the entries in the > directory. > The dmod source is attached. To compile and use, see > /usr/demo/mdb/README. > > have fun. > max > > ------------------------------------------------------------------------ > > /* > * Copyright 2007 Max Bruning > */ > > #include <sys/mdb_modapi.h> > > #include <sys/types.h> > #include <sys/sysmacros.h> > #include <sys/stat.h> > #include <sys/fs/ufs_inode.h> > #include <sys/fs/ufs_acl.h> > #include <sys/fs/ufs_fs.h> > #include <sys/fs/ufs_fsdir.h> > > typedef struct ufsdir_walk_data { > int uw_dsize; > int uw_off; > longlong_t uw_dinoaddr; > struct fs *uw_fs; > } ufsdir_walk_data_t; > > /* > * Find highest one bit set. from lib/libc/port/gen/mktemp.c (?) > * Returns bit number of highest bit that is set. > * Low order bit is number 0, high order bit is number 31. > */ > static int > uhighbit(uint_t i) > { > int h = 0; > > if (i & 0xffff0000) > h += 16, i >>= 16; > if (i & 0xff00) > h += 8, i >>= 8; > if (i & 0xf0) > h += 4, i >>= 4; > if (i & 0xc) > h += 2, i >>= 2; > if (i & 0x2) > h += 1; > return (h); > } > > static int > ufsdir_walk_init(mdb_walk_state_t *wsp) > { > ufsdir_walk_data_t *uw; > struct dinode di; > struct fs *fs = mdb_alloc(sizeof(struct fs), UM_SLEEP); > > if (wsp->walk_addr == NULL) { > mdb_warn("ufsdir does not support global walks\n"); > mdb_warn(" You must specify disk inode location\n"); > return (WALK_ERR); > } > > /* > * first, get the superblock for some size info... > * this assumes the first superblock is ok. Later, > * I'll add a "setsb" dcmd that allows one to specify > * an alternate superblock. > */ > if (mdb_vread(fs, sizeof(struct fs), 0x2000) == -1) { > mdb_warn("failed to read superblock\n"); > return (WALK_ERR); > } > > /* read and check the inode */ > if (mdb_vread(&di, sizeof(struct dinode), wsp->walk_addr) == -1) { > mdb_warn("failed to read inode at %x\n", wsp->walk_addr); > return (WALK_DONE); > } > > if (!(di.di_un.di_icom.ic_smode & S_IFDIR)) { > mdb_warn("inode is not for a directory"); > return (WALK_ERR); > } > > uw = mdb_alloc(sizeof(ufsdir_walk_data_t), UM_SLEEP); > uw->uw_fs = fs; > uw->uw_dinoaddr = wsp->walk_addr; > uw->uw_off = 0; > /* assume fragment size is 1024 (blkno<<10) */ > wsp->walk_addr = (uintptr_t)(di.di_un.di_icom.ic_db[0]<<10); > mdb_printf("%x\n", wsp->walk_addr); > wsp->walk_data = uw; > > return (WALK_NEXT); > } > > /* > * the following is largely hacked from bmap_read(), > os/common/fs/ufs/ufs_bmap.c > */ > static int > ufsdir_walk_step(mdb_walk_state_t *wsp) > { > int status; > struct direct dirp; > struct dinode di; > ufsdir_walk_data_t *uw; > int iblks[2048]; /* assumes blk size is 8192 bytes */ > /* the following between lbn and nindiroffset is from bmap_read() */ > daddr_t lbn; > struct fs *fs; > int i, j, boff; > int shft; /* we maintain sh = 1 << shft */ > daddr_t ob, nb, tbn; > daddr32_t bap[8192]; /* XXX should be dynamically allocated based on > fs.bsize */ > int nindirshift, nindiroffset; > > uw = (ufsdir_walk_data_t *)wsp->walk_data; > > fs = uw->uw_fs; > > if (mdb_vread(&dirp, sizeof(struct direct), wsp->walk_addr) == -1) { > mdb_warn("cannot read directory entry at %p\n", wsp->walk_addr); > return (WALK_ERR); > } > > /* read the inode every time in the step function (in case of changes) > */ > if (mdb_vread(&di, sizeof(struct dinode), uw->uw_dinoaddr) == -1) { > mdb_warn("cannot read disk inode\n"); > return (WALK_ERR); > } > > /* > * Now, find the next address. Normally this is the old address > * plus the reclen. But, we need to handle crossing block > * boundaries and very large directories that use indirect blocks. > */ > > uw->uw_off += dirp.d_reclen; > > if (uw->uw_off >= di.di_un.di_icom.ic_lsize) > return (WALK_DONE); > > /* most of the rest of this code comes from bmap_read() */ > lbn = (daddr_t)lblkno(fs, uw->uw_off); > boff = (int)blkoff(fs, uw->uw_off); > if (lbn < 0) { > mdb_warn("directory is too big!\n"); > return (WALK_ERR); > } > > /* > * The first NDADDR blocks are direct blocks. > */ > if (lbn < NDADDR) { > wsp->walk_addr = (di.di_un.di_icom.ic_db[lbn]*fs->fs_fsize) + > (uw->uw_off % fs->fs_bsize); > status = wsp->walk_callback(wsp->walk_addr, wsp->walk_data, > wsp->walk_cbdata); > return (status); > } > > nindiroffset = fs->fs_nindir - 1; > nindirshift = uhighbit(nindiroffset); > > /* > * Determine how many levels of indirection. > */ > shft = 0; /* sh = 1 */ > tbn = lbn - NDADDR; > for (j = NIADDR; j > 0; j--) { > longlong_t sh; > > shft += nindirshift; /* sh *= nindir */ > sh = 1LL << shft; > if (tbn < sh) > break; > tbn -= sh; > } > if (j == 0) > return (WALK_ERR); > > /* > * Fetch the first indirect block. > */ > nb = di.di_un.di_icom.ic_ib[NIADDR - j]; > if (nb == 0) { /* directories can have holes??? */ > return (WALK_ERR); > } > > /* > * Fetch through the indirect blocks. > */ > for (; j <= NIADDR; j++) { > ob = nb; > if (mdb_vread(bap, fs->fs_bsize, (fsbtodb(fs, > ob)*fs->fs_fsize)) == -1) { > mdb_warn("error reading indirect block\n"); > return (WALK_ERR); > } > > shft -= nindirshift; /* sh / nindir */ > i = (tbn >> shft) & nindiroffset; /* (tbn / sh) % nindir */ > nb = bap[i]; > if (nb == 0) { /* directories can have holes??? */ > mdb_warn("hole in directory file\n"); > return (WALK_ERR); > } > } > > wsp->walk_addr = (bap[i] << 10) + (uw->uw_off % fs->fs_bsize); > > status = wsp->walk_callback(wsp->walk_addr, wsp->walk_data, > wsp->walk_cbdata); > > return (status); > > } > > static void > ufsdir_walk_fini(mdb_walk_state_t *wsp) > { > ufsdir_walk_data_t *uw = (ufsdir_walk_data_t *)wsp->walk_data; > mdb_free(uw->uw_fs, sizeof(struct fs)); > mdb_free(wsp->walk_data, sizeof (ufsdir_walk_data_t)); > } > > static int > inum2inode(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) > { > struct fs fs; > > /* XXX - assume using primary superblock */ > if (mdb_vread(&fs, sizeof (struct fs), 0x2000) == -1) { > mdb_printf("cannot read superblock"); > return (DCMD_ERR); > } > > mdb_printf("%x\n", ((addr/fs.fs_ipg)*(fs.fs_fpg*fs.fs_fsize)) > + ((addr/fs.fs_ipg)*(fs.fs_cgoffset*fs.fs_fsize)) > + (fs.fs_iblkno*fs.fs_fsize) + ((addr%fs.fs_ipg) * > sizeof(struct dinode))); > } > > /* > * MDB module linkage information: > * > * We declare a list of structures describing our dcmds, a list of structures > * describing our walkers, and a function named _mdb_init to return a pointer > * to our module information. > */ > > static const mdb_dcmd_t dcmds[] = { > { "inum2inode", NULL, "given inumber, return address of inode on disk", > inum2inode }, > { NULL } > }; > > static const mdb_walker_t walkers[] = { > { "ufsdir", "given a disk inode, walk list of ufs directory entries on > disk", ufsdir_walk_init, ufsdir_walk_step, ufsdir_walk_fini }, > { NULL } > }; > > static const mdb_modinfo_t modinfo = { > MDB_API_VERSION, dcmds, walkers > }; > > const mdb_modinfo_t * > _mdb_init(void) > { > return (&modinfo); > } > > ------------------------------------------------------------------------ > > _______________________________________________ > opensolaris-discuss mailing list > opensolaris-discuss@opensolaris.org _______________________________________________ opensolaris-discuss mailing list opensolaris-discuss@opensolaris.org