vieyahn2017 / pypy

python trial collections
1 stars 1 forks source link

2024.1.31 C结构体转换为python #25

Open vieyahn2017 opened 8 months ago

vieyahn2017 commented 8 months ago

C结构体转换为python工具

vieyahn2017 commented 8 months ago

最初来自

https://www.cnblogs.com/iclodq/p/9216763.html

@vieyahn2017 Owner Author vieyahn2017 commented on Feb 25, 2022 完整代码:https://gitee.com/iclodq/codes/e81qfpxw3dnkju594yi6b90 【已失效】】

vieyahn2017 commented 8 months ago
# python basecode.py -s source.c
# python basecode.py -c ext4_extent -h "10 00 00 00  01 00 02 00 1E 86 00 00"
# python basecode.py -c ext4_inode -r hexdump
# python basecode.py -c ext4_super_block -r vi
vieyahn2017 commented 8 months ago

basecode.py

#!/usr/bin/python
# -*- coding: utf-8 -*-

"""
基础类型参考BaseCode._type_map,实际由struct模块提供
嵌套自定义类型时,需要在子类中重新定义_type_map,并把BaseCode类的_type_map深拷贝到子类中
"""

import traceback
import inspect
import struct
import json
import re
import pprint
import getopt
import sys
import time
import copy

# main正常,需要这边import。因为存在交叉引用,因此这边打开的时候,basecode_structs本身执行会失败
from basecode_structs import *

GLOBAL_SIZE_DICT = {}
GLOBAL_SIZE_DICT["ext4_extent"] = 12
GLOBAL_SIZE_DICT["ext4_extent_idx"] = 12
GLOBAL_SIZE_DICT["ext4_extent_header"] = 12
GLOBAL_SIZE_DICT["ext4_inode"] = 160

def my_try_except_warpper(is_exit=False, err_msg=None):
    def _try_except_warpper(actual_do):
        def add_robust(*args, **keyargs):
            try:
                return actual_do(*args, **keyargs)
            except:
                print("Error: ", traceback.format_exc())
                print('Error execute: {}'.format(actual_do.__name__))
                if err_msg:
                    print(err_msg)
                if is_exit:
                    exit(1)
        return add_robust
    return _try_except_warpper

class EncodeError(Exception):
    def __init__(self, error_info='error'):
        super().__init__(self)
        self.error_info = error_info

    def __str__(self):
        return self.error_info

def debug_log(*obj):
    return # 调试时打开
    info = inspect.getframeinfo(inspect.currentframe().f_back, 0)

    print(*obj, '| ' + info.filename, info.function, info.lineno)

## not used
def has_class_attr(name, attr):
    """
    判断类中是否有类属性
    :param name: 类名
    :param attr: 类属性名
    :return:
    """
    token_list = eval('dir(' + name + ')')
    if attr in token_list:
        return True
    return False

class FieldType(object):
    # 把之前的tuple格式的field改成现在的FieldType,简直太清爽
    __slots__ = ('ctype', 'name', 'raw_field', 'name', 'reverse', 'length')

    def __init__(self, ctype, name, **kwargs):
        self.ctype = ctype
        self.name = name
        self.reverse = kwargs.get("reverse", False)
        self.length = int(kwargs.get("length", 1))
        self.raw_field = kwargs.get("raw_field", "")

    def __getitem__(self, key):
        if key == 0:
            return self.ctype
        elif key == 1:
            return self.name
        elif key == 2:
            return {"length": self.length, "reverse": self.reverse}

    def is_addtional(self):
        if self.length > 1:
            return True
        # if self.reverse:
        #     return True
        return False

    def get_field_length(self):
        return self.length

    def is_little_endian(self):
        return self.reverse

    def get_endian_char(self):
        # !网络序(同大端序),> (big-endian) , < (little-endian)
        return "<" if self.reverse else ">"

    def get_raw_field(self):
        # get这样调用函数,set直接赋值也可以通过kwargs传递
        return self.raw_field

    @staticmethod
    def get_little_endian_int16(int_num):
        hex_str_raw = hex(int_num)
        hex_str = hex_str_raw[2:].rjust(4, '0')
        hex_le = '0x' + hex_str[2:4] + hex_str[0:2]
        return int(hex_le, 16)

    @staticmethod
    def get_little_endian_int32(int_num):
        hex_str_raw = hex(int_num)
        hex_str = hex_str_raw[2:].rjust(8, '0')
        hex_le = '0x' + hex_str[6:8] + hex_str[4:6] + hex_str[2:4] + hex_str[0:2]
        return int(hex_le, 16)

    @staticmethod
    def get_little_endian_int64(int_num):
        hex_str_raw = hex(int_num)
        hex_str = hex_str_raw[2:].rjust(16, '0')
        hex_le = '0x' + hex_str[15:16] + hex_str[13:14]+ hex_str[11:12]+ hex_str[9:10] + hex_str[6:8] + hex_str[4:6] + hex_str[2:4] + hex_str[0:2]
        return int(hex_le, 16)

    @staticmethod
    def get_little_endian_hex(hex_str):
        pass

