Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.8/site-packages/archinfo/arch_pcode.py: 15%
92 statements
« prev ^ index » next coverage.py v7.3.1, created at 2023-09-25 06:15 +0000
« prev ^ index » next coverage.py v7.3.1, created at 2023-09-25 06:15 +0000
1import logging
2from typing import Union
4try:
5 import pypcode
6except ImportError:
7 pypcode = None
9from .arch import Arch, Endness, Register
10from .tls import TLSArchInfo
11from .archerror import ArchError
14log = logging.getLogger("__name__")
17class ArchPcode(Arch):
18 """
19 archinfo interface to pypcode architectures. Provides minimal mapping for
20 architectural info like register file map, endianness, bit width, etc.
21 """
23 def __init__(self, language: Union["pypcode.ArchLanguage", str]):
24 if pypcode is None:
25 raise ArchError("pypcode not installed")
27 if isinstance(language, str):
28 language = self._get_language_by_id(language)
30 self.name = language.id
31 self.pcode_arch = language.id
32 self.description = language.description
33 self.bits = int(language.size)
34 self.endness = {"little": Endness.LE, "big": Endness.BE}[language.endian]
35 self.instruction_endness = self.endness
36 self.sizeof = {"short": 16, "int": 32, "long": 64, "long long": 64}
37 self.elf_tls = TLSArchInfo(1, 8, [], [0], [], 0, 0)
39 # Build registers list
40 ctx = pypcode.Context(language)
41 archinfo_regs = {rname.lower(): Register(rname.lower(), r.size, r.offset) for rname, r in ctx.registers.items()}
43 # Get program counter register
44 pc_offset = None
45 pc_tag = language.pspec.find("programcounter")
46 if pc_tag is not None:
47 pc_reg = pc_tag.attrib.get("register", None)
48 if pc_reg is not None:
49 # FIXME: Assumes RAM space
50 pc_offset = ctx.registers[pc_reg].offset
51 aliases = {"pc", "ip"}
52 aliases.discard(pc_reg.lower())
53 for alias in aliases:
54 archinfo_regs.pop(alias, None)
55 archinfo_regs[pc_reg.lower()].alias_names = tuple(aliases)
57 if pc_offset is None:
58 log.warning("Unknown program counter register offset?")
59 pc_offset = 0x80000000
61 sp_offset = None
62 ret_offset = None
63 if len(language.cspecs):
65 def find_matching_cid(language, desired):
66 for cid in language.cspecs:
67 if cid[0] == desired:
68 return cid
69 return None
71 cspec_id = (
72 find_matching_cid(language, "default") or find_matching_cid(language, "gcc") or list(language.cspecs)[0]
73 )
74 cspec = language.cspecs[cspec_id]
76 # Get stack pointer register
77 sp_tag = cspec.find("stackpointer")
78 if sp_tag is not None:
79 sp_reg = sp_tag.attrib.get("register", None)
80 if sp_reg is not None:
81 # FIXME: Assumes RAM space
82 sp_offset = ctx.registers[sp_reg].offset
83 if sp_reg.lower() != "sp":
84 if "sp" in archinfo_regs:
85 log.warning("Unexpected SP conflict")
86 del archinfo_regs["sp"]
87 archinfo_regs[sp_reg.lower()].alias_names += ("sp",)
89 # Get return offset
90 proto_tags = cspec.find("default_proto")
91 if proto_tags is not None and len(proto_tags) >= 1:
92 proto_tag = proto_tags[0]
93 output_tags = proto_tag.find("output")
94 if output_tags is not None and len(output_tags) >= 1:
95 output_tag = output_tags[0]
96 output_register_tag = output_tag.find("register")
97 if output_register_tag is not None:
98 output_reg = output_register_tag.attrib["name"]
99 ret_offset = ctx.registers[output_reg].offset
101 if sp_offset is None:
102 log.warning("Unknown stack pointer register offset?")
103 sp_offset = 0x80000008
105 self.instruction_alignment = 1
106 self.ip_offset = pc_offset
107 self.sp_offset = sp_offset
108 self.bp_offset = sp_offset
109 self.ret_offset = ret_offset
110 self.register_list = list(archinfo_regs.values())
111 self.initial_sp = (0x8000 << (self.bits - 16)) - 1
112 self.linux_name = "" # FIXME
113 self.triplet = "" # FIXME
115 # TODO: Replace the following hardcoded function prologues by data sourced from patterns.xml
116 if "PowerPC:BE" in self.name:
117 self.function_prologs = [
118 # stwu r1, xx(r1); mfspr rx, lr
119 b"\x94\x21[\xc0-\xff][\x00\x10\x20\x30\x40\x50\x60\x70\x80\x90\xa0\xb0\xc0\xd0\xe0\xf0]"
120 b"[\x7c-\x7f][\x08\x28\x48\x68\x88\xa8\xc8\xe8]\x02\xa6",
121 ]
123 super().__init__(endness=self.endness, instruction_endness=self.instruction_endness)
125 @staticmethod
126 def _get_language_by_id(lang_id) -> "pypcode.ArchLanguage":
127 for arch in pypcode.Arch.enumerate():
128 for lang in arch.languages:
129 if lang.id == lang_id:
130 return lang
131 raise ArchError("Language not found")