Skip to content

Commit e43f41b

Browse files
authored
Merge pull request #1345 from stineje/main
add Python script used to analyze an ELF file to see instructions from ELF file
2 parents d764a5d + f42900a commit e43f41b

File tree

1 file changed

+83
-0
lines changed

1 file changed

+83
-0
lines changed

bin/analyze_riscv_elf.py

Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
#!/usr/bin/env python3
2+
3+
###########################################
4+
## analyze_riscv_elf.py
5+
##
6+
## Written: james.stine@okstate.edu
7+
## Created: April 7, 2025
8+
##
9+
## Purpose: Analyze a RISC-V ELF file and report which instructions are used,
10+
## along with their frequency. The script disassembles the ELF using
11+
## riscv64-unknown-elf-objdump, filters real instructions (excluding
12+
## pseudo-ops and section headers), and displays a histogram of
13+
## instruction use.Simulate a L1 D$ or I$ for comparison with Wally
14+
##
15+
## A component of the CORE-V-WALLY configurable RISC-V project.
16+
## https://github.com/openhwgroup/cvw
17+
##
18+
## Copyright (C) 2021-25 Harvey Mudd College & Oklahoma State University
19+
##
20+
## SPDX-License-Identifier: Apache-2.0 WITH SHL-2.1
21+
##
22+
## Licensed under the Solderpad Hardware License v 2.1 (the “License”); you may not use this file
23+
## except in compliance with the License, or, at your option, the Apache License version 2.0. You
24+
## may obtain a copy of the License at
25+
##
26+
## https:##solderpad.org/licenses/SHL-2.1/
27+
##
28+
## Unless required by applicable law or agreed to in writing, any work distributed under the
29+
## License is distributed on an “AS IS” BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
30+
## either express or implied. See the License for the specific language governing permissions
31+
## and limitations under the License.
32+
################################################################################################
33+
34+
import re
35+
import subprocess
36+
import sys
37+
from collections import Counter
38+
39+
40+
def disassemble_elf(elf_path):
41+
try:
42+
result = subprocess.run(
43+
["riscv64-unknown-elf-objdump", "-d", "-M", "no-aliases", elf_path],
44+
capture_output=True,
45+
text=True,
46+
check=True
47+
)
48+
return result.stdout
49+
except subprocess.CalledProcessError as e:
50+
print(f"Error running objdump: {e.stderr}")
51+
sys.exit(1)
52+
53+
def extract_instructions(disassembly):
54+
instructions = []
55+
for line in disassembly.splitlines():
56+
# Match instruction lines only: address: machine-code instruction [operands...]
57+
match = re.match(r'^\s*[0-9a-f]+:\s+([0-9a-f]{8}|\s{8})\s+(\S+)', line)
58+
if match:
59+
instr = match.group(2)
60+
instructions.append(instr)
61+
return instructions
62+
63+
def main():
64+
if len(sys.argv) != 2:
65+
print("Usage: python3 analyze_riscv_elf.py <file.elf>")
66+
sys.exit(1)
67+
68+
elf_path = sys.argv[1]
69+
disassembly = disassemble_elf(elf_path)
70+
instructions = extract_instructions(disassembly)
71+
counter = Counter(instructions)
72+
73+
print(f"\nInstruction usage in {elf_path}:\n")
74+
if not counter:
75+
print("No instructions found (did you use the correct target ELF file?)")
76+
else:
77+
for instr, count in counter.most_common():
78+
count_str = f"{count:,}" # Add comma as thousands separator
79+
print(f"{instr:<10} {count_str}")
80+
81+
if __name__ == "__main__":
82+
main()
83+

0 commit comments

Comments
 (0)