class BaseCode(object):

    _type_map_index_pack_tag = 1
    _type_map_index_pack_size = 2  # unused
    _type_map = {
        # C类型:(说明, 编码标志)
        'char': ('int', 'B'),
        'string': ('str', 'B'),
        'uint32_t': ('int', 'I'),
        'int32_t': ('int', 'i'),
        'int64_t': ('int', 'q'),
        'uint64_t': ('int', 'Q'),
        'uint16_t': ('short', 'H'),
        'int16_t': ('short', 'h'),
        'float': ('float', 'f'),
        'double': ('double', 'd'),
    }

    # 每种基础类型所占字节数
    _ctype_size_map = {'I': 4, 'B': 1, 'i': 4, 'b': 1, 'Q': 8, 'q': 8, 'f': 4, 'd': 8, 'h': 2, 'H': 2}

    _fields_index_ctype = 0
    _fields_index_value_name = 1
    _fields_index_array_length = 2 # 之前的第三个参数的数字length
    _fields_index_addtion_dict = 2 # 现在我改成字典 {"length":1, "reverse":True}  reverse=True,表示小端序

    # 用元组,扩展性很差,改成FieldType,为了兼容性良好,__init__构造的一致,实现了__getitem__,也支持[]读取
    _fields = [
        # (C类型, 变量名)
        FieldType('uint32_t', 'nUint'),
        FieldType('string', 'szString', **{"length": 20}),
        FieldType('int32_t', 'nInt3'),
        FieldType('uint32_t', 'nUintArray', **{"length": 4}),
    ]

    def __init__(self):
        """
        初始都置空
        """
        for one in self._fields:
            setattr(self, one[self._fields_index_value_name], None)

    def encode(self, nest=1):
        data = b''
        tmp = b''
        debug_log("&" * nest, self.__class__.__name__, "encode struct start :")
        for one in self._fields:
            debug_log("#" * nest, "encode one element:", one)
            ctype = one[self._fields_index_ctype]
            value = getattr(self, one[self._fields_index_value_name])

            if one.is_addtional():
                # _addtions = one[self._fields_index_addtion_dict]
                # if type(_addtions) != dict:
                #     print("param one[2] error: %s", _addtions)
                #     exit(1)
                endian_char = one.get_endian_char()
                length = one.get_field_length()
                if length > 1:
                    tmp = self._encode_array(ctype, value, length, endian_char)
                else: # 这子域的是复制外面那个else分支的代码,只是修改了endian_char
                    if ctype not in BaseCode._type_map:
                        tmp = value.encode(nest + 1)
                    else:
                        fmt = endian_char + self._type_map[ctype][self._type_map_index_pack_tag]
                        tmp = struct.pack(fmt, value)

            else:
                # 不是基础类型,即嵌套定义
                if ctype not in BaseCode._type_map:
                    tmp = value.encode(nest + 1)
                else:  # !网络序(同大端序),> (big-endian) , < (little-endian)
                    fmt = '!' + self._type_map[ctype][self._type_map_index_pack_tag]
                    tmp = struct.pack(fmt, value)
                    # debug_log(fmt, type(value), value)
            debug_log("#" * nest,"encode one element:", len(tmp), tmp)
            data += tmp
        debug_log("&" * nest, self.__class__.__name__, "encode end: len=", len(data), data)
        return data

    def _encode_array(self, ctype, value, max_length, endian_char="!"):
        """
        打包数组
        如果是字符串类型 需要做下特殊处理
        :param ctype:
        :param value:
        :param max_length:
        :param endian_char --  !网络序(同大端序),> (big-endian) , < (little-endian)
        :return:
        """
        debug_log('ctype:', ctype, type(ctype))
        if ctype == 'string':
            max_length -= 1  # 字符串长度需要减一
            value = bytes(value, encoding='utf8')
            #print(value)

        if len(value) > max_length:
            raise EncodeError('the length of  array is too long')

        # # # pack长度
        # data = struct.pack(endian_char + 'H', len(value))
        # debug_log("array count:", len(value), "value:", value, type(value))
        data = b""
        # pack数组内容
        for one in value:
            #debug_log("self._type_map[ctype][1]=", self._type_map[ctype][self._type_map_index_pack_tag], one)
            if ctype not in BaseCode._type_map:
                data += one.encode()
            else:
                data += struct.pack(endian_char + self._type_map[ctype][self._type_map_index_pack_tag], one)
        return data

    def decode(self, data, offset=0, nest=1):
        """
        :param data:
        :return:
        """
        debug_log("&" * nest, self.__class__.__name__, "decode struct start :")
        for one in self._fields:
            debug_log("#" * nest, "decode one element:", one)
            ctype = one[self._fields_index_ctype]

            if one.is_addtional():
                # _addtions = one[self._fields_index_addtion_dict]
                # if type(_addtions) != dict:
                #     print("param one[2] error: %s", _addtions)
                #     exit(1)
                endian_char = one.get_endian_char()
                length = one.get_field_length()
                if length > 1:
                    offset = self._decode_array(one, data, offset, nest)
                else: # 这子域的是复制外面那个else分支的代码,只是修改了endian_char
                    ctype_attr = self._type_map[ctype]
                    if ctype not in BaseCode._type_map:
                        value = eval(ctype + '()')
                        offset = value.decode(data, offset, nest)
                        setattr(self, one[self._fields_index_value_name], value)
                    else:
                        fmt = endian_char + ctype_attr[self._type_map_index_pack_tag]
                        value, = struct.unpack_from(fmt, data, offset)
                        offset += self._ctype_size_map[ctype_attr[self._type_map_index_pack_tag]]
                        debug_log(one, one[self._fields_index_value_name])
                        setattr(self, one[self._fields_index_value_name], value)

            else:
                ctype_attr = self._type_map[ctype]
                endian_char = one.get_endian_char()
                if ctype not in BaseCode._type_map:
                    value = eval(ctype + '()')
                    offset = value.decode(data, offset, nest)
                    setattr(self, one[self._fields_index_value_name], value)
                else:
                    fmt = endian_char + ctype_attr[self._type_map_index_pack_tag]
                    value, = struct.unpack_from(fmt, data, offset)
                    offset += self._ctype_size_map[ctype_attr[self._type_map_index_pack_tag]]
                    debug_log(one, one[self._fields_index_value_name])
                    setattr(self, one[self._fields_index_value_name], value)
            debug_log("#" * nest, "decode one element end:", offset, one)
        return offset

    def _decode_array(self, field, data, offset, nest):
        ctype = field[self._fields_index_ctype]
        # array_num, = struct.unpack_from('!H', data, offset)  # 之前该同学的代码会把长度序列化和反序列化
        # offset += 2
        array_num = field.get_field_length()
        value = []
        ctype_attr = self._type_map[ctype]
        endian_char = field.get_endian_char()
        debug_log("$" * nest, "decode array count", array_num, field)

        while array_num > 0:
            array_num -= 1
            if ctype not in BaseCode._type_map:
                one = eval(ctype + '()')
                offset = one.decode(data, offset, nest)
                value.append(one)
            else:
                one, = struct.unpack_from(endian_char + ctype_attr[self._type_map_index_pack_tag], data, offset)
                value.append(one)
                offset += self._ctype_size_map[ctype_attr[self._type_map_index_pack_tag]]

        if ctype == 'string':
            # 这里是因为字符串是按照单个字符解包,会解成python的int,通过chr()转化为字符型
            # value = [97,98]
            # list(map(chr,value)) 后等于 ['a','b']
            # ''.join() 就转成'ab'

            value = ''.join(list(map(chr, value)))
            value = bytes(value, encoding='latin1').decode('utf8')

        setattr(self, field[self._fields_index_value_name], value)
        debug_log("$" * nest, "decode array ok", array_num, field)
        return offset

    def tprint(self, tab=0):
        prefix = '  ' * tab
        debug_log(prefix, self.__class__, ":")
        for one in self._fields:
            ctype = one[self._fields_index_ctype]
            value = getattr(self, one[self._fields_index_value_name])
            if ctype not in BaseCode._type_map:
                debug_log(prefix, one[self._fields_index_value_name] + ' =')
                if type(value) == list:
                    [el.tprint(tab + 1) for el in value]
                else:
                    value.tprint(tab + 1)
            else:
                debug_log(prefix, one[self._fields_index_value_name] + ' =', value)

    def todict(self):
        """
        把字段转成字典
        :param ret:
        :return:
        """
        ret = {}
        for one in self._fields:
            ctype = one[self._fields_index_ctype]
            key = one[self._fields_index_value_name]
            value = getattr(self, key)
            # print(key + ' =', value)
            if ctype not in BaseCode._type_map:
                # 自定义类型
                if type(value) == list:
                    # 数组
                    ret[key] = [el.todict() for el in value]
                else:
                    ret[key] = value.todict()

            else:
                # 基本类型
                ret[key] = value

        return ret

    def tojson_print1(self):
        print(json.dumps(self.todict(), indent=4, separators=(', ', ': '), ensure_ascii=False))

    def tojson_print2(self):  # 美观度不如1
        pp = pprint.PrettyPrinter(indent=2)
        pp.pprint(self.todict())

    @staticmethod
    def parse_hex_str_2_time(hex_str):
        """ '0x6215e413' to '2022-02-23 15:36:51' """
        return time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(int(hex_str, 16)))

    @staticmethod
    def parse_hex_str_ipv4_address(hex_str):
        """ '0x33200954' to '51.32.9.84' """
        ip_p3 = hex_str[-8:-6]
        ip_p2 = hex_str[-6:-4]
        ip_p1 = hex_str[-4:-2]
        ip_p0 = hex_str[-2:]
        return ".".join([str(int(x, 16)) for x in [ip_p3, ip_p2, ip_p1, ip_p0]])

    @staticmethod
    def print_cmp_with_hex_static(ctype, _input_data):
        loc = locals()
        exec("test_obj = {}();".format(ctype))
        test_obj = loc["test_obj"]
        test_obj.print_cmp_with_hex(_input_data)

    def print_cmp_with_hex(self, _input_data):
        """
        输出诸如
        struct ext4_extent {
            __le32  ee_block      : 00 00 00 00 :  0      : 0
            __le16  ee_len        : 01 00       :  0x1    : 1
            __le16  ee_start_hi;  : 00 00       :  0      : 0
            __le32  ee_start_lo;  : 1e 86 00 00 :  0x861e : 34334
        };

        嵌套的自动解包:
            先把嵌套类型的名字和原始数据打出来
            再把参入放入yield_params
            最后用exec调用执行转换

        占位格式化
        mat = "{:020}\t{:010}\t{:12}"  # 冒号后面指定输出宽度,冒号后的第一个0表示用0占位
        print(mat.format(1,2,3333))    # 00000000000000000001    0000000002              3333

        """

        results = []
        results.append("struct %s {" % self.__class__.__name__)

        yield_params = []

        key_width = 30
        mat = "    {:10}{:%s} : {:30}: {:30} : {:20} {:20}" % key_width
        mat2 = "    {:10}{:%s} : {:62} : {:20}" % key_width
        offset = 0
        for one in self._fields:
            key = one[self._fields_index_value_name]
            value = getattr(self, key)
            raw_field = one.get_raw_field()
            ctype = one[self._fields_index_ctype]

            if ctype not in BaseCode._type_map:
                length = one.get_field_length()
                ctype_size = 12  ### 要实际计算,之前测试全是ext4_extent的三个对象,都是12的size
                # 已知类型,直接返回其size
                if ctype in GLOBAL_SIZE_DICT.keys():
                    ctype_size = GLOBAL_SIZE_DICT[ctype]
                else:
                    # 未知类型,实时计算
                    # 可能还需要import类型
                    loc = locals()
                    exec("_size_by_exec = %s().calculate_size(True)" % ctype)
                    ctype_size = loc["_size_by_exec"]
                    GLOBAL_SIZE_DICT[ctype] = ctype_size
                for i in range(length):
                    hex_data = []
                    for i in range(ctype_size):
                        hex_data.append(_input_data[offset + i])
                    offset += ctype_size
                    hex_list_str = " ".join(hex_data)
                    line_str = mat2.format(" ", raw_field, hex_list_str, " sizeof=%s" % ctype_size)
                    results.append(line_str)
                    yield_params.append((ctype, hex_data))
            else:
                ctype_size = self._ctype_size_map[self._type_map[ctype][self._type_map_index_pack_tag]]
                ctype_length = 1
                if type(value) == list:
                    ctype_length = len(value)

                hex_data = []
                for i in range(ctype_size * ctype_length):
                    hex_data.append(_input_data[offset + i])
                offset += ctype_size * ctype_length
                if one.is_little_endian():
                    hex_list_str = " ".join(hex_data)
                    hex_str = "0x" + "".join(hex_data[::-1])
                else:
                    hex_list_str = " ".join(hex_data)
                    hex_str = "0x" + "".join(hex_data)

                if not value:
                    value = int(hex_str, 16)  # exec调用的时候,上面的value获取值似乎有问题
                if type(value) == list:
                    if ctype == "char":
                        value = ''.join([chr(c) for c in value])
                    else:
                        value = str(value)
                # print(raw_field, key, hex_list_str, hex_str, value, " ")
                if len(hex_list_str) > 23:
                    hex_list_str = hex_list_str[:15] + "..." +  hex_list_str[-11:]
                if len(hex_str) > 23:
                    hex_str = hex_str[:18] + "..." +  hex_str[-8:]
                line_str = mat.format(raw_field, key, hex_list_str, hex_str, value, " ")
                if "\r" in line_str: # 修正了一个输出格式不对的bug
                    line_str = line_str.replace("\r", "")
                if "\n" in line_str:
                    line_str = line_str.replace("\n", "")
                if key.endswith("time"):
                    try:
                        time_parse = BaseCode.parse_hex_str_2_time(hex_str)
                        line_str = mat.format(raw_field, key, hex_list_str, hex_str, value, " : " + time_parse)
                    except:
                        pass
                if key.endswith("ipv4_address"):
                    try:
                        ip_parse = BaseCode.parse_hex_str_ipv4_address(hex_str)
                        line_str = mat.format(raw_field, key, hex_list_str, hex_str, value, " : " + ip_parse)
                    except:
                        pass

                results.append(line_str)

        results.append("}")
        print('\n'.join(results))

        if yield_params:
            print(" >>> extend instances :")
            # print(yield_params)
            for ctype1, hex_data1 in yield_params:
                BaseCode.print_cmp_with_hex_static(ctype1, hex_data1)

    def calculate_size(self, is_print=False):
        """
        最新:已经完成嵌套的功能,但是局限性在于:
        必须在 【# 自定义类型】处,手动import嵌套的子类型,要不然会报类型找不到
        而且:嵌套的子类型是通过exec来执行的,debug会出错。
        (因此:最新把exec代码局限在_exec_calc_size内部函数里)
        """
        result = 0
        for one in self._fields:
            ctype = one[self._fields_index_ctype]
            key = one[self._fields_index_value_name]
            if ctype in BaseCode._type_map: # 基本类型
                if not one.is_addtional():
                    result += self._ctype_size_map[self._type_map[ctype][self._type_map_index_pack_tag]]
                else:
                    length = one.get_field_length()
                    result += length * self._ctype_size_map[self._type_map[ctype][self._type_map_index_pack_tag]]
            else:
                # 自定义类型

                # 自定义类型的size,如果动态获取,只能通过exec,局限性略大
                def _exec_calc_size(ctype_name):
                    from basecode_structs import ext4_extent
                    from basecode_structs import ext4_extent_header
                    loc = locals()
                    # exec("test_obj = {}();print(test_obj)".format(ctype))
                    exec("test_obj = {}();".format(ctype))
                    test_obj = loc["test_obj"]
                    _ctype_size = test_obj.calculate_size()
                    return _ctype_size

                one_ctype_size = 0
                # 已知类型,直接返回其size
                if ctype in GLOBAL_SIZE_DICT.keys():
                    one_ctype_size = GLOBAL_SIZE_DICT[ctype]
                else:
                    one_ctype_size = _exec_calc_size(ctype)
                    GLOBAL_SIZE_DICT[ctype] = one_ctype_size

                if not one.is_addtional():
                    result += one_ctype_size
                else:
                    length = one.get_field_length()
                    result += length * one_ctype_size

        if is_print:
            print("    # [calculate_size]: class %s, size=%s" % (self.__class__.__name__, result))
        return result

