免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 1372 | 回复: 0
打印 上一主题 下一主题

UML调试 [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2008-09-17 13:27 |只看该作者 |倒序浏览

                                2006-8-2  真是没有用过linux,很多事情搞不清楚呢还。读mm/shmem.c 的时候看到mmap 的私有共享影射使用了tmpfs的文件,但是ls /dev/shm并没有看到那个dev/zero名字的文件。于是想搞清楚。(mm/shmem.c shmem_zero_setup)    先是考虑ls使用什么系统调用读取文件夹内的文件名列表,开始没有经验,就是搜索到了sysv_readdir这个系统调用.顺着看下去,觉得vfs_readdir是个关键的函数。并通过查看tmpfs的相关代码确认了这一点。sys_open->dentry_open->fops_get(inode->i_fop)然后看tmpfs的inode,shmem_get_inode 使用的是simple_dir_operations。   然后看dcache_readdir,开始没有仔细看,只是注意到有如下的一句:  (本文实际上都是采用kernel2.6.14)  if (d_unhashed(next) || !next->d_inode)                    continue;    直接注释掉,编译内核,测试。不幸,什么都没有。        如此反复了好几次,后来又改shemem_setup_zero,初看觉得inode->i_link被置位0了,去掉(注意,这里已经走入歧途了),还是没有结果。这样改来改去没有任何结果编译了多次内核。倒是体会到,这样的小改动只需要  make  即可,无须make clean等操作。    过了几天,感觉需要先找个什么方法看看是不是这样行的通。于是直接将shmem_zero_setup的shmem_file_setup换成相应的filp_open(注意需要创建,并且名字不能相同)。居然可以了。(后来意识到这样不过是饮鸩止渴)于是认定只要走一个完整的filp_open就可以将问题找出来(没想到这样是在错误的方向上越走越远)。于是将filp_open拆分,改动到shmem.c.经历了‘成功’后,这次痛苦的时间更长了。下面是相关的改动(注意这不能工作,老是死机):int shmem_do_open_namei(const char * pathname, int flag, int mode, struct nameidata *nd){    struct dentry *dentry;    struct dentry *dir;    struct qstr *this;/*prepare ND */    /* Fill in the open() intent data */    nd->intent.open.flags = flag;    nd->intent.open.create_mode = mode;    /*     * Create - we need to know the parent.      */    /*Get parent nd*/#if 0    error = path_lookup(pathname, LOOKUP_PARENT|LOOKUP_OPEN|LOOKUP_CREATE, nd);    if (error)        return error;#endif            nd->dentry = shm_mnt->mnt_root;     nd->mnt   = mntget(shm_mnt);     nd->last_type= LAST_NORM;{ /*prepare last compnet hash*/         this= &nd->last;         unsigned long hash;      unsigned char c;          this->name = pathname;      c = *(const unsigned char *)pathname;     hash = init_name_hash();     do {            pathname++;            hash = partial_name_hash(c, hash);            c = *(const unsigned char *)pathname;    } while (c && (c != '/'));     this->len = pathname - (const char *) this->name;     this->hash = end_name_hash(hash);}        dir = shm_mnt->mnt_root;    nd->flags &= ~LOOKUP_PARENT;    {        /*dentry = shmem__lookup_hash(&nd->last, nd->dentry, nd);*/     dentry  = d_alloc(dir, &nd->last);     if (!dentry)        return 0;}      /* dentry = inode->i_op->lookup(inode, new, nd); */     d_add(dentry, NULL);        /* Negative dentry, just create the file */    /*error = shmem_create(dir->d_inode, dentry, mode, nd);*/    struct inode *inode = shmem_get_inode(dir->d_sb, S_IFREG | S_IRWXUGO, 0);;        if (inode) {           dir->d_inode->i_size += BOGO_DIRENT_SIZE;           dir->d_inode->i_ctime = dir->d_inode->i_mtime = CURRENT_TIME;           d_instantiate(dentry, inode);                   }else             return -ENOSPC;             nd->dentry = dentry;            return 0;}struct file *shmem_filp_open(const char * filename, int flags, int mode){    int error;    struct nameidata nd;    error = shmem_do_open_namei(filename, flags, mode, &nd);       {       /*           if (!error)               return dentry_open(nd.dentry, nd.mnt, flags);*/           struct file * f;           struct inode *inode;           int error;                  error = -ENFILE;           f = get_empty_filp();           if (!f)               goto cleanup_dentry;           f->f_flags = flags;           f->f_mode = FMODE_WRITE | FMODE_READ;;           inode = nd.dentry->d_inode;                         file_ra_state_init(&f->f_ra, inode->i_mapping);           f->f_dentry = nd.dentry;           f->f_vfsmnt =nd.mnt;           f->f_pos = 0;           f->f_op = &shmem_file_operations;           file_move(f, &inode->i_sb->s_files);                         return f;              cleanup_dentry:           dput(nd.dentry);           mntput(nd.mnt);           return ERR_PTR(error);       }}/* * shmem_zero_setup - setup a shared anonymous mapping * * @vma: the vma to be mmapped is prepared by do_mmap_pgoff */void itoax(char *str, int num){  int i=32;  while(i)  {    if(num&0x1) *str++ = '1';    else *str++='0';    num>>=1;    i--;    if(num==0) break;  }    *str=0;}int shmem_zero_setup(struct vm_area_struct *vma){    struct file *file;    loff_t size = vma->vm_end - vma->vm_start;    /*file = shmem_file_setup("zero", size, vma->vm_flags);*/{  static int i=0;        char name[128], num[33];        strcpy(name,"zerov");        itoax(num,i);        strcat(name,num);        /*file  = shmem_filp_open(name,FMODE_READ|FMODE_WRITE,0700);*/      filp_open(name,O_WRONLY|O_CREAT,0700);      file = shmem_file_setup(name, size, vma->vm_flags);        file->f_dentry->d_inode->i_size=size;        i++;}    if (IS_ERR(file))        return PTR_ERR(file);    if (vma->vm_file)        fput(vma->vm_file);    vma->vm_file = file;    vma->vm_ops = &shmem_vm_ops;    return 0;}                    痛苦的久了就想到了‘万能’的调试,实在是增很printk(何况还不知道如何查看输出信息,ft)。只是知道printk,kgdb,qmenu(?)可以工作,但是我感觉User mode linux对付这个问题才是王道。于是查找uml的使用指南,并逐步实施。      I) 首先是找一个合适的内核版本来编译ARCH=um的内核。我选择了2.6.14,后来证明这个内核比较稳定,编译没有问题。      解压缩到/usr/src/linux2.6.14-uml。    II)到上述目录      make clean      make mrproper (这两个操作对于以前编译过其他arch的情况比较重要)      make xconfig ARCH=um      make all ARCH=um            现在目录下有个linux的可执行文件。    III)不幸,运行uml还需要一个rootfs,就是uml的‘硬盘’啦。当然下载一个  比较快,http://user-mode-linux.sourceforge.net/dl-sf.html  选择了Debian-3.0r0.ext2.bz2,解压缩后改名为root_fs    IV)./linux ubd0=root_fs  这样就搞定了。      V)其实还有要注意的事情:make xconfig ARCH=um的时候注意        1.如果有如下提示:     VFS: Cannot open root device "ubd0" or unknown-block(0,0)      则大概问题如下     1)需要支持rootfs的文件类型,选上ext2,ext3支持     2)选上Block devices/Virtual block device
  • (ubd支持)         2.如果提示: Cannot open init console       则你的rootfs 的/dev/console文件不存在,需要      mount -o loop root_fs /mnt       #cp -dpR /dev/tty[0-9] /mnt/dev      #cp -dpR /dev/ram* /mnt/dev      #cp -dpR /dev/console /mnt/dev    3.如果提示:cannot setup  thead-local storage: cannot setup LDT for       thread-local storage, 那么证明你的rootfs使用了NPTL,不幸现在uml      还不能很好支持这个特性。换个简单点的rootfs吧。        VI)具体到我推荐的这个rootfs,还是有些问题的:     1。竟然没有启动bash, 在相应的runlevel中加上启动bash的命令即可     2。没有安装shm,编辑fstab加上相应条目即可     3。fstab文件中 / 安装在 /dev/ubd/0,改为/dev/ubd0     4。编译uml的时候当然要选上proc支持       VII)我使用的host linux也是linux2.6.14,挺好用,如果你么有发现更好的     用这个就可以了。并且我使用的是FC4,不推荐FC5。        这样,搞定了uml,可以测试了。我写了一个小程序,只有一行:#include #include #include #include main(int argc, char** argv){    int i;    char *p_map;    char temp;    p_map=(char*)mmap(NULL,10*10,PROT_READ|PROT_WRITE,MAP_SHARED|MAP_ANONYMOUS,-1,0);       if(p_map==NULL)           printf("mmap error!\n");}    在host linux下编译,拷贝到uml rootfs即可。测试的时候执行  shm&,让他后台运行。          至于调试,就是:(直接在/usr/src/linux2.6.14-uml下执行)        #gdb    # (gdb) set args ubd0=root_fs    # (gdb) file linux    # (gdb) run    # (gdb) c  (不断回车直到uml启动完成)    # (gdb) break dcache_readdir    # (gdb) c    进入到uml    #(none):shm&    #(none):ls /dev/shm       好,会在一个奇怪的地方断住, c,然后就到了dcache_readdir.不断的用n,s,finish等命令调试你的uml内核即可. 可以用p命令打印相应变量.info break 可以看断点,clear 可以清楚断点.好像我就用了这几个命令.bt都没有用过.    调试的结果很令人不快.问题依然.要注意的是内核编译有-O2优化,代码执行起来怪怪的,如果你想加一段程序,gcc看起来没有用就会不执行到(甚至都没有,优化掉了),解决的方法是:      var=....;      pirntk("",var);            这样可以骗过gcc,保留你的代码.      如果你改动了几个文件,只需要            make ARCH=um即可,编译很快的.                不再详述调试过程了,最后的转机是在2006.8.1号,昨天,突然注意到,dcache_readdir中filp->f_dentry(/dev/shm->root of tmpfs)的地址并不是shm_mnt->root的地址,终于明白了,原来不是一棵树,赫赫.剩下的就简单了,只要修改dcache_readdir将    struct dentry *dentry = filp->f_dentry;    换成    struct dentry *dentry = shm_mnt->root;/*注意,需要将shm_mnt声明为非static*/    然后删除:    if (d_unhashed(next) || !next->d_inode)                    continue;    就可以在ls /dev/shm的时候看到一堆  dev/zero文件了.int dcache_readdir(struct file * filp, void * dirent, filldir_t filldir){    struct dentry *dentry = filp->f_dentry;    struct dentry *cursor = filp->private_data; /*dcache_dir_open 将cursor 设置为dentry ''.''*/                                         /* cursor d_child 挂入了filp->f_dentry->d_subdirs */    struct list_head *p, *q = &cursor->d_child;     ino_t ino;    int i = filp->f_pos;    switch (i) {        case 0:            ino = dentry->d_inode->i_ino;            if (filldir(dirent, ".", 1, i, ino, DT_DIR)                 break;            filp->f_pos++;            i++;            /* fallthrough */        case 1:            ino = parent_ino(dentry);            if (filldir(dirent, "..", 2, i, ino, DT_DIR)                 break;            filp->f_pos++;            i++;            /* fallthrough */        default:            spin_lock(&dcache_lock);            if (filp->f_pos == 2) { /* pos=2 意味从头开始 */                list_del(q);/*将cursor从f_dentry->d_subdirs 删除*/                list_add(q, &dentry->d_subdirs);/*又加回来,从而位于subdir之首*/            }            /*从cursor 的下一个subdir 开始*/            for (p=q->next; p != &dentry->d_subdirs; p=p->next) {                struct dentry *next;                next = list_entry(p, struct dentry, d_child);                if (d_unhashed(next) || !next->d_inode)                    continue;                spin_unlock(&dcache_lock);                if (filldir(dirent, next->d_name.name, next->d_name.len, filp->f_pos,                 next->d_inode->i_ino, dt_type(next->d_inode))                     return 0;                spin_lock(&dcache_lock);                /* next is still alive */                list_del(q); /*q 是cursor, 后移一个位置 */                list_add(q, p);                p = q; /*从cursor 取下一个subdir*/                filp->f_pos++;            }            spin_unlock(&dcache_lock);    }    return 0;}            最后, ls 使用的函数是:sys_getdents64.                         2006.8.2 by hyl.
                   
                   
                   
                   

    本文来自ChinaUnix博客,如果查看原文请点:http://blog.chinaunix.net/u2/79526/showart_1200080.html
  • 您需要登录后才可以回帖 登录 | 注册

    本版积分规则 发表回复

      

    北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
    未成年举报专区
    中国互联网协会会员  联系我们:huangweiwei@itpub.net
    感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

    清除 Cookies - ChinaUnix - Archiver - WAP - TOP