I2C works
This commit is contained in:
parent
9f55b6dc08
commit
03195921b8
388
.gdbdash
388
.gdbdash
|
@ -5,11 +5,9 @@ python
|
||||||
# https://github.com/cyrus-and/gdb-dashboard
|
# https://github.com/cyrus-and/gdb-dashboard
|
||||||
|
|
||||||
import ast
|
import ast
|
||||||
import fcntl
|
|
||||||
import os
|
import os
|
||||||
import re
|
import re
|
||||||
import struct
|
import struct
|
||||||
import termios
|
|
||||||
import traceback
|
import traceback
|
||||||
import math
|
import math
|
||||||
|
|
||||||
|
@ -34,8 +32,23 @@ The list of all the available styles can be obtained with (from GDB itself):
|
||||||
python from pygments.styles import get_all_styles as styles
|
python from pygments.styles import get_all_styles as styles
|
||||||
python for s in styles(): print(s)
|
python for s in styles(): print(s)
|
||||||
""",
|
""",
|
||||||
'default': 'vim',
|
'default': 'vim'
|
||||||
'type': str
|
},
|
||||||
|
# values formatting
|
||||||
|
'compact_values': {
|
||||||
|
'doc': 'Display complex objects in a single line.',
|
||||||
|
'default': False,
|
||||||
|
'type': bool
|
||||||
|
},
|
||||||
|
'max_value_length': {
|
||||||
|
'doc': 'Maximum length for displayed values.',
|
||||||
|
'default': 0,
|
||||||
|
'type': int
|
||||||
|
},
|
||||||
|
'dereference': {
|
||||||
|
'doc': 'Annotate pointers with the pointed value.',
|
||||||
|
'default': True,
|
||||||
|
'type': bool
|
||||||
},
|
},
|
||||||
# prompt
|
# prompt
|
||||||
'prompt': {
|
'prompt': {
|
||||||
|
@ -183,39 +196,59 @@ def to_string(value):
|
||||||
value_string = str(value)
|
value_string = str(value)
|
||||||
except UnicodeEncodeError:
|
except UnicodeEncodeError:
|
||||||
value_string = unicode(value).encode('utf8')
|
value_string = unicode(value).encode('utf8')
|
||||||
|
except gdb.error as e:
|
||||||
|
value_string = ansi(e, R.style_error)
|
||||||
return value_string
|
return value_string
|
||||||
|
|
||||||
def format_address(address):
|
def format_address(address):
|
||||||
pointer_size = gdb.parse_and_eval('$pc').type.sizeof
|
pointer_size = gdb.parse_and_eval('$pc').type.sizeof
|
||||||
return ('0x{{:0{}x}}').format(pointer_size * 2).format(address)
|
return ('0x{{:0{}x}}').format(pointer_size * 2).format(address)
|
||||||
|
|
||||||
def format_value(value):
|
def format_value(value, compact=None):
|
||||||
# format references as referenced values
|
# format references as referenced values
|
||||||
# (TYPE_CODE_RVALUE_REF is not supported by old GDB)
|
# (TYPE_CODE_RVALUE_REF is not supported by old GDB)
|
||||||
if value.type.code in (getattr(gdb, 'TYPE_CODE_REF', None),
|
if value.type.code in (getattr(gdb, 'TYPE_CODE_REF', None),
|
||||||
getattr(gdb, 'TYPE_CODE_RVALUE_REF', None)):
|
getattr(gdb, 'TYPE_CODE_RVALUE_REF', None)):
|
||||||
try:
|
value = value.referenced_value()
|
||||||
return to_string(value.referenced_value())
|
# format the value
|
||||||
except gdb.MemoryError:
|
out = to_string(value)
|
||||||
return to_string(value)
|
# dereference up to the actual value if requested
|
||||||
else:
|
if R.dereference and value.type.code == gdb.TYPE_CODE_PTR:
|
||||||
try:
|
while value.type.code == gdb.TYPE_CODE_PTR:
|
||||||
return to_string(value)
|
try:
|
||||||
except gdb.MemoryError as e:
|
value = value.dereference()
|
||||||
return ansi(e, R.style_error)
|
except gdb.error as e:
|
||||||
|
break
|
||||||
|
else:
|
||||||
|
formatted = to_string(value)
|
||||||
|
out += '{} {}'.format(ansi(':', R.style_low), formatted)
|
||||||
|
# compact the value
|
||||||
|
if compact is not None and compact or R.compact_values:
|
||||||
|
out = re.sub(r'$\s*', '', out, flags=re.MULTILINE)
|
||||||
|
# truncate the value
|
||||||
|
if R.max_value_length > 0 and len(out) > R.max_value_length:
|
||||||
|
out = out[0:R.max_value_length] + ansi('[...]', R.style_error)
|
||||||
|
return out
|
||||||
|
|
||||||
class Beautifier():
|
class Beautifier():
|
||||||
def __init__(self, filename, tab_size=4):
|
def __init__(self, hint, tab_size=4):
|
||||||
self.tab_spaces = ' ' * tab_size
|
self.tab_spaces = ' ' * tab_size
|
||||||
self.active = False
|
self.active = False
|
||||||
if not R.ansi:
|
if not R.ansi:
|
||||||
return
|
return
|
||||||
# attempt to set up Pygments
|
# attempt to set up Pygments
|
||||||
try:
|
try:
|
||||||
from pygments.lexers import get_lexer_for_filename
|
import pygments
|
||||||
|
from pygments.lexers import GasLexer, NasmLexer
|
||||||
from pygments.formatters import Terminal256Formatter
|
from pygments.formatters import Terminal256Formatter
|
||||||
|
if hint == 'att':
|
||||||
|
self.lexer = GasLexer()
|
||||||
|
elif hint == 'intel':
|
||||||
|
self.lexer = NasmLexer()
|
||||||
|
else:
|
||||||
|
from pygments.lexers import get_lexer_for_filename
|
||||||
|
self.lexer = get_lexer_for_filename(hint, stripnl=False)
|
||||||
self.formatter = Terminal256Formatter(style=R.syntax_highlighting)
|
self.formatter = Terminal256Formatter(style=R.syntax_highlighting)
|
||||||
self.lexer = get_lexer_for_filename(filename, stripnl=False)
|
|
||||||
self.active = True
|
self.active = True
|
||||||
except ImportError:
|
except ImportError:
|
||||||
# Pygments not available
|
# Pygments not available
|
||||||
|
@ -383,8 +416,13 @@ class Dashboard(gdb.Command):
|
||||||
# skip disabled modules
|
# skip disabled modules
|
||||||
if not instance:
|
if not instance:
|
||||||
continue
|
continue
|
||||||
# ask the module to generate the content
|
try:
|
||||||
lines = instance.lines(width, style_changed)
|
# ask the module to generate the content
|
||||||
|
lines = instance.lines(width, style_changed)
|
||||||
|
except Exception as e:
|
||||||
|
# allow to continue on exceptions in modules
|
||||||
|
stacktrace = traceback.format_exc().strip()
|
||||||
|
lines = [ansi(stacktrace, R.style_error)]
|
||||||
# create the divider accordingly
|
# create the divider accordingly
|
||||||
div = divider(width, instance.label(), True, lines)
|
div = divider(width, instance.label(), True, lines)
|
||||||
# write the data
|
# write the data
|
||||||
|
@ -427,10 +465,22 @@ class Dashboard(gdb.Command):
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def get_term_width(fd=1): # defaults to the main terminal
|
def get_term_width(fd=1): # defaults to the main terminal
|
||||||
# first 2 shorts (4 byte) of struct winsize
|
if sys.platform == 'win32':
|
||||||
raw = fcntl.ioctl(fd, termios.TIOCGWINSZ, ' ' * 4)
|
try:
|
||||||
height, width = struct.unpack('hh', raw)
|
import curses
|
||||||
return int(width)
|
# XXX always neglects the fd parameter
|
||||||
|
_, width = curses.initscr().getmaxyx()
|
||||||
|
curses.endwin()
|
||||||
|
return int(width)
|
||||||
|
except ImportError:
|
||||||
|
return 80 # hardcoded fallback value
|
||||||
|
else:
|
||||||
|
import termios
|
||||||
|
import fcntl
|
||||||
|
# first 2 shorts (4 byte) of struct winsize
|
||||||
|
raw = fcntl.ioctl(fd, termios.TIOCGWINSZ, ' ' * 4)
|
||||||
|
_, width = struct.unpack('hh', raw)
|
||||||
|
return int(width)
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def set_custom_prompt(dashboard):
|
def set_custom_prompt(dashboard):
|
||||||
|
@ -959,11 +1009,9 @@ instructions constituting the current statement are marked, if available."""
|
||||||
frame = gdb.selected_frame() # PC is here
|
frame = gdb.selected_frame() # PC is here
|
||||||
disassemble = frame.architecture().disassemble
|
disassemble = frame.architecture().disassemble
|
||||||
try:
|
try:
|
||||||
# try to fetch the function boundaries using the disassemble command
|
# disassemble the current block
|
||||||
output = run('disassemble').split('\n')
|
block = gdb.block_for_pc(frame.pc())
|
||||||
start = int(re.split('[ :]', output[1][3:], 1)[0], 16)
|
asm = disassemble(block.start, end_pc=block.end - 1)
|
||||||
end = int(re.split('[ :]', output[-3][3:], 1)[0], 16)
|
|
||||||
asm = disassemble(start, end_pc=end)
|
|
||||||
# find the location of the PC
|
# find the location of the PC
|
||||||
pc_index = next(index for index, instr in enumerate(asm)
|
pc_index = next(index for index, instr in enumerate(asm)
|
||||||
if instr['addr'] == frame.pc())
|
if instr['addr'] == frame.pc())
|
||||||
|
@ -974,7 +1022,7 @@ instructions constituting the current statement are marked, if available."""
|
||||||
# line_info is not None but line_info.last is None
|
# line_info is not None but line_info.last is None
|
||||||
line_info = gdb.find_pc_line(frame.pc())
|
line_info = gdb.find_pc_line(frame.pc())
|
||||||
line_info = line_info if line_info.last else None
|
line_info = line_info if line_info.last else None
|
||||||
except (gdb.error, StopIteration):
|
except (gdb.error, RuntimeError, StopIteration):
|
||||||
# if it is not possible (stripped binary or the PC is not present in
|
# if it is not possible (stripped binary or the PC is not present in
|
||||||
# the output of `disassemble` as per issue #31) start from PC and
|
# the output of `disassemble` as per issue #31) start from PC and
|
||||||
# end after twice the context
|
# end after twice the context
|
||||||
|
@ -995,17 +1043,13 @@ instructions constituting the current statement are marked, if available."""
|
||||||
func_start = to_unsigned(value)
|
func_start = to_unsigned(value)
|
||||||
except gdb.error:
|
except gdb.error:
|
||||||
pass # e.g., @plt
|
pass # e.g., @plt
|
||||||
# fetch the assembly flavor and the extension used by Pygments
|
# fetch the assembly flavor anduse it as hint for Pygments
|
||||||
try:
|
try:
|
||||||
flavor = gdb.parameter('disassembly-flavor')
|
flavor = gdb.parameter('disassembly-flavor')
|
||||||
except:
|
except:
|
||||||
flavor = None # not always defined (see #36)
|
flavor = 'att' # not always defined (see #36)
|
||||||
filename = {
|
|
||||||
'att': '.s',
|
|
||||||
'intel': '.asm'
|
|
||||||
}.get(flavor, '.s')
|
|
||||||
# prepare the highlighter
|
# prepare the highlighter
|
||||||
highlighter = Beautifier(filename)
|
highlighter = Beautifier(flavor)
|
||||||
# compute the maximum offset size
|
# compute the maximum offset size
|
||||||
if func_start:
|
if func_start:
|
||||||
max_offset = max(len(str(abs(asm[0]['addr'] - func_start))),
|
max_offset = max(len(str(abs(asm[0]['addr'] - func_start))),
|
||||||
|
@ -1087,6 +1131,84 @@ instructions constituting the current statement are marked, if available."""
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class Variables(Dashboard.Module):
|
||||||
|
"""Show arguments and locals of the selected frame."""
|
||||||
|
|
||||||
|
def label(self):
|
||||||
|
return 'Variables'
|
||||||
|
|
||||||
|
def lines(self, term_width, style_changed):
|
||||||
|
return Variables.format_variables(
|
||||||
|
gdb.selected_frame(),
|
||||||
|
self.show_arguments, self.show_locals, self.compact)
|
||||||
|
|
||||||
|
def attributes(self):
|
||||||
|
return {
|
||||||
|
'arguments': {
|
||||||
|
'doc': 'Frame arguments visibility flag.',
|
||||||
|
'default': True,
|
||||||
|
'name': 'show_arguments',
|
||||||
|
'type': bool
|
||||||
|
},
|
||||||
|
'locals': {
|
||||||
|
'doc': 'Frame locals visibility flag.',
|
||||||
|
'default': True,
|
||||||
|
'name': 'show_locals',
|
||||||
|
'type': bool
|
||||||
|
},
|
||||||
|
'compact': {
|
||||||
|
'doc': 'Single-line display flag.',
|
||||||
|
'default': False,
|
||||||
|
'type': bool
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def format_variables(frame, show_arguments, show_locals, compact):
|
||||||
|
out = []
|
||||||
|
# fetch frame arguments and locals
|
||||||
|
decorator = gdb.FrameDecorator.FrameDecorator(frame)
|
||||||
|
separator = ansi(', ', R.style_low)
|
||||||
|
if show_arguments:
|
||||||
|
def prefix(line):
|
||||||
|
return Stack.format_line('arg', line)
|
||||||
|
frame_args = decorator.frame_args()
|
||||||
|
args_lines = Variables.fetch(frame, frame_args, compact)
|
||||||
|
if args_lines:
|
||||||
|
if compact:
|
||||||
|
args_line = separator.join(args_lines)
|
||||||
|
single_line = prefix(args_line)
|
||||||
|
out.append(single_line)
|
||||||
|
else:
|
||||||
|
out.extend(map(prefix, args_lines))
|
||||||
|
else:
|
||||||
|
out.append(ansi('(no arguments)', R.style_low))
|
||||||
|
if show_locals:
|
||||||
|
def prefix(line):
|
||||||
|
return Stack.format_line('loc', line)
|
||||||
|
frame_locals = decorator.frame_locals()
|
||||||
|
locals_lines = Variables.fetch(frame, frame_locals, compact)
|
||||||
|
if locals_lines:
|
||||||
|
if compact:
|
||||||
|
locals_line = separator.join(locals_lines)
|
||||||
|
single_line = prefix(locals_line)
|
||||||
|
out.append(single_line)
|
||||||
|
else:
|
||||||
|
out.extend(map(prefix, locals_lines))
|
||||||
|
else:
|
||||||
|
out.append(ansi('(no locals)', R.style_low))
|
||||||
|
return out
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def fetch(frame, data, compact):
|
||||||
|
lines = []
|
||||||
|
for elem in data or []:
|
||||||
|
name = elem.sym
|
||||||
|
equal = ansi('=', R.style_low)
|
||||||
|
value = format_value(elem.sym.value(frame), compact)
|
||||||
|
lines.append('{} {} {}'.format(name, equal, value))
|
||||||
|
return lines
|
||||||
|
|
||||||
class Stack(Dashboard.Module):
|
class Stack(Dashboard.Module):
|
||||||
"""Show the current stack trace including the function name and the file
|
"""Show the current stack trace including the function name and the file
|
||||||
location, if available. Optionally list the frame arguments and locals too."""
|
location, if available. Optionally list the frame arguments and locals too."""
|
||||||
|
@ -1119,40 +1241,9 @@ location, if available. Optionally list the frame arguments and locals too."""
|
||||||
info = Stack.get_pc_line(frame, style)
|
info = Stack.get_pc_line(frame, style)
|
||||||
frame_lines = []
|
frame_lines = []
|
||||||
frame_lines.append('[{}] {}'.format(frame_id, info))
|
frame_lines.append('[{}] {}'.format(frame_id, info))
|
||||||
# fetch frame arguments and locals
|
# add frame arguments and locals
|
||||||
decorator = gdb.FrameDecorator.FrameDecorator(frame)
|
frame_lines.extend(Variables.format_variables(
|
||||||
separator = ansi(', ', R.style_low)
|
frame, self.show_arguments, self.show_locals, self.compact))
|
||||||
strip_newlines = re.compile(r'$\s*', re.MULTILINE)
|
|
||||||
if self.show_arguments:
|
|
||||||
def prefix(line):
|
|
||||||
return Stack.format_line('arg', line)
|
|
||||||
frame_args = decorator.frame_args()
|
|
||||||
args_lines = Stack.fetch_frame_info(frame, frame_args)
|
|
||||||
if args_lines:
|
|
||||||
if self.compact:
|
|
||||||
args_line = separator.join(args_lines)
|
|
||||||
args_line = strip_newlines.sub('', args_line)
|
|
||||||
single_line = prefix(args_line)
|
|
||||||
frame_lines.append(single_line)
|
|
||||||
else:
|
|
||||||
frame_lines.extend(map(prefix, args_lines))
|
|
||||||
else:
|
|
||||||
frame_lines.append(ansi('(no arguments)', R.style_low))
|
|
||||||
if self.show_locals:
|
|
||||||
def prefix(line):
|
|
||||||
return Stack.format_line('loc', line)
|
|
||||||
frame_locals = decorator.frame_locals()
|
|
||||||
locals_lines = Stack.fetch_frame_info(frame, frame_locals)
|
|
||||||
if locals_lines:
|
|
||||||
if self.compact:
|
|
||||||
locals_line = separator.join(locals_lines)
|
|
||||||
locals_line = strip_newlines.sub('', locals_line)
|
|
||||||
single_line = prefix(locals_line)
|
|
||||||
frame_lines.append(single_line)
|
|
||||||
else:
|
|
||||||
frame_lines.extend(map(prefix, locals_lines))
|
|
||||||
else:
|
|
||||||
frame_lines.append(ansi('(no locals)', R.style_low))
|
|
||||||
# add frame
|
# add frame
|
||||||
frames.append(frame_lines)
|
frames.append(frame_lines)
|
||||||
# next
|
# next
|
||||||
|
@ -1178,16 +1269,6 @@ location, if available. Optionally list the frame arguments and locals too."""
|
||||||
prefix = ansi(prefix, R.style_low)
|
prefix = ansi(prefix, R.style_low)
|
||||||
return '{} {}'.format(prefix, line)
|
return '{} {}'.format(prefix, line)
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def fetch_frame_info(frame, data):
|
|
||||||
lines = []
|
|
||||||
for elem in data or []:
|
|
||||||
name = elem.sym
|
|
||||||
equal = ansi('=', R.style_low)
|
|
||||||
value = format_value(elem.sym.value(frame))
|
|
||||||
lines.append('{} {} {}'.format(name, equal, value))
|
|
||||||
return lines
|
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def get_pc_line(frame, style):
|
def get_pc_line(frame, style):
|
||||||
frame_pc = ansi(format_address(frame.pc()), style)
|
frame_pc = ansi(format_address(frame.pc()), style)
|
||||||
|
@ -1220,13 +1301,13 @@ location, if available. Optionally list the frame arguments and locals too."""
|
||||||
return {
|
return {
|
||||||
'limit': {
|
'limit': {
|
||||||
'doc': 'Maximum number of displayed frames (0 means no limit).',
|
'doc': 'Maximum number of displayed frames (0 means no limit).',
|
||||||
'default': 2,
|
'default': 10,
|
||||||
'type': int,
|
'type': int,
|
||||||
'check': check_ge_zero
|
'check': check_ge_zero
|
||||||
},
|
},
|
||||||
'arguments': {
|
'arguments': {
|
||||||
'doc': 'Frame arguments visibility flag.',
|
'doc': 'Frame arguments visibility flag.',
|
||||||
'default': True,
|
'default': False,
|
||||||
'name': 'show_arguments',
|
'name': 'show_arguments',
|
||||||
'type': bool
|
'type': bool
|
||||||
},
|
},
|
||||||
|
@ -1275,6 +1356,61 @@ class History(Dashboard.Module):
|
||||||
class Memory(Dashboard.Module):
|
class Memory(Dashboard.Module):
|
||||||
"""Allow to inspect memory regions."""
|
"""Allow to inspect memory regions."""
|
||||||
|
|
||||||
|
class Region():
|
||||||
|
def __init__(self, address, length, module):
|
||||||
|
self.address = address
|
||||||
|
self.length = length
|
||||||
|
self.module = module
|
||||||
|
self.original = None
|
||||||
|
self.latest = None
|
||||||
|
|
||||||
|
def format(self):
|
||||||
|
# fetch the memory content
|
||||||
|
try:
|
||||||
|
inferior = gdb.selected_inferior()
|
||||||
|
memory = inferior.read_memory(self.address, self.length)
|
||||||
|
# set the original memory snapshot if needed
|
||||||
|
if not self.original:
|
||||||
|
self.original = memory
|
||||||
|
except gdb.error:
|
||||||
|
msg = 'Cannot access {} bytes starting at {}'
|
||||||
|
msg = msg.format(self.length, format_address(self.address))
|
||||||
|
return [ansi(msg, R.style_error)]
|
||||||
|
|
||||||
|
# format the memory content
|
||||||
|
out = []
|
||||||
|
for i in range(0, len(memory), self.module.row_length):
|
||||||
|
region = memory[i:i + self.module.row_length]
|
||||||
|
pad = self.module.row_length - len(region)
|
||||||
|
address = format_address(self.address + i)
|
||||||
|
# compute changes
|
||||||
|
hexa = []
|
||||||
|
text = []
|
||||||
|
for j in range(len(region)):
|
||||||
|
rel = i + j
|
||||||
|
byte = memory[rel]
|
||||||
|
hexa_byte = '{:02x}'.format(ord(byte))
|
||||||
|
text_byte = Memory.format_byte(byte)
|
||||||
|
# differences against the latest have the highest priority
|
||||||
|
if self.latest and memory[rel] != self.latest[rel]:
|
||||||
|
hexa_byte = ansi(hexa_byte, R.style_selected_1)
|
||||||
|
text_byte = ansi(text_byte, R.style_selected_1)
|
||||||
|
# cumulative changes if enabled
|
||||||
|
elif (self.module.cumulative and
|
||||||
|
memory[rel] != self.original[rel]):
|
||||||
|
hexa_byte = ansi(hexa_byte, R.style_selected_2)
|
||||||
|
text_byte = ansi(text_byte, R.style_selected_2)
|
||||||
|
hexa.append(hexa_byte)
|
||||||
|
text.append(text_byte)
|
||||||
|
# output the formatted line
|
||||||
|
out.append('{} {}{} {}{}'.format(
|
||||||
|
ansi(address, R.style_low),
|
||||||
|
' '.join(hexa), ansi(pad * ' --', R.style_low),
|
||||||
|
''.join(text), ansi(pad * '.', R.style_low)))
|
||||||
|
# update the latest memory snapshot
|
||||||
|
self.latest = memory
|
||||||
|
return out
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def format_byte(byte):
|
def format_byte(byte):
|
||||||
# `type(byte) is bytes` in Python 3
|
# `type(byte) is bytes` in Python 3
|
||||||
|
@ -1294,35 +1430,13 @@ class Memory(Dashboard.Module):
|
||||||
self.row_length = 16
|
self.row_length = 16
|
||||||
self.table = {}
|
self.table = {}
|
||||||
|
|
||||||
def format_memory(self, start, memory):
|
|
||||||
out = []
|
|
||||||
for i in range(0, len(memory), self.row_length):
|
|
||||||
region = memory[i:i + self.row_length]
|
|
||||||
pad = self.row_length - len(region)
|
|
||||||
address = format_address(start + i)
|
|
||||||
hexa = (' '.join('{:02x}'.format(ord(byte)) for byte in region))
|
|
||||||
text = (''.join(Memory.format_byte(byte) for byte in region))
|
|
||||||
out.append('{} {}{} {}{}'.format(ansi(address, R.style_low),
|
|
||||||
hexa,
|
|
||||||
ansi(pad * ' --', R.style_low),
|
|
||||||
ansi(text, R.style_high),
|
|
||||||
ansi(pad * '.', R.style_low)))
|
|
||||||
return out
|
|
||||||
|
|
||||||
def label(self):
|
def label(self):
|
||||||
return 'Memory'
|
return 'Memory'
|
||||||
|
|
||||||
def lines(self, term_width, style_changed):
|
def lines(self, term_width, style_changed):
|
||||||
out = []
|
out = []
|
||||||
inferior = gdb.selected_inferior()
|
for address, region in sorted(self.table.items()):
|
||||||
for address, length in sorted(self.table.items()):
|
out.extend(region.format())
|
||||||
try:
|
|
||||||
memory = inferior.read_memory(address, length)
|
|
||||||
out.extend(self.format_memory(address, memory))
|
|
||||||
except gdb.error:
|
|
||||||
msg = 'Cannot access {} bytes starting at {}'
|
|
||||||
msg = msg.format(length, format_address(address))
|
|
||||||
out.append(ansi(msg, R.style_error))
|
|
||||||
out.append(divider(term_width))
|
out.append(divider(term_width))
|
||||||
# drop last divider
|
# drop last divider
|
||||||
if out:
|
if out:
|
||||||
|
@ -1337,7 +1451,7 @@ class Memory(Dashboard.Module):
|
||||||
length = Memory.parse_as_address(length)
|
length = Memory.parse_as_address(length)
|
||||||
else:
|
else:
|
||||||
length = self.row_length
|
length = self.row_length
|
||||||
self.table[address] = length
|
self.table[address] = Memory.Region(address, length, self)
|
||||||
else:
|
else:
|
||||||
raise Exception('Specify an address')
|
raise Exception('Specify an address')
|
||||||
|
|
||||||
|
@ -1372,6 +1486,15 @@ class Memory(Dashboard.Module):
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
def attributes(self):
|
||||||
|
return {
|
||||||
|
'cumulative': {
|
||||||
|
'doc': 'Highlight changes cumulatively, watch again to reset.',
|
||||||
|
'default': False,
|
||||||
|
'type': bool
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
class Registers(Dashboard.Module):
|
class Registers(Dashboard.Module):
|
||||||
"""Show the CPU registers and their values."""
|
"""Show the CPU registers and their values."""
|
||||||
|
|
||||||
|
@ -1385,11 +1508,18 @@ class Registers(Dashboard.Module):
|
||||||
# skip if the current thread is not stopped
|
# skip if the current thread is not stopped
|
||||||
if not gdb.selected_thread().is_stopped():
|
if not gdb.selected_thread().is_stopped():
|
||||||
return []
|
return []
|
||||||
|
# obtain the registers to display
|
||||||
|
if style_changed:
|
||||||
|
self.table = {}
|
||||||
|
if self.register_list:
|
||||||
|
register_list = self.register_list.split()
|
||||||
|
else:
|
||||||
|
register_list = list(map(lambda line: line.split(None, 1)[0],
|
||||||
|
run('info registers').strip().split('\n')))
|
||||||
|
|
||||||
# fetch registers status
|
# fetch registers status
|
||||||
registers = []
|
registers = []
|
||||||
for reg_info in run('info registers').strip().split('\n'):
|
for name in register_list:
|
||||||
# fetch register and update the table
|
|
||||||
name = reg_info.split(None, 1)[0]
|
|
||||||
# Exclude registers with a dot '.' or parse_and_eval() will fail
|
# Exclude registers with a dot '.' or parse_and_eval() will fail
|
||||||
if '.' in name:
|
if '.' in name:
|
||||||
continue
|
continue
|
||||||
|
@ -1404,15 +1534,10 @@ class Registers(Dashboard.Module):
|
||||||
max_name = max(len(name) for name, _, _ in registers)
|
max_name = max(len(name) for name, _, _ in registers)
|
||||||
max_value = max(len(value) for _, value, _ in registers)
|
max_value = max(len(value) for _, value, _ in registers)
|
||||||
max_width = max_name + max_value + 2
|
max_width = max_name + max_value + 2
|
||||||
per_line = int((term_width + 1) / max_width) or 1
|
per_line = min(int((term_width + 1) / max_width) or 1, len(registers))
|
||||||
# redistribute extra space among columns
|
# redistribute extra space among columns
|
||||||
extra = int((term_width + 1 - max_width * per_line) / per_line)
|
extra = int((term_width + 1 - max_width * per_line) / per_line)
|
||||||
if per_line == 1:
|
max_name += int(extra / 2)
|
||||||
# center when there is only one column
|
|
||||||
max_name += int(extra / 2)
|
|
||||||
max_value += int(extra / 2)
|
|
||||||
else:
|
|
||||||
max_value += extra
|
|
||||||
# format registers info
|
# format registers info
|
||||||
partial = []
|
partial = []
|
||||||
for name, value, changed in registers:
|
for name, value, changed in registers:
|
||||||
|
@ -1440,6 +1565,12 @@ class Registers(Dashboard.Module):
|
||||||
'default': False,
|
'default': False,
|
||||||
'name': 'column_major',
|
'name': 'column_major',
|
||||||
'type': bool
|
'type': bool
|
||||||
|
},
|
||||||
|
'list': {
|
||||||
|
'doc': """String of space-separated register names to display.
|
||||||
|
The empty list (default) causes to show all the available registers.""",
|
||||||
|
'default': '',
|
||||||
|
'name': 'register_list',
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1468,13 +1599,22 @@ class Threads(Dashboard.Module):
|
||||||
restore_frame = gdb.selected_thread().is_stopped()
|
restore_frame = gdb.selected_thread().is_stopped()
|
||||||
if restore_frame:
|
if restore_frame:
|
||||||
selected_frame = gdb.selected_frame()
|
selected_frame = gdb.selected_frame()
|
||||||
for thread in gdb.Inferior.threads(gdb.selected_inferior()):
|
# fetch the thread list
|
||||||
|
threads = []
|
||||||
|
for inferior in gdb.inferiors():
|
||||||
|
if self.all_inferiors or inferior == gdb.selected_inferior():
|
||||||
|
threads += gdb.Inferior.threads(inferior)
|
||||||
|
for thread in threads:
|
||||||
# skip running threads if requested
|
# skip running threads if requested
|
||||||
if self.skip_running and thread.is_running():
|
if self.skip_running and thread.is_running():
|
||||||
continue
|
continue
|
||||||
is_selected = (thread.ptid == selected_thread.ptid)
|
is_selected = (thread.ptid == selected_thread.ptid)
|
||||||
style = R.style_selected_1 if is_selected else R.style_selected_2
|
style = R.style_selected_1 if is_selected else R.style_selected_2
|
||||||
number = ansi(str(thread.num), style)
|
if self.all_inferiors:
|
||||||
|
number = '{}.{}'.format(thread.inferior.num, thread.num)
|
||||||
|
else:
|
||||||
|
number = str(thread.num)
|
||||||
|
number = ansi(number, style)
|
||||||
tid = ansi(str(thread.ptid[1] or thread.ptid[2]), style)
|
tid = ansi(str(thread.ptid[1] or thread.ptid[2]), style)
|
||||||
info = '[{}] id {}'.format(number, tid)
|
info = '[{}] id {}'.format(number, tid)
|
||||||
if thread.name:
|
if thread.name:
|
||||||
|
@ -1500,7 +1640,13 @@ class Threads(Dashboard.Module):
|
||||||
'default': False,
|
'default': False,
|
||||||
'name': 'skip_running',
|
'name': 'skip_running',
|
||||||
'type': bool
|
'type': bool
|
||||||
}
|
},
|
||||||
|
'all-inferiors': {
|
||||||
|
'doc': 'Show threads from all inferiors.',
|
||||||
|
'default': False,
|
||||||
|
'name': 'all_inferiors',
|
||||||
|
'type': bool
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
class Expressions(Dashboard.Module):
|
class Expressions(Dashboard.Module):
|
||||||
|
@ -1579,7 +1725,7 @@ set python print-stack full
|
||||||
python Dashboard.start()
|
python Dashboard.start()
|
||||||
|
|
||||||
# ------------------------------------------------------------------------------
|
# ------------------------------------------------------------------------------
|
||||||
# Copyright (c) 2015-2017 Andrea Cardaci <cyrus.and@gmail.com>
|
# Copyright (c) 2015-2019 Andrea Cardaci <cyrus.and@gmail.com>
|
||||||
#
|
#
|
||||||
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
# of this software and associated documentation files (the "Software"), to deal
|
# of this software and associated documentation files (the "Software"), to deal
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
authors = ["sebastian"]
|
authors = ["sebastian"]
|
||||||
edition = "2018"
|
edition = "2018"
|
||||||
readme = "README.md"
|
readme = "README.md"
|
||||||
name = "STM32F1Test"
|
name = "cheapsdo"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
|
@ -27,7 +27,7 @@ features = ["unproven"]
|
||||||
|
|
||||||
# this lets you use `cargo fix`!
|
# this lets you use `cargo fix`!
|
||||||
[[bin]]
|
[[bin]]
|
||||||
name = "STM32F1Test"
|
name = "cheapsdo"
|
||||||
test = false
|
test = false
|
||||||
bench = false
|
bench = false
|
||||||
|
|
||||||
|
|
2
run.sh
2
run.sh
|
@ -1,3 +1,3 @@
|
||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
cargo build || exit -1
|
cargo build || exit -1
|
||||||
arm-none-eabi-gdb target/thumbv7m-none-eabi/debug/STM32F1Test
|
arm-none-eabi-gdb target/thumbv7m-none-eabi/debug/cheapsdo
|
||||||
|
|
36
src/main.rs
36
src/main.rs
|
@ -1,21 +1,16 @@
|
||||||
//! Blinks an LED
|
|
||||||
//!
|
|
||||||
//! This assumes that a LED is connected to pc13 as is the case on the blue pill board.
|
|
||||||
//!
|
|
||||||
//! Note: Without additional hardware, PC13 should not be used to drive an LED, see page 5.1.2 of
|
|
||||||
//! the reference manaual for an explanation. This is not an issue on the blue pill.
|
|
||||||
|
|
||||||
#![deny(unsafe_code)]
|
#![deny(unsafe_code)]
|
||||||
#![no_std]
|
#![no_std]
|
||||||
#![no_main]
|
#![no_main]
|
||||||
|
|
||||||
use panic_halt as _;
|
use panic_halt as _;
|
||||||
|
use cortex_m_semihosting::hprintln; // logs messages to the host; requires a debugger
|
||||||
|
|
||||||
use nb::block;
|
use nb::block;
|
||||||
|
|
||||||
use stm32f1xx_hal::{
|
use stm32f1xx_hal::{
|
||||||
prelude::*,
|
prelude::*,
|
||||||
pac,
|
pac,
|
||||||
|
i2c,
|
||||||
timer::Timer,
|
timer::Timer,
|
||||||
};
|
};
|
||||||
use cortex_m_rt::entry;
|
use cortex_m_rt::entry;
|
||||||
|
@ -23,6 +18,7 @@ use embedded_hal::digital::v2::OutputPin;
|
||||||
|
|
||||||
#[entry]
|
#[entry]
|
||||||
fn main() -> ! {
|
fn main() -> ! {
|
||||||
|
|
||||||
// Get access to the core peripherals from the cortex-m crate
|
// Get access to the core peripherals from the cortex-m crate
|
||||||
let cp = cortex_m::Peripherals::take().unwrap();
|
let cp = cortex_m::Peripherals::take().unwrap();
|
||||||
// Get access to the device specific peripherals from the peripheral access crate
|
// Get access to the device specific peripherals from the peripheral access crate
|
||||||
|
@ -32,6 +28,7 @@ fn main() -> ! {
|
||||||
// HAL structs
|
// HAL structs
|
||||||
let mut flash = dp.FLASH.constrain();
|
let mut flash = dp.FLASH.constrain();
|
||||||
let mut rcc = dp.RCC.constrain();
|
let mut rcc = dp.RCC.constrain();
|
||||||
|
let mut afio = dp.AFIO.constrain(&mut rcc.apb2);
|
||||||
|
|
||||||
// Freeze the configuration of all the clocks in the system and store the frozen frequencies in
|
// Freeze the configuration of all the clocks in the system and store the frozen frequencies in
|
||||||
// `clocks`
|
// `clocks`
|
||||||
|
@ -40,6 +37,23 @@ fn main() -> ! {
|
||||||
// Acquire the GPIOC peripheral
|
// Acquire the GPIOC peripheral
|
||||||
let mut gpioc = dp.GPIOC.split(&mut rcc.apb2);
|
let mut gpioc = dp.GPIOC.split(&mut rcc.apb2);
|
||||||
|
|
||||||
|
let mut gpiob = dp.GPIOB.split(&mut rcc.apb2);
|
||||||
|
let scl = gpiob.pb6.into_alternate_open_drain(&mut gpiob.crl);
|
||||||
|
let sda = gpiob.pb7.into_alternate_open_drain(&mut gpiob.crl);
|
||||||
|
|
||||||
|
let mut i2c = i2c::BlockingI2c::i2c1(dp.I2C1, (scl, sda),
|
||||||
|
&mut afio.mapr,
|
||||||
|
i2c::Mode::Standard{frequency: 400_000},
|
||||||
|
clocks,
|
||||||
|
&mut rcc.apb1,
|
||||||
|
5,
|
||||||
|
1,
|
||||||
|
5,
|
||||||
|
5);
|
||||||
|
|
||||||
|
hprintln!("I2C setup").unwrap();
|
||||||
|
|
||||||
|
|
||||||
// Configure gpio C pin 13 as a push-pull output. The `crh` register is passed to the function
|
// Configure gpio C pin 13 as a push-pull output. The `crh` register is passed to the function
|
||||||
// in order to configure the port. For pins 0-7, crl should be passed instead.
|
// in order to configure the port. For pins 0-7, crl should be passed instead.
|
||||||
let mut led = gpioc.pc13.into_push_pull_output(&mut gpioc.crh);
|
let mut led = gpioc.pc13.into_push_pull_output(&mut gpioc.crh);
|
||||||
|
@ -50,6 +64,14 @@ fn main() -> ! {
|
||||||
loop {
|
loop {
|
||||||
block!(timer.wait()).unwrap();
|
block!(timer.wait()).unwrap();
|
||||||
led.set_high().unwrap();
|
led.set_high().unwrap();
|
||||||
|
|
||||||
|
let res = i2c.write(96, &[0x23, 0x82]);
|
||||||
|
if res.is_ok() {
|
||||||
|
hprintln!("write worked!").unwrap();
|
||||||
|
} else {
|
||||||
|
hprintln!("write failed!").unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
block!(timer.wait()).unwrap();
|
block!(timer.wait()).unwrap();
|
||||||
led.set_low().unwrap();
|
led.set_low().unwrap();
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue