pebble/tools/gdb_driver.py
2025-01-27 11:38:16 -08:00

113 lines
3.4 KiB
Python

# Copyright 2024 Google LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import logging
import subprocess
import time
def find_gdb_path():
""" Find the first arm gdb on our path"""
prioritized_names = ['pebble-gdb', 'arm-none-eabi-gdb-py', 'arm-none-eabi-gdb']
for name in prioritized_names:
try:
which_all_cmd = 'which %s' % name
out = subprocess.check_output(which_all_cmd, shell=True)
except subprocess.CalledProcessError, e:
if e.returncode == 1:
continue # `which` returns with 1 when nothing is found
raise e
path = out.splitlines()[0]
logging.info("Found %s at %s" % (name, path))
return path
return None
class GDBDriver(object):
def __init__(self, elf_path, gdb_path=None, server_port=1234):
self.gdb_path = gdb_path or find_gdb_path()
if not self.gdb_path:
raise Exception("pebble-gdb not found on your path, nor"
" was it specified using the `gdb_path` argument")
self.elf_path = elf_path
self.server_port = server_port
self.pipe = None
self.interface = GDBInterface(self)
def _gdb_command(self):
cmd = self.gdb_path
cmd += " %s" % self.elf_path
cmd += " -ex=\"target remote :%u\"" % self.server_port
return cmd
def start(self):
if self.pipe:
raise Exception("GDB Already running.")
# Run GDB:
cmd = self._gdb_command()
try:
self.pipe = subprocess.Popen(cmd, stdin=subprocess.PIPE,
shell=True)
except:
logging.error("Failed to start GDB.\nCommand: `%s`" % cmd)
return
time.sleep(0.1) # FIXME
logging.info("GDB started.")
def stop(self):
if self.pipe:
self.pipe.kill()
logging.info("GDB stopped.")
self.pipe = None
def write_stdin(self, cmd):
if not self.pipe:
logging.error("GDB not running")
return
self.pipe.stdin.write(cmd)
def send_signal(self, signal):
self.pipe.send_signal(signal)
class GDBInterface(object):
def __init__(self, gdb_driver):
assert gdb_driver
self.gdb_driver = gdb_driver
def _send(self, cmd):
self.gdb_driver.write_stdin(cmd)
def _send_signal(self, signal):
self.gdb_driver.send_signal(signal)
def interrupt(self):
self._send_signal(signal.SIGINT)
def cont(self):
self._send("c\n")
def source(self, script_file_name):
self._send("source %s\n" % script_file_name)
def set(self, var_name, expr):
self._send("set %s=%s\n" % (var_name, expr))
def disable_breakpoints(self):
self._send("dis\n")
def set_pagination(self, enabled):
enabled_str = "on" if enabled else "off"
self._send("set pagination %s\n" % enabled_str)