从/ proc / <pid> / pagemap转储pfn不会提供预期的内容</pid>

时间:2014-10-03 13:06:53

标签: c linux memory-management virtual-memory

我使用此代码http://fivelinesofcode.blogspot.com/2014/03/how-to-translate-virtual-to-physical.html转储与从/ proc /&#34; pid&#34; / maps中获取的给定虚拟地址相关的pfn。

获得PFN后,我将其转储到特定的内核模块。这是代码的片段:

static int write_pfn(phys_addr_t pfn)
{
    struct page *p;
    void *v;
    int s =0,ret =0;

    p = pfn_to_page((pfn) >> PAGE_SHIFT);
    v = kmap(p);

    DBG("Writing page %d(mapped addr=0x%lx) - pfn: 0x%lx", p,v,pfn);

    s = write_vaddr(v, PAGE_SIZE);

    if (s != PAGE_SIZE) {
        DBG("Error sending page %d(addr=0x%lx)", s,v);
        return (int) s;
        ret-=1;
    }               
    kunmap(p);

    return ret;
}

但是,我注意到如果我将与内核模块一起转储的PFN与流程内相应虚拟地址的实际内容进行比较,那么内容就完全不同了。 请注意,我使用命令&#34; x&#34;转储进程虚拟地址的内容。来自(gdb)。

有什么想法吗?这是我的内核版本:

Linux 3.14.7-rt5 #1 SMP Mon Jun 23 14:55:19 CEST 2014 x86_64 GNU/Linux

2 个答案:

答案 0 :(得分:0)

逻辑上你的解决方案是正确的,但我不确定页面映射阅读器代码的正确性。无论如何,有一种方法来检查它。当您在内核中时(在目标应用程序的上下文中),您可以使用此内核API获取与指定VA相对应的页面:

1. mm = current->mm
2. struct vm_area_struct *find_vma(struct mm_struct *mm, unsigned long addr)
3. static inline struct page *follow_page(struct vm_area_struct *vma,
                unsigned long address, unsigned int foll_flags)
4. page_to_pfn

你可以实现这个并与你的结果进行比较,希望这会有所帮助。

答案 1 :(得分:0)

谢谢Alex。 您的解决方案的问题是某些符号未导出(例如follow_page())因此我无法在我的模块中使用它们。

然而,我找到了这个解决方案:     mm = ts-> mm;

pgd_t * pgd = pgd_offset(mm, vaddr);
pud_t * pud = pud_offset(pgd, vaddr);
pmd_t * pmd = pmd_offset(pud, vaddr);  
pte_t * pte = pte_offset_map(pmd, vaddr);  
p = pte_page(*pte);
if(p)
    DBG("page frame struct is @ %p", p);

v = kmap(p);

DBG("Writing page 0x%lx(mapped addr=0x%lx) - pid: %d", v,vaddr,pidnr);

s = write_vaddr(v, PAGE_SIZE);

if (s != PAGE_SIZE) {
    DBG("Error sending page %d(addr=0x%lx pid=%d)", v,vaddr,pidnr);
    ret-=1;
}               
kunmap(p);
pte_unmap(pte);