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

1import logging 

2from typing import Union 

3 

4try: 

5 import pypcode 

6except ImportError: 

7 pypcode = None 

8 

9from .arch import Arch, Endness, Register 

10from .tls import TLSArchInfo 

11from .archerror import ArchError 

12 

13 

14log = logging.getLogger("__name__") 

15 

16 

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 """ 

22 

23 def __init__(self, language: Union["pypcode.ArchLanguage", str]): 

24 if pypcode is None: 

25 raise ArchError("pypcode not installed") 

26 

27 if isinstance(language, str): 

28 language = self._get_language_by_id(language) 

29 

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) 

38 

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()} 

42 

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) 

56 

57 if pc_offset is None: 

58 log.warning("Unknown program counter register offset?") 

59 pc_offset = 0x80000000 

60 

61 sp_offset = None 

62 ret_offset = None 

63 if len(language.cspecs): 

64 

65 def find_matching_cid(language, desired): 

66 for cid in language.cspecs: 

67 if cid[0] == desired: 

68 return cid 

69 return None 

70 

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] 

75 

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",) 

88 

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 

100 

101 if sp_offset is None: 

102 log.warning("Unknown stack pointer register offset?") 

103 sp_offset = 0x80000008 

104 

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 

114 

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 ] 

122 

123 super().__init__(endness=self.endness, instruction_endness=self.instruction_endness) 

124 

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")