diff --git a/parse_xml/Src/parse_xml.py b/parse_xml/Src/parse_xml.py index 5c0ebd8..13c52b8 100644 --- a/parse_xml/Src/parse_xml.py +++ b/parse_xml/Src/parse_xml.py @@ -1,5 +1,5 @@ -# pyinstaller --onefile --distpath . --workpath ./build --specpath ./build parse_xml.py -# python -m nuitka --standalone --onefile --output-dir=./build parse_xml.py +# pyinstaller --onefile --distpath ./parse_xml --workpath ./build --specpath ./build parse_xml/Src/parse_xml.py +# python -m nuitka --standalone --onefile --output-dir=./build parse_xml/Src/parse_xml.py import xml.etree.ElementTree as ET import xml.dom.minidom import sys @@ -12,6 +12,16 @@ if len(sys.argv) < 3: input_path = sys.argv[1] info_path = sys.argv[2] +base_type_sizes = { + "char": 2, + "short": 2, + "int": 2, + "long": 4, + "long long": 8, + "float": 4, + "double": 8, +} + if len(sys.argv) >= 4: output_path = sys.argv[3] else: @@ -42,13 +52,25 @@ def get_attr(die, attr_type): return None def get_die_size(die): - """Вернуть размер DIE в байтах из атрибута DW_AT_byte_size.""" + """Вернуть размер DIE в байтах из атрибута DW_AT_byte_size или по ключевым словам имени типа.""" + + # Сначала пытаемся получить размер из DW_AT_byte_size for attr in die.findall("attribute"): type_elem = attr.find("type") if type_elem is not None and type_elem.text == "DW_AT_byte_size": const_elem = attr.find("value/const") if const_elem is not None: return int(const_elem.text, 0) + + # Если не нашли, пробуем определить размер по ключевым словам в имени типа + name_elem = die.find("attribute[@name='DW_AT_name']/value/const") + if name_elem is not None: + type_name = name_elem.text.lower() + + for key, size in base_type_sizes.items(): + if key in type_name: + return size + return None def resolve_type_die(type_id): @@ -136,48 +158,66 @@ def parse_offset(offset_text): return 0 + def get_array_dimensions(array_die): - """Рекурсивно получить размеры всех измерений массива из DIE с тегом DW_TAG_array_type.""" + """ + Собрать размеры всех измерений массива. + Возвращает список размеров [dim0, dim1, ...] во внешне-внутреннем порядке. + """ dims = [] - # Ищем размер текущего измерения - # Размер может быть в DW_AT_upper_bound, либо вычисляться из DW_AT_byte_size и типа элемента - # Но часто в DWARF размер указывается через дочерние die с тегом DW_TAG_subrange_type - - subrange = None + # Ищем DW_TAG_subrange_type — для каждого измерения for child in array_die.findall("die"): - if child.findtext("tag") == "DW_TAG_subrange_type": - subrange = child - break + if child.findtext("tag") != "DW_TAG_subrange_type": + continue - dim_size = None - if subrange is not None: - # Ищем атрибут DW_AT_upper_bound - ub_attr = get_attr(subrange, "DW_AT_upper_bound") + dim_size = None + + # Попытка получить upper_bound + ub_attr = get_attr(child, "DW_AT_upper_bound") if ub_attr is not None: val = ub_attr.find("value/const") if val is not None: - # Размер измерения равен верхней границе + 1 (т.к. верхняя граница индексируется с 0) - dim_size = int(val.text, 0) + 1 + try: + # В DWARF верхняя граница включительно, значит размер = upper_bound + 1 + dim_size = int(val.text, 0) + 1 + except Exception: + pass - if dim_size is None: - # Если размер не нашли, попробуем вычислить через общий размер / размер элемента + # Если не получилось — попытаться из count + if dim_size is None: + ct_attr = get_attr(child, "DW_AT_count") + if ct_attr is not None: + val = ct_attr.find("value/const") + if val is not None: + try: + dim_size = int(val.text, 0) + except Exception: + pass + + # Если ничего не найдено — ставим 0 + if dim_size is None: + dim_size = 0 + + dims.append(dim_size) + + # Если subrange не нашли (например, в случае typedef), попробуем через размер типа + if not dims: arr_size = get_die_size(array_die) + elem_size = None element_type_ref = get_attr(array_die, "DW_AT_type") if element_type_ref is not None and element_type_ref.find("ref") is not None: element_type_id = element_type_ref.find("ref").attrib.get("idref") - element_type_die = resolve_type_die(element_type_id) - elem_size = get_die_size(element_type_die) if element_type_die is not None else None + elem_die = resolve_type_die(element_type_id) + if elem_die is not None: + elem_size = get_die_size(elem_die) + + if arr_size is not None and elem_size: + dims.append(arr_size // elem_size) + else: + dims.append(0) - if arr_size is not None and elem_size: - dim_size = arr_size // elem_size - - if dim_size is None: - dim_size = 0 # Неизвестно - - dims.append(dim_size) - - # Рекурсивно проверяем, если элемент типа тоже массив (многомерный) + # Рекурсия — если элементный тип массива тоже массив, добавляем размеры вложенного element_type_ref = get_attr(array_die, "DW_AT_type") if element_type_ref is not None and element_type_ref.find("ref") is not None: element_type_id = element_type_ref.find("ref").attrib.get("idref") @@ -188,60 +228,79 @@ def get_array_dimensions(array_die): return dims - +def get_base_type_die(array_die): + """Спускаемся по цепочке DW_AT_type, пока не дойдем до не-массива (базового типа).""" + current_die = array_die + while True: + ref = get_attr(current_die, "DW_AT_type") + if ref is None or ref.find("ref") is None: + break + next_die = resolve_type_die(ref.find("ref").attrib.get("idref")) + if next_die is None: + break + if next_die.findtext("tag") == "DW_TAG_array_type": + current_die = next_die + else: + return next_die + return current_die def handle_array_type(member_elem, resolved_type, offset=0): dims = get_array_dimensions(resolved_type) - # Получаем элементарный тип массива (наибольший элемент в цепочке массивов) - def get_base_element_type(die): - ref = get_attr(die, "DW_AT_type") - if ref is not None and ref.find("ref") is not None: - type_id = ref.find("ref").attrib.get("idref") - type_die = resolve_type_die(type_id) - if type_die is not None and type_die.findtext("tag") == "DW_TAG_array_type": - return get_base_element_type(type_die) - else: - return type_die - return None + # Определяем базовый тип (не массив) + base_die = get_base_type_die(resolved_type) + base_name = "unknown" + base_size = None + if base_die is not None: + base_id = base_die.attrib.get("id") + if base_id: + base_name = get_type_name(base_id) + base_size = get_die_size(base_die) + else: + base_name = get_type_name(base_die.attrib.get("id", "")) - element_type_die = get_base_element_type(resolved_type) - element_type_name = get_type_name(element_type_die.attrib.get("id")) if element_type_die is not None else "unknown" + member_elem.set("type", base_name + "[]" * len(dims)) - # Формируем строку типа с нужным количеством [] - type_with_array = element_type_name + "[]" * len(dims) - member_elem.set("type", type_with_array) + # Вычисляем общий размер массива — произведение размеров * размер базового элемента + if base_size is None: + base_size = 0 - # Размер всего массива - arr_size = get_die_size(resolved_type) - if arr_size is not None: - member_elem.set("size", str(arr_size)) + total_elements = 1 + for d in dims: + if d == 0: + total_elements = 0 + break + total_elements *= d - # Добавляем атрибуты size1, size2, ... + total_size = total_elements * base_size if base_size is not None else 0 + if total_size: + member_elem.set("size", str(total_size)) + else: + # fallback: если не удалось, можно попробовать get_die_size + arr_size = get_die_size(resolved_type) + if arr_size: + member_elem.set("size", str(arr_size)) + + # Записываем размеры измерений size1, size2 ... for i, dim in enumerate(dims, 1): member_elem.set(f"size{i}", str(dim)) member_elem.set("kind", "array") - # Если базовый элемент - структура, рекурсивно добавляем её члены - if element_type_die is not None and element_type_die.findtext("tag") == "DW_TAG_structure_type": - add_members_recursive(member_elem, element_type_die, offset) + # Если элемент базового типа — структура, разворачиваем её поля + if base_die is not None and base_die.findtext("tag") == "DW_TAG_structure_type": + add_members_recursive(member_elem, base_die, offset) def add_members_recursive(parent_elem, struct_die, base_offset=0): - tag = struct_die.findtext("tag") - is_union = tag == "DW_TAG_union_type" - - - # Получаем размер структуры/объединения + is_union = struct_die.findtext("tag") == "DW_TAG_union_type" size = get_die_size(struct_die) if size is not None: parent_elem.set("size", hex(size)) - for member in struct_die.findall("die"): if member.findtext("tag") != "DW_TAG_member": continue @@ -249,40 +308,28 @@ def add_members_recursive(parent_elem, struct_die, base_offset=0): name_attr = get_attr(member, "DW_AT_name") offset_attr = get_attr(member, "DW_AT_data_member_location") type_attr = get_attr(member, "DW_AT_type") - if name_attr is None or offset_attr is None or type_attr is None: continue name = name_attr.findtext("string") - offset_text = offset_attr.findtext("block") - offset = parse_offset(offset_text) + base_offset + offset = parse_offset(offset_attr.findtext("block")) + base_offset type_id = type_attr.find("ref").attrib.get("idref") resolved_type = resolve_type_die(type_id) type_name = get_type_name(type_id) - if type_name == "unknown": continue - member_elem = ET.SubElement( - parent_elem, "member", name=name, offset=hex(offset), type=type_name - ) - + member_elem = ET.SubElement(parent_elem, "member", name=name, offset=hex(offset), type=type_name) if is_union: member_elem.set("kind", "union") if resolved_type is not None: - subtag = resolved_type.findtext("tag") - - # Обработка массива - if subtag == "DW_TAG_array_type": + tag = resolved_type.findtext("tag") + if tag == "DW_TAG_array_type": handle_array_type(member_elem, resolved_type, offset) - # Обработка структур и объединений - elif subtag in ("DW_TAG_structure_type", "DW_TAG_union_type"): + elif tag in ("DW_TAG_structure_type", "DW_TAG_union_type"): member_elem.set("type", type_name) add_members_recursive(member_elem, resolved_type, offset) - else: - member_elem.set("type", type_name) - output_root = ET.Element("variables") for die in root.iter("die"): @@ -292,13 +339,10 @@ for die in root.iter("die"): name_attr = get_attr(die, "DW_AT_name") addr_attr = get_attr(die, "DW_AT_location") type_attr = get_attr(die, "DW_AT_type") - if name_attr is None or addr_attr is None or type_attr is None: continue name = name_attr.findtext("string") - - # Пропускаем переменные с '$' в имени if "$" in name: continue @@ -310,43 +354,27 @@ for die in root.iter("die"): type_id = type_attr.find("ref").attrib.get("idref") resolved_type = resolve_type_die(type_id) type_name = get_type_name(type_id) - # Пропускаем переменные, находящиеся в памяти периферии - if 0x800 <= addr < 0x8000: - continue - - # Проверка на DW_TAG_subroutine_type - пропускаем такие переменные - if type_name == "unknown": + if 0x800 <= addr < 0x8000 or type_name == "unknown": continue var_elem = ET.SubElement(output_root, "variable", name=name, address=hex(addr), type=type_name) if resolved_type is not None: - tag = resolved_type.findtext("tag") - - if tag == "DW_TAG_array_type": - handle_array_type(var_elem, resolved_type) - - elif tag in ("DW_TAG_structure_type", "DW_TAG_union_type"): - add_members_recursive(var_elem, resolved_type) - + tag = resolved_type.findtext("tag") + if tag == "DW_TAG_array_type": + handle_array_type(var_elem, resolved_type) + elif tag in ("DW_TAG_structure_type", "DW_TAG_union_type"): + add_members_recursive(var_elem, resolved_type) timestamp = extract_timestamp(info_path) - -# Создаём новый элемент с текстом timestamp timestamp_elem = ET.Element("timestamp") timestamp_elem.text = timestamp - -# Вставляем тег timestamp в начало (или куда хочешь) -output_root.insert(0, timestamp_elem) # В начало списка дочерних элементов - -# Красивый вывод +output_root.insert(0, timestamp_elem) rough_string = ET.tostring(output_root, encoding="utf-8") -reparsed = xml.dom.minidom.parseString(rough_string) -pretty_xml = reparsed.toprettyxml(indent=" ") - +pretty_xml = xml.dom.minidom.parseString(rough_string).toprettyxml(indent=" ") with open(output_path, "w", encoding="utf-8") as f: f.write(pretty_xml) os.remove(input_path) os.remove(info_path) -print(f"Simplified and formatted XML saved to: {output_path}") +print(f"Simplified and formatted XML saved to: {output_path}") \ No newline at end of file diff --git a/parse_xml/parse_xml.exe b/parse_xml/parse_xml.exe index cfee623..649285a 100644 Binary files a/parse_xml/parse_xml.exe and b/parse_xml/parse_xml.exe differ