1#!/usr/bin/env python3
2#
3# Copyright (c) 2022 Huawei Technologies SASU
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
16
17class RegNum():
18    X0 = 0          # X0-X29 - 30 GP registers
19    X1 = 1
20    X2 = 2
21    X3 = 3
22    X4 = 4
23    X5 = 5
24    X6 = 6
25    X7 = 7
26    X8 = 8
27    X9 = 9
28    X10 = 10
29    X11 = 11
30    X12 = 12
31    X13 = 13
32    X14 = 14
33    X15 = 15
34    X16 = 16
35    X17 = 17
36    X18 = 18
37    X19 = 19
38    X20 = 20
39    X21 = 21
40    X22 = 22
41    X23 = 23
42    X24 = 24
43    X25 = 25
44    X26 = 26
45    X27 = 27
46    X28 = 28
47    X29 = 29         # Frame pointer register
48    LR      = 30     # X30 Link Register(LR)
49    SP_EL0  = 31     # Stack pointer EL0 (SP_EL0)
50    PC      = 32     # Program Counter (PC)
51
52
53class GdbStub_ARM64(GdbStub):
54    ARCH_DATA_BLK_STRUCT    = "<QQQQQQQQQQQQQQQQQQQQQQ"
55
56    # Default signal used by all other script, just using the same
57    GDB_SIGNAL_DEFAULT = 7
58
59    # The number of registers expected by GDB
60    GDB_G_PKT_NUM_REGS = 33
61
62
63    def __init__(self, logfile, elffile):
64        super().__init__(logfile=logfile, elffile=elffile)
65        self.registers = None
66        self.gdb_signal = self.GDB_SIGNAL_DEFAULT
67
68        self.parse_arch_data_block()
69
70    def parse_arch_data_block(self):
71
72        arch_data_blk = self.logfile.get_arch_data()['data']
73
74        tu = struct.unpack(self.ARCH_DATA_BLK_STRUCT, arch_data_blk)
75
76        self.registers = dict()
77
78        self.registers[RegNum.X0]   = tu[0]
79        self.registers[RegNum.X1]   = tu[1]
80        self.registers[RegNum.X2]   = tu[2]
81        self.registers[RegNum.X3]   = tu[3]
82        self.registers[RegNum.X4]   = tu[4]
83        self.registers[RegNum.X5]   = tu[5]
84        self.registers[RegNum.X6]   = tu[6]
85        self.registers[RegNum.X7]   = tu[7]
86        self.registers[RegNum.X8]   = tu[8]
87        self.registers[RegNum.X9]   = tu[9]
88        self.registers[RegNum.X10]  = tu[10]
89        self.registers[RegNum.X11]  = tu[11]
90        self.registers[RegNum.X12]  = tu[12]
91        self.registers[RegNum.X13]  = tu[13]
92        self.registers[RegNum.X14]  = tu[14]
93        self.registers[RegNum.X15]  = tu[15]
94        self.registers[RegNum.X16]  = tu[16]
95        self.registers[RegNum.X17]  = tu[17]
96        self.registers[RegNum.X18]  = tu[18]
97
98        # Callee saved registers are not provided in __esf structure
99        # So they will be omitted (set to undefined) when stub generates the
100        # packet in handle_register_group_read_packet.
101
102        self.registers[RegNum.LR]       = tu[19]
103        self.registers[RegNum.SP_EL0]   = tu[20]
104        self.registers[RegNum.PC]       = tu[21]
105
106
107    def handle_register_group_read_packet(self):
108        reg_fmt = "<Q"
109
110        idx = 0
111        pkt = b''
112
113        while idx < self.GDB_G_PKT_NUM_REGS:
114            if idx in self.registers:
115                bval = struct.pack(reg_fmt, self.registers[idx])
116                pkt += binascii.hexlify(bval)
117            else:
118                # Register not in coredump -> unknown value
119                # Send in "xxxxxxxx"
120                pkt += b'x' * 16
121
122            idx += 1
123
124        self.put_gdb_packet(pkt)
125
126    def handle_register_single_read_packet(self, pkt):
127        # Mark registers as "<unavailable>".
128        # 'p' packets are usually used for registers
129        # other than the general ones (e.g. eax, ebx)
130        # so we can safely reply "xxxxxxxx" here.
131        self.put_gdb_packet(b'x' * 16)
132