diff -u -N dumpread.O/Arch.py dumpread/Arch.py --- dumpread.O/Arch.py 2006-04-24 10:20:00.000000000 +0900 +++ dumpread/Arch.py 2006-05-10 15:15:12.000000000 +0900 @@ -1,11 +1,12 @@ class Arch: - def __init__(self, name, page_shift, pt_format): + def __init__(self, name, page_shift=0, pt_format='', max_vcpu=0): 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 def maddr_to_mfn(self, maddr): '''return mfn from maddr''' @@ -25,9 +26,11 @@ -x86_32 = Arch('x86_32', 12, 'L') -x86_64 = Arch('x86_64', 12, 'Q') -ia64 = Arch('ia64', 14, 'Q') + + +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, diff -u -N dumpread.O/ElfCore.py dumpread/ElfCore.py --- dumpread.O/ElfCore.py 2006-04-24 10:20:00.000000000 +0900 +++ dumpread/ElfCore.py 2006-05-10 15:15:12.000000000 +0900 @@ -1,6 +1,7 @@ import os import re import CoreDump +import Register command = 'LANG=C readelf -l %s' @@ -33,9 +34,10 @@ def __init__(self, corefilename, arch): CoreDump.CoreDump.__init__(self, corefilename, arch) self.sections = self._read_sections() + self.filename = corefilename self.file = file(corefilename, 'r') if len(self.sections) == 0: - raise ValueError, 'section not found in ELF format' + raise ValueError, 'section isn\'t found' def _read_sections(self): ''' @@ -90,9 +92,16 @@ pages = [] for sec in self.sections: - start_mfn = self.arch.maddr_to_mfn(sec.maddr) - end_mfn = self.arch.maddr_to_mfn(sec.maddr + sec.memsize) - pages.append(range(start_mfn, end_mfn+1)) + 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] diff -u -N dumpread.O/PageTable.py dumpread/PageTable.py --- dumpread.O/PageTable.py 2006-04-24 10:20:00.000000000 +0900 +++ dumpread/PageTable.py 2006-05-10 15:15:12.000000000 +0900 @@ -20,8 +20,8 @@ '''create new pagetable from addressed page mfn''' self.dump = dump # CoreDump obj self.arch = dump.arch - self.pt = mfn # mfn of l1 page table - self.l1 = self.read_l1(self.pt) + self.mfn = mfn # mfn of l1 page table + self.l1 = self.read_l1(self.mfn) if self.arch.name != 'x86_32': raise NotImplementedError # x86_32 only. diff -u -N dumpread.O/Register.py dumpread/Register.py --- dumpread.O/Register.py 1970-01-01 09:00:00.000000000 +0900 +++ dumpread/Register.py 2006-05-10 15:15:12.000000000 +0900 @@ -0,0 +1,211 @@ +#!/usr/bin/env python + +'''Convert register information between ELF and Xen ''' +import struct +import re + +class Register(dict): + '''Register abstruction class''' + + def __init__(self): + self.elffmt = '' + self.elfregs = () + self.xenfmt = '' + self.xenregs = () + + def __repr__(self): + ret = ['{'] + keys = self.keys() + keys.sort() + for key in keys: + ret.append(key) + ret.append(': %08x, ' % self[key]) + ret.append('}') + return ''.join(ret) + + def fromString(self, fmt, names, regstring): + '''convert from string''' + + regs = struct.unpack(fmt, regstring) + for key, val in zip(names, regs): + self[key] = val + return self + + def fromElf(self, regstring): + '''convert from ELF context format''' + + return self.fromString(self.elffmt, self.elfregs, regstring) + + def fromXen(self, regstring): + '''convert from Xen context format''' + + return self.fromString(self.xenfmt, self.xenregs, regstring) + + def asString(self, fmt, names): + '''convert to string''' + + regs = [] + for regname in names: + if regname in self: + regs.append(self[regname]) + else: + regs.append(0) + return struct.pack(fmt, *regs) + + def asElf(self): + '''convert to ELF context format''' + + return self.asString(self.elffmt, self.elfregs) + + def asXen(self): + '''convert to Xen context format''' + + return self.asString(self.xenfmt, self.xenregs) + + + +class Register_x86_32(Register): + '''xs86_32 register info''' + + def __init__(self): + Register.__init__(self) + + # from: $(LINUX)/include/asm-i486/user.h + self.elffmt = 'LLLLLLLHHHHHHHHLLHHLLHH' + self.elfregs = ('ebx', 'ecx', 'edx', 'esi', 'edi', 'ebp', 'eax', + 'ds', '__ds', 'es', '__es', + 'fs', '__fs', 'gs', '__gs', + 'orig_eax', 'eip', + 'cs', '__cs', + 'eflags', 'esp', + 'ss', '__ss') + + # from: $(XEN)/xen/include/public/arch-x86_32.h + self.xenfmt = 'LLLLLLLHHLHBBLLHHHHHHHHHH' + self.xenregs = ( + 'ebx', 'ecx', 'edx', 'esi', 'edi', 'ebp', 'eax', + 'error_code', 'entry_vector', 'eip', 'cs', + 'saved_upcall_mask', '_pad0', + 'eflags', + 'esp', + 'ss', '_pad1', 'es', '_pad2', + 'ds', '_pad3', 'fs', '_pad4', + 'gs', '_pad5', + ) + + +class Register_x86_64(Register): + '''xs86_64 register info''' + # XXX not used or tested yet + + def __init__(self): + Register.__init__(self) + + # from: $(LINUX)/include/asm-x86_64/user.h + self.elffmt = 'QQQQQQQQQQQQQQQQQQQQQQQQQQQ' + self.elfregs = ( + 'r15', 'r14', 'r13', 'r12', + 'rbp', 'rbx', 'r11', 'r10', + 'r9', 'r8', 'rax', 'rcx', + 'rdx', 'rsi', 'rdi', 'orig_rax', + 'rip', 'cs', 'eflags', + 'rsp', 'ss', + 'fs_base', 'gs_base', + 'ds', 'es', 'fs', 'gs') + + # from: $(XEN)/xen/include/public/arch-x86_32.h + self.xenfmt = 'QQQQQQQQQQQQQQQQQQQLLQHHBBBBQQHHHHHHHHHHHHHHHHHHHH' + self.xenregs = ( + 'r15', 'r14', 'r13', 'r12', + 'rbp', 'rbx', 'r11', 'r10', + 'r9', 'r8', 'rax', 'rcx', + 'rdx', 'rsi', 'rdi', + 'error_code', + 'entry_vector', + 'rip', + 'cs', '_pad0', + 'saved_upcall_mask', '_pad10', '_pad11', '_pad12', + 'rflags', + 'rsp', + 'ss', '_pad20', '_pad21', '_pad22', + 'es', '_pad30', '_pad31', '_pad32', + 'ds', '_pad40', '_pad41', '_pad42', + 'fs', '_pad50', '_pad51', '_pad52', + 'gs', '_pad60', '_pad61', '_pad62', + ) + +class Register_ia64(Register): + '''IA64 register info''' + + # XXX not used or tested yet + def __init__(self): + Register.__init__(self) + + # from: $(LINUX)/include/asm-ia64/ptrace.h + self.elffmt = '44Q6Q' + self.elfregs = ( + 'b6', 'b7', 'ar_csd', 'ar_ssd', + 'r8', 'r9', 'r10', 'r11', + 'cr_ipsr', 'cr_iip', 'cr_ifs', + 'ar_unat', 'ar_pfs', 'ar_rsc', 'ar_rnat', 'ar_bspstore', + 'pr', 'b0', 'loadrs', + 'r1', 'r12', + 'r13', 'ar_fpsr', 'r15', 'r14', 'r2', 'r3', 'r16', 'r17', 'r18', 'r19', 'r20', 'r21', 'r22', 'r23', + 'r24', 'r25', 'r26', 'r27', + 'r28', 'r29', 'r30', 'r31', 'ar_ccv', + 'f6a', 'f6b', 'f7a', 'f7b', 'f8a', 'f8b', 'f9a', 'f9b', 'f10a', 'f10b', 'f11a', 'f11b', + ) + + # from: $(XEN)/xen/include/public/arch-ia64.h + self.xenfmt = '44Q6Q6Q' + self.xenregs = self.elfregs + ( + 'r4', 'r5', 'r6', 'r7', 'eml_unat', 'rfi_pfs', + ) + + + +def read_objdump(text): + '''read objdump -s output and return binary string''' + + lines = text.split('\n') + dat = [] + for line in lines: + m = re.search('^ [0-9a-f]+ (([0-9a-f]{8} ){1,4})', line) + if m: + nums = m.group(1) + for m in re.finditer('[0-9a-f][0-9a-f]', nums): + if m: + c = chr(int(m.group(0), 16)) + dat.append(c) + return ''.join(dat) + + +arch = {'x86_32': Register_x86_32, + 'x86_64': Register_x86_64, + 'ia64': Register_ia64, + } + + + +if __name__ == '__main__': + import pprint + # 'objdump -s -j .reg dumpfile' output + instr = '''dump: file format elf32-i386 + +Contents of section .reg: + 0000 0022c8c0 00c0f4fb 01000000 00000000 .".............. + 0010 63000000 00000000 00000000 7b000000 c...........{... + 0020 7b000000 00000000 33000000 88ee5dc0 {.......3.....]. + 0030 5af213c0 61000000 46020000 d8fed8c0 Z...a...F....... + 0040 69000000 i... +''' + + regstring = read_objdump(instr) + reg = Register_x86_32() + reg.fromElf(regstring) + print 'ELF' + pprint.pprint(reg.asElf()) + print 'Xen' + pprint.pprint(reg.asXen()) + + pprint.pprint(reg) diff -u -N dumpread.O/XenCore.py dumpread/XenCore.py --- dumpread.O/XenCore.py 2006-04-24 10:20:00.000000000 +0900 +++ dumpread/XenCore.py 2006-05-10 15:15:12.000000000 +0900 @@ -4,7 +4,7 @@ and their abstruct class XenCore ''' - +import StringIO as StringIO import CoreDump import struct import array @@ -12,6 +12,60 @@ 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''' def __init__(self, corefilename, arch): @@ -24,7 +78,7 @@ self.xch_index_offset = None # pfn index offset self.xch_pages_offset = None # page data offset - self.ctxt = '' # CPU contexts(as string) + self.ctxts = [] # CPU contexts(as list of context obj) self.pages = [] # pfn index (as list of numbers) self.pageoffsetmap = {} # mfn -> file offset hash self.file = None # dump file itself @@ -93,7 +147,7 @@ raise ValueError, 'magic number is not valid in Xen core image format' self.file.seek(self.xch_ctxt_offset) - self.ctxt = self.file.read(self.xch_index_offset-self.xch_ctxt_offset) + self.ctxts = self.file.read(self.xch_index_offset-self.xch_ctxt_offset) pt_format = self.arch.pt_format * self.xch_nr_pages self.file.seek(self.xch_index_offset) @@ -110,12 +164,23 @@ XenCore.__init__(self, corefilename, arch) self.file = file(corefilename, 'r+') - def set_context(self, nr_vcpus, ctxt): + def set_context(self, nr_vcpus, ctxts): '''set CPU(s) num and contexts''' self.xch_nr_vcpus = nr_vcpus - self.ctxt = ''.join(ctxt) # XXX may be align problem + 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''' @@ -126,7 +191,7 @@ '''recalc header offset data.''' self.xch_ctxt_offset = struct.calcsize(HEADER_FORMAT) - self.xch_index_offset = (struct.calcsize(HEADER_FORMAT) + len("".join(self.ctxt))) + 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() @@ -167,7 +232,7 @@ self.file.write(header) self.file.seek(self.xch_ctxt_offset) - self.file.write(self.ctxt) + self.file.write(''.join([str(ctxt) for ctxt in self.ctxts])) self.file.seek(self.xch_index_offset) pageindex = array.array('L') diff -u -N dumpread.O/dom0cut_x86_32.py dumpread/dom0cut_x86_32.py --- dumpread.O/dom0cut_x86_32.py 2006-04-24 10:20:00.000000000 +0900 +++ dumpread/dom0cut_x86_32.py 2006-05-10 15:15:12.000000000 +0900 @@ -9,6 +9,7 @@ import debug_info import os.path import array +import struct from optparse import OptionParser import XenCore import ElfCore @@ -55,6 +56,7 @@ table_offset = self.tree.calc_struct_member_offset('vcpu', 'arch') table_offset += self.tree.calc_struct_member_offset('arch_vcpu', 'guest_table') + # domain->vcpu[0]->arch.guest_table domain_vcpu = self.dump.read_struct(self.pt.v2m(domainp + vcpu_offset), 'L')[0] domain_pt_mfn = self.dump.read_struct(self.pt.v2m(domain_vcpu + table_offset), 'L')[0] @@ -64,18 +66,26 @@ def get_domain_context(self, domainp): '''get domain context informations''' - - # XXX UniProcessor only!! need SMP + # domain->vcpu[0] vcpu_offset = self.tree.calc_struct_member_offset('domain', 'vcpu') # vcpu[0] - domain_vcpu = self.dump.read_struct(self.pt.v2m(domainp + vcpu_offset), 'L')[0] + domain_vcpus = [ + self.dump.read_struct(self.pt.v2m(domainp + + vcpu_offset + + struct.calcsize(self.dump.arch.pt_format) * i), + 'L')[0] + for i in range(self.dump.arch.max_vcpu)] # vcpu->arch.vcpu_guest_context - context_offset = self.tree.calc_struct_member_offset('vcpu', 'arch') - context_offset += self.tree.calc_struct_member_offset('arch_vcpu', 'guest_context') - context_size = self.tree.get_struct_size('vcpu_guest_context') + ctxt_offset = self.tree.calc_struct_member_offset('vcpu', 'arch') + ctxt_domain_offset = self.tree.calc_struct_member_offset('vcpu', 'domain') + ctxt_offset += self.tree.calc_struct_member_offset('arch_vcpu', 'guest_context') + ctxt_size = self.tree.get_struct_size('vcpu_guest_context') - return self.pt.load_data(domain_vcpu + context_offset, context_size) + ctxts = [XenCore.XenContext(self.tree, context=self.pt.load_data(vcpu + ctxt_offset, ctxt_size)) + for vcpu in domain_vcpus if vcpu != 0] + + return ctxts class DomainImage: @@ -133,18 +143,22 @@ xenimg = XenImage(dump, xensyms) - # get dom0 info + # get dom0 info from xen dom0p = xenimg.get_dom0p() dom0_pt = xenimg.get_domain_pt(dom0p) dom0context = xenimg.get_domain_context(dom0p) - # get dom0 image + # make dom0 image dom0img = DomainImage(dump, vmlinux, dom0_pt) - + # set header info - outdump.set_context(1, dom0context) - outdump.set_nr_pages(dom0img.nr_pages) + outdump.set_context(len(dom0context), dom0context) + 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) diff -u -N dumpread.O/dumpread.py dumpread/dumpread.py --- dumpread.O/dumpread.py 2006-04-24 10:20:00.000000000 +0900 +++ dumpread/dumpread.py 2006-05-10 15:15:12.000000000 +0900 @@ -17,9 +17,32 @@ 'elf': ElfCore.ElfCoreReader, } +def list2range(lst): + '''make iterator of ranges of contiguous numbers from a list of integers''' + + tmplst = lst[:] + tmplst.sort() + ranges = [] + start = tmplst[0] + + currentrange = [start, start + 1] + + for item in tmplst[1:]: + if currentrange[1] == item: + # contiguous + currentrange[1] += 1 + else: + # new range start + yield tuple(currentrange) + currentrange = [item, item + 1] + + # last range + yield tuple(currentrange) + def print_range(dump): '''print page frame numbers''' - sys.stdout.write(str(dump.pages)) + sys.stdout.write(str(list(list2range(dump.get_pagelist())))) + sys.stdout.write('\n') def print_page(dump, mfn): '''output raw page data'''