aboutsummaryrefslogtreecommitdiff
path: root/tests/functional/qemu_test/gdb.py
blob: 558d476a68296d289ca370a749c5834f6b53e8fc (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
# SPDX-License-Identifier: GPL-2.0-or-later
#
# A simple interface module built around pygdbmi for handling GDB commands.
#
# Copyright (c) 2025 Linaro Limited
#
# Author:
#  Gustavo Romero <gustavo.romero@linaro.org>
#

import re


class GDB:
    """Provides methods to run and capture GDB command output."""


    def __init__(self, gdb_path, echo=True, suffix='# ', prompt="$ "):
        from pygdbmi.gdbcontroller import GdbController
        from pygdbmi.constants import GdbTimeoutError
        type(self).TimeoutError = GdbTimeoutError

        gdb_cmd = [gdb_path, "-q", "--interpreter=mi2"]
        self.gdbmi = GdbController(gdb_cmd)
        self.echo = echo
        self.suffix = suffix
        self.prompt = prompt
        self.response = None
        self.cmd_output = None


    def get_payload(self, response, kind):
        output = []
        for o in response:
            # Unpack payloads of the same type.
            _type, _, payload, *_ = o.values()
            if _type == kind:
                output += [payload]

        # Some output lines do not end with \n but begin with it,
        # so remove the leading \n and merge them with the next line
        # that ends with \n.
        lines = [line.lstrip('\n') for line in output]
        lines = "".join(lines)
        lines = lines.splitlines(keepends=True)

        return lines


    def cli(self, cmd, timeout=32.0):
        self.response = self.gdbmi.write(cmd, timeout_sec=timeout)
        self.cmd_output = self.get_payload(self.response, kind="console")
        if self.echo:
            print(self.suffix + self.prompt + cmd)

            if len(self.cmd_output) > 0:
                cmd_output = self.suffix.join(self.cmd_output)
                print(self.suffix + cmd_output, end="")

        return self


    def get_addr(self):
        address_pattern = r"0x[0-9A-Fa-f]+"
        cmd_output = "".join(self.cmd_output) # Concat output lines.

        match = re.search(address_pattern, cmd_output)

        return int(match[0], 16) if match else None


    def get_log(self):
        r = self.get_payload(self.response, kind="log")
        r = "".join(r)

        return r


    def get_console(self):
        r = "".join(self.cmd_output)

        return r


    def exit(self):
        self.gdbmi.exit()