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

Reply via email to