|
5 | 5 |
|
6 | 6 | from typing import Iterator, Mapping, Optional, Sequence, Tuple |
7 | 7 | from pathlib import PurePath |
| 8 | +from xml.etree import ElementTree, ElementInclude |
8 | 9 |
|
9 | 10 | from qiling.arch.arm_const import reg_map as arm_regs |
10 | 11 | from qiling.arch.arm_const import reg_vfp as arm_regs_vfp |
11 | 12 | from qiling.arch.arm64_const import reg_map as arm64_regs |
12 | 13 | from qiling.arch.arm64_const import reg_map_v as arm64_regs_v |
13 | 14 | from qiling.arch.mips_const import reg_map as mips_regs_gpr |
14 | 15 | from qiling.arch.mips_const import reg_map_fpu as mips_regs_fpu |
15 | | -from qiling.arch.x86_const import reg_map_16 as x86_regs_16 |
16 | 16 | from qiling.arch.x86_const import reg_map_32 as x86_regs_32 |
17 | 17 | from qiling.arch.x86_const import reg_map_64 as x86_regs_64 |
18 | 18 | from qiling.arch.x86_const import reg_map_misc as x86_regs_misc |
|
21 | 21 | from qiling.arch.x86_const import reg_map_xmm as x86_regs_xmm |
22 | 22 | from qiling.arch.x86_const import reg_map_ymm as x86_regs_ymm |
23 | 23 |
|
24 | | -from qiling.const import QL_ARCH |
| 24 | +from qiling.const import QL_ARCH, QL_OS |
25 | 25 |
|
26 | 26 | RegEntry = Tuple[Optional[int], int, int] |
27 | 27 |
|
28 | | -# define a local dummy function to let us reference this module |
29 | | -__anchor__ = lambda x: x |
| 28 | +class QlGdbFeatures: |
| 29 | + def __init__(self, archtype: QL_ARCH, ostype: QL_OS): |
| 30 | + xmltree = QlGdbFeatures.__load_target_xml(archtype, ostype) |
| 31 | + regsmap = QlGdbFeatures.__load_regsmap(archtype, xmltree) |
30 | 32 |
|
31 | | -def __get_xml_path(archtype: QL_ARCH) -> Tuple[str, PurePath]: |
32 | | - import inspect |
| 33 | + self.xmltree = xmltree |
| 34 | + self.regsmap = regsmap |
33 | 35 |
|
34 | | - p = PurePath(inspect.getfile(__anchor__)) |
35 | | - basedir = p.parent / 'xml' / archtype.name.lower() |
36 | | - filename = basedir / 'target.xml' |
| 36 | + def tostring(self) -> str: |
| 37 | + root = self.xmltree.getroot() |
37 | 38 |
|
38 | | - return str(filename), basedir |
| 39 | + return ElementTree.tostring(root, encoding='unicode', xml_declaration=True) |
39 | 40 |
|
40 | | -def __walk_xml_regs(filename: str, base_url: PurePath) -> Iterator[Tuple[int, str, int]]: |
41 | | - from xml.etree import ElementTree, ElementInclude |
| 41 | + @staticmethod |
| 42 | + def __get_xml_path(archtype: QL_ARCH) -> Tuple[str, PurePath]: |
| 43 | + import inspect |
42 | 44 |
|
43 | | - tree = ElementTree.parse(filename) |
44 | | - root = tree.getroot() |
| 45 | + p = PurePath(inspect.getfile(QlGdbFeatures)) |
| 46 | + basedir = p.parent / 'xml' / archtype.name.lower() |
| 47 | + filename = basedir / 'target.xml' |
45 | 48 |
|
46 | | - # NOTE: this is needed to load xinclude hrefs relative to the main xml file. starting |
47 | | - # from python 3.9 ElementInclude.include has an argument for that called 'base_url'. |
48 | | - # this is a workaround for earlier python versions such as 3.8 |
| 49 | + return str(filename), basedir |
49 | 50 |
|
50 | | - def my_loader(base: PurePath): |
51 | | - def __wrapped(href: str, parse, encoding=None): |
52 | | - abshref = base / href |
| 51 | + @staticmethod |
| 52 | + def __load_target_xml(archtype: QL_ARCH, ostype: QL_OS) -> ElementTree.ElementTree: |
| 53 | + filename, base_url = QlGdbFeatures.__get_xml_path(archtype) |
53 | 54 |
|
54 | | - return ElementInclude.default_loader(str(abshref), parse, encoding) |
| 55 | + tree = ElementTree.parse(filename) |
55 | 56 |
|
56 | | - return __wrapped |
| 57 | + # NOTE: this is needed to load xinclude hrefs relative to the main xml file. starting |
| 58 | + # from python 3.9 ElementInclude.include has an argument for that called 'base_url'. |
| 59 | + # this is a workaround for earlier python versions such as 3.8 |
57 | 60 |
|
58 | | - ElementInclude.include(root, loader=my_loader(base_url)) |
| 61 | + # <WORKAROUND> |
| 62 | + def my_loader(base: PurePath): |
| 63 | + def __wrapped(href: str, parse, encoding=None): |
| 64 | + abshref = base / href |
59 | 65 |
|
60 | | - regnum = -1 |
| 66 | + return ElementInclude.default_loader(str(abshref), parse, encoding) |
61 | 67 |
|
62 | | - for reg in root.iter('reg'): |
63 | | - # if regnum is not specified, assume it follows the previous one |
64 | | - regnum = int(reg.get('regnum', regnum + 1)) |
| 68 | + return __wrapped |
| 69 | + # </WORKAROUND> |
65 | 70 |
|
66 | | - name = reg.attrib['name'] |
67 | | - bitsize = reg.attrib['bitsize'] |
| 71 | + # inline all xi:include elements |
| 72 | + ElementInclude.include(tree.getroot(), loader=my_loader(base_url)) |
68 | 73 |
|
69 | | - yield regnum, name, int(bitsize) |
| 74 | + # patch xml osabi element with the appropriate abi tag |
| 75 | + osabi = tree.find('osabi') |
70 | 76 |
|
71 | | -def load_regsmap(archtype: QL_ARCH) -> Sequence[RegEntry]: |
72 | | - """Initialize registers map using available target XML files. |
| 77 | + if osabi is not None: |
| 78 | + # NOTE: the 'Windows' abi tag is supported starting from gdb 10. |
| 79 | + # earlier gdb versions use 'Cygwin' instead |
73 | 80 |
|
74 | | - Args: |
75 | | - archtype: target architecture type |
| 81 | + abitag = { |
| 82 | + QL_OS.LINUX : 'GNU/Linux', |
| 83 | + QL_OS.FREEBSD : 'FreeBSD', |
| 84 | + QL_OS.MACOS : 'Darwin', |
| 85 | + QL_OS.WINDOWS : 'Windows', |
| 86 | + QL_OS.UEFI : 'Windows', |
| 87 | + QL_OS.DOS : 'Windows', |
| 88 | + QL_OS.QNX : 'QNX-Neutrino' |
| 89 | + }.get(ostype, 'unknown') |
76 | 90 |
|
77 | | - Returns: a list representing registers data |
78 | | - """ |
| 91 | + osabi.text = abitag |
79 | 92 |
|
80 | | - # retreive the relevant set of registers; their order of appearance is not |
81 | | - # important as it is determined by the info read from the xml files |
82 | | - ucregs: Mapping[str, int] = { |
83 | | - QL_ARCH.A8086 : dict(**x86_regs_32, **x86_regs_misc, **x86_regs_cr, **x86_regs_st), |
84 | | - QL_ARCH.X86 : dict(**x86_regs_32, **x86_regs_misc, **x86_regs_cr, **x86_regs_st, **x86_regs_xmm), |
85 | | - QL_ARCH.X8664 : dict(**x86_regs_64, **x86_regs_misc, **x86_regs_cr, **x86_regs_st, **x86_regs_xmm, **x86_regs_ymm), |
86 | | - QL_ARCH.ARM : dict(**arm_regs, **arm_regs_vfp), |
87 | | - QL_ARCH.CORTEX_M : arm_regs, |
88 | | - QL_ARCH.ARM64 : dict(**arm64_regs, **arm64_regs_v), |
89 | | - QL_ARCH.MIPS : dict(**mips_regs_gpr, **mips_regs_fpu) |
90 | | - }[archtype] |
| 93 | + return tree |
91 | 94 |
|
92 | | - xmlpath = __get_xml_path(archtype) |
93 | | - regsinfo = sorted(__walk_xml_regs(*xmlpath)) |
| 95 | + @staticmethod |
| 96 | + def __walk_xml_regs(xmltree: ElementTree.ElementTree) -> Iterator[Tuple[int, str, int]]: |
| 97 | + regnum = -1 |
94 | 98 |
|
95 | | - # pre-allocate regmap and occupy it with null entries |
96 | | - last_regnum = regsinfo[-1][0] |
97 | | - regmap: Sequence[RegEntry] = [(None, 0, 0)] * (last_regnum + 1) |
| 99 | + for reg in xmltree.iter('reg'): |
| 100 | + # if regnum is not specified, assume it follows the previous one |
| 101 | + regnum = int(reg.get('regnum', regnum + 1)) |
98 | 102 |
|
99 | | - pos = 0 |
| 103 | + name = reg.attrib['name'] |
| 104 | + bitsize = reg.attrib['bitsize'] |
100 | 105 |
|
101 | | - for regnum, name, bitsize in sorted(regsinfo): |
102 | | - # reg value size in nibbles |
103 | | - nibbles = bitsize // 4 |
| 106 | + yield regnum, name, int(bitsize) |
104 | 107 |
|
105 | | - regmap[regnum] = (ucregs.get(name), pos, nibbles) |
| 108 | + @staticmethod |
| 109 | + def __load_regsmap(archtype: QL_ARCH, xmltree: ElementTree.ElementTree) -> Sequence[RegEntry]: |
| 110 | + """Initialize registers map using available target XML files. |
106 | 111 |
|
107 | | - # value position of next reg |
108 | | - pos += nibbles |
| 112 | + Args: |
| 113 | + archtype: target architecture type |
109 | 114 |
|
110 | | - return regmap |
| 115 | + Returns: a list representing registers data |
| 116 | + """ |
111 | 117 |
|
112 | | -__all__ = ['RegEntry', 'load_regsmap'] |
| 118 | + # retreive the relevant set of registers; their order of appearance is not |
| 119 | + # important as it is determined by the info read from the xml files |
| 120 | + ucregs: Mapping[str, int] = { |
| 121 | + QL_ARCH.A8086 : dict(**x86_regs_32, **x86_regs_misc, **x86_regs_cr, **x86_regs_st), |
| 122 | + QL_ARCH.X86 : dict(**x86_regs_32, **x86_regs_misc, **x86_regs_cr, **x86_regs_st, **x86_regs_xmm), |
| 123 | + QL_ARCH.X8664 : dict(**x86_regs_64, **x86_regs_misc, **x86_regs_cr, **x86_regs_st, **x86_regs_xmm, **x86_regs_ymm), |
| 124 | + QL_ARCH.ARM : dict(**arm_regs, **arm_regs_vfp), |
| 125 | + QL_ARCH.CORTEX_M : arm_regs, |
| 126 | + QL_ARCH.ARM64 : dict(**arm64_regs, **arm64_regs_v), |
| 127 | + QL_ARCH.MIPS : dict(**mips_regs_gpr, **mips_regs_fpu) |
| 128 | + }[archtype] |
| 129 | + |
| 130 | + regsinfo = sorted(QlGdbFeatures.__walk_xml_regs(xmltree)) |
| 131 | + |
| 132 | + # pre-allocate regmap and occupy it with null entries |
| 133 | + last_regnum = regsinfo[-1][0] |
| 134 | + regmap: Sequence[RegEntry] = [(None, 0, 0)] * (last_regnum + 1) |
| 135 | + |
| 136 | + pos = 0 |
| 137 | + |
| 138 | + for regnum, name, bitsize in sorted(regsinfo): |
| 139 | + # reg value size in nibbles |
| 140 | + nibbles = bitsize // 4 |
| 141 | + |
| 142 | + regmap[regnum] = (ucregs.get(name), pos, nibbles) |
| 143 | + |
| 144 | + # value position of next reg |
| 145 | + pos += nibbles |
| 146 | + |
| 147 | + return regmap |
| 148 | + |
| 149 | + |
| 150 | +__all__ = ['RegEntry', 'QlGdbFeatures'] |
0 commit comments