class FormatDecoder(object):

    def __init__(self, ptype='input'):
        self.ptype = ptype
        self.input_raw = None
        self.input_length = 0
        self.input_bytes = bytes([0])
        self.output_data = None
        self.test_obj = None

    @staticmethod
    def parse_struct(ccode):
        """
        struct ext4_extent_header {
            __le16  eh_magic;   /* probably will support different formats
                                (i add a new line)       #define EXT4_EXT_MAGIC     cpu_to_le16(0xf30a)
                                */
            __le16  eh_entries; /* number of valid entries */
            __le16  eh_max;     /* capacity of store in entries */
            __le16  eh_depth;   /* has tree real underlying blocks? */
                                // i add a new line
            __le32  eh_generation;  // generation of the tree
        };

        c代码的定义 转换成 python代码:
        class ext4_extent_header(BaseCode):
            _fields = [
                FieldType('uint16_t', 'eh_magic', **{"raw_field": "__le16", "reverse": True}),
                FieldType('uint16_t', 'eh_entries', **{"raw_field": "__le16", "reverse": True}),
                FieldType('uint16_t', 'eh_max', **{"raw_field": "__le16", "reverse": True}),
                FieldType('uint16_t', 'eh_depth', **{"raw_field": "__le16", "reverse": True}),
                FieldType('uint32_t', 'eh_generation', **{"raw_field": "__le32", "reverse": True}),
            ]
        """

        content1 = re.sub(r'/\*.*?\*/', '', ccode, flags=re.S)  # 删除代码中的注释
        content = re.sub(r'(//.*)', '', content1)  # 删除代码中的注释
        lines = content.split("\n")
        start_line_no = 0
        for i, line in enumerate(lines):
            if "struct" in line:
                start_line_no = i
                break

        new_lines = []
        python_codes = []
        for line in lines[start_line_no + 1:]:
            line_strip = line.strip()
            if line_strip == '};':
                break
            if line_strip == '':
                continue
            new_lines.append(line_strip.rstrip(";").replace("\t", "    "))
        # print(new_lines)

        max_key_width = 18
        for field_line in new_lines:
            key_width1 = len(field_line) - 10
            if key_width1 > max_key_width:
                max_key_width = key_width1

        def _get_class_name(struct_line):
            arr1 = struct_line.replace("\t", "    ").split(" ")
            return list(filter(lambda x: x, arr1))[1]

        space_regex = re.compile('\s+')

        def _parse_line_field(field_line, key_width=18):
            # c语言的代码__le16  ee_start_hi  转换成python代码,本文件定义的field格式 ('uint16_t', 'ee_start_hi', {"reverse": True}),
            arr2 = space_regex.split(field_line)
            # print(arr2)
            field_name = arr2[-1]  # field_name = arr2[1]
            field_type = arr2[0]
            field_type_mapped = "char"
            field_addtional_reverse = False
            if len(arr2) > 2:
                field_type = " ".join(arr2[:-1])

            if field_type == "u8":
                field_type_mapped = "char"
            elif field_type == "_u8":
                field_type_mapped = "char"
            elif field_type == "__u8":
                field_type_mapped = "char"
            elif field_type == "u16":
                field_type_mapped = "uint16_t"
            elif field_type == "_u16":
                field_type_mapped = "uint16_t"
            elif field_type == "__u16":
                field_type_mapped = "uint16_t"
            elif field_type == "u32":
                field_type_mapped = "uint32_t"
            elif field_type == "_u32":
                field_type_mapped = "uint32_t"
            elif field_type == "__u32":
                field_type_mapped = "uint32_t"
            elif field_type == "u64":
                field_type_mapped = "uint64_t"
            elif field_type == "_u64":
                field_type_mapped = "uint64_t"
            elif field_type == "__u64":
                field_type_mapped = "uint64_t"
            elif field_type == "__be16":
                field_type_mapped = "uint16_t"
            elif field_type == "__be32":
                field_type_mapped = "uint32_t"
            elif field_type == "__be64":
                field_type_mapped = "uint64_t"
            elif field_type == "__le16":
                field_type_mapped = "uint16_t"
            elif field_type == "__le32":
                field_type_mapped = "uint32_t"
            elif field_type == "__le64":
                field_type_mapped = "uint64_t"
            elif field_type == "unsigned short":
                field_type_mapped = "uint16_t"
            elif field_type == "unsigned int":
                field_type_mapped = "uint32_t"
            elif field_type == "unsigned long":
                field_type_mapped = "uint64_t"
            elif field_type == "unsigned long long":
                field_type_mapped = "uint64_t"
            elif field_type == "short":
                field_type_mapped = "int16_t"
            elif field_type == "int":
                field_type_mapped = "int32_t"
            elif field_type == "long":
                field_type_mapped = "int64_t"
            elif field_type == "long long":
                field_type_mapped = "int64_t"
            else:
                if "struct" in field_type:
                    # print("[%s] not base datatype, not supported." % field_type)
                    # field_type_mapped = field_type   # 原计划原值返回,但是会不可执行,直接return吧
                    field_type_mapped = field_type.split(" ")[1]
                elif "union" in field_type:
                    # print("[%s] not base datatype, not supported." % field_type)
                    # field_type_mapped = field_type   # 原计划原值返回,但是会不可执行,直接return吧
                    return
                else:
                    return

            if field_type in ["__le16", "__le32", "__le64"]:
                field_addtional_reverse = True

            # 占位格式化
            mat = "        FieldType({:12}\t{:%s}\t{:48})," % key_width
            addtional_dict = {"raw_field": field_type}
            if field_addtional_reverse:
                addtional_dict["reverse"] = True
            if field_name.endswith("]"):
                field_size = field_name.split("[")[1][:-1]
                addtional_dict["length"] = int(field_size)
                field_name = field_name.split("[")[0]
            addtional_dict_str = '**' + str(addtional_dict).replace("'", '"')
            field_code = mat.format("'%s'," % field_type_mapped, "'%s'," % field_name, addtional_dict_str)
            return field_code

        try:
            class_name = _get_class_name(lines[start_line_no])

            python_codes.append("class {}(BaseCode):".format(class_name))
            python_codes.append("    _fields = [")
            for field_line in new_lines:
                _parse_field = _parse_line_field(field_line, max_key_width)
                if _parse_field:
                    python_codes.append(_parse_field)
            python_codes.append("    ]")

            ccode_result = "\n".join(python_codes)
            print(ccode_result)
            return ccode_result, class_name

        except Exception as e:
            # print("Error: ", e)
            print("Error: ", traceback.format_exc())
            print("struct source format error")
            exit(1)

    @my_try_except_warpper(is_exit=True, err_msg="Decode hex data source format error")
    def parse_chr_array_2_bytes(self, chrs):
        """
        10 00 00 00  01 00 02 00  1E 86 00 00
        转换成<class 'bytes'>
        b'\x00\x00\x00\x10\x00\x01\x00\x02\x00\x00\x86\x1e'
        也支持 10000000010002001E860000

        === 严格来说,要严格校验chrs的格式
        """
        raw_data = []
        if " " in chrs:
            raw_data = list(filter(lambda x: x, chrs.split(" ")))
        else:
            for i, x in enumerate(chrs):
                if i % 2:
                    raw_data.append(chrs[i - 1] + x)
        hex_2_dec_data = [int(item, 16) for item in raw_data]
        result = bytes(hex_2_dec_data)
        print("[parse_chr_array_2_bytes]: %s" % result)
        if self.ptype == "input":
            self.input_bytes = result
            self.input_length = len(hex_2_dec_data)
        return result, len(hex_2_dec_data)

    def parse_chr_array_2_hex_list(self, chrs):
        """
        输入chrs 从hexdump来的 数据样式为  ' 00 00 c8 00 00 00 20 03  00 00 28 00 f3 35 0f 03  '
        输入chrs 内容没有被分割 数据样式为  '000064000000900100001400e87c8701'
        hex格式化输出使用,因此在parse_chr_array_2_bytes剪了部分代码过来
        输出:['00', '00', 'c8', '00', '00', '00', '20', '03', '00', '00', '28', '00', 'f3', '35', '0f', '03']
        """
        raw_data = []
        if " " in chrs:
            raw_data = list(filter(lambda x: x, chrs.split(" ")))
        else:
            for i, x in enumerate(chrs):
                if i % 2:
                    raw_data.append(chrs[i - 1] + x)
        if self.ptype == "input":
            self.output_data = raw_data
        return raw_data

    def decode_hex(self, class_type):
        loc = locals()
        try:
            exec("test_obj = {}()".format(class_type))
        except NameError:
            print("NameError when decode_hex")
            help(sys.argv[0])
        test_obj = loc['test_obj']
        test_obj_size = test_obj.calculate_size()

        if self.input_length < test_obj_size:
            print("input hex size [%s] less than sizeof(%s)=[%s]" % (self.input_length, class_type, test_obj_size))
            exit(1)
        elif self.input_length > test_obj_size:
            print("input hex size [%s] more than sizeof(%s)=[%s], " % (self.input_length, class_type, test_obj_size))
            self.input_bytes = self.input_bytes[:test_obj_size]
            print("only use the previous required data: %s" % self.input_bytes)

        test_obj.decode(self.input_bytes)
        self.test_obj = test_obj

    def parse_to_bytes(self, **kwargs):
        if self.ptype == "input":
            self.input_raw = kwargs.get("input")
            return self.parse_chr_array_2_bytes(self.input_raw)
        print("type is unsupported")

    def parse_to_hex_list(self):
        if self.ptype == "input":
            return self.parse_chr_array_2_hex_list(self.input_raw)
        print("type is unsupported")

    def show_output(self):
        if self.test_obj and self.output_data:
            # self.test_obj.tojson_print1()
            self.test_obj.print_cmp_with_hex(self.output_data)

    def run(self):
        if self.test_obj and self.output_data:
            # self.test_obj.tojson_print1()
            self.test_obj.print_cmp_with_hex(self.output_data)

class FormatDecoderHexdump(FormatDecoder):

    def __init__(self, rst_file=''):
        super().__init__(ptype="hexdump")
        self.rst_file = rst_file or "hexdump.rst"

    @my_try_except_warpper(is_exit=True, err_msg="Decode hexdump file hexdump.rst format error")
    def parse_to_bytes(self, **kwargs):
        raw_data = []
        with open(self.rst_file) as file1:
            rcode = file1.read()
            for line in rcode.split("\n"):  # line = "00000400  00 00 c8 00 00 00 20 03  00 00 28 00 f3 35 0f 03  |...... ...(..5..|"
                line_parse = line.split("|")[0][9:]
                raw_data.extend(self.parse_chr_array_2_hex_list(line_parse))
        hex_2_dec_data = [int(item, 16) for item in raw_data]
        result = bytes(hex_2_dec_data)
        print("[parse_hexdump_rst]: %s" % result)
        self.input_bytes = result
        self.input_length = len(hex_2_dec_data)

    def parse_to_hex_list(self):
        """
        hex格式化输出使用,因此在parse_hexdump_rst_2_bytes剪了部分代码过来
        """
        raw_data = []
        with open(self.rst_file) as file1:
            rcode = file1.read()
            for line in rcode.split("\n"):
                line_parse = line.split("|")[0][9:]
                raw_data.extend(self.parse_chr_array_2_hex_list(line_parse))
        self.output_data = raw_data

class FormatDecoderVib(FormatDecoder):
    def __init__(self, rst_file=''):
        super().__init__(ptype="vib")
        self.rst_file = rst_file or "vib2xxd.rst"

    @my_try_except_warpper(is_exit=True, err_msg="Decode hexdump file vib2xxd.rst format error")
    def parse_to_bytes(self, **kwargs):
        # FC新环境没有hexdump,用vi来操作,vi -b ttt1 二进制打开文件  :%!xxd 转换成十六进制
        raw_data = []
        with open(self.rst_file) as file1:
            rcode = file1.read()
            for line in rcode.split("\n"):  # line = "00000400: 0000 6400 0000 9001 0000 1400 e87c 8701  ..d..........|.."
                line_parse = "".join(line.split(":")[1][1:40].split(" "))
                raw_data.extend(self.parse_chr_array_2_hex_list(line_parse))
        hex_2_dec_data = [int(item, 16) for item in raw_data]
        result = bytes(hex_2_dec_data)
        print("[parse_vib2xxd_rst]: %s" % result)
        self.input_bytes = result
        self.input_length = len(hex_2_dec_data)

    def parse_to_hex_list(self):
        raw_data = []
        with open(self.rst_file) as file1:
            rcode = file1.read()
            for line in rcode.split("\n"):
                line_parse = "".join(line.split(":")[1][1:40].split(" "))
                raw_data.extend(self.parse_chr_array_2_hex_list(line_parse))
        self.output_data = raw_data

### 以下是基本功能测试片段
class ext4_extent__test(BaseCode):
    _fields =[
        FieldType('uint32_t', 'ee_block', **{"reverse": True}),
        FieldType('uint16_t', 'ee_len', **{"reverse": True}),
        FieldType('uint16_t', 'ee_start_hi', **{"reverse": True}),
        FieldType('uint32_t', 'ee_start_lo', **{"reverse": True}),
    ]

class ext4_extent__unreverse(BaseCode):
    _fields =[
        FieldType('uint32_t', 'ee_block'),
        FieldType('uint16_t', 'ee_len'),
        FieldType('uint16_t', 'ee_start_hi'),
        FieldType('uint32_t', 'ee_start_lo'),
    ]

#【10 00 00 00  01 00 02 00  1E 86 00 00】的ext4_extent(sizeof=12), 10是ee_len, 02 00是ee_start_hi; 1E 86 00 00 ee_start_lo; 高16位,低32位,合在一起是 0x00020000861E
def ext4_test():
    extent1 = ext4_extent__unreverse() # b'\x00\x00\x00\x10\x00\x01\x00\x02\x00\x00\x86\x1e'
    extent1.ee_block = 16
    extent1.ee_len = 1
    extent1.ee_start_hi = 2
    extent1.ee_start_lo = 34334  # 0x861E
    data1 = extent1.encode()
    print('extent1 **final:', len(data1), type(data1), data1)

    print("extent2")
    extent2 = ext4_extent__unreverse()
    extent2.decode(data1)
    extent2.tojson_print1()

    print("c1")  # 因为是小端对象,不能这么赋值了
    c1 = ext4_extent__test()
    c1.ee_block = 16
    c1.ee_len = 1
    c1.ee_start_hi = 2
    c1.ee_start_lo = 34334  # 0x861E
    data_c1 = c1.encode()
    print('c1 **final:', len(data_c1), type(data_c1), data_c1)

    print("c2")
    c2 = ext4_extent__test()
    c2.decode(data_c1)
    c2.tojson_print1()

    """
    c1 **final: 12 <class 'bytes'> b'\x00\x00\x00\x10\x00\x01\x00\x02\x00\x00\x86\x1e'
    c2
    {
        "ee_block": 268435456, 
        "ee_len": 256, 
        "ee_start_hi": 512, 
        "ee_start_lo": 512098304  # 是 0x1E860000
    }
    """

    print("c3")  # 因为是小端对象,不能这么赋值了
    c3 = ext4_extent__test()
    c3.ee_block = FieldType.get_little_endian_int32(16)     # hex(268435456) '0x10000000'
    c3.ee_len = FieldType.get_little_endian_int16(1)        # hex(256) '0x0100
    c3.ee_start_hi = FieldType.get_little_endian_int16(2)   #  hex(512) '0x0200'
    c3.ee_start_lo = FieldType.get_little_endian_int32(34334)  # 0x861E  ## hex(512098304) '0x1e860000'
    data_c3 = c3.encode()
    print('c3 **final:', len(data_c3), type(data_c3), data_c3)

    print("c4")
    c4 = ext4_extent__test()
    c4.decode(data_c3)
    c4.tojson_print1()

    print("ttt")
    ttt = ext4_extent__test()
    formater = FormatDecoder()
    tttbytes0 = formater.parse_chr_array_2_bytes('10000000010002001E860000')
    print(tttbytes0)
    tttbytes = formater.parse_chr_array_2_bytes('10 00 00 00  01 00 02 00  1E 86 00 00')
    print(tttbytes)
    ttt.decode(tttbytes[0])
    ttt.tojson_print1()

