diff -u -N dumpread.O/Arch.py dumpread/Arch.py --- dumpread.O/Arch.py 2006-05-10 15:15:12.000000000 +0900 +++ dumpread/Arch.py 2006-05-19 17:48:01.000000000 +0900 @@ -1,12 +1,15 @@ +import libelf class Arch: - def __init__(self, name, page_shift=0, pt_format='', max_vcpu=0): + def __init__(self, name, **kw): self.name = name - self.page_shift = page_shift - self.page_size = 1 << page_shift - self.pagemask = (1 << page_shift) - 1 - self.pt_format = pt_format - self.max_vcpu = max_vcpu + self.page_shift = kw['page_shift'] + self.page_size = 1 << kw['page_shift'] + self.pagemask = (1 << kw['page_shift']) - 1 + self.pt_format = kw['pt_format'] + self.max_vcpu = kw['max_vcpu'] + self.elf_format = kw['elf_format'] + self.elf_machine = kw['elf_machine'] def maddr_to_mfn(self, maddr): '''return mfn from maddr''' @@ -16,6 +19,10 @@ '''return maddr from mfn''' return mfn << self.page_shift + def pfn_to_vaddr(self, pfn): + '''return vaddr from pfn''' + return pfn << self.page_shift + def page_offset(self, maddr): '''return offset in page''' return maddr & self.pagemask @@ -26,13 +33,29 @@ - - -x86_32 = Arch('x86_32', page_shift=12, pt_format='L', max_vcpu=32) -x86_64 = Arch('x86_64', page_shift=12, pt_format='Q', max_vcpu=32) -ia64 = Arch('ia64', page_shift=14, pt_format='Q', max_vcpu=4) - -arch = {'x86_32': x86_32, - 'x86_64': x86_64, - 'ia64': ia64, +archparam = {'x86_32': + {'page_shift': 12, + 'pt_format':'L', + 'max_vcpu': 32, + 'elf_format': 'ELF32', + 'elf_machine': libelf.EM_386, + }, + 'x86_64': + {'page_shift': 12, + 'pt_format':'Q', + 'max_vcpu': 32, + 'elf_format': 'ELF64', + 'elf_machine': libelf.EM_386, + }, + 'ia64': + {'page_shift': 14, + 'pt_format':'Q', + 'max_vcpu': 4, + 'elf_format': 'ELF64', + 'elf_machine': libelf.EM_IA_64, + }} + +arch = {'x86_32': Arch('x86_32', **archparam['x86_32']), + 'x86_64': Arch('x86_64', **archparam['x86_64']), + 'ia64': Arch('ia64', **archparam['ia64']), } Binary files dumpread.O/Arch.pyc and dumpread/Arch.pyc differ diff -u -N dumpread.O/CoreDump.py dumpread/CoreDump.py --- dumpread.O/CoreDump.py 2006-05-10 15:15:12.000000000 +0900 +++ dumpread/CoreDump.py 2006-05-19 17:48:01.000000000 +0900 @@ -23,6 +23,18 @@ '''return a list of all available mfn''' raise NotImplementedError + def set_context(self, ctxts): + '''set CPU(s) num and contexts''' + raise NotImplementedError + + def set_registers(self, regs): + '''overwrite user registers on context''' + raise NotImplementedError + + def set_p2m(self, p2m): + '''set pfn2mfn for this dump image''' + raise NotImplementedError + def read_addr(self, maddr, size): '''read 'size' bytes data from address''' Binary files dumpread.O/CoreDump.pyc and dumpread/CoreDump.pyc differ diff -u -N dumpread.O/ElfCore.py dumpread/ElfCore.py --- dumpread.O/ElfCore.py 2006-05-10 15:15:12.000000000 +0900 +++ dumpread/ElfCore.py 2006-05-19 17:48:01.000000000 +0900 @@ -1,10 +1,56 @@ +''' +ELF core file image interface. +This module define ElfCoreReader, ElfCoreWriter, +and their abstruct class ElfCore +''' + import os import re import CoreDump import Register +import libelf +from XenContext import XenContext command = 'LANG=C readelf -l %s' +def m2v_to_sections(m2v, mfns): + mfns.sort() + start = mfns[0] + mfns = mfns[1:] + + sections = [] + total_pages = 0 + + currentrange = [start, start + 1] + oldoffset = start - m2v[start] + + for mfn in mfns: + if not mfn in m2v: + continue # this page is not mapped + offset = mfn - m2v[mfn] + if oldoffset == offset and currentrange[1] == mfn: + # contiguous + currentrange[1] += 1 + else: + # new section + sections.append({'startmfn': currentrange[0], + 'startvfn': currentrange[0] - oldoffset, + 'nr_pages': currentrange[1] - currentrange[0], + 'total_pages': total_pages, + }) + total_pages += currentrange[1] - currentrange[0] + + currentrange = [mfn, mfn + 1] + oldoffset = offset + # last section + sections.append({'startmfn': currentrange[0], + 'startvfn': currentrange[0] - oldoffset, + 'nr_pages': currentrange[1] - currentrange[0], + 'total_pages': total_pages, + }) + + return sections + class ElfSection: ''' Elf Section header class. @@ -26,19 +72,136 @@ def maddr_to_offset(self, maddr): return maddr - self.maddr + self.offset -class ElfCoreReader(CoreDump.CoreDump): + +class ElfCore(CoreDump.CoreDump): ''' Elf Core file reader interface ''' - def __init__(self, corefilename, arch): CoreDump.CoreDump.__init__(self, corefilename, arch) + self.sections = [] + self.pages = [] + self.file = None + self.m2v = None + self.p2m = None + self.note = '' + + def mfn2offset(self, mfn): + offset = None + for sec in self.sections: + if sec.has_maddr(self.arch.mfn_to_maddr(mfn)): + offset = sec.maddr_to_offset(self.arch.mfn_to_maddr(mfn)) + break + if offset == None: + raise KeyError, '%s not found' % mfn + return offset + + def read_page(self, mfn): + '''return a page data''' + offset = self.mfn2offset(mfn) + self.file.seek(offset) + data = self.file.read(self.arch.page_size) + return data + + def has_page(self, mfn): + '''return a page is there or not''' + return mfn in self.pages + + def get_pagelist(self): + '''return a list of all available mfn''' + return self.pages + + def get_registers(self): + '''return Register''' + # XXX UniProcessor only + f = os.popen('LANG=C objdump -s -j .reg %s' % self.corefilename) + reg = Register.arch[self.arch.name]() + reg.fromElf(Register.read_objdump(f.read())) + return [reg] + + def set_context(self, ctxts): + '''set CPU(s) num and contexts''' + self.nr_vcpus = len(ctxts) + self.ctxts = ctxts + + def set_registers(self, regs): + '''overwrite user registers on context''' + + for i, reg in enumerate(regs): + self.ctxts[i].set_register(reg) + + def set_ctrlreg(self, num, val): + '''set all ctrlreg[num] as val ''' + # it isn't used at elf + pass + + def set_m2v(self, m2v): + '''set machine to virtual mapping''' + self.m2v = m2v + if self.p2m: + self._update_sections() + + def set_p2m(self, p2m): + '''set pfn2mfn for this dump image''' + self.p2m = p2m + if self.m2v: + self._update_sections() + + + def _update_sections(self): + '''update section info from p2m & m2v''' + + pagemap = m2v_to_sections(self.m2v, self.p2m.values()) + dataoffset = self.arch.round_pgup( + # ELF heaer + libelf.sizeof_elf32_ehdr + + # PT_NOTE,PT_LOAD header + (1 + len(pagemap)) * libelf.sizeof_elf32_phdr + + # NT_PRSTATUS header and notes + len(self.note)) + + self.sections = [ElfSection('LOAD', + dataoffset + self.arch.page_size * s['total_pages'], # offset + self.arch.pfn_to_vaddr(s['startvfn']), # vaddr + self.arch.mfn_to_maddr(s['startmfn']), # maddr + self.arch.page_size * s['nr_pages'], # filesize + self.arch.page_size * s['nr_pages'], # memsize + 'RWE', + self.arch.page_size, # page align + ) + for s in pagemap] + + +class ElfCoreReader(ElfCore): + ''' + ELF core image file reader class. + ''' + + def __init__(self, corefilename, arch): + ElfCore.__init__(self, corefilename, arch) + self.file = file(self.corefilename, 'r') self.sections = self._read_sections() - self.filename = corefilename - self.file = file(corefilename, 'r') if len(self.sections) == 0: raise ValueError, 'section isn\'t found' - + self.pages = self._get_pages() + self.note = self.get_note() + + def get_note(self): + '''copy PT_NOTE section contents''' + f = os.popen('LANG=C objdump -s -j note0 %s' % self.corefilename) + return Register.read_objdump(f.read()) + + def _get_pages(self): + '''return pages from self.sections''' + + pages = [] + for sec in self.sections: + if sec.typename == 'LOAD': + start_mfn = self.arch.maddr_to_mfn(sec.maddr) + end_mfn = self.arch.maddr_to_mfn(sec.maddr + sec.memsize) + pages = pages + range(start_mfn, end_mfn+1) + return pages + def _read_sections(self): ''' read section header informations via readelf @@ -56,6 +219,7 @@ (typename, offset, vaddr, paddr, filesize, memsize, flag, align) = m.groups() offset = int(offset, 16) + vaddr = int(vaddr, 16) paddr = int(paddr, 16) filesize = int(filesize, 16) memsize = int(memsize, 16) @@ -65,43 +229,104 @@ return sections - def read_page(self, mfn): - '''return a page data''' - offset = None - for sec in self.sections: - if sec.has_maddr(self.arch.mfn_to_maddr(mfn)): - offset = sec.maddr_to_offset(self.arch.mfn_to_maddr(mfn)) - break - if offset == None: - raise KeyError, '%s not found' % mfn - self.file.seek(offset) - data = self.file.read(self.arch.page_size) - return data - - def has_page(self, mfn): - '''return a page is there or not''' +class ElfCoreWriter(ElfCore): + ''' + Xen core image file writer class. + ''' + def __init__(self, corefilename, arch): + ElfCore.__init__(self, corefilename, arch) + self.file = file(corefilename, 'r+') - for sec in self.sections: - if sec.has_maddr(self.arch.mfn_to_maddr(mfn)): - return True - return False - def get_pagelist(self): - '''return a list of all available mfn''' + def set_note(self, note): + self.note = note + + def _elf_init(self): + libelf.format(self.arch.elf_format) + libelf.version(libelf.EV_CURRENT) + self.elf = libelf.begin(self.file, libelf.ELF_C_WRITE, None) + ehdr = self.elf.newehdr() + + # set elf header + ehdr.e_type = libelf.ET_CORE + ehdr.e_machine = self.arch.elf_machine + ehdr.e_version = libelf.EV_CURRENT + ehdr.e_entry = 0 + ehdr.e_flags = 0 + self.phdrs = self.elf.newphdr(1+len(self.sections)) + + def _fill_note_hdr(self): + '''make PT_NOTE header''' + self.note_offset = (libelf.sizeof_elf32_ehdr + + (1 + len(self.sections)) * libelf.sizeof_elf32_phdr) + phdr = self.phdrs[0] + phdr.p_type = libelf.PT_NOTE + phdr.p_flags = 0 + phdr.p_offset = self.note_offset + phdr.p_vaddr = 0 + phdr.p_paddr = 0 + phdr.p_filesz = len(self.note) + phdr.p_memsz = 0 + phdr.p_align = 0 + + + def _fill_load_hdr(self): + '''make PT_LOAD header''' + for i, sec in enumerate(self.sections): + phdr = self.phdrs[1 + i] + phdr.p_type = libelf.PT_LOAD + phdr.p_flags = libelf.PF_R | libelf.PF_W | libelf.PF_X + phdr.p_offset = sec.offset + phdr.p_vaddr = sec.vaddr + phdr.p_paddr = sec.maddr + phdr.p_filesz = sec.filesize + phdr.p_memsz = sec.memsize + phdr.p_align = sec.align + + def _elf_write_notes(self): + '''make ELF notes''' + self.file.seek(self.note_offset) + self.file.write(self.note) + + def _elf_end(self): + self.elf.update(libelf.ELF_C_WRITE) + self._header_size = self.elf.end() + + def write_header(self): + '''write header''' + + self._elf_init() + + # make program headers + note = self._fill_note_hdr() + loads = self._fill_load_hdr() + + self._elf_write_notes() + # write headers, set self.page_offset + offset = self._elf_end() + + + def fetch_pages(self, other): + '''copy pages from other dump''' + count = 0 + pagebuf = {} + + pages = self.p2m.values() + pages.sort() - pages = [] - for sec in self.sections: - if sec.typename == 'LOAD': - start_mfn = self.arch.maddr_to_mfn(sec.maddr) - end_mfn = self.arch.maddr_to_mfn(sec.maddr + sec.memsize) - pages = pages + range(start_mfn, end_mfn+1) - return pages - - def get_registers(self): - '''return Register''' - # XXX UniProcessor only - f = os.popen('LANG=C objdump -s -j .reg %s' % self.filename) - reg = Register.arch[self.arch.name]() - reg.fromElf(Register.read_objdump(f.read())) - return [reg] + for mfn in pages: + pagebuf[mfn] = other.read_page(mfn) + count += 1 + if count % 1024 == 0 or count == len(pages): + for mfn in pagebuf: + self.write_page(mfn, pagebuf[mfn]) # write mfn + pagebuf = {} + + def write_page(self, mfn, data): + '''put a page into index and write data into file. header is not updated by this.''' + # data on disk + self.file.seek(self.mfn2offset(mfn)) + self.file.write(data) + + Binary files dumpread.O/ElfCore.pyc and dumpread/ElfCore.pyc differ diff -u -N dumpread.O/ElfCore.py~ dumpread/ElfCore.py~ --- dumpread.O/ElfCore.py~ 1970-01-01 09:00:00.000000000 +0900 +++ dumpread/ElfCore.py~ 2006-05-19 17:22:16.000000000 +0900 @@ -0,0 +1,331 @@ +''' +ELF core file image interface. +This module define ElfCoreReader, ElfCoreWriter, +and their abstruct class ElfCore +''' + +import os +import re +import CoreDump +import Register +import libelf +from XenContext import XenContext + +command = 'LANG=C readelf -l %s' + +def m2v_to_sections(m2v, mfns): + mfns.sort() + start = mfns[0] + mfns = mfns[1:] + + sections = [] + total_pages = 0 + + currentrange = [start, start + 1] + oldoffset = start - m2v[start] + + for mfn in mfns: + if not mfn in m2v: + continue # this page is not mapped + offset = mfn - m2v[mfn] + if oldoffset == offset and currentrange[1] == mfn: + # contiguous + currentrange[1] += 1 + else: + # new section + sections.append({'startmfn': currentrange[0], + 'startvfn': currentrange[0] - oldoffset, + 'nr_pages': currentrange[1] - currentrange[0], + 'total_pages': total_pages, + }) + total_pages += currentrange[1] - currentrange[0] + + currentrange = [mfn, mfn + 1] + oldoffset = offset + # last section + sections.append({'startmfn': currentrange[0], + 'startvfn': currentrange[0] - oldoffset, + 'nr_pages': currentrange[1] - currentrange[0], + 'total_pages': total_pages, + }) + + return sections + +class ElfSection: + ''' + Elf Section header class. + ''' + + def __init__(self, typename, offset, vaddr, maddr, filesize, memsize, flag, align): + self.typename = typename + self.offset = offset + self.vaddr = vaddr + self.maddr = maddr + self.filesize = filesize + self.memsize = memsize + self.flag = flag + self.align = align + + def has_maddr(self, maddr): + return self.maddr <= maddr < self.maddr + self.memsize + + def maddr_to_offset(self, maddr): + return maddr - self.maddr + self.offset + + +class ElfCore(CoreDump.CoreDump): + ''' + Elf Core file reader interface + ''' + def __init__(self, corefilename, arch): + CoreDump.CoreDump.__init__(self, corefilename, arch) + self.sections = [] + self.pages = [] + self.file = None + self.m2v = None + self.p2m = None + + def mfn2offset(self, mfn): + offset = None + for sec in self.sections: + if sec.has_maddr(self.arch.mfn_to_maddr(mfn)): + offset = sec.maddr_to_offset(self.arch.mfn_to_maddr(mfn)) + break + if offset == None: + raise KeyError, '%s not found' % mfn + return offset + + def read_page(self, mfn): + '''return a page data''' + offset = self.mfn2offset(mfn) + self.file.seek(offset) + data = self.file.read(self.arch.page_size) + return data + + def has_page(self, mfn): + '''return a page is there or not''' + return mfn in self.pages + + def get_pagelist(self): + '''return a list of all available mfn''' + return self.pages + + def get_registers(self): + '''return Register''' + # XXX UniProcessor only + f = os.popen('LANG=C objdump -s -j .reg %s' % self.corefilename) + reg = Register.arch[self.arch.name]() + reg.fromElf(Register.read_objdump(f.read())) + return [reg] + + def set_context(self, ctxts): + '''set CPU(s) num and contexts''' + self.nr_vcpus = len(ctxts) + self.ctxts = ctxts + + def set_registers(self, regs): + '''overwrite user registers on context''' + + for i, reg in enumerate(regs): + self.ctxts[i].set_register(reg) + + def set_ctrlreg(self, num, val): + '''set all ctrlreg[num] as val ''' + # it isn't used at elf + pass + + def set_m2v(self, m2v): + '''set machine to virtual mapping''' + self.m2v = m2v + if self.p2m: + self._update_sections() + + def set_p2m(self, p2m): + '''set pfn2mfn for this dump image''' + self.p2m = p2m + if self.m2v: + self._update_sections() + + + def _update_sections(self): + '''update section info from p2m & m2v''' + + pagemap = m2v_to_sections(self.m2v, self.p2m.values()) + dataoffset = self.arch.round_pgup( + # ELF heaer + libelf.sizeof_elf32_ehdr + + # PT_NOTE,PT_LOAD header + (1 + len(pagemap)) * libelf.sizeof_elf32_phdr + # NT_PRSTATUS header and notes + # + ((libelf.sizeof_elf32_nhdr + 4) + sizeof_elf_prstatus()) * self.nr_vcpus + ) + + self.sections = [ElfSection('LOAD', + dataoffset + self.arch.page_size * s['total_pages'], # offset + self.arch.pfn_to_vaddr(s['startvfn']), # vaddr + self.arch.mfn_to_maddr(s['startmfn']), # maddr + self.arch.page_size * s['nr_pages'], # filesize + self.arch.page_size * s['nr_pages'], # memsize + 'RWE', + self.arch.page_size, # page align + ) + for s in pagemap] + + +class ElfCoreReader(ElfCore): + ''' + ELF core image file reader class. + ''' + + def __init__(self, corefilename, arch): + ElfCore.__init__(self, corefilename, arch) + self.file = file(self.corefilename, 'r') + self.sections = self._read_sections() + if len(self.sections) == 0: + raise ValueError, 'section isn\'t found' + self.pages = self._get_pages() + + def get_note(self): + '''copy PT_NOTE section contents''' + f = os.popen('LANG=C objdump -s -j note0 %s' % self.corefilename) + return Register.read_objdump(f.read()) + + def _get_pages(self): + '''return pages from self.sections''' + + pages = [] + for sec in self.sections: + if sec.typename == 'LOAD': + start_mfn = self.arch.maddr_to_mfn(sec.maddr) + end_mfn = self.arch.maddr_to_mfn(sec.maddr + sec.memsize) + pages = pages + range(start_mfn, end_mfn+1) + return pages + + def _read_sections(self): + ''' + read section header informations via readelf + ''' + + sections = [] + f = os.popen(command % self.corefilename, 'r') + + section_pattern = '\s+(?P\w+)\s+(?P0x[0-9a-f]+) (?P0x[0-9a-f]+) (?P0x[0-9a-f]+) (?P0x[0-9a-f]+) (?P0x[0-9a-f]+) (?P[R ][W ][E ]) (?P[0-9]+)' + section_prog = re.compile(section_pattern) + + for line in f: + m = section_prog.search(line) + if m: + (typename, offset, vaddr, paddr, filesize, memsize, flag, align) = m.groups() + + offset = int(offset, 16) + vaddr = int(vaddr, 16) + paddr = int(paddr, 16) + filesize = int(filesize, 16) + memsize = int(memsize, 16) + align = int(align, 16) + + sections.append( ElfSection(typename, offset, vaddr, paddr, filesize, memsize, flag, align) ) + + return sections + + +class ElfCoreWriter(ElfCore): + ''' + Xen core image file writer class. + ''' + def __init__(self, corefilename, arch): + ElfCore.__init__(self, corefilename, arch) + self.file = file(corefilename, 'r+') + + + def set_note(self, note): + self.note = note + + def _elf_init(self): + libelf.format(self.arch.elf_format) + libelf.version(libelf.EV_CURRENT) + self.elf = libelf.begin(self.file, libelf.ELF_C_WRITE, None) + ehdr = self.elf.newehdr() + + # set elf header + ehdr.e_type = libelf.ET_CORE + ehdr.e_machine = self.arch.elf_machine + ehdr.e_version = libelf.EV_CURRENT + ehdr.e_entry = 0 + ehdr.e_flags = 0 + self.phdrs = self.elf.newphdr(1+len(self.sections)) + + def _fill_note_hdr(self): + '''make PT_NOTE header''' + self.note_offset = (libelf.sizeof_elf32_ehdr + + (1 + len(self.sections)) * libelf.sizeof_elf32_phdr) + phdr = self.phdrs[0] + phdr.p_type = libelf.PT_NOTE + phdr.p_flags = 0 + phdr.p_offset = self.note_offset + phdr.p_vaddr = 0 + phdr.p_paddr = 0 + phdr.p_filesz = len(self.note) + phdr.p_memsz = 0 + phdr.p_align = 0 + + + def _fill_load_hdr(self): + '''make PT_LOAD header''' + for i, sec in enumerate(self.sections): + phdr = self.phdrs[1 + i] + phdr.p_type = libelf.PT_LOAD + phdr.p_flags = libelf.PF_R | libelf.PF_W | libelf.PF_X + phdr.p_offset = sec.offset + phdr.p_vaddr = sec.vaddr + phdr.p_paddr = sec.maddr + phdr.p_filesz = sec.filesize + phdr.p_memsz = sec.memsize + phdr.p_align = sec.align + + def _elf_write_notes(self): + '''make ELF notes''' + self.file.seek(self.note_offset) + self.file.write(self.note) + + def _elf_end(self): + self.elf.update(libelf.ELF_C_WRITE) + self._header_size = self.elf.end() + + def write_header(self): + '''write header''' + + self._elf_init() + + # make program headers + note = self._fill_note_hdr() + loads = self._fill_load_hdr() + + self._elf_write_notes() + # write headers, set self.page_offset + offset = self._elf_end() + + + def fetch_pages(self, other): + '''copy pages from other dump''' + count = 0 + pagebuf = {} + + pages = self.p2m.values() + pages.sort() + + for mfn in pages: + pagebuf[mfn] = other.read_page(mfn) + count += 1 + if count % 1024 == 0 or count == len(pages): + for mfn in pagebuf: + self.write_page(mfn, pagebuf[mfn]) # write mfn + pagebuf = {} + + def write_page(self, mfn, data): + '''put a page into index and write data into file. header is not updated by this.''' + # data on disk + self.file.seek(self.mfn2offset(mfn)) + self.file.write(data) + + diff -u -N dumpread.O/PageTable.py dumpread/PageTable.py --- dumpread.O/PageTable.py 2006-05-10 15:15:12.000000000 +0900 +++ dumpread/PageTable.py 2006-05-19 17:48:01.000000000 +0900 @@ -39,6 +39,35 @@ v2m = virt_to_machine # alias + def get_present_virt(self): + '''return all pages with present flag''' + + ranges = [] + for page in self.l1: + pte = self.l1[page] + if pte & FLAGPRESENT: + if pte & FLAG4MB: + ranges.append((page, 1024)) + else: + mfn = self.arch.maddr_to_mfn(pte) + l2 = self.read_l2(mfn) + for subpage in l2: + pte = l2[subpage] + if pte & FLAGPRESENT: + ranges.append((page|subpage, 1)) + return ranges + + def get_machine_to_virt(self): + '''return virtual page to machine page mapping''' + pages = self.get_present_virt() + mach2virt = {} + shift = 12 + for base, nr in pages: + for i in range(nr): + page = base + i * self.arch.page_size + mach2virt[self.v2m(page) >> shift] = page >> shift + return mach2virt + def read_l1(self, mfn): '''read level-1 pagetable''' @@ -84,3 +113,4 @@ xendump = ElfCore.ElfCoreReader('dump', 'x86_32') pt = PageTable(xendump, 0x176000 >> 12) print hex(pt.v2m(0xff177440L)) # dom0 + print pt.get_machine_to_virt() Binary files dumpread.O/PageTable.pyc and dumpread/PageTable.pyc differ diff -u -N dumpread.O/README dumpread/README --- dumpread.O/README 2006-05-10 15:15:49.000000000 +0900 +++ dumpread/README 2006-05-19 17:37:52.000000000 +0900 @@ -7,9 +7,28 @@ Libs: debug_info.py -- parse 'readelf -wi' output for structure's member offset + XenContext.py -- Xen Core format vcpu context class + Register.py -- register info class PageTable.py -- pagetable class for dump file (x86_32 non-PAE) SymbolTable.py -- symbol table dictionary to analyse dump (parse 'nm -s' output) ElfCore.py -- ELF Core Format Reader XenCore.py -- Xen Core Format Reader/Writer CoreDump.py -- Core file base class Arch.py -- architecture information class + +Usage: dom0cut_x86_32.py [options] + +options: + -h, --help show this help message and exit + -oDOM0DUMPNAME, --dom0dump=DOM0DUMPNAME + dom0 dump file for output + -dDUMPNAME, --xendump=DUMPNAME + xen dump file for input + -xXENSYMS, --xensyms=XENSYMS + xen binary with symbols + -vVMLINUX, --vmlinux=VMLINUX + linux binary with symbols + -aARCH, --arch=ARCH architecture (now 'x86_32' only) + -tFILETYPE, --type=FILETYPE + output file type("xen" or "elf") + -f, --force overwrite output file diff -u -N dumpread.O/README~ dumpread/README~ --- dumpread.O/README~ 1970-01-01 09:00:00.000000000 +0900 +++ dumpread/README~ 2006-05-10 15:15:49.000000000 +0900 @@ -0,0 +1,15 @@ +Docs: + README -- this file + +Reader: + dom0cut_x86_32.py -- extract dom0 image (for x86_32) + dumpread.py -- dump read by address command line utility + +Libs: + debug_info.py -- parse 'readelf -wi' output for structure's member offset + PageTable.py -- pagetable class for dump file (x86_32 non-PAE) + SymbolTable.py -- symbol table dictionary to analyse dump (parse 'nm -s' output) + ElfCore.py -- ELF Core Format Reader + XenCore.py -- Xen Core Format Reader/Writer + CoreDump.py -- Core file base class + Arch.py -- architecture information class Binary files dumpread.O/Register.pyc and dumpread/Register.pyc differ Binary files dumpread.O/SymbolTable.pyc and dumpread/SymbolTable.pyc differ diff -u -N dumpread.O/XenContext.py dumpread/XenContext.py --- dumpread.O/XenContext.py 1970-01-01 09:00:00.000000000 +0900 +++ dumpread/XenContext.py 2006-05-19 17:48:01.000000000 +0900 @@ -0,0 +1,57 @@ +import struct +import Register +import StringIO as StringIO + +class XenContext: + def __init__(self, tree, context=None): + self.tree = tree + self.ctxt_size = tree.get_struct_size('vcpu_guest_context') + self.reg_offset = tree.calc_struct_member_offset('vcpu_guest_context', 'user_regs') + self.reg_size = tree.get_struct_size('cpu_user_regs') + self.ctrlreg_offset = tree.calc_struct_member_offset('vcpu_guest_context', 'ctrlreg') + self.ctrlreg_format = 'L' + self.ctrlreg_size = struct.calcsize('L') + self.max_ctrlreg = 7 # 0-7 + + if context: + self.context = context + else: + self.context = "\x00" * self.ctxt_size + + self.ctxtf = StringIO.StringIO(self.context) + + def __str__(self): + return self.ctxtf.getvalue() + + def clone(self): + return XenContext(self.tree, self.ctxtf.getvalue()) + + def set_register(self, reg): + regstr = reg.asXen() + + self.ctxtf.seek(self.reg_offset) + self.ctxtf.write(regstr) + + def get_register(self, reg): + self.ctxtf.seek(self.reg_offset) + regstr = self.ctxtf.read(self.reg_size) + reg = Register.Register() + reg.fromXen(regstr) + return reg + + def set_ctrlreg(self, num, val): + if num > self.max_ctrlreg or num < 0: + raise IndexError + + regstr = struct.pack(self.ctrlreg_format, val) + self.ctxtf.seek(self.ctrlreg_offset + self.ctrlreg_size * num) + self.ctxtf.write(regstr) + + def get_ctrlreg(self, num): + if num > self.max_ctrlreg or num < 0: + raise IndexError + + self.ctxtf.seek(self.ctrlreg_offset + self.ctrlreg_size * num) + regstr = self.ctxtf.read(self.ctrlreg_size) + return struct.unpack(self.ctrlreg_format, regstr) + Binary files dumpread.O/XenContext.pyc and dumpread/XenContext.pyc differ diff -u -N dumpread.O/XenCore.py dumpread/XenCore.py --- dumpread.O/XenCore.py 2006-05-10 15:15:12.000000000 +0900 +++ dumpread/XenCore.py 2006-05-19 17:48:01.000000000 +0900 @@ -4,67 +4,15 @@ and their abstruct class XenCore ''' -import StringIO as StringIO import CoreDump import struct import array +from XenContext import XenContext + CORE_MAGIC = 0xF00FEBEDL HEADER_FORMAT = "LLLLLL" - -class XenContext: - def __init__(self, tree, context=''): - self.tree = tree - self.ctxt_size = tree.get_struct_size('vcpu_guest_context') - self.reg_offset = tree.calc_struct_member_offset('vcpu_guest_context', 'user_regs') - self.reg_size = tree.get_struct_size('cpu_user_regs') - self.ctrlreg_offset = tree.calc_struct_member_offset('vcpu_guest_context', 'ctrlreg') - self.ctrlreg_size = struct.calcsize('L') - self.max_ctrlreg = 7 # 0-7 - - if context: - self.context = context - else: - self.context = "\x00" * self.ctxt_size - - self.ctxtf = StringIO.StringIO(self.context) - - def __str__(self): - return self.ctxtf.getvalue() - - def clone(self): - return XenContext(self.tree, self.ctxtf.getvalue()) - - def set_register(self, reg): - regstr = reg.asXen() - - self.ctxtf.seek(self.reg_offset) - self.ctxtf.write(regstr) - - def get_register(self, reg): - self.ctxtf.seek(self.reg_offset) - regstr = self.ctxtf.read(self.reg_size) - reg = Register.Register() - reg.fromXen(regstr) - return reg - - def set_ctrlreg(self, num, val): - if num > self.max_ctrlreg or num < 0: - raise IndexError - - regstr = struct.pack('L', val) - self.ctxtf.seek(self.ctrlreg_offset + self.ctrlreg_size * num) - self.ctxtf.write(regstr) - - def get_ctrlreg(self, num): - if num > self.max_ctrlreg or num < 0: - raise IndexError - - self.ctxtf.seek(self.ctrlreg_offset + self.ctrlreg_size * num) - regstr = self.ctxtf.read(regstr, self.ctrlreg_size) - return struct.unpack('L', regstr) - class XenCore(CoreDump.CoreDump): '''xen dump file abstract class''' @@ -100,10 +48,6 @@ return self.pageoffsetmap.keys() ## pageoffsetmap maintainer - def _append_pageoffsetmap(self, index, mfn): - '''append a new page into pageoffsetmap''' - self.pageoffsetmap[mfn] = self.xch_pages_offset + index * self.arch.page_size - def _build_pageoffsetmap(self): '''build self.pageoffsetmap from self.pages''' self.pageoffsetmap = {} @@ -111,8 +55,21 @@ if not self.pages: # no pages return - for i, mfn in enumerate(self.pages): - self._append_pageoffsetmap(i, mfn) + for index, mfn in enumerate(self.pages): + self.pageoffsetmap[mfn] = (self.xch_pages_offset + + index * self.arch.page_size) + + def _update_offsets(self): + '''recalc header offset data.''' + + self.xch_ctxt_offset = struct.calcsize(HEADER_FORMAT) + self.xch_index_offset = (struct.calcsize(HEADER_FORMAT) + + len(''.join([str(ctxt) for ctxt in self.ctxts]))) + self.xch_pages_offset = self.arch.round_pgup( + self.xch_index_offset + + self.xch_nr_pages * struct.calcsize(self.arch.pt_format)) + + self._build_pageoffsetmap() def clear_pages(self): '''delete all pages''' @@ -120,6 +77,41 @@ self.pageoffsetmap = {} + def set_context(self, ctxts): + '''set CPU(s) num and contexts''' + self.xch_nr_vcpus = len(ctxts) + self.ctxts = ctxts + + self._update_offsets() + + def set_registers(self, regs): + '''overwrite user registers on context''' + + for i, reg in enumerate(regs): + self.ctxts[i].set_register(reg) + + def set_ctrlreg(self, num, val): + '''set all ctrlreg[num] as val''' + # XXXX it works on uni processor only + # walkaround to generate Xen core header.. + for ctxt in self.ctxts: + ctxt.set_ctrlreg(num, val) + + def set_m2v(self, m2v): + # not used in Xen core format. + pass + + def set_p2m(self, p2m): + '''set pfn2mfn for this dump image''' + # xen core format doesn't use p2m mapping, + # it is processed by gdbserver-xen with cr3 value + self.pages = p2m.values() + self.pages.sort() + self.xch_nr_pages = len(self.pages) + + self._update_offsets() + + class XenCoreReader(XenCore): ''' @@ -164,64 +156,9 @@ XenCore.__init__(self, corefilename, arch) self.file = file(corefilename, 'r+') - def set_context(self, nr_vcpus, ctxts): - '''set CPU(s) num and contexts''' - self.xch_nr_vcpus = nr_vcpus - self.ctxts = ctxts - self.update_offsets() - - def set_registers(self, regs): - '''set user registers''' - - for i, reg in enumerate(regs): - self.ctxts[i].set_register(reg) - - def set_ctrlreg(self, num, val): - '''set all ctrlreg[num] as val''' - for ctxt in self.ctxts: - ctxt.set_ctrlreg(num, val) - - def set_nr_pages(self, nr_pages): - '''set number of pages''' - - self.xch_nr_pages = nr_pages - self.update_offsets() - - def update_offsets(self): - '''recalc header offset data.''' - - self.xch_ctxt_offset = struct.calcsize(HEADER_FORMAT) - self.xch_index_offset = (struct.calcsize(HEADER_FORMAT) + len(''.join([str(ctxt) for ctxt in self.ctxts]))) - self.xch_pages_offset = self.arch.round_pgup( - self.xch_index_offset + self.xch_nr_pages * struct.calcsize('L')) - self._build_pageoffsetmap() - - def fetch_pages(self, other, pages): - '''copy pages from other dump''' - count = 0 - pagebuf = {} - for mfn in pages: - pagebuf[mfn] = other.read_page(mfn) - count += 1 - if count % 1024 == 0 or count == len(pages): - for mfn in pagebuf: - self.write_page(mfn, pagebuf[mfn]) # write mfn - pagebuf = {} - - def write_page(self, mfn, data): - '''put a page into index and write data into file. header is not updated by this.''' - # index update - if mfn not in self.pages: - self.pages.append(mfn) - self._append_pageoffsetmap(len(self.pages)-1, mfn) - - # data on disk - self.file.seek(self.pageoffsetmap[mfn]) - self.file.write(data) - - def writeheader(self): + def write_header(self): '''write header''' - self.update_offsets() + self._update_offsets() header = struct.pack( HEADER_FORMAT, @@ -235,8 +172,29 @@ self.file.write(''.join([str(ctxt) for ctxt in self.ctxts])) self.file.seek(self.xch_index_offset) - pageindex = array.array('L') + pageindex = array.array(self.arch.pt_format) pageindex.fromlist(self.pages) self.file.write(pageindex.tostring()) + def fetch_pages(self, other): + '''copy pages from other dump''' + count = 0 + pagebuf = {} + pagelist = self.pages[:] + pagelist.sort() + for mfn in pagelist: + pagebuf[mfn] = other.read_page(mfn) + count += 1 + if count % 1024 == 0 or count == len(pagelist): + for mfn in pagebuf: + self.write_page(mfn, pagebuf[mfn]) # write mfn + pagebuf = {} + + def write_page(self, mfn, data): + '''put a page data into file. header is not updated by this.''' + if mfn in self.pageoffsetmap: + # data on disk + self.file.seek(self.pageoffsetmap[mfn]) + self.file.write(data) + Binary files dumpread.O/XenCore.pyc and dumpread/XenCore.pyc differ Binary files dumpread.O/debug_info.pyc and dumpread/debug_info.pyc differ diff -u -N dumpread.O/dom0cut_x86_32.py dumpread/dom0cut_x86_32.py --- dumpread.O/dom0cut_x86_32.py 2006-05-10 15:15:12.000000000 +0900 +++ dumpread/dom0cut_x86_32.py 2006-05-19 17:48:01.000000000 +0900 @@ -16,8 +16,8 @@ typemap = { - 'xen': XenCore.XenCoreReader, - 'elf': ElfCore.ElfCoreReader, + 'xen': XenCore.XenCoreWriter, + 'elf': ElfCore.ElfCoreWriter, } @@ -107,7 +107,6 @@ self.max_pfn = self.get_max_pfn() self.pfn2mfn = self.get_p2m() - self.nr_pages = len(self.pfn2mfn) def get_max_pfn(self): '''return max page frame number''' @@ -129,11 +128,6 @@ pfn2mfn[pfn] = mfn return pfn2mfn - def need_pages(self): - '''return need pages by list of mfn''' - pages = self.pfn2mfn.values() - pages.sort() - return pages def dom0extract(outdump, dump, xensyms, vmlinux): @@ -152,18 +146,28 @@ dom0img = DomainImage(dump, vmlinux, dom0_pt) # set header info - outdump.set_context(len(dom0context), dom0context) + outdump.set_context(dom0context) + if isinstance(outdump, XenCore.XenCoreWriter): + dom0regs = dump.get_registers() + outdump.set_registers(dom0regs) + outdump.set_ctrlreg(3, dom0img.pt.mfn * outdump.arch.page_size) - dom0regs = dump.get_registers() - outdump.set_registers(dom0regs) - outdump.set_ctrlreg(3, dom0img.pt.mfn * outdump.arch.page_size) - - outdump.set_nr_pages(dom0img.nr_pages) - pages = dom0img.need_pages() - outdump.fetch_pages(dump, pages) + if isinstance(outdump, ElfCore.ElfCoreWriter): + outdump.set_note(dump.get_note()) + + + p2m = dom0img.get_p2m() + outdump.set_p2m(p2m) + + m2v = dom0_pt.get_machine_to_virt() + outdump.set_m2v(m2v) # write header - outdump.writeheader() + outdump.write_header() + + # copy pages + outdump.fetch_pages(dump) + def main(): @@ -175,7 +179,8 @@ oparser.add_option('-x', '--xensyms', dest='xensyms', default='xen-syms', type='string', help='xen binary with symbols') oparser.add_option('-v', '--vmlinux', dest='vmlinux', default='vmlinux', type='string', help='linux binary with symbols') oparser.add_option('-a', '--arch', dest='arch', type='string', default='x86_32', help="architecture (now 'x86_32' only)") - oparser.add_option("-t", "--type", dest="filetype", default="xen", type="string", help='dump file type("xen" or "elf")') + oparser.add_option("-t", "--type", dest="filetype", default="xen", type="string", help='output file type("xen" or "elf")') + oparser.add_option("-f", "--force", dest="force", default=False, action='store_true', help='overwrite output file') (options, args) = oparser.parse_args() @@ -194,16 +199,16 @@ return # filetype, file, arch - coretype = typemap[options.filetype] - dump = coretype(options.dumpname, options.arch) + dump = ElfCore.ElfCoreReader(options.dumpname, options.arch) - if os.path.exists(options.dom0dumpname): + if os.path.exists(options.dom0dumpname) and not (options.force): print options.dom0dumpname, 'already exists!' return else: file(options.dom0dumpname, 'w') # create blank file - dom0dump = XenCore.XenCoreWriter(options.dom0dumpname, options.arch) + outputFormat = typemap[options.filetype] + dom0dump = outputFormat(options.dom0dumpname, options.arch) dom0extract(dom0dump, dump, options.xensyms, options.vmlinux) if __name__ == '__main__':