Skip to content

Commit 4becb32

Browse files
committed
add linker script parser
1 parent 2adcdda commit 4becb32

File tree

3 files changed

+95
-0
lines changed

3 files changed

+95
-0
lines changed

pyproject.toml

+1
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ dependencies = [
1111
"angr",
1212
"pyelftools",
1313
"pypcode",
14+
"lark",
1415
"lief",
1516
"keystone-engine",
1617
"intelhex",
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
start: (memoryblock | sectionblock | OHTERBLOCK)*
2+
3+
memoryblock: "MEMORY" "{" memory_def* "}"
4+
memory_def: memory_name ["(" memory_attr ")"] ":" "ORIGIN" "=" memory_origin "," "LENGTH" "=" memory_length
5+
memory_attr: CNAME
6+
memory_name: CNAME
7+
memory_origin: HEX | INT
8+
memory_length: HEX | INT | SIZE
9+
10+
sectionblock: "SECTIONS" "{" section_stmt* "}"
11+
section_stmt: section_def | IGNORE_ASSN
12+
section_def: section_name section_addr? ":" IGNORE_BRACE section_region? section_lma_region?
13+
section_addr: HEX | INT
14+
section_name: SECTION_NAME
15+
section_region: ">" CNAME
16+
section_lma_region: "AT>" CNAME
17+
18+
OHTERBLOCK: IGNORE_STMT
19+
20+
IGNORE_PAREN: "(" /[^\(\)]+/s ")"
21+
IGNORE_BRACE: "{" /[^\{\}]+/s "}"
22+
IGNORE_ASSN: /[^=;]+/s "=" /[^=;]+/s ";"
23+
IGNORE_STMT: ("_"|UCASE_LETTER) ("_"|UCASE_LETTER|DIGIT)* (IGNORE_BRACE | IGNORE_PAREN)
24+
25+
SECTION_NAME: "." ("."|CNAME)* "*"?
26+
SIZE: INT ["K" | "M" | "G"]
27+
HEX: "0x" HEXDIGIT+
28+
29+
%import common.LETTER
30+
%import common.UCASE_LETTER
31+
%import common.CNAME
32+
%import common.HEXDIGIT
33+
%import common.DIGIT
34+
%import common.WS
35+
%import common.INT
36+
%import common.CPP_COMMENT
37+
%import common.C_COMMENT
38+
39+
%ignore CPP_COMMENT
40+
%ignore C_COMMENT
41+
%ignore WS
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
import os
2+
3+
import lark
4+
5+
6+
class LinkerScriptParser:
7+
def __init__(self, linker_script_content: str) -> None:
8+
self.linker_script_content = linker_script_content
9+
self.ast = self._parse()
10+
11+
@staticmethod
12+
def from_file(linker_script_path: str):
13+
with open(linker_script_path) as f:
14+
return LinkerScriptParser(f.read())
15+
16+
@staticmethod
17+
def from_string(linker_script_content: str):
18+
return LinkerScriptParser(linker_script_content)
19+
20+
def _parse(self):
21+
with open(os.path.join(os.path.dirname(__file__), "linker_script.lark")) as f:
22+
parser = lark.Lark(f.read())
23+
return parser.parse(self.linker_script_content)
24+
25+
def _get_ast_data(self, tree, name):
26+
node = next(tree.find_data(name), None)
27+
return node.children[0].value if node else None
28+
29+
def get_memory_regions(self):
30+
memory_regions = []
31+
for mem_def in self.ast.find_data("memory_def"):
32+
memory_regions.append(
33+
{
34+
"name": self._get_ast_data(mem_def, "memory_name"),
35+
"attr": self._get_ast_data(mem_def, "memory_attr"),
36+
"origin": self._get_ast_data(mem_def, "memory_origin"),
37+
"length": self._get_ast_data(mem_def, "memory_length"),
38+
}
39+
)
40+
return memory_regions
41+
42+
def get_sections(self):
43+
sections = []
44+
for section_def in self.ast.find_data("section_def"):
45+
sections.append(
46+
{
47+
"name": self._get_ast_data(section_def, "section_name"),
48+
"addr": self._get_ast_data(section_def, "section_addr"),
49+
"region": self._get_ast_data(section_def, "section_region"),
50+
"lma_region": self._get_ast_data(section_def, "section_lma_region"),
51+
}
52+
)
53+
return sections

0 commit comments

Comments
 (0)