def ext4_ccode_test1():
    ccode = """
        int i;
        int cl;
    struct ext4_extent_header_mytest {
        __le16  eh_magic;   /* probably will support different formats
                            (i add a new line)       #define EXT4_EXT_MAGIC     cpu_to_le16(0xf30a)
                            */
        __le16  eh_entries; /* number of valid entries */
        __le16  eh_max;     /* capacity of store in entries */
        __le16  eh_depth;   /* has tree real underlying blocks? */
                            // i add a new line
        __le32  eh_generation;  // generation of the tree
        unsigned       long long   test_field;
    };
    """
    length = 0
    ccode_result, class_name = FormatDecoder.parse_struct(ccode)
    ccode_result += "\n"
    ccode_result += "test_obj = {}()".format(class_name)
    ccode_result += "\n"
    ccode_result += "length = test_obj.calculate_size()"
    ccode_result += "\n"
    ccode_result += "print(length)"
    # eval(ccode_result)  # eval new对象 - 报错 SyntaxError: invalid syntax
    # eval("test_obj = {}()".format(class_name))
    # eval("length = test_obj.calculate_size()")
    # 换成exec,结合locals搞定
    loc = locals()
    exec(ccode_result)
    class_ext4_extent_header_mytest = loc['ext4_extent_header_mytest']
    print(class_ext4_extent_header_mytest)
    test_obj =class_ext4_extent_header_mytest()
    test_obj.calculate_size()

class ext4_extent_header_mytest2(BaseCode):
    _fields = [
        FieldType('uint16_t', 'eh_magic', **{"reverse": True}),
        FieldType('uint16_t', 'eh_entries', **{"reverse": True}),
        FieldType('uint16_t', 'eh_max', **{"reverse": True}),
        FieldType('uint16_t', 'eh_depth', **{"reverse": True}),
        FieldType('uint32_t', 'eh_generation', **{"reverse": True}),
        # FieldType('uint64_t', 'test_field'),
    ]

def ext4_ccode_test2():
    test_obj = ext4_extent_header_mytest2()
    length = test_obj.calculate_size()
    print(length)

def ext4_ccode_test3():
    exec("ext4_extent_header_mytest2().calculate_size()")
    exec("test_obj = ext4_extent_header_mytest2(); test_obj.calculate_size()")

    loc = locals()
    exec("test_obj = ext4_extent_header_mytest2()")  # 这里exec的对象,下文中无法使用
    # 为了修正这样的错误,你需要在调用 exec() 之前使用 locals() 函数来得到一个局部变量字典。 之后你就能从局部字典中获取修改过后的变量值了。
    test_obj = loc['test_obj']
    print(test_obj)
    length = test_obj.calculate_size()
    print(length)

def ext4_inode_hexdump_test():
    print("\n\n========ext4_inode_hexdump_test========")
    input_bytes = b'\xa0\x81\x00\x00\x18\x1b\x00\x00\x13\xe4\x15bY\xe4\x15bY\xe4\x15b\x00\x00\x00\x00\x00\x00\x01\x00\x10\x00\x00\x00\x00\x00\x08\x00\x01\x00\x00\x00\n\xf3\x02\x00\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\x88\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x8a\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x05\x03\xac\xb3\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00g\xe3\x00\x00 \x00\xe9\xa2(\xaa\x96\xd7(\xaa\x96\xd7\xac\xda\xc4C\x13\xe4\x15b\xac\xda\xc4C\x00\x00\x00\x00\x00\x00\x00\x00'
    # input_length = len(input_bytes) # 160
    test_obj = ext4_inode()
    test_obj.decode(input_bytes)

    _input_data = ['a0', '81', '00', '00', '18', '1b', '00', '00',  '13', 'e4', '15', '62', '59', 'e4', '15', '62',
                   '59', 'e4', '15', '62', '00', '00', '00', '00',  '00', '00', '01', '00', '10', '00', '00', '00',
                   '00', '00', '08', '00', '01', '00', '00', '00',  '0a', 'f3', '02', '00', '04', '00', '00', '00',
                   '00', '00', '00', '00', '00', '00', '00', '00',  '01', '00', '00', '00', '00', '88', '00', '00',
                   '01', '00', '00', '00', '01', '00', '00', '00',  '00', '8a', '00', '00', '00', '00', '00', '00',
                   '00', '00', '00', '00', '00', '00', '00', '00',  '00', '00', '00', '00', '00', '00', '00', '00',
                   '00', '00', '00', '00', '05', '03', 'ac', 'b3',  '00', '00', '00', '00', '00', '00', '00', '00',
                   '00', '00', '00', '00', '00', '00', '00', '00',  '00', '00', '00', '00', '67', 'e3', '00', '00',
                   '20', '00', 'e9', 'a2', '28', 'aa', '96', 'd7',  '28', 'aa', '96', 'd7', 'ac', 'da', 'c4', '43',
                   '13', 'e4', '15', '62', 'ac', 'da', 'c4', '43', '00', '00', '00', '00', '00', '00', '00', '00']
    test_obj.print_cmp_with_hex(_input_data)

@my_try_except_warpper()
def ext4_sb_hexdump_test():
    print("\n\n========ext4_super_block_hexdump_test========")
    test_obj = ext4_super_block()
    hexdump_rst="test/hexdump_ext4_super_block.rst"
    formater = FormatDecoderHexdump(hexdump_rst)
    formater.parse_to_bytes()
    test_obj.decode(formater.input_bytes)
    formater.parse_to_hex_list()
    test_obj.print_cmp_with_hex(formater.output_data)

@my_try_except_warpper()
def gernel_test():
    ext4_test()
    ext4_ccode_test1()
    ext4_ccode_test2()
    ext4_ccode_test3()
    ext4_inode_hexdump_test()
    # ext4_sb_hexdump_test()

## 拆分到basecode_structs始终还有问题,嵌套子类型不能声明在那边,eval的时候找不到
class ext4_extent(BaseCode):
    _fields = [
        FieldType('uint32_t', 'ee_block', **{"raw_field": "__le32", "reverse": True}),
        FieldType('uint16_t', 'ee_len', **{"raw_field": "__le16", "reverse": True}),
        FieldType('uint16_t', 'ee_start_hi', **{"raw_field": "__le16", "reverse": True}),
        FieldType('uint32_t', 'ee_start_lo', **{"raw_field": "__le32", "reverse": True}),
    ]
    # [calculate_size]: class ext_extent, size=12

class ext4_extent_idx(BaseCode):
    _fields = [
        FieldType('uint32_t', 'ei_block', **{"raw_field": "__le32", "reverse": True}),
        FieldType('uint32_t', 'ei_leaf_lo', **{"raw_field": "__le32", "reverse": True}),
        FieldType('uint16_t', 'ei_leaf_hi', **{"raw_field": "__le16", "reverse": True}),
        FieldType('uint16_t', 'ei_unused', **{"raw_field": "__u16"}),
    ]
    # [calculate_size]: class ext4_extent_idx, size=12

class ext4_extent_header(BaseCode):
    _fields = [
        FieldType('uint16_t', 'eh_magic', **{"raw_field": "__le16", "reverse": True}),
        FieldType('uint16_t', 'eh_entries', **{"raw_field": "__le16", "reverse": True}),
        FieldType('uint16_t', 'eh_max', **{"raw_field": "__le16", "reverse": True}),
        FieldType('uint16_t', 'eh_depth', **{"raw_field": "__le16", "reverse": True}),
        FieldType('uint32_t', 'eh_generation', **{"raw_field": "__le32", "reverse": True}),
    ]
    # [calculate_size]: class ext4_extent_header, size=12

if __name__ == '__main__1':
    gernel_test()

# 不用动name了,直接在这改0和1
TEST_SWITCH = 0

def help(selfname):
    print('<hex input> is missing')
    print('%s -c <class> -h <hex chars input>' % selfname)
    print('%s -c <class> -r <hexdump/vi>' % selfname)
    exit(1)

# python basecode.py -s source.c
# python basecode.py -c ext4_extent -h "10 00 00 00  01 00 02 00 1E 86 00 00"
# python basecode.py -c ext4_inode -r hexdump
# python basecode.py -c ext4_super_block -r vi
if __name__ == '__main__':
    if TEST_SWITCH:
        gernel_test()
        exit(0)

    class_type = None
    hex_input = None
    hex_rst_type = None
    src_code = None
    try:
        shortargs = 'c:h:r:s:'
        longargs = ['--class', '--hex',  '--resource', '--source']
        opts, args = getopt.getopt(sys.argv[1:], shortargs, longargs)
        for opt, arg in opts:
            if opt in ("-c", "--class"):
                class_type = arg
            elif opt in ("-h", "--hex"):
                hex_input = arg
            elif opt in ("-r", "--resource_type"):
                hex_rst_type = arg
            elif opt in ("-s", "--source"):
                src_code = arg

        if src_code:
            file0 = open(src_code, mode='r')
            ccode = file0.read()
            ccode_result, class_name = FormatDecoder.parse_struct(ccode)
            exit(0)

        if class_type:
            formater = FormatDecoder('input')
            if hex_input:
                formater.parse_to_bytes(input=hex_input)
            elif hex_rst_type:
                if hex_rst_type in ["hexdump", "hd"]:
                    formater = FormatDecoderHexdump()
                    formater.parse_to_bytes()
                elif hex_rst_type == "vi":
                    formater = FormatDecoderVib()
                    formater.parse_to_bytes()
                else:
                    help(sys.argv[0])
            else:
                help(sys.argv[0])

            formater.decode_hex(class_type)
            formater.parse_to_hex_list()
            formater.show_output()

    except getopt.GetoptError:
        print('%s -c <class> -h <hex chars input>' % sys.argv[0])
        print('%s -s <source code>' % sys.argv[0])
        exit(2)
vieyahn2017 commented 8 months ago

basecode_structs.py

#!/usr/bin/python
# -*- coding: utf-8 -*-

import copy
from basecode import BaseCode, FieldType

class ext4_extent(BaseCode):
    _fields = [
        FieldType('uint32_t',   'ee_block',         **{"raw_field": "__le32", "reverse": True}      ),
        FieldType('uint16_t',   'ee_len',           **{"raw_field": "__le16", "reverse": True}      ),
        FieldType('uint16_t',   'ee_start_hi',      **{"raw_field": "__le16", "reverse": True}      ),
        FieldType('uint32_t',   'ee_start_lo',      **{"raw_field": "__le32", "reverse": True}      ),
    ]
    # [calculate_size]: class ext_extent, size=12

class ext4_extent_idx(BaseCode):
    _fields = [
        FieldType('uint32_t',   'ei_block',         **{"raw_field": "__le32", "reverse": True}      ),
        FieldType('uint32_t',   'ei_leaf_lo',       **{"raw_field": "__le32", "reverse": True}      ),
        FieldType('uint16_t',   'ei_leaf_hi',       **{"raw_field": "__le16", "reverse": True}      ),
        FieldType('uint16_t',   'ei_unused',        **{"raw_field": "__u16"}                        ),
    ]
    # [calculate_size]: class ext4_extent_idx, size=12

class ext4_extent_header(BaseCode):
    _fields = [
        FieldType('uint16_t',   'eh_magic',         **{"raw_field": "__le16", "reverse": True}      ),
        FieldType('uint16_t',   'eh_entries',       **{"raw_field": "__le16", "reverse": True}      ),
        FieldType('uint16_t',   'eh_max',           **{"raw_field": "__le16", "reverse": True}      ),
        FieldType('uint16_t',   'eh_depth',         **{"raw_field": "__le16", "reverse": True}      ),
        FieldType('uint32_t',   'eh_generation',    **{"raw_field": "__le32", "reverse": True}      ),
    ]
    # [calculate_size]: class ext4_extent_header, size=12

