попытка сделать в parse_xml парсинг вложенных массивов [][]
определяет вложенные массивы но не определяет их размерности (нули)
This commit is contained in:
parent
788ad19464
commit
e99de603e6
@ -1,5 +1,5 @@
|
|||||||
# pyinstaller --onefile --distpath . --workpath ./build --specpath ./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.py
|
# python -m nuitka --standalone --onefile --output-dir=./build parse_xml/Src/parse_xml.py
|
||||||
import xml.etree.ElementTree as ET
|
import xml.etree.ElementTree as ET
|
||||||
import xml.dom.minidom
|
import xml.dom.minidom
|
||||||
import sys
|
import sys
|
||||||
@ -12,6 +12,16 @@ if len(sys.argv) < 3:
|
|||||||
input_path = sys.argv[1]
|
input_path = sys.argv[1]
|
||||||
info_path = sys.argv[2]
|
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:
|
if len(sys.argv) >= 4:
|
||||||
output_path = sys.argv[3]
|
output_path = sys.argv[3]
|
||||||
else:
|
else:
|
||||||
@ -42,13 +52,25 @@ def get_attr(die, attr_type):
|
|||||||
return None
|
return None
|
||||||
|
|
||||||
def get_die_size(die):
|
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"):
|
for attr in die.findall("attribute"):
|
||||||
type_elem = attr.find("type")
|
type_elem = attr.find("type")
|
||||||
if type_elem is not None and type_elem.text == "DW_AT_byte_size":
|
if type_elem is not None and type_elem.text == "DW_AT_byte_size":
|
||||||
const_elem = attr.find("value/const")
|
const_elem = attr.find("value/const")
|
||||||
if const_elem is not None:
|
if const_elem is not None:
|
||||||
return int(const_elem.text, 0)
|
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
|
return None
|
||||||
|
|
||||||
def resolve_type_die(type_id):
|
def resolve_type_die(type_id):
|
||||||
@ -136,48 +158,66 @@ def parse_offset(offset_text):
|
|||||||
return 0
|
return 0
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def get_array_dimensions(array_die):
|
def get_array_dimensions(array_die):
|
||||||
"""Рекурсивно получить размеры всех измерений массива из DIE с тегом DW_TAG_array_type."""
|
"""
|
||||||
|
Собрать размеры всех измерений массива.
|
||||||
|
Возвращает список размеров [dim0, dim1, ...] во внешне-внутреннем порядке.
|
||||||
|
"""
|
||||||
dims = []
|
dims = []
|
||||||
|
|
||||||
# Ищем размер текущего измерения
|
# Ищем DW_TAG_subrange_type — для каждого измерения
|
||||||
# Размер может быть в DW_AT_upper_bound, либо вычисляться из DW_AT_byte_size и типа элемента
|
|
||||||
# Но часто в DWARF размер указывается через дочерние die с тегом DW_TAG_subrange_type
|
|
||||||
|
|
||||||
subrange = None
|
|
||||||
for child in array_die.findall("die"):
|
for child in array_die.findall("die"):
|
||||||
if child.findtext("tag") == "DW_TAG_subrange_type":
|
if child.findtext("tag") != "DW_TAG_subrange_type":
|
||||||
subrange = child
|
continue
|
||||||
break
|
|
||||||
|
|
||||||
dim_size = None
|
dim_size = None
|
||||||
if subrange is not None:
|
|
||||||
# Ищем атрибут DW_AT_upper_bound
|
# Попытка получить upper_bound
|
||||||
ub_attr = get_attr(subrange, "DW_AT_upper_bound")
|
ub_attr = get_attr(child, "DW_AT_upper_bound")
|
||||||
if ub_attr is not None:
|
if ub_attr is not None:
|
||||||
val = ub_attr.find("value/const")
|
val = ub_attr.find("value/const")
|
||||||
if val is not None:
|
if val is not None:
|
||||||
# Размер измерения равен верхней границе + 1 (т.к. верхняя граница индексируется с 0)
|
try:
|
||||||
dim_size = int(val.text, 0) + 1
|
# В 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)
|
arr_size = get_die_size(array_die)
|
||||||
|
elem_size = None
|
||||||
element_type_ref = get_attr(array_die, "DW_AT_type")
|
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:
|
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_id = element_type_ref.find("ref").attrib.get("idref")
|
||||||
element_type_die = resolve_type_die(element_type_id)
|
elem_die = resolve_type_die(element_type_id)
|
||||||
elem_size = get_die_size(element_type_die) if element_type_die is not None else None
|
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")
|
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:
|
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_id = element_type_ref.find("ref").attrib.get("idref")
|
||||||
@ -188,60 +228,79 @@ def get_array_dimensions(array_die):
|
|||||||
return dims
|
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):
|
def handle_array_type(member_elem, resolved_type, offset=0):
|
||||||
dims = get_array_dimensions(resolved_type)
|
dims = get_array_dimensions(resolved_type)
|
||||||
|
|
||||||
# Получаем элементарный тип массива (наибольший элемент в цепочке массивов)
|
# Определяем базовый тип (не массив)
|
||||||
def get_base_element_type(die):
|
base_die = get_base_type_die(resolved_type)
|
||||||
ref = get_attr(die, "DW_AT_type")
|
base_name = "unknown"
|
||||||
if ref is not None and ref.find("ref") is not None:
|
base_size = None
|
||||||
type_id = ref.find("ref").attrib.get("idref")
|
if base_die is not None:
|
||||||
type_die = resolve_type_die(type_id)
|
base_id = base_die.attrib.get("id")
|
||||||
if type_die is not None and type_die.findtext("tag") == "DW_TAG_array_type":
|
if base_id:
|
||||||
return get_base_element_type(type_die)
|
base_name = get_type_name(base_id)
|
||||||
else:
|
base_size = get_die_size(base_die)
|
||||||
return type_die
|
else:
|
||||||
return None
|
base_name = get_type_name(base_die.attrib.get("id", ""))
|
||||||
|
|
||||||
element_type_die = get_base_element_type(resolved_type)
|
member_elem.set("type", base_name + "[]" * len(dims))
|
||||||
element_type_name = get_type_name(element_type_die.attrib.get("id")) if element_type_die is not None else "unknown"
|
|
||||||
|
|
||||||
# Формируем строку типа с нужным количеством []
|
# Вычисляем общий размер массива — произведение размеров * размер базового элемента
|
||||||
type_with_array = element_type_name + "[]" * len(dims)
|
if base_size is None:
|
||||||
member_elem.set("type", type_with_array)
|
base_size = 0
|
||||||
|
|
||||||
# Размер всего массива
|
total_elements = 1
|
||||||
arr_size = get_die_size(resolved_type)
|
for d in dims:
|
||||||
if arr_size is not None:
|
if d == 0:
|
||||||
member_elem.set("size", str(arr_size))
|
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):
|
for i, dim in enumerate(dims, 1):
|
||||||
member_elem.set(f"size{i}", str(dim))
|
member_elem.set(f"size{i}", str(dim))
|
||||||
|
|
||||||
member_elem.set("kind", "array")
|
member_elem.set("kind", "array")
|
||||||
|
|
||||||
# Если базовый элемент - структура, рекурсивно добавляем её члены
|
# Если элемент базового типа — структура, разворачиваем её поля
|
||||||
if element_type_die is not None and element_type_die.findtext("tag") == "DW_TAG_structure_type":
|
if base_die is not None and base_die.findtext("tag") == "DW_TAG_structure_type":
|
||||||
add_members_recursive(member_elem, element_type_die, offset)
|
add_members_recursive(member_elem, base_die, offset)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def add_members_recursive(parent_elem, struct_die, base_offset=0):
|
def add_members_recursive(parent_elem, struct_die, base_offset=0):
|
||||||
tag = struct_die.findtext("tag")
|
is_union = struct_die.findtext("tag") == "DW_TAG_union_type"
|
||||||
is_union = tag == "DW_TAG_union_type"
|
|
||||||
|
|
||||||
|
|
||||||
# Получаем размер структуры/объединения
|
|
||||||
size = get_die_size(struct_die)
|
size = get_die_size(struct_die)
|
||||||
if size is not None:
|
if size is not None:
|
||||||
parent_elem.set("size", hex(size))
|
parent_elem.set("size", hex(size))
|
||||||
|
|
||||||
|
|
||||||
for member in struct_die.findall("die"):
|
for member in struct_die.findall("die"):
|
||||||
if member.findtext("tag") != "DW_TAG_member":
|
if member.findtext("tag") != "DW_TAG_member":
|
||||||
continue
|
continue
|
||||||
@ -249,40 +308,28 @@ def add_members_recursive(parent_elem, struct_die, base_offset=0):
|
|||||||
name_attr = get_attr(member, "DW_AT_name")
|
name_attr = get_attr(member, "DW_AT_name")
|
||||||
offset_attr = get_attr(member, "DW_AT_data_member_location")
|
offset_attr = get_attr(member, "DW_AT_data_member_location")
|
||||||
type_attr = get_attr(member, "DW_AT_type")
|
type_attr = get_attr(member, "DW_AT_type")
|
||||||
|
|
||||||
if name_attr is None or offset_attr is None or type_attr is None:
|
if name_attr is None or offset_attr is None or type_attr is None:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
name = name_attr.findtext("string")
|
name = name_attr.findtext("string")
|
||||||
offset_text = offset_attr.findtext("block")
|
offset = parse_offset(offset_attr.findtext("block")) + base_offset
|
||||||
offset = parse_offset(offset_text) + base_offset
|
|
||||||
type_id = type_attr.find("ref").attrib.get("idref")
|
type_id = type_attr.find("ref").attrib.get("idref")
|
||||||
resolved_type = resolve_type_die(type_id)
|
resolved_type = resolve_type_die(type_id)
|
||||||
type_name = get_type_name(type_id)
|
type_name = get_type_name(type_id)
|
||||||
|
|
||||||
if type_name == "unknown":
|
if type_name == "unknown":
|
||||||
continue
|
continue
|
||||||
|
|
||||||
member_elem = ET.SubElement(
|
member_elem = ET.SubElement(parent_elem, "member", name=name, offset=hex(offset), type=type_name)
|
||||||
parent_elem, "member", name=name, offset=hex(offset), type=type_name
|
|
||||||
)
|
|
||||||
|
|
||||||
if is_union:
|
if is_union:
|
||||||
member_elem.set("kind", "union")
|
member_elem.set("kind", "union")
|
||||||
|
|
||||||
if resolved_type is not None:
|
if resolved_type is not None:
|
||||||
subtag = resolved_type.findtext("tag")
|
tag = resolved_type.findtext("tag")
|
||||||
|
if tag == "DW_TAG_array_type":
|
||||||
# Обработка массива
|
|
||||||
if subtag == "DW_TAG_array_type":
|
|
||||||
handle_array_type(member_elem, resolved_type, offset)
|
handle_array_type(member_elem, resolved_type, offset)
|
||||||
# Обработка структур и объединений
|
elif tag in ("DW_TAG_structure_type", "DW_TAG_union_type"):
|
||||||
elif subtag in ("DW_TAG_structure_type", "DW_TAG_union_type"):
|
|
||||||
member_elem.set("type", type_name)
|
member_elem.set("type", type_name)
|
||||||
add_members_recursive(member_elem, resolved_type, offset)
|
add_members_recursive(member_elem, resolved_type, offset)
|
||||||
else:
|
|
||||||
member_elem.set("type", type_name)
|
|
||||||
|
|
||||||
|
|
||||||
output_root = ET.Element("variables")
|
output_root = ET.Element("variables")
|
||||||
for die in root.iter("die"):
|
for die in root.iter("die"):
|
||||||
@ -292,13 +339,10 @@ for die in root.iter("die"):
|
|||||||
name_attr = get_attr(die, "DW_AT_name")
|
name_attr = get_attr(die, "DW_AT_name")
|
||||||
addr_attr = get_attr(die, "DW_AT_location")
|
addr_attr = get_attr(die, "DW_AT_location")
|
||||||
type_attr = get_attr(die, "DW_AT_type")
|
type_attr = get_attr(die, "DW_AT_type")
|
||||||
|
|
||||||
if name_attr is None or addr_attr is None or type_attr is None:
|
if name_attr is None or addr_attr is None or type_attr is None:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
name = name_attr.findtext("string")
|
name = name_attr.findtext("string")
|
||||||
|
|
||||||
# Пропускаем переменные с '$' в имени
|
|
||||||
if "$" in name:
|
if "$" in name:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
@ -310,43 +354,27 @@ for die in root.iter("die"):
|
|||||||
type_id = type_attr.find("ref").attrib.get("idref")
|
type_id = type_attr.find("ref").attrib.get("idref")
|
||||||
resolved_type = resolve_type_die(type_id)
|
resolved_type = resolve_type_die(type_id)
|
||||||
type_name = get_type_name(type_id)
|
type_name = get_type_name(type_id)
|
||||||
# Пропускаем переменные, находящиеся в памяти периферии
|
if 0x800 <= addr < 0x8000 or type_name == "unknown":
|
||||||
if 0x800 <= addr < 0x8000:
|
|
||||||
continue
|
|
||||||
|
|
||||||
# Проверка на DW_TAG_subroutine_type - пропускаем такие переменные
|
|
||||||
if type_name == "unknown":
|
|
||||||
continue
|
continue
|
||||||
|
|
||||||
var_elem = ET.SubElement(output_root, "variable", name=name, address=hex(addr), type=type_name)
|
var_elem = ET.SubElement(output_root, "variable", name=name, address=hex(addr), type=type_name)
|
||||||
if resolved_type is not None:
|
if resolved_type is not None:
|
||||||
tag = resolved_type.findtext("tag")
|
tag = resolved_type.findtext("tag")
|
||||||
|
if tag == "DW_TAG_array_type":
|
||||||
if tag == "DW_TAG_array_type":
|
handle_array_type(var_elem, resolved_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)
|
||||||
elif tag in ("DW_TAG_structure_type", "DW_TAG_union_type"):
|
|
||||||
add_members_recursive(var_elem, resolved_type)
|
|
||||||
|
|
||||||
|
|
||||||
timestamp = extract_timestamp(info_path)
|
timestamp = extract_timestamp(info_path)
|
||||||
|
|
||||||
# Создаём новый элемент <timestamp> с текстом timestamp
|
|
||||||
timestamp_elem = ET.Element("timestamp")
|
timestamp_elem = ET.Element("timestamp")
|
||||||
timestamp_elem.text = timestamp
|
timestamp_elem.text = timestamp
|
||||||
|
output_root.insert(0, timestamp_elem)
|
||||||
# Вставляем тег timestamp в начало (или куда хочешь)
|
|
||||||
output_root.insert(0, timestamp_elem) # В начало списка дочерних элементов
|
|
||||||
|
|
||||||
# Красивый вывод
|
|
||||||
|
|
||||||
rough_string = ET.tostring(output_root, encoding="utf-8")
|
rough_string = ET.tostring(output_root, encoding="utf-8")
|
||||||
reparsed = xml.dom.minidom.parseString(rough_string)
|
pretty_xml = xml.dom.minidom.parseString(rough_string).toprettyxml(indent=" ")
|
||||||
pretty_xml = reparsed.toprettyxml(indent=" ")
|
|
||||||
|
|
||||||
with open(output_path, "w", encoding="utf-8") as f:
|
with open(output_path, "w", encoding="utf-8") as f:
|
||||||
f.write(pretty_xml)
|
f.write(pretty_xml)
|
||||||
|
|
||||||
os.remove(input_path)
|
os.remove(input_path)
|
||||||
os.remove(info_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}")
|
Binary file not shown.
Loading…
Reference in New Issue
Block a user