mirror of
https://github.com/izzy2lost/xemu.git
synced 2026-07-06 00:20:22 -07:00
Merge QEMU v9.2.1
This commit is contained in:
+103
-39
@@ -65,6 +65,9 @@ class MigrationFile(object):
|
||||
def tell(self):
|
||||
return self.file.tell()
|
||||
|
||||
def seek(self, a, b):
|
||||
return self.file.seek(a, b)
|
||||
|
||||
# The VMSD description is at the end of the file, after EOF. Look for
|
||||
# the last NULL byte, then for the beginning brace of JSON.
|
||||
def read_migration_debug_json(self):
|
||||
@@ -272,11 +275,24 @@ class S390StorageAttributes(object):
|
||||
self.section_key = section_key
|
||||
|
||||
def read(self):
|
||||
pos = 0
|
||||
while True:
|
||||
addr_flags = self.file.read64()
|
||||
flags = addr_flags & 0xfff
|
||||
if (flags & (self.STATTR_FLAG_DONE | self.STATTR_FLAG_EOS)):
|
||||
|
||||
if flags & self.STATTR_FLAG_DONE:
|
||||
pos = self.file.tell()
|
||||
continue
|
||||
elif flags & self.STATTR_FLAG_EOS:
|
||||
return
|
||||
else:
|
||||
# No EOS came after DONE, that's OK, but rewind the
|
||||
# stream because this is not our data.
|
||||
if pos:
|
||||
self.file.seek(pos, os.SEEK_SET)
|
||||
return
|
||||
raise Exception("Unknown flags %x", flags)
|
||||
|
||||
if (flags & self.STATTR_FLAG_ERROR):
|
||||
raise Exception("Error in migration stream")
|
||||
count = self.file.read64()
|
||||
@@ -401,6 +417,28 @@ class VMSDFieldIntLE(VMSDFieldInt):
|
||||
super(VMSDFieldIntLE, self).__init__(desc, file)
|
||||
self.dtype = '<i%d' % self.size
|
||||
|
||||
class VMSDFieldNull(VMSDFieldGeneric):
|
||||
NULL_PTR_MARKER = b'0'
|
||||
|
||||
def __init__(self, desc, file):
|
||||
super(VMSDFieldNull, self).__init__(desc, file)
|
||||
|
||||
def __repr__(self):
|
||||
# A NULL pointer is encoded in the stream as a '0' to
|
||||
# disambiguate from a mere 0x0 value and avoid consumers
|
||||
# trying to follow the NULL pointer. Displaying '0', 0x30 or
|
||||
# 0x0 when analyzing the JSON debug stream could become
|
||||
# confusing, so use an explicit term instead.
|
||||
return "nullptr"
|
||||
|
||||
def __str__(self):
|
||||
return self.__repr__()
|
||||
|
||||
def read(self):
|
||||
super(VMSDFieldNull, self).read()
|
||||
assert(self.data == self.NULL_PTR_MARKER)
|
||||
return self.data
|
||||
|
||||
class VMSDFieldBool(VMSDFieldGeneric):
|
||||
def __init__(self, desc, file):
|
||||
super(VMSDFieldBool, self).__init__(desc, file)
|
||||
@@ -429,6 +467,9 @@ class VMSDFieldStruct(VMSDFieldGeneric):
|
||||
super(VMSDFieldStruct, self).__init__(desc, file)
|
||||
self.data = collections.OrderedDict()
|
||||
|
||||
if 'fields' not in self.desc['struct']:
|
||||
raise Exception("No fields in struct. VMSD:\n%s" % self.desc)
|
||||
|
||||
# When we see compressed array elements, unfold them here
|
||||
new_fields = []
|
||||
for field in self.desc['struct']['fields']:
|
||||
@@ -461,15 +502,25 @@ class VMSDFieldStruct(VMSDFieldGeneric):
|
||||
field['data'] = reader(field, self.file)
|
||||
field['data'].read()
|
||||
|
||||
if 'index' in field:
|
||||
if field['name'] not in self.data:
|
||||
self.data[field['name']] = []
|
||||
a = self.data[field['name']]
|
||||
if len(a) != int(field['index']):
|
||||
raise Exception("internal index of data field unmatched (%d/%d)" % (len(a), int(field['index'])))
|
||||
a.append(field['data'])
|
||||
fname = field['name']
|
||||
fdata = field['data']
|
||||
|
||||
# The field could be:
|
||||
# i) a single data entry, e.g. uint64
|
||||
# ii) an array, indicated by it containing the 'index' key
|
||||
#
|
||||
# However, the overall data after parsing the whole
|
||||
# stream, could be a mix of arrays and single data fields,
|
||||
# all sharing the same field name due to how QEMU breaks
|
||||
# up arrays with NULL pointers into multiple compressed
|
||||
# array segments.
|
||||
if fname not in self.data:
|
||||
self.data[fname] = fdata
|
||||
elif type(self.data[fname]) == list:
|
||||
self.data[fname].append(fdata)
|
||||
else:
|
||||
self.data[field['name']] = field['data']
|
||||
tmp = self.data[fname]
|
||||
self.data[fname] = [tmp, fdata]
|
||||
|
||||
if 'subsections' in self.desc['struct']:
|
||||
for subsection in self.desc['struct']['subsections']:
|
||||
@@ -477,6 +528,10 @@ class VMSDFieldStruct(VMSDFieldGeneric):
|
||||
raise Exception("Subsection %s not found at offset %x" % ( subsection['vmsd_name'], self.file.tell()))
|
||||
name = self.file.readstr()
|
||||
version_id = self.file.read32()
|
||||
|
||||
if not subsection:
|
||||
raise Exception("Empty description for subsection: %s" % name)
|
||||
|
||||
self.data[name] = VMSDSection(self.file, version_id, subsection, (name, 0))
|
||||
self.data[name].read()
|
||||
|
||||
@@ -535,6 +590,7 @@ vmsd_field_readers = {
|
||||
"bitmap" : VMSDFieldGeneric,
|
||||
"struct" : VMSDFieldStruct,
|
||||
"capability": VMSDFieldCap,
|
||||
"nullptr": VMSDFieldNull,
|
||||
"unknown" : VMSDFieldGeneric,
|
||||
}
|
||||
|
||||
@@ -574,10 +630,13 @@ class MigrationDump(object):
|
||||
}
|
||||
self.filename = filename
|
||||
self.vmsd_desc = None
|
||||
self.vmsd_json = ""
|
||||
|
||||
def read(self, desc_only = False, dump_memory = False, write_memory = False):
|
||||
def read(self, desc_only = False, dump_memory = False,
|
||||
write_memory = False):
|
||||
# Read in the whole file
|
||||
file = MigrationFile(self.filename)
|
||||
self.vmsd_json = file.read_migration_debug_json()
|
||||
|
||||
# File magic
|
||||
data = file.read32()
|
||||
@@ -635,9 +694,11 @@ class MigrationDump(object):
|
||||
file.close()
|
||||
|
||||
def load_vmsd_json(self, file):
|
||||
vmsd_json = file.read_migration_debug_json()
|
||||
self.vmsd_desc = json.loads(vmsd_json, object_pairs_hook=collections.OrderedDict)
|
||||
self.vmsd_desc = json.loads(self.vmsd_json,
|
||||
object_pairs_hook=collections.OrderedDict)
|
||||
for device in self.vmsd_desc['devices']:
|
||||
if 'fields' not in device:
|
||||
raise Exception("vmstate for device %s has no fields" % device['name'])
|
||||
key = (device['name'], device['instance_id'])
|
||||
value = ( VMSDSection, device )
|
||||
self.section_classes[key] = value
|
||||
@@ -666,31 +727,34 @@ args = parser.parse_args()
|
||||
|
||||
jsonenc = JSONEncoder(indent=4, separators=(',', ': '))
|
||||
|
||||
if args.extract:
|
||||
dump = MigrationDump(args.file)
|
||||
|
||||
dump.read(desc_only = True)
|
||||
print("desc.json")
|
||||
f = open("desc.json", "w")
|
||||
f.truncate()
|
||||
f.write(jsonenc.encode(dump.vmsd_desc))
|
||||
f.close()
|
||||
|
||||
dump.read(write_memory = True)
|
||||
dict = dump.getDict()
|
||||
print("state.json")
|
||||
f = open("state.json", "w")
|
||||
f.truncate()
|
||||
f.write(jsonenc.encode(dict))
|
||||
f.close()
|
||||
elif args.dump == "state":
|
||||
dump = MigrationDump(args.file)
|
||||
dump.read(dump_memory = args.memory)
|
||||
dict = dump.getDict()
|
||||
print(jsonenc.encode(dict))
|
||||
elif args.dump == "desc":
|
||||
dump = MigrationDump(args.file)
|
||||
dump.read(desc_only = True)
|
||||
print(jsonenc.encode(dump.vmsd_desc))
|
||||
else:
|
||||
if not any([args.extract, args.dump == "state", args.dump == "desc"]):
|
||||
raise Exception("Please specify either -x, -d state or -d desc")
|
||||
|
||||
try:
|
||||
dump = MigrationDump(args.file)
|
||||
|
||||
if args.extract:
|
||||
dump.read(desc_only = True)
|
||||
|
||||
print("desc.json")
|
||||
f = open("desc.json", "w")
|
||||
f.truncate()
|
||||
f.write(jsonenc.encode(dump.vmsd_desc))
|
||||
f.close()
|
||||
|
||||
dump.read(write_memory = True)
|
||||
dict = dump.getDict()
|
||||
print("state.json")
|
||||
f = open("state.json", "w")
|
||||
f.truncate()
|
||||
f.write(jsonenc.encode(dict))
|
||||
f.close()
|
||||
elif args.dump == "state":
|
||||
dump.read(dump_memory = args.memory)
|
||||
dict = dump.getDict()
|
||||
print(jsonenc.encode(dict))
|
||||
elif args.dump == "desc":
|
||||
dump.read(desc_only = True)
|
||||
print(jsonenc.encode(dump.vmsd_desc))
|
||||
except Exception:
|
||||
raise Exception("Full JSON dump:\n%s", dump.vmsd_json)
|
||||
|
||||
+30
-1
@@ -10,6 +10,27 @@
|
||||
# This work is licensed under the terms of the GNU GPLv2 or later.
|
||||
# See the COPYING file in the top-level directory.
|
||||
|
||||
function subproject_dir() {
|
||||
if test ! -f "subprojects/$1.wrap"; then
|
||||
error "scripts/archive-source.sh should only process wrap subprojects"
|
||||
fi
|
||||
|
||||
# Print the directory key of the wrap file, defaulting to the
|
||||
# subproject name. The wrap file is in ini format and should
|
||||
# have a single section only. There should be only one section
|
||||
# named "[wrap-*]", which helps keeping the script simple.
|
||||
local dir
|
||||
dir=$(sed -n \
|
||||
-e '/^\[wrap-[a-z][a-z]*\]$/,/^\[/{' \
|
||||
-e '/^directory *= */!b' \
|
||||
-e 's///p' \
|
||||
-e 'q' \
|
||||
-e '}' \
|
||||
"subprojects/$1.wrap")
|
||||
|
||||
echo "${dir:-$1}"
|
||||
}
|
||||
|
||||
if [ $# -ne 2 ]; then
|
||||
echo "Usage:"
|
||||
echo " $0 gitrepo version"
|
||||
@@ -51,5 +72,13 @@ meson subprojects download $SUBPROJECTS
|
||||
CryptoPkg/Library/OpensslLib/openssl \
|
||||
MdeModulePkg/Library/BrotliCustomDecompressLib/brotli)
|
||||
popd
|
||||
tar --exclude=.git -cJf ${destination}.tar.xz ${destination}
|
||||
|
||||
exclude=(--exclude=.git)
|
||||
# include the tarballs in subprojects/packagecache but not their expansion
|
||||
for sp in $SUBPROJECTS; do
|
||||
if grep -xqF "[wrap-file]" subprojects/$sp.wrap; then
|
||||
exclude+=(--exclude=subprojects/"$(subproject_dir $sp)")
|
||||
fi
|
||||
done
|
||||
tar "${exclude[@]}" -cJf ${destination}.tar.xz ${destination}
|
||||
rm -rf ${destination}
|
||||
|
||||
Reference in New Issue
Block a user