class ext4_inode(BaseCode):
    _type_map = copy.deepcopy(BaseCode._type_map)
    _type_map['ext4_extent'] = ('class', 'ext4_extent')
    _type_map['ext4_extent_header'] = ('class', 'ext4_extent_header')
    _type_map['ext4_extent_idx'] = ('class', 'ext4_extent_idx')
    _fields = [
        FieldType('uint16_t',   'i_mode',           **{"raw_field": "__le16", "reverse": True}      ),
        FieldType('uint16_t',   'i_uid',            **{"raw_field": "__le16", "reverse": True}      ),
        FieldType('uint32_t',   'i_size_lo',        **{"raw_field": "__le32", "reverse": True}      ),
        FieldType('uint32_t',   'i_atime',          **{"raw_field": "__le32", "reverse": True}      ),
        FieldType('uint32_t',   'i_ctime',          **{"raw_field": "__le32", "reverse": True}      ),
        FieldType('uint32_t',   'i_mtime',          **{"raw_field": "__le32", "reverse": True}      ),
        FieldType('uint32_t',   'i_dtime',          **{"raw_field": "__le32", "reverse": True}      ),
        FieldType('uint16_t',   'i_gid',            **{"raw_field": "__le16", "reverse": True}      ),
        FieldType('uint16_t',   'i_links_count',    **{"raw_field": "__le16", "reverse": True}      ),
        FieldType('uint32_t',   'i_blocks_lo',      **{"raw_field": "__le32", "reverse": True}      ),
        FieldType('uint32_t',   'i_flags',          **{"raw_field": "__le32", "reverse": True}      ),
        FieldType('uint32_t',   'l_i_version',      **{"raw_field": "__le32", "reverse": True}      ),  #   union { struct {__le32  l_i_version;} linux1;} osd1;
        # FieldType('uint32_t',     'h_i_translator', **{"raw_field": "__u32"}                        ),  #     union { struct {__u32  h_i_translator;} hurd1;} osd1;
        # FieldType('uint32_t',     'm_i_reserved1',    **{"raw_field": "__u32"}                        ),  #   union { struct {__u32  m_i_reserved1;} masix1;} osd1;

        # FieldType('uint32_t',     'i_block[15]',      **{"raw_field": "__le32", "reverse": True, "length": 15}),
        FieldType('ext4_extent_header',     'i_block__ext4_extent_header',      **{"raw_field": "struct ext4_extent_header"}),
        FieldType('ext4_extent_idx',    'i_block__ext4_extent_idx',     **{"raw_field": "struct ext4_extent_idx", "length": 4}),

        FieldType('uint32_t',   'i_generation',     **{"raw_field": "__le32", "reverse": True}      ),
        FieldType('uint32_t',   'i_file_acl_lo',    **{"raw_field": "__le32", "reverse": True}      ),
        FieldType('uint32_t',   'i_size_high',      **{"raw_field": "__le32", "reverse": True}      ),
        FieldType('uint32_t',   'i_obso_faddr',     **{"raw_field": "__le32", "reverse": True}      ),

        FieldType('uint16_t',   'l_i_blocks_high',  **{"raw_field": "__le16", "reverse": True}      ),
        FieldType('uint16_t',   'l_i_file_acl_high',    **{"raw_field": "__le16", "reverse": True}      ),
        FieldType('uint16_t',   'l_i_uid_high',     **{"raw_field": "__le16", "reverse": True}      ),
        FieldType('uint16_t',   'l_i_gid_high',     **{"raw_field": "__le16", "reverse": True}      ),
        FieldType('uint16_t',   'l_i_checksum_lo',  **{"raw_field": "__le16", "reverse": True}      ),
        FieldType('uint16_t',   'l_i_reserved',     **{"raw_field": "__le16", "reverse": True}      ),

        # FieldType('uint16_t',     'h_i_reserved1',    **{"raw_field": "__le16", "reverse": True}      ),
        # FieldType('uint16_t',     'h_i_mode_high',    **{"raw_field": "__u16"}                        ),
        # FieldType('uint16_t',     'h_i_uid_high',     **{"raw_field": "__u16"}                        ),
        # FieldType('uint16_t',     'h_i_gid_high',     **{"raw_field": "__u16"}                        ),
        # FieldType('uint32_t',     'h_i_author',       **{"raw_field": "__u32"}                        ),

        # FieldType('uint16_t',     'h_i_reserved1',    **{"raw_field": "__le16", "reverse": True}      ),
        # FieldType('uint16_t',     'm_i_file_acl_high',    **{"raw_field": "__le16", "reverse": True}      ),
        # FieldType('uint32_t',     'm_i_reserved2[2]', **{"raw_field": "__u32", "length": 2}                        ),

        FieldType('uint16_t',   'i_extra_isize',    **{"raw_field": "__le16", "reverse": True}      ),
        FieldType('uint16_t',   'i_checksum_hi',    **{"raw_field": "__le16", "reverse": True}      ),
        FieldType('uint32_t',   'i_ctime_extra',    **{"raw_field": "__le32", "reverse": True}      ),
        FieldType('uint32_t',   'i_mtime_extra',    **{"raw_field": "__le32", "reverse": True}      ),
        FieldType('uint32_t',   'i_atime_extra',    **{"raw_field": "__le32", "reverse": True}      ),
        FieldType('uint32_t',   'i_crtime',         **{"raw_field": "__le32", "reverse": True}      ),
        FieldType('uint32_t',   'i_crtime_extra',   **{"raw_field": "__le32", "reverse": True}      ),
        FieldType('uint32_t',   'i_version_hi',     **{"raw_field": "__le32", "reverse": True}      ),
        FieldType('uint32_t',   'i_projid',         **{"raw_field": "__le32", "reverse": True}      ),
    ]
    # [calculate_size]: class ext4_inode, size=160

class ext4_super_block(BaseCode):
    _fields = [
        FieldType('uint32_t',   's_inodes_count',           **{"raw_field": "__le32", "reverse": True}      ),
        FieldType('uint32_t',   's_blocks_count_lo',        **{"raw_field": "__le32", "reverse": True}      ),
        FieldType('uint32_t',   's_r_blocks_count_lo',      **{"raw_field": "__le32", "reverse": True}      ),
        FieldType('uint32_t',   's_free_blocks_count_lo',   **{"raw_field": "__le32", "reverse": True}      ),
        FieldType('uint32_t',   's_free_inodes_count',      **{"raw_field": "__le32", "reverse": True}      ),
        FieldType('uint32_t',   's_first_data_block',       **{"raw_field": "__le32", "reverse": True}      ),
        FieldType('uint32_t',   's_log_block_size',         **{"raw_field": "__le32", "reverse": True}      ),
        FieldType('uint32_t',   's_log_cluster_size',       **{"raw_field": "__le32", "reverse": True}      ),
        FieldType('uint32_t',   's_blocks_per_group',       **{"raw_field": "__le32", "reverse": True}      ),
        FieldType('uint32_t',   's_clusters_per_group',     **{"raw_field": "__le32", "reverse": True}      ),
        FieldType('uint32_t',   's_inodes_per_group',       **{"raw_field": "__le32", "reverse": True}      ),
        FieldType('uint32_t',   's_mtime',                  **{"raw_field": "__le32", "reverse": True}      ),
        FieldType('uint32_t',   's_wtime',                  **{"raw_field": "__le32", "reverse": True}      ),
        FieldType('uint16_t',   's_mnt_count',              **{"raw_field": "__le16", "reverse": True}      ),
        FieldType('uint16_t',   's_max_mnt_count',          **{"raw_field": "__le16", "reverse": True}      ),
        FieldType('uint16_t',   's_magic',                  **{"raw_field": "__le16", "reverse": True}      ),
        FieldType('uint16_t',   's_state',                  **{"raw_field": "__le16", "reverse": True}      ),
        FieldType('uint16_t',   's_errors',                 **{"raw_field": "__le16", "reverse": True}      ),
        FieldType('uint16_t',   's_minor_rev_level',        **{"raw_field": "__le16", "reverse": True}      ),
        FieldType('uint32_t',   's_lastcheck',              **{"raw_field": "__le32", "reverse": True}      ),
        FieldType('uint32_t',   's_checkinterval',          **{"raw_field": "__le32", "reverse": True}      ),
        FieldType('uint32_t',   's_creator_os',             **{"raw_field": "__le32", "reverse": True}      ),
        FieldType('uint32_t',   's_rev_level',              **{"raw_field": "__le32", "reverse": True}      ),
        FieldType('uint16_t',   's_def_resuid',             **{"raw_field": "__le16", "reverse": True}      ),
        FieldType('uint16_t',   's_def_resgid',             **{"raw_field": "__le16", "reverse": True}      ),
        FieldType('uint32_t',   's_first_ino',              **{"raw_field": "__le32", "reverse": True}      ),
        FieldType('uint16_t',   's_inode_size',             **{"raw_field": "__le16", "reverse": True}      ),
        FieldType('uint16_t',   's_block_group_nr',         **{"raw_field": "__le16", "reverse": True}      ),
        FieldType('uint32_t',   's_feature_compat',         **{"raw_field": "__le32", "reverse": True}      ),
        FieldType('uint32_t',   's_feature_incompat',       **{"raw_field": "__le32", "reverse": True}      ),
        FieldType('uint32_t',   's_feature_ro_compat',      **{"raw_field": "__le32", "reverse": True}      ),
        FieldType('char',       's_uuid',                   **{"raw_field": "__u8", "length": 16}           ),
        FieldType('char',       's_volume_name',            **{"raw_field": "char", "length": 16}           ),
        FieldType('char',       's_last_mounted',           **{"raw_field": "char", "length": 64}           ),
        FieldType('uint32_t',   's_algorithm_usage_bitmap', **{"raw_field": "__le32", "reverse": True}      ),
        FieldType('char',       's_prealloc_blocks',        **{"raw_field": "__u8"}                         ),
        FieldType('char',       's_prealloc_dir_blocks',    **{"raw_field": "__u8"}                         ),
        FieldType('uint16_t',   's_reserved_gdt_blocks',    **{"raw_field": "__le16", "reverse": True}      ),
        FieldType('char',       's_journal_uuid',           **{"raw_field": "__u8", "length": 16}           ),
        FieldType('uint32_t',   's_journal_inum',           **{"raw_field": "__le32", "reverse": True}      ),
        FieldType('uint32_t',   's_journal_dev',            **{"raw_field": "__le32", "reverse": True}      ),
        FieldType('uint32_t',   's_last_orphan',            **{"raw_field": "__le32", "reverse": True}      ),
        FieldType('uint32_t',   's_hash_seed',              **{"raw_field": "__le32", "reverse": True, "length": 4}),
        FieldType('char',       's_def_hash_version',       **{"raw_field": "__u8"}                         ),
        FieldType('char',       's_jnl_backup_type',        **{"raw_field": "__u8"}                         ),
        FieldType('uint16_t',   's_desc_size',              **{"raw_field": "__le16", "reverse": True}      ),
        FieldType('uint32_t',   's_default_mount_opts',     **{"raw_field": "__le32", "reverse": True}      ),
        FieldType('uint32_t',   's_first_meta_bg',          **{"raw_field": "__le32", "reverse": True}      ),
        FieldType('uint32_t',   's_mkfs_time',              **{"raw_field": "__le32", "reverse": True}      ),
        FieldType('uint32_t',   's_jnl_blocks',             **{"raw_field": "__le32", "reverse": True, "length": 17}),
        FieldType('uint32_t',   's_blocks_count_hi',        **{"raw_field": "__le32", "reverse": True}      ),
        FieldType('uint32_t',   's_r_blocks_count_hi',      **{"raw_field": "__le32", "reverse": True}      ),
        FieldType('uint32_t',   's_free_blocks_count_hi',   **{"raw_field": "__le32", "reverse": True}      ),
        FieldType('uint16_t',   's_min_extra_isize',        **{"raw_field": "__le16", "reverse": True}      ),
        FieldType('uint16_t',   's_want_extra_isize',       **{"raw_field": "__le16", "reverse": True}      ),
        FieldType('uint32_t',   's_flags',                  **{"raw_field": "__le32", "reverse": True}      ),
        FieldType('uint16_t',   's_raid_stride',            **{"raw_field": "__le16", "reverse": True}      ),
        FieldType('uint16_t',   's_mmp_update_interval',    **{"raw_field": "__le16", "reverse": True}      ),
        FieldType('uint64_t',   's_mmp_block',              **{"raw_field": "__le64", "reverse": True}      ),
        FieldType('uint32_t',   's_raid_stripe_width',      **{"raw_field": "__le32", "reverse": True}      ),
        FieldType('char',       's_log_groups_per_flex',    **{"raw_field": "__u8"}                         ),
        FieldType('char',       's_checksum_type',          **{"raw_field": "__u8"}                         ),
        FieldType('char',       's_encryption_level',       **{"raw_field": "__u8"}                         ),
        FieldType('char',       's_reserved_pad',           **{"raw_field": "__u8"}                         ),
        FieldType('uint64_t',   's_kbytes_written',         **{"raw_field": "__le64", "reverse": True}      ),
        FieldType('uint32_t',   's_snapshot_inum',          **{"raw_field": "__le32", "reverse": True}      ),
        FieldType('uint32_t',   's_snapshot_id',            **{"raw_field": "__le32", "reverse": True}      ),
        FieldType('uint64_t',   's_snapshot_r_blocks_count',    **{"raw_field": "__le64", "reverse": True}      ),
        FieldType('uint32_t',   's_snapshot_list',          **{"raw_field": "__le32", "reverse": True}      ),
        FieldType('uint32_t',   's_error_count',            **{"raw_field": "__le32", "reverse": True}      ),
        FieldType('uint32_t',   's_first_error_time',       **{"raw_field": "__le32", "reverse": True}      ),
        FieldType('uint32_t',   's_first_error_ino',        **{"raw_field": "__le32", "reverse": True}      ),
        FieldType('uint64_t',   's_first_error_block',      **{"raw_field": "__le64", "reverse": True}      ),
        FieldType('char',       's_first_error_func',       **{"raw_field": "__u8", "length": 32}           ),
        FieldType('uint32_t',   's_first_error_line',       **{"raw_field": "__le32", "reverse": True}      ),
        FieldType('uint32_t',   's_last_error_time',        **{"raw_field": "__le32", "reverse": True}      ),
        FieldType('uint32_t',   's_last_error_ino',         **{"raw_field": "__le32", "reverse": True}      ),
        FieldType('uint32_t',   's_last_error_line',        **{"raw_field": "__le32", "reverse": True}      ),
        FieldType('uint64_t',   's_last_error_block',       **{"raw_field": "__le64", "reverse": True}      ),
        FieldType('char',       's_last_error_func',        **{"raw_field": "__u8", "length": 32}           ),
        FieldType('char',       's_mount_opts',             **{"raw_field": "__u8", "length": 64}           ),
        FieldType('uint32_t',   's_usr_quota_inum',         **{"raw_field": "__le32", "reverse": True}      ),
        FieldType('uint32_t',   's_grp_quota_inum',         **{"raw_field": "__le32", "reverse": True}      ),
        FieldType('uint32_t',   's_overhead_clusters',      **{"raw_field": "__le32", "reverse": True}      ),
        FieldType('uint32_t',   's_backup_bgs',             **{"raw_field": "__le32", "reverse": True, "length": 2}),
        FieldType('char',       's_encrypt_algos',          **{"raw_field": "__u8", "length": 4}            ),
        FieldType('char',       's_encrypt_pw_salt',        **{"raw_field": "__u8", "length": 16}           ),
        FieldType('uint32_t',   's_lpf_ino',                **{"raw_field": "__le32", "reverse": True}      ),
        FieldType('uint32_t',   's_prj_quota_inum',         **{"raw_field": "__le32", "reverse": True}      ),
        FieldType('uint32_t',   's_checksum_seed',          **{"raw_field": "__le32", "reverse": True}      ),
        FieldType('uint32_t',   's_reserved',               **{"raw_field": "__le32", "reverse": True, "length": 98}),
        FieldType('uint32_t',   's_checksum',               **{"raw_field": "__le32", "reverse": True}      ),
    ]
    # [calculate_size]: class ext4_super_block, size=1024

