I have modified the script to support the dump of the images to the file. Earlier, everything was saved to the memory and later the processing was taking place. Now, I have tried to solve that issue with only using the required memory.
After discussion with David, I have tried to select a base 2 matrix dimension like 512 X 512 or 1024 X 512 etc for the dumping of the bitmap. But, I am still supporting the default square root based method of dimension selection. Signed-off-by: Sanidhya Kashyap <sanidhya.ii...@gmail.com> --- scripts/extract-bitmap.py | 213 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 213 insertions(+) create mode 100755 scripts/extract-bitmap.py diff --git a/scripts/extract-bitmap.py b/scripts/extract-bitmap.py new file mode 100755 index 0000000..9a5a481 --- /dev/null +++ b/scripts/extract-bitmap.py @@ -0,0 +1,213 @@ +#!/usr/bin/python +# This python script helps in extracting the dirty bitmap present +# in the file after executing the log-dirty-bitmap command either +# from the qmp or hmp interface. This file only processes binary +# file obtained via command. +# +# Copyright (C) 2014 Sanidhya Kashyap <sanidhya.ii...@gmail.com> +# +# Authors: +# Sanidhya Kashyap +# +# +# This work is licensed under the terms of the GNU GPL, version 2 or later. + +import struct +import argparse +from functools import partial +from math import sqrt +from numpy import array +from pylab import figure, imshow, savefig, gray, xlim, ylim +from os import path, makedirs + +long_bytes = 8 +byte_size = 8 +int_bytes = 4 +block_list = [] +total_blocks = 0 + +def get_unsigned_long_integer(value): + return struct.unpack('<Q', value)[0] + +def get_long_integer(value): + return struct.unpack('<q', value)[0] + +def get_integer(value): + return struct.unpack('<i', value)[0] + +def get_char(value): + return struct.unpack('<c', value)[0] + +def get_string(value, length): + name = struct.unpack('<'+str(length)+'s', value)[0] + for i in range(len(name)): + if name[i] == '\x00': + return name[:i] + +def dec2bin(decimal): + bin_value = bin(decimal)[2:] + if len(bin_value) < long_bytes * byte_size: + add_zeroes = long_bytes * byte_size - len(bin_value) + for i in range(add_zeroes): + bin_value += "0" + return str(bin_value) + +def get_bitmap_length(ram_bitmap_pages): + bitmap_length = ram_bitmap_pages / (long_bytes * byte_size) + if ram_bitmap_pages % (long_bytes * byte_size) != 0: + bitmap_length += 1 + return bitmap_length + +def get_block_info(): + print "Select any one of the following:" + for i in range(len(block_list)): + print str(i) + " " + block_list[i]['name'] + return int(raw_input('Enter the number: ')) + +def get_matrix(all_digits, y, x): + v = [] + xlim(xmin = 0, xmax = x) + ylim(ymin = 0, ymax = y) + for i in range(y): + v1 = [] + for j in range(x): + v1.append(int(all_digits[i * x + j])) + v.append(v1) + return v + +def get_matrix_base2(all_digits): + l = len(all_digits) + sqrtvalue = int(sqrt(l)) + x = 2 ** (sqrtvalue.bit_length() - 1) + y = x * 2 + if (x * y - l < 0): + x = y + for i in range(x * y - l): + all_digits += "0" + + return get_matrix(all_digits, x, y); + +def get_matrix_sqrt(all_digits): + l = len(all_digits) + sqrtvalue = int(sqrt(l)) + for i in range(sqrtvalue * (sqrtvalue + 1) - l): + all_digits += "0" + + if sqrtvalue * sqrtvalue == l: + return get_matrix(all_digits, sqrtvalue, sqrtvalue) + else: + return get_matrix(all_digits, sqrtvalue, sqrtvalue + 1) + +def dump_ram_block_info(infile): + total_blocks = get_integer(infile.read(int_bytes)) + for i in range(total_blocks): + block_name_length = get_integer(infile.read(int_bytes)) + block_name = get_string(infile.read(block_name_length), block_name_length) + block_offset = get_unsigned_long_integer(infile.read(long_bytes)) + block_length = get_unsigned_long_integer(infile.read(long_bytes)) + block_list.append(dict(name=block_name, offset=block_offset, length=block_length)) + +def generate_image(all_digits, num, debug, dir, base): + v = [] + + if base is False: + v = get_matrix_sqrt(all_digits) + else: + v = get_matrix_base2(all_digits) + + im_array = array(v) + figure(num) + imshow(im_array, cmap=gray()) + + filename=dir + "/" + "out_" + str(num) + ".png" + del v + savefig(filename) + if debug is True: + print 'file ' + filename + ' dumped' + + +def dump_bitmap(args): + marker = 'M' + count = 0 + value = ' ' + block_offset = 0 + block_length = 0 + block_num = 0 + current_ram_bitmap_pages = 0 + prev_ram_bitmap_pages = 0 + infile = open(format(args.infile), 'rb') + debug = args.debug + dump_all = args.dump_all + dir = args.dir + base = args.base + + if not path.exists(dir): + makedirs(dir) + + while True: + if len(value) == 0 or marker != 'M': + print "issue with the dump" + return + bitmap_page_raw_value = infile.read(long_bytes) + if not bitmap_page_raw_value: + break + current_ram_bitmap_pages = get_long_integer(bitmap_page_raw_value) + if current_ram_bitmap_pages != prev_ram_bitmap_pages: + prev_ram_bitmap_pages = current_ram_bitmap_pages + dump_ram_block_info(infile) + # asking what should be printed + if dump_all is False: + if count == 0: + block_num = get_block_info() + if debug is True: + print block_list[block_num]['name'] + ' selected' + else: + x = block_num + y = len(block_list) / total_blocks + block_num = total_blocks * (y-1) + x + block_offset = block_list[block_num]['offset'] + block_length = block_list[block_num]['length'] + if debug is True: + print 'total ram bitmap pages: ' + str(current_ram_bitmap_pages) + print block_list[block_num]['name'] + ' offset: ' + str(block_offset) + print block_list[block_num]['name'] + ' length: ' + str(block_length) + + bitmap_length = get_bitmap_length(current_ram_bitmap_pages) + bitmap_raw_value = infile.read(long_bytes * bitmap_length) + if not bitmap_raw_value: + break + + count+=1 + all_digits="" + for i in range(bitmap_length): + mark = i * long_bytes + all_digits += dec2bin(get_unsigned_long_integer(bitmap_raw_value[mark : mark + long_bytes])) + + if dump_all is False: + generate_image(all_digits[block_offset : block_offset + block_length], count, debug, dir, base) + else: + generate_image(all_digits, count, debug, dir, base) + value = infile.read(1) + marker = get_char(value) + infile.close() + +def main(): + extracter = argparse.ArgumentParser(description='Extract dirty bitmap from binary file.') + extracter.add_argument('-f', '--file', dest='infile', + help='Input file to extract the bitmap', metavar='FILE') + extracter.add_argument('-a', '--all', action='store_true', dest='dump_all', default=False, + help='Use all memory blocks for the figure') + extracter.add_argument('-d', '--debug', action='store_true', dest='debug', default=False, + help='print the debug info') + extracter.add_argument('-dir', dest='dir', default='.', + help='directory to store the image files') + extracter.add_argument('-b', '--base2', dest='base', action='store_true', default=False, + help='dump the bitmap array in powers of 2') + + args = extracter.parse_args() + print 'The filename is {}'.format(args.infile) + + dump_bitmap(args) + +if __name__ == '__main__': + main() -- 1.9.1