我使用此代码http://fivelinesofcode.blogspot.com/2014/03/how-to-translate-virtual-to-physical.html转储与从/ proc /" pid" / 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与流程内相应虚拟地址的实际内容进行比较,那么内容就完全不同了。 请注意,我使用命令" x"转储进程虚拟地址的内容。来自(gdb)。
有什么想法吗?这是我的内核版本:
Linux 3.14.7-rt5 #1 SMP Mon Jun 23 14:55:19 CEST 2014 x86_64 GNU/Linux
答案 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);