def size_calc():
    ext4_super_block().calculate_size(True)

if __name__ == '__main__':
    size_calc()

__all__  =  (
             # 'ext4_extent',
             # 'ext4_extent_idx',
             # 'ext4_extent_header',
             'ext4_inode',
             'ext4_super_block',
             'size_calc',
             )
vieyahn2017 commented 8 months ago

source.c

struct ext4_super_block {
/*00*/  __le32  s_inodes_count;     /* Inodes count */
    __le32  s_blocks_count_lo;  /* Blocks count */
    __le32  s_r_blocks_count_lo;    /* Reserved blocks count */
    __le32  s_free_blocks_count_lo; /* Free blocks count */
/*10*/  __le32  s_free_inodes_count;    /* Free inodes count */
    __le32  s_first_data_block; /* First Data Block */
    __le32  s_log_block_size;   /* Block size */
    __le32  s_log_cluster_size; /* Allocation cluster size */
/*20*/  __le32  s_blocks_per_group; /* # Blocks per group */
    __le32  s_clusters_per_group;   /* # Clusters per group */
    __le32  s_inodes_per_group; /* # Inodes per group */
    __le32  s_mtime;        /* Mount time */
/*30*/  __le32  s_wtime;        /* Write time */
    __le16  s_mnt_count;        /* Mount count */
    __le16  s_max_mnt_count;    /* Maximal mount count */
    __le16  s_magic;        /* Magic signature */
    __le16  s_state;        /* File system state */
    __le16  s_errors;       /* Behaviour when detecting errors */
    __le16  s_minor_rev_level;  /* minor revision level */
/*40*/  __le32  s_lastcheck;        /* time of last check */
    __le32  s_checkinterval;    /* max. time between checks */
    __le32  s_creator_os;       /* OS */
    __le32  s_rev_level;        /* Revision level */
/*50*/  __le16  s_def_resuid;       /* Default uid for reserved blocks */
    __le16  s_def_resgid;       /* Default gid for reserved blocks */
    /*
     * These fields are for EXT4_DYNAMIC_REV superblocks only.
     *
     * Note: the difference between the compatible feature set and
     * the incompatible feature set is that if there is a bit set
     * in the incompatible feature set that the kernel doesn't
     * know about, it should refuse to mount the filesystem.
     *
     * e2fsck's requirements are more strict; if it doesn't know
     * about a feature in either the compatible or incompatible
     * feature set, it must abort and not try to meddle with
     * things it doesn't understand...
     */
    __le32  s_first_ino;        /* First non-reserved inode */
    __le16  s_inode_size;       /* size of inode structure */
    __le16  s_block_group_nr;   /* block group # of this superblock */
    __le32  s_feature_compat;   /* compatible feature set */
/*60*/  __le32  s_feature_incompat; /* incompatible feature set */
    __le32  s_feature_ro_compat;    /* readonly-compatible feature set */
/*68*/  __u8    s_uuid[16];     /* 128-bit uuid for volume */
/*78*/  char    s_volume_name[16];  /* volume name */
/*88*/  char    s_last_mounted[64]; /* directory where last mounted */
/*C8*/  __le32  s_algorithm_usage_bitmap; /* For compression */
    /*
     * Performance hints.  Directory preallocation should only
     * happen if the EXT4_FEATURE_COMPAT_DIR_PREALLOC flag is on.
     */
    __u8    s_prealloc_blocks;  /* Nr of blocks to try to preallocate*/
    __u8    s_prealloc_dir_blocks;  /* Nr to preallocate for dirs */
    __le16  s_reserved_gdt_blocks;  /* Per group desc for online growth */
    /*
     * Journaling support valid if EXT4_FEATURE_COMPAT_HAS_JOURNAL set.
     */
/*D0*/  __u8    s_journal_uuid[16]; /* uuid of journal superblock */
/*E0*/  __le32  s_journal_inum;     /* inode number of journal file */
    __le32  s_journal_dev;      /* device number of journal file */
    __le32  s_last_orphan;      /* start of list of inodes to delete */
    __le32  s_hash_seed[4];     /* HTREE hash seed */
    __u8    s_def_hash_version; /* Default hash version to use */
    __u8    s_jnl_backup_type;
    __le16  s_desc_size;        /* size of group descriptor */
/*100*/ __le32  s_default_mount_opts;
    __le32  s_first_meta_bg;    /* First metablock block group */
    __le32  s_mkfs_time;        /* When the filesystem was created */
    __le32  s_jnl_blocks[17];   /* Backup of the journal inode */
    /* 64bit support valid if EXT4_FEATURE_COMPAT_64BIT */
/*150*/ __le32  s_blocks_count_hi;  /* Blocks count */
    __le32  s_r_blocks_count_hi;    /* Reserved blocks count */
    __le32  s_free_blocks_count_hi; /* Free blocks count */
    __le16  s_min_extra_isize;  /* All inodes have at least # bytes */
    __le16  s_want_extra_isize;     /* New inodes should reserve # bytes */
    __le32  s_flags;        /* Miscellaneous flags */
    __le16  s_raid_stride;      /* RAID stride */
    __le16  s_mmp_update_interval;  /* # seconds to wait in MMP checking */
    __le64  s_mmp_block;            /* Block for multi-mount protection */
    __le32  s_raid_stripe_width;    /* blocks on all data disks (N*stride)*/
    __u8    s_log_groups_per_flex;  /* FLEX_BG group size */
    __u8    s_checksum_type;    /* metadata checksum algorithm used */
    __u8    s_encryption_level; /* versioning level for encryption */
    __u8    s_reserved_pad;     /* Padding to next 32bits */
    __le64  s_kbytes_written;   /* nr of lifetime kilobytes written */
    __le32  s_snapshot_inum;    /* Inode number of active snapshot */
    __le32  s_snapshot_id;      /* sequential ID of active snapshot */
    __le64  s_snapshot_r_blocks_count; /* reserved blocks for active
                          snapshot's future use */
    __le32  s_snapshot_list;    /* inode number of the head of the
                       on-disk snapshot list */

    __le32  s_error_count;      /* number of fs errors */
    __le32  s_first_error_time; /* first time an error happened */
    __le32  s_first_error_ino;  /* inode involved in first error */
    __le64  s_first_error_block;    /* block involved of first error */
    __u8    s_first_error_func[32]; /* function where the error happened */
    __le32  s_first_error_line; /* line number where error happened */
    __le32  s_last_error_time;  /* most recent time of an error */
    __le32  s_last_error_ino;   /* inode involved in last error */
    __le32  s_last_error_line;  /* line number where error happened */
    __le64  s_last_error_block; /* block involved of last error */
    __u8    s_last_error_func[32];  /* function where the error happened */

    __u8    s_mount_opts[64];
    __le32  s_usr_quota_inum;   /* inode for tracking user quota */
    __le32  s_grp_quota_inum;   /* inode for tracking group quota */
    __le32  s_overhead_clusters;    /* overhead blocks/clusters in fs */
    __le32  s_backup_bgs[2];    /* groups with sparse_super2 SBs */
    __u8    s_encrypt_algos[4]; /* Encryption algorithms in use  */
    __u8    s_encrypt_pw_salt[16];  /* Salt used for string2key algorithm */
    __le32  s_lpf_ino;      /* Location of the lost+found inode */
    __le32  s_prj_quota_inum;   /* inode for tracking project quota */
    __le32  s_checksum_seed;    /* crc32c(uuid) if csum_seed set */
    __le32  s_reserved[98];     /* Padding to the end of the block */
    __le32  s_checksum;     /* crc32c(superblock) */
};
vieyahn2017 commented 8 months ago

basecode_gen_ccode.py

#!/usr/bin/python
# -*- coding: utf-8 -*-

from basecode import *
## 需要注释掉basecode里的 from basecode_structs import *

# python basecode.py -s source.c 单独拎出来
if __name__ == '__main__':
    # gernel_test()
    src_code = "source.c"
    src_file = open(src_code, mode='r', encoding="utf8")
    ccode = src_file.read()
    ccode_result, class_name = FormatDecoder.parse_struct(ccode)
    exec(ccode_result)
    exec("%s().calculate_size(True)" % class_name)
    # loc = locals()
    # test_class = loc[class_name]
    # print(test_class)  # <class '__main__.ext_extent'>
    # exec("%s.__init__().calculate_size()" % test_class)  # 不行
vieyahn2017 commented 8 months ago

python basecode.py -c ext4_inode -r hexdump

hexdump.rst

