1#!/usr/bin/env python3
2#
3# Copyright (c) 2021 Facebook, Inc. and its affiliates
4#
5# SPDX-License-Identifier: Apache-2.0
6
7import binascii
8import logging
9import struct
10
11from gdbstubs.gdbstub import GdbStub
12
13
14logger = logging.getLogger("gdbstub")
15
16class RegNum():
17    ZERO = 0
18    RA = 1
19    SP = 2
20    GP = 3
21    TP = 4
22    T0 = 5
23    T1 = 6
24    T2 = 7
25    FP = 8
26    S1 = 9
27    A0 = 10
28    A1 = 11
29    A2 = 12
30    A3 = 13
31    A4 = 14
32    A5 = 15
33    A6 = 16
34    A7 = 17
35    S2 = 18
36    S3 = 19
37    S4 = 20
38    S5 = 21
39    S6 = 22
40    S7 = 23
41    S8 = 24
42    S9 = 25
43    S10 = 26
44    S11 = 27
45    T3 = 28
46    T4 = 29
47    T5 = 30
48    T6 = 31
49    PC = 32
50
51
52class GdbStub_RISC_V(GdbStub):
53    ARCH_DATA_BLK_STRUCT    = "<IIIIIIIIIIIIIIIIII"
54    ARCH_DATA_BLK_STRUCT_2  = "<QQQQQQQQQQQQQQQQQQ"
55
56    GDB_SIGNAL_DEFAULT = 7
57
58    GDB_G_PKT_NUM_REGS = 33
59
60    def __init__(self, logfile, elffile):
61        super().__init__(logfile=logfile, elffile=elffile)
62        self.registers = None
63        self.gdb_signal = self.GDB_SIGNAL_DEFAULT
64
65        self.parse_arch_data_block()
66
67    def parse_arch_data_block(self):
68        arch_data_blk = self.logfile.get_arch_data()['data']
69        self.arch_data_ver = self.logfile.get_arch_data()['hdr_ver']
70
71        if self.arch_data_ver == 1:
72            tu = struct.unpack(self.ARCH_DATA_BLK_STRUCT, arch_data_blk)
73        elif self.arch_data_ver == 2:
74            tu = struct.unpack(self.ARCH_DATA_BLK_STRUCT_2, arch_data_blk)
75
76        self.registers = dict()
77
78        self.registers[RegNum.RA] = tu[0]
79        self.registers[RegNum.TP] = tu[1]
80        self.registers[RegNum.T0] = tu[2]
81        self.registers[RegNum.T1] = tu[3]
82        self.registers[RegNum.T2] = tu[4]
83        self.registers[RegNum.A0] = tu[5]
84        self.registers[RegNum.A1] = tu[6]
85        self.registers[RegNum.A2] = tu[7]
86        self.registers[RegNum.A3] = tu[8]
87        self.registers[RegNum.A4] = tu[9]
88        self.registers[RegNum.A5] = tu[10]
89        self.registers[RegNum.A6] = tu[11]
90        self.registers[RegNum.A7] = tu[12]
91        self.registers[RegNum.T3] = tu[13]
92        self.registers[RegNum.T4] = tu[14]
93        self.registers[RegNum.T5] = tu[15]
94        self.registers[RegNum.T6] = tu[16]
95        self.registers[RegNum.PC] = tu[17]
96
97    def handle_register_group_read_packet(self):
98        reg_fmt = "<I" if self.arch_data_ver == 1 else "<Q"
99
100        idx = 0
101        pkt = b''
102
103        while idx < self.GDB_G_PKT_NUM_REGS:
104            if idx in self.registers:
105                bval = struct.pack(reg_fmt, self.registers[idx])
106                pkt += binascii.hexlify(bval)
107            else:
108                # Register not in coredump -> unknown value
109                # Send in "xxxxxxxx"
110                length = 8 if self.arch_data_ver == 1 else 16
111                pkt += b'x' * length
112
113            idx += 1
114
115        self.put_gdb_packet(pkt)
116
117    def handle_register_single_read_packet(self, pkt):
118        # Mark registers as "<unavailable>". 'p' packets are not sent for the registers
119        # currently handled in this file so we can safely reply "xxxxxxxx" here.
120        length = 8 if self.arch_data_ver == 1 else 16
121        self.put_gdb_packet(b'x' * length)
122