forked from leveldown-security/SVD-Loader-Ghidra
-
Notifications
You must be signed in to change notification settings - Fork 0
/
SVD-Loader-Ghidra.py
executable file
·132 lines (103 loc) · 4.05 KB
/
SVD-Loader-Ghidra.py
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
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
# Load specified SVD and generate peripheral memory maps & structures.
#@author Thomas Roth [email protected]
#@category leveldown security
#@keybinding
#@menupath
#@toolbar
# More information:
# https://leveldown.de/blog/svd-loader/
# License: GPLv3
from cmsis_svd.parser import SVDParser
from ghidra.program.model.data import Structure, StructureDataType, UnsignedIntegerDataType, DataTypeConflictHandler
from ghidra.program.model.data import UnsignedShortDataType, ByteDataType, UnsignedLongLongDataType
from ghidra.program.model.mem import MemoryBlockType
from ghidra.program.model.address import AddressFactory
from ghidra.program.model.symbol import SourceType
from ghidra.program.model.mem import MemoryConflictException
from helpers import *
svd_file = askFile("Choose SVD file", "Load SVD File")
print("Loading SVD file...")
parser = SVDParser.for_xml_file(str(svd_file))
print("\tDone!")
# CM0, CM4, etc
cpu_type = parser.get_device().cpu.name
# little/big
cpu_endian = parser.get_device().cpu.endian
default_register_size = parser.get_device().size
# Not all SVDs contain these fields
if cpu_type and not cpu_type.startswith("CM"):
print("Currently only Cortex-M CPUs are supported.")
print("Supplied CPU type was: " + cpu_type)
sys.exit(1)
if cpu_endian and cpu_endian != "little":
print("Currently only little endian CPUs are supported.")
print("Supplied CPU endian was: " + cpu_endian)
sys.exit(1)
# Get things we need
listing = currentProgram.getListing()
symtbl = currentProgram.getSymbolTable()
dtm = currentProgram.getDataTypeManager()
space = currentProgram.getAddressFactory().getDefaultAddressSpace()
namespace = symtbl.getNamespace("Peripherals", None)
if not namespace:
namespace = currentProgram.getSymbolTable().createNameSpace(None, "Peripherals", SourceType.ANALYSIS)
peripherals = parser.get_device().peripherals
print("Generating memory regions...")
# First, we need to generate a list of memory regions.
# This is because some SVD files have overlapping peripherals...
memory_regions = []
for peripheral in peripherals:
start = peripheral.base_address
length = peripheral.address_block.offset + peripheral.address_block.size
end = peripheral.base_address + length
memory_regions.append(MemoryRegion(peripheral.name, start, end))
memory_regions = reduce_memory_regions(memory_regions)
# Create memory blocks:
for r in memory_regions:
try:
addr = space.getAddress(r.start)
length = r.length()
t = currentProgram.memory.createUninitializedBlock(r.name, addr, length, False)
t.setRead(True)
t.setWrite(True)
t.setExecute(False)
t.setVolatile(True)
t.setComment("Generated by SVD-Loader.")
except:
print("\tFailed to generate memory block for: " + r.name)
print("\t", e)
print("\tDone!")
print("Generating peripherals...")
for peripheral in peripherals:
print("\t" + peripheral.name)
if(len(peripheral.registers) == 0):
print("\t\tNo registers.")
continue
try:
# Iterage registers to get size of peripheral
# Most SVDs have an address-block that specifies the size, but
# they are often far too large, leading to issues with overlaps.
length = calculate_peripheral_size(peripheral,default_register_size)
# Generate structure for the peripheral
peripheral_struct = StructureDataType(peripheral.name, length)
peripheral_start = peripheral.base_address
peripheral_end = peripheral_start + length
for register in peripheral.registers:
r_type = UnsignedIntegerDataType()
rs = register._size / 8
if rs == 1:
r_type = ByteDataType()
elif rs == 2:
r_type = UnsignedShortDataType()
elif rs == 8:
r_type = UnsignedLongLongDataType()
peripheral_struct.replaceAtOffset(register.address_offset, r_type, register._size/8, register.name, register.description)
addr = space.getAddress(peripheral_start)
dtm.addDataType(peripheral_struct, DataTypeConflictHandler.REPLACE_HANDLER)
listing.createData(addr, peripheral_struct, False)
symtbl.createLabel(addr,
peripheral.name,
namespace,
SourceType.USER_DEFINED );
except:
print("\t\tFailed to generate peripheral " + peripheral.name)