00000000  a0 81 00 00 18 1b 00 00  13 e4 15 62 59 e4 15 62  |...........bY..b|
00000010  59 e4 15 62 00 00 00 00  00 00 01 00 10 00 00 00  |Y..b............|
00000020  00 00 08 00 01 00 00 00  0a f3 02 00 04 00 00 00  |................|
00000030  00 00 00 00 00 00 00 00  01 00 00 00 00 88 00 00  |................|
00000040  01 00 00 00 01 00 00 00  00 8a 00 00 00 00 00 00  |................|
00000050  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
00000060  00 00 00 00 05 03 ac b3  00 00 00 00 00 00 00 00  |................|
00000070  00 00 00 00 00 00 00 00  00 00 00 00 67 e3 00 00  |............g...|
00000080  20 00 e9 a2 28 aa 96 d7  28 aa 96 d7 ac da c4 43  | ...(...(......C|
00000090  13 e4 15 62 ac da c4 43  00 00 00 00 00 00 00 00  |...b...C........|

测试效果

python basecode.py -c ext4_inode -r hexdump
[parse_hexdump_rst]: b'\xa0\x81\x00\x00\x18\x1b\x00\x00\x13\xe4\x15bY\xe4\x15bY\xe4\x15b\x00\x00\x00\x00\x00\x00\x01\x00\x10\x00\x00\x00\x00\x00\x08\x00\x01\x00\x00\x00\n\xf3\x02\x00\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\x88\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x8a\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x05\x03\xac\xb3\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00g\xe3\x00\x00 \x00\xe9\xa2(\xaa\x96\xd7(\xaa\x96\xd7\xac\xda\xc4C\x13\xe4\x15b\xac\xda\xc4C\x00\x00\x00\x00\x00\x00\x00\x00'
struct ext4_inode {
    __le16    i_mode                         : a0 81                         : 0x81a0                         :                33184                     
    __le16    i_uid                          : 00 00                         : 0x0000                         :                    0                     
    __le32    i_size_lo                      : 18 1b 00 00                   : 0x00001b18                     :                 6936                     
    __le32    i_atime                        : 13 e4 15 62                   : 0x6215e413                     :           1645601811  : 2022-02-23 15:36:51
    __le32    i_ctime                        : 59 e4 15 62                   : 0x6215e459                     :           1645601881  : 2022-02-23 15:38:01
    __le32    i_mtime                        : 59 e4 15 62                   : 0x6215e459                     :           1645601881  : 2022-02-23 15:38:01
    __le32    i_dtime                        : 00 00 00 00                   : 0x00000000                     :                    0  : 1970-01-01 08:00:00
    __le16    i_gid                          : 00 00                         : 0x0000                         :                    0                     
    __le16    i_links_count                  : 01 00                         : 0x0001                         :                    1                     
    __le32    i_blocks_lo                    : 10 00 00 00                   : 0x00000010                     :                   16                     
    __le32    i_flags                        : 00 00 08 00                   : 0x00080000                     :               524288                     
    __le32    l_i_version                    : 01 00 00 00                   : 0x00000001                     :                    1                     
              struct ext4_extent_header      : 0a f3 02 00 04 00 00 00 00 00 00 00                            :  sizeof=12          
              struct ext4_extent_idx         : 00 00 00 00 01 00 00 00 00 88 00 00                            :  sizeof=12          
              struct ext4_extent_idx         : 01 00 00 00 01 00 00 00 00 8a 00 00                            :  sizeof=12          
              struct ext4_extent_idx         : 00 00 00 00 00 00 00 00 00 00 00 00                            :  sizeof=12          
              struct ext4_extent_idx         : 00 00 00 00 00 00 00 00 00 00 00 00                            :  sizeof=12          
    __le32    i_generation                   : 05 03 ac b3                   : 0xb3ac0305                     :           3014394629                     
    __le32    i_file_acl_lo                  : 00 00 00 00                   : 0x00000000                     :                    0                     
    __le32    i_size_high                    : 00 00 00 00                   : 0x00000000                     :                    0                     
    __le32    i_obso_faddr                   : 00 00 00 00                   : 0x00000000                     :                    0                     
    __le16    l_i_blocks_high                : 00 00                         : 0x0000                         :                    0                     
    __le16    l_i_file_acl_high              : 00 00                         : 0x0000                         :                    0                     
    __le16    l_i_uid_high                   : 00 00                         : 0x0000                         :                    0                     
    __le16    l_i_gid_high                   : 00 00                         : 0x0000                         :                    0                     
    __le16    l_i_checksum_lo                : 67 e3                         : 0xe367                         :                58215                     
    __le16    l_i_reserved                   : 00 00                         : 0x0000                         :                    0                     
    __le16    i_extra_isize                  : 20 00                         : 0x0020                         :                   32                     
    __le16    i_checksum_hi                  : e9 a2                         : 0xa2e9                         :                41705                     
    __le32    i_ctime_extra                  : 28 aa 96 d7                   : 0xd796aa28                     :           3616975400                     
    __le32    i_mtime_extra                  : 28 aa 96 d7                   : 0xd796aa28                     :           3616975400                     
    __le32    i_atime_extra                  : ac da c4 43                   : 0x43c4daac                     :           1136974508                     
    __le32    i_crtime                       : 13 e4 15 62                   : 0x6215e413                     :           1645601811  : 2022-02-23 15:36:51
    __le32    i_crtime_extra                 : ac da c4 43                   : 0x43c4daac                     :           1136974508                     
    __le32    i_version_hi                   : 00 00 00 00                   : 0x00000000                     :                    0                     
    __le32    i_projid                       : 00 00 00 00                   : 0x00000000                     :                    0                     
}
 >>> extend instances :
struct ext4_extent_header {
    __le16    eh_magic                       : 0a f3                         : 0xf30a                         :                62218                     
    __le16    eh_entries                     : 02 00                         : 0x0002                         :                    2                     
    __le16    eh_max                         : 04 00                         : 0x0004                         :                    4                     
    __le16    eh_depth                       : 00 00                         : 0x0000                         :                    0                     
    __le32    eh_generation                  : 00 00 00 00                   : 0x00000000                     :                    0                     
}
struct ext4_extent_idx {
    __le32    ei_block                       : 00 00 00 00                   : 0x00000000                     :                    0                     
    __le32    ei_leaf_lo                     : 01 00 00 00                   : 0x00000001                     :                    1                     
    __le16    ei_leaf_hi                     : 00 88                         : 0x8800                         :                34816                     
    __u16     ei_unused                      : 00 00                         : 0x0000                         :                    0                     
}
struct ext4_extent_idx {
    __le32    ei_block                       : 01 00 00 00                   : 0x00000001                     :                    1                     
    __le32    ei_leaf_lo                     : 01 00 00 00                   : 0x00000001                     :                    1                     
    __le16    ei_leaf_hi                     : 00 8a                         : 0x8a00                         :                35328                     
    __u16     ei_unused                      : 00 00                         : 0x0000                         :                    0                     
}
struct ext4_extent_idx {
    __le32    ei_block                       : 00 00 00 00                   : 0x00000000                     :                    0                     
    __le32    ei_leaf_lo                     : 00 00 00 00                   : 0x00000000                     :                    0                     
    __le16    ei_leaf_hi                     : 00 00                         : 0x0000                         :                    0                     
    __u16     ei_unused                      : 00 00                         : 0x0000                         :                    0                     
}
struct ext4_extent_idx {
    __le32    ei_block                       : 00 00 00 00                   : 0x00000000                     :                    0                     
    __le32    ei_leaf_lo                     : 00 00 00 00                   : 0x00000000                     :                    0                     
    __le16    ei_leaf_hi                     : 00 00                         : 0x0000                         :                    0                     
    __u16     ei_unused                      : 00 00                         : 0x0000                         :                    0                     
}
vieyahn2017 commented 8 months ago

python basecode.py -c ext4_super_block -r vi

vi -b ttt1 然后 :%!xxd 转换成十六进制,复制其中的文本出来 hexdump -Cv ttt1

vib2xxd.rst

00000400: 0000 6400 0000 9001 0000 1400 e87c 8701  ..d..........|..
00000410: f5ff 6300 0000 0000 0200 0000 0200 0000  ..c.............
00000420: 0080 0000 0080 0000 0020 0000 766f b763  ......... ..vo.c
00000430: 766f b763 0100 ffff 53ef 0100 0100 0000  vo.c....S.......
00000440: 3f6f b763 0000 0000 0000 0000 0100 0000  ?o.c............
00000450: 0000 0000 0b00 0000 0001 0000 3c00 0000  ............<...
00000460: c602 0000 6b04 0000 40a8 8b44 4017 470d  ....k...@..D@.G.
00000470: 8790 4978 b37c de41 0000 0000 0000 0000  ..Ix.|.A........
00000480: 0000 0000 0000 0000 0000 0000 0000 0000  ................
00000490: 0000 0000 0000 0000 0000 0000 0000 0000  ................
000004a0: 0000 0000 0000 0000 0000 0000 0000 0000  ................
000004b0: 0000 0000 0000 0000 0000 0000 0000 0000  ................
000004c0: 0000 0000 0000 0000 0000 0000 0000 0004  ................
000004d0: 0000 0000 0000 0000 0000 0000 0000 0000  ................
000004e0: 0800 0000 0000 0000 0000 0000 4543 2fa5  ............EC/.
000004f0: 4baf 41ee b0ea 8ae1 b57a 0f20 0101 4000  K.A......z. ..@.
00000500: 0c00 0000 0000 0000 3f6f b763 0af3 0400  ........?o.c....
00000510: 0400 0000 0000 0000 0000 0000 0080 0000  ................
00000520: 0080 c800 0080 0000 0080 0000 0000 c900  ................
00000530: 0000 0100 0080 0000 0080 c900 0080 0100  ................
00000540: 0080 0000 0000 ca00 0000 0000 0000 0020  ...............
00000550: 0000 0000 0000 0000 0000 0000 2000 2000  ............ . .
00000560: 0100 0000 0000 0000 0000 0000 0000 0000  ................
00000570: 0000 0000 0401 0000 ec10 0000 0000 0000  ................
00000580: 0000 0000 0000 0000 0000 0000 0000 0000  ................
00000590: 0000 0000 0000 0000 0000 0000 0000 0000  ................
000005a0: 0000 0000 0000 0000 0000 0000 0000 0000  ................
000005b0: 0000 0000 0000 0000 0000 0000 0000 0000  ................
000005c0: 0000 0000 0000 0000 0000 0000 0000 0000  ................
000005d0: 0000 0000 0000 0000 0000 0000 0000 0000  ................
000005e0: 0000 0000 0000 0000 0000 0000 0000 0000  ................
000005f0: 0000 0000 0000 0000 0000 0000 0000 0000  ................
00000600: 0000 0000 0000 0000 0000 0000 0000 0000  ................
00000610: 0000 0000 0000 0000 0000 0000 0000 0000  ................
00000620: 0000 0000 0000 0000 0000 0000 0000 0000  ................
00000630: 0000 0000 0000 0000 0000 0000 0000 0000  ................
00000640: 0000 0000 0000 0000 0000 0000 0000 0000  ................
00000650: 0000 0000 0000 0000 0000 0000 0000 0000  ................
00000660: 0000 0000 0000 0000 0000 0000 0000 0000  ................
00000670: 0000 0000 0000 0000 0000 0000 0000 0000  ................
00000680: 0000 0000 0000 0000 0000 0000 0000 0000  ................
00000690: 0000 0000 0000 0000 0000 0000 0000 0000  ................
000006a0: 0000 0000 0000 0000 0000 0000 0000 0000  ................
000006b0: 0000 0000 0000 0000 0000 0000 0000 0000  ................
000006c0: 0000 0000 0000 0000 0000 0000 0000 0000  ................
000006d0: 0000 0000 0000 0000 0000 0000 0000 0000  ................
000006e0: 0000 0000 0000 0000 0000 0000 0000 0000  ................
000006f0: 0000 0000 0000 0000 0000 0000 0000 0000  ................
00000700: 0000 0000 0000 0000 0000 0000 0000 0000  ................
00000710: 0000 0000 0000 0000 0000 0000 0000 0000  ................
00000720: 0000 0000 0000 0000 0000 0000 0000 0000  ................
00000730: 0000 0000 0000 0000 0000 0000 0000 0000  ................
00000740: 0000 0000 0000 0000 0000 0000 0000 0000  ................
00000750: 0000 0000 0000 0000 0000 0000 0000 0000  ................
00000760: 0000 0000 0000 0000 0000 0000 0000 0000  ................
00000770: 0000 0000 0000 0000 0000 0000 0000 0000  ................
00000780: 0000 0000 0000 0000 0000 0000 0000 0000  ................
00000790: 0000 0000 0000 0000 0000 0000 0000 0000  ................
000007a0: 0000 0000 0000 0000 0000 0000 0000 0000  ................
000007b0: 0000 0000 0000 0000 0000 0000 0000 0000  ................
000007c0: 0000 0000 0000 0000 0000 0000 0000 0000  ................
000007d0: 0000 0000 0000 0000 0000 0000 0000 0000  ................
000007e0: 0000 0000 0000 0000 0000 0000 0000 0000  ................
000007f0: 0000 0000 0000 0000 0000 0000 29b6 1249  ............)..I

结果为

[parse_vib2xxd_rst]: b'\x00\x00d\x00\x00\x00\x90\x01\x00\x00\x14\x00\xe8|\x87\x01\xf5\xffc\x00\x00\x00\x00\x00\x02\x00\x00\x00\x02\x00\x00\x00\x00\x80\x00\x00\x00\x80\x00\x00\x00 \x00\x00vo\xb7cvo\xb7c\x01\x00\xff\xffS\xef\x01\x00\x01\x00\x00\x00?o\xb7c\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x0b\x00\x00\x00\x00\x01\x00\x00<\x00\x00\x00\xc6\x02\x00\x00k\x04\x00\x00@\xa8\x8bD@\x17G\r\x87\x90Ix\xb3|\xdeA\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x08\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00EC/\xa5K\xafA\xee\xb0\xea\x8a\xe1\xb5z\x0f \x01\x01@\x00\x0c\x00\x00\x00\x00\x00\x00\x00?o\xb7c\n\xf3\x04\x00\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x80\x00\x00\x00\x80\xc8\x00\x00\x80\x00\x00\x00\x80\x00\x00\x00\x00\xc9\x00\x00\x00\x01\x00\x00\x80\x00\x00\x00\x80\xc9\x00\x00\x80\x01\x00\x00\x80\x00\x00\x00\x00\xca\x00\x00\x00\x00\x00\x00\x00\x00 \x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00 \x00 \x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x04\x01\x00\x00\xec\x10\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00)\xb6\x12I'
struct ext4_super_block {
    __le32    s_inodes_count                 : 00 00 64 00                   : 0x00640000                     :              6553600
    __le32    s_blocks_count_lo              : 00 00 90 01                   : 0x01900000                     :             26214400
    __le32    s_r_blocks_count_lo            : 00 00 14 00                   : 0x00140000                     :              1310720
    __le32    s_free_blocks_count_lo         : e8 7c 87 01                   : 0x01877ce8                     :             25656552
    __le32    s_free_inodes_count            : f5 ff 63 00                   : 0x0063fff5                     :              6553589
    __le32    s_first_data_block             : 00 00 00 00                   : 0x00000000                     :                    0
    __le32    s_log_block_size               : 02 00 00 00                   : 0x00000002                     :                    2
    __le32    s_log_cluster_size             : 02 00 00 00                   : 0x00000002                     :                    2
    __le32    s_blocks_per_group             : 00 80 00 00                   : 0x00008000                     :                32768
    __le32    s_clusters_per_group           : 00 80 00 00                   : 0x00008000                     :                32768
    __le32    s_inodes_per_group             : 00 20 00 00                   : 0x00002000                     :                 8192
    __le32    s_mtime                        : 76 6f b7 63                   : 0x63b76f76                     :           1672966006  : 2023-01-06 08:46:46
    __le32    s_wtime                        : 76 6f b7 63                   : 0x63b76f76                     :           1672966006  : 2023-01-06 08:46:46
    __le16    s_mnt_count                    : 01 00                         : 0x0001                         :                    1
    __le16    s_max_mnt_count                : ff ff                         : 0xffff                         :                65535
    __le16    s_magic                        : 53 ef                         : 0xef53                         :                61267
    __le16    s_state                        : 01 00                         : 0x0001                         :                    1
    __le16    s_errors                       : 01 00                         : 0x0001                         :                    1
    __le16    s_minor_rev_level              : 00 00                         : 0x0000                         :                    0
    __le32    s_lastcheck                    : 3f 6f b7 63                   : 0x63b76f3f                     :           1672965951
    __le32    s_checkinterval                : 00 00 00 00                   : 0x00000000                     :                    0
    __le32    s_creator_os                   : 00 00 00 00                   : 0x00000000                     :                    0
    __le32    s_rev_level                    : 01 00 00 00                   : 0x00000001                     :                    1
    __le16    s_def_resuid                   : 00 00                         : 0x0000                         :                    0
    __le16    s_def_resgid                   : 00 00                         : 0x0000                         :                    0
    __le32    s_first_ino                    : 0b 00 00 00                   : 0x0000000b                     :                   11
    __le16    s_inode_size                   : 00 01                         : 0x0100                         :                  256
    __le16    s_block_group_nr               : 00 00                         : 0x0000                         :                    0
    __le32    s_feature_compat               : 3c 00 00 00                   : 0x0000003c                     :                   60
    __le32    s_feature_incompat             : c6 02 00 00                   : 0x000002c6                     :                  710
    __le32    s_feature_ro_compat            : 6b 04 00 00                   : 0x0000046b                     :                 1131
    __u8      s_uuid                         : 40 a8 8b 44 40 ...b3 7c de 41 : 0x40a88b444017470d...b37cde41  : @¨�D@�G��Ix³|ÞA
    char      s_volume_name                  : 00 00 00 00 00 ...00 00 00 00 : 0x0000000000000000...00000000  :
    char      s_last_mounted                 : 00 00 00 00 00 ...00 00 00 00 : 0x0000000000000000...00000000  :
    __le32    s_algorithm_usage_bitmap       : 00 00 00 00                   : 0x00000000                     :                    0
    __u8      s_prealloc_blocks              : 00                            : 0x00                           :                    0
    __u8      s_prealloc_dir_blocks          : 00                            : 0x00                           :                    0
    __le16    s_reserved_gdt_blocks          : 00 04                         : 0x0400                         :                 1024
    __u8      s_journal_uuid                 : 00 00 00 00 00 ...00 00 00 00 : 0x0000000000000000...00000000  :
    __le32    s_journal_inum                 : 08 00 00 00                   : 0x00000008                     :                    8
    __le32    s_journal_dev                  : 00 00 00 00                   : 0x00000000                     :                    0
    __le32    s_last_orphan                  : 00 00 00 00                   : 0x00000000                     :                    0
    __le32    s_hash_seed                    : 45 43 2f a5 4b ...b5 7a 0f 20 : 0x200f7ab5e18aeab0...a52f4345  : [2771338053, 3997282123, 3783977648, 537885365]
    __u8      s_def_hash_version             : 01                            : 0x01                           :                    1
    __u8      s_jnl_backup_type              : 01                            : 0x01                           :                    1
    __le16    s_desc_size                    : 40 00                         : 0x0040                         :                   64
    __le32    s_default_mount_opts           : 0c 00 00 00                   : 0x0000000c                     :                   12
    __le32    s_first_meta_bg                : 00 00 00 00                   : 0x00000000                     :                    0
    __le32    s_mkfs_time                    : 3f 6f b7 63                   : 0x63b76f3f                     :           1672965951  : 2023-01-06 08:45:51
    __le32    s_jnl_blocks                   : 0a f3 04 00 04 ...00 00 00 20 : 0x2000000000000000...0004f30a  : [324362, 4, 0, 0, 32768, 13139968, 32768, 32768, 13172736, 65536, 32768, 13205504, 98304, 32768, 13238272, 0, 536870912]
    __le32    s_blocks_count_hi              : 00 00 00 00                   : 0x00000000                     :                    0
    __le32    s_r_blocks_count_hi            : 00 00 00 00                   : 0x00000000                     :                    0
    __le32    s_free_blocks_count_hi         : 00 00 00 00                   : 0x00000000                     :                    0
    __le16    s_min_extra_isize              : 20 00                         : 0x0020                         :                   32
    __le16    s_want_extra_isize             : 20 00                         : 0x0020                         :                   32
    __le32    s_flags                        : 01 00 00 00                   : 0x00000001                     :                    1
    __le16    s_raid_stride                  : 00 00                         : 0x0000                         :                    0
    __le16    s_mmp_update_interval          : 00 00                         : 0x0000                         :                    0
    __le64    s_mmp_block                    : 00 00 00 00 00 00 00 00       : 0x0000000000000000             :                    0
    __le32    s_raid_stripe_width            : 00 00 00 00                   : 0x00000000                     :                    0
    __u8      s_log_groups_per_flex          : 04                            : 0x04                           :                    4
    __u8      s_checksum_type                : 01                            : 0x01                           :                    1
    __u8      s_encryption_level             : 00                            : 0x00                           :                    0
    __u8      s_reserved_pad                 : 00                            : 0x00                           :                    0
    __le64    s_kbytes_written               : ec 10 00 00 00 00 00 00       : 0x00000000000010ec             :                 4332
    __le32    s_snapshot_inum                : 00 00 00 00                   : 0x00000000                     :                    0
    __le32    s_snapshot_id                  : 00 00 00 00                   : 0x00000000                     :                    0
    __le64    s_snapshot_r_blocks_count      : 00 00 00 00 00 00 00 00       : 0x0000000000000000             :                    0
    __le32    s_snapshot_list                : 00 00 00 00                   : 0x00000000                     :                    0
    __le32    s_error_count                  : 00 00 00 00                   : 0x00000000                     :                    0
    __le32    s_first_error_time             : 00 00 00 00                   : 0x00000000                     :                    0  : 1970-01-01 08:00:00
    __le32    s_first_error_ino              : 00 00 00 00                   : 0x00000000                     :                    0
    __le64    s_first_error_block            : 00 00 00 00 00 00 00 00       : 0x0000000000000000             :                    0
    __u8      s_first_error_func             : 00 00 00 00 00 ...00 00 00 00 : 0x0000000000000000...00000000  :
    __le32    s_first_error_line             : 00 00 00 00                   : 0x00000000                     :                    0
    __le32    s_last_error_time              : 00 00 00 00                   : 0x00000000                     :                    0  : 1970-01-01 08:00:00
    __le32    s_last_error_ino               : 00 00 00 00                   : 0x00000000                     :                    0
    __le32    s_last_error_line              : 00 00 00 00                   : 0x00000000                     :                    0
    __le64    s_last_error_block             : 00 00 00 00 00 00 00 00       : 0x0000000000000000             :                    0
    __u8      s_last_error_func              : 00 00 00 00 00 ...00 00 00 00 : 0x0000000000000000...00000000  :
    __u8      s_mount_opts                   : 00 00 00 00 00 ...00 00 00 00 : 0x0000000000000000...00000000  :
    __le32    s_usr_quota_inum               : 00 00 00 00                   : 0x00000000                     :                    0
    __le32    s_grp_quota_inum               : 00 00 00 00                   : 0x00000000                     :                    0
    __le32    s_overhead_clusters            : 00 00 00 00                   : 0x00000000                     :                    0
    __le32    s_backup_bgs                   : 00 00 00 00 00 00 00 00       : 0x0000000000000000             : [0, 0]
    __u8      s_encrypt_algos                : 00 00 00 00                   : 0x00000000                     :
    __u8      s_encrypt_pw_salt              : 00 00 00 00 00 ...00 00 00 00 : 0x0000000000000000...00000000  :
    __le32    s_lpf_ino                      : 00 00 00 00                   : 0x00000000                     :                    0
    __le32    s_prj_quota_inum               : 00 00 00 00                   : 0x00000000                     :                    0
    __le32    s_checksum_seed                : 00 00 00 00                   : 0x00000000                     :                    0
    __le32    s_reserved                     : 00 00 00 00 00 ...00 00 00 00 : 0x0000000000000000...00000000  : [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
    __le32    s_checksum                     : 29 b6 12 49                   : 0x4912b629                     :           1225963049
}
vieyahn2017 commented 8 months ago

basecode_decode_bytes.py

#!/usr/bin/python
# -*- coding: utf-8 -*-

from basecode import *

# python basecode.py -c ext4_extent -h "10 00 00 00  01 00 02 00 1E 86 00 00" 单独拎出来
def decode_hex(class_type, hex_input):

    loc = locals()
    try:
        exec("test_obj = {}()".format(class_type))
    except NameError:
        print('param <class> %s  is not existed.' % class_type)
        print('%s -c <class> -h <hex chars input>' % sys.argv[0])
        exit(1)
    test_obj = loc['test_obj']
    test_obj_size = test_obj.calculate_size()

    formater = FormatDecoder('input')
    input_bytes, input_length = formater.parse_chr_array_2_bytes(hex_input)
    if input_length < test_obj_size:
        print("input hex size [%s] less than sizeof(%s)=[%s]" % (input_length, class_type, test_obj_size))
        exit(1)
    elif input_length > test_obj_size:
        print("input hex size [%s] more than sizeof(%s)=[%s], " % (input_length, class_type, test_obj_size))
        input_bytes = input_bytes[:test_obj_size]
        print("only use the previous required data: %s" % input_bytes)

    test_obj.decode(input_bytes)
    # test_obj.tojson_print1()
    test_obj.print_cmp_with_hex(formater.parse_chr_array_2_hex_list(hex_input))

def test01():
    class_type = "ext4_extent"
    hex_input = "10 00 00 00  01 00 02 00 1E 86 00 00"
    decode_hex(class_type, hex_input)

"""
以这个inode=18为例,来研究extent_tree吧

00000120  00 00 08 00 01 00 00 00  0a f3 01 00 04 00 00 00  |................|
00000130  00 00 00 00 00 00 00 00  04 00 00 00 b0 84 00 00  |................|
00000140  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
00000150  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
00000160  00 00 00 00  

debugfs:  stat <18>
EXTENTS:
(0-3):33968-33971

"""

if __name__ == '__main__':
    class_type = "ext4_extent_header"
    hex_input = "0a f3 01 00 04 00 00 00  00 00 00 00"
    decode_hex(class_type, hex_input)
    class_type = "ext4_extent_idx"
    hex_input = "00 00 00 00  04 00 00 00 b0 84 00 00 "
    decode_hex(class_type, hex_input)