Merge remote-tracking branch 'origin/Ghidra_12.1'

This commit is contained in:
ghidra1
2026-03-23 15:40:39 -04:00
41 changed files with 33990 additions and 0 deletions
@@ -1,7 +1,12 @@
MODULE FILE LICENSE: pypkg/dist/capstone-5.0.6-py3-none-win_amd64.whl BSD-3-CAPSTONE
MODULE FILE LICENSE: pypkg/dist/comtypes-1.4.13-py3-none-any.whl MIT
MODULE FILE LICENSE: pypkg/dist/pybag-2.2.16-py3-none-any.whl MIT
MODULE FILE LICENSE: pypkg/dist/pywin32-311-cp39-cp39-win_amd64.whl Python Software Foundation License
MODULE FILE LICENSE: pypkg/dist/pywin32-311-cp310-cp310-win_amd64.whl Python Software Foundation License
MODULE FILE LICENSE: pypkg/dist/pywin32-311-cp311-cp311-win_amd64.whl Python Software Foundation License
MODULE FILE LICENSE: pypkg/dist/pywin32-311-cp312-cp312-win_amd64.whl Python Software Foundation License
MODULE FILE LICENSE: pypkg/dist/pywin32-311-cp313-cp313-win_amd64.whl Python Software Foundation License
MODULE FILE LICENSE: pypkg/dist/pywin32-311-cp314-cp314-win_amd64.whl Python Software Foundation License
MODULE FILE LICENSE: pypkg/dist/win32more-0.7.0-py3-none-any.whl MIT
MODULE FILE LICENSE: pypkg/dist/win32more_appsdk-0.7.3-py2.py3-none-any.whl MIT
MODULE FILE LICENSE: pypkg/dist/win32more_core-0.7.0-py2.py3-none-any.whl MIT
@@ -84,7 +84,12 @@ task prebuildTlb(type: Copy) {
distributePyDep("pybag-2.2.16-py3-none-any.whl")
distributePyDep("capstone-5.0.6-py3-none-win_amd64.whl")
distributePyDep("comtypes-1.4.13-py3-none-any.whl")
distributePyDep("pywin32-311-cp39-cp39-win_amd64.whl")
distributePyDep("pywin32-311-cp310-cp310-win_amd64.whl")
distributePyDep("pywin32-311-cp311-cp311-win_amd64.whl")
distributePyDep("pywin32-311-cp312-cp312-win_amd64.whl")
distributePyDep("pywin32-311-cp313-cp313-win_amd64.whl")
distributePyDep("pywin32-311-cp314-cp314-win_amd64.whl")
distributePyDep("win32more-0.7.0-py3-none-any.whl")
distributePyDep("win32more_appsdk-0.7.3-py2.py3-none-any.whl")
distributePyDep("win32more_core-0.7.0-py2.py3-none-any.whl")
View File
+35
View File
@@ -0,0 +1,35 @@
/* ###
* IP: GHIDRA
*
* 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.
*/
apply from: "$rootProject.projectDir/gradle/distributableGhidraModule.gradle"
apply from: "$rootProject.projectDir/gradle/javaProject.gradle"
apply from: "$rootProject.projectDir/gradle/jacocoProject.gradle"
apply from: "$rootProject.projectDir/gradle/javaTestProject.gradle"
apply from: "$rootProject.projectDir/gradle/processorProject.gradle"
apply plugin: 'eclipse'
eclipse.project.name = 'Processors Hexagon'
dependencies {
api project(":BytePatterns")
api project(":Emulation")
testImplementation project(path: ':SoftwareModeling', configuration: 'testArtifacts')
testImplementation project(path: ':Emulation', configuration: 'testArtifacts')
}
sleighCompileOptions = [
"-l",
"-t"
]
+16
View File
@@ -0,0 +1,16 @@
##VERSION: 2.0
Module.manifest||GHIDRA||||END|
data/languages/Hexagon.opinion||GHIDRA||||END|
data/languages/hexagon.cspec||GHIDRA||||END|
data/languages/hexagon.dwarf||GHIDRA||||END|
data/languages/hexagon.ldefs||GHIDRA||||END|
data/languages/hexagon.pspec||GHIDRA||||END|
data/languages/hexagon.sinc||GHIDRA||||END|
data/languages/hexagon.slaspec||GHIDRA||||END|
data/languages/hexagon_float.sinc||GHIDRA||||END|
data/languages/hexagon_hvx.sinc||GHIDRA||||END|
data/languages/hexagon_hvx.txt||GHIDRA|exclude|||END|
data/languages/hexagon_left.sinc||GHIDRA||||END|
data/languages/hexagon_right.sinc||GHIDRA||||END|
data/patterns/Hexagon_patterns.xml||GHIDRA||||END|
data/patterns/patternconstraints.xml||GHIDRA||||END|
+5
View File
@@ -0,0 +1,5 @@
<opinions>
<constraint loader="Executable and Linking Format (ELF)" compilerSpecID="default">
<constraint primary="164" processor="Hexagon" size="32" />
</constraint>
</opinions>
+154
View File
@@ -0,0 +1,154 @@
<?xml version="1.0" encoding="UTF-8"?>
<compiler_spec>
<data_organization>
<absolute_max_alignment value="0" />
<machine_alignment value="8" />
<default_alignment value="1" />
<default_pointer_alignment value="4" />
<char_type signed="false" />
<pointer_size value="4" />
<wchar_size value="4" />
<short_size value="2" />
<integer_size value="4" />
<long_size value="4" />
<long_long_size value="8" />
<float_size value="4" />
<double_size value="8" />
<long_double_size value="8" />
<size_alignment_map>
<entry size="1" alignment="1" />
<entry size="2" alignment="2" />
<entry size="4" alignment="4" />
<entry size="8" alignment="8" />
</size_alignment_map>
</data_organization>
<global>
<range space="ram"/>
<range space="register" first="0x800" last="0x8ff" /> <!-- Registers: S0-S63 -->
</global>
<stackpointer register="SP" space="ram"/>
<prefersplit style="inhalf">
<register name="R1R0_"/>
<register name="R1R0"/>
<register name="R3R2_"/>
<register name="R3R2"/>
<register name="R5R4_"/>
<register name="R5R4"/>
<register name="R7R6_"/>
<register name="R7R6"/>
<register name="R9R8_"/>
<register name="R9R8"/>
<register name="R11R10_"/>
<register name="R11R10"/>
<register name="R13R12_"/>
<register name="R13R12"/>
<register name="R15R14_"/>
<register name="R15R14"/>
<register name="R17R16_"/>
<register name="R17R16"/>
<register name="R19R18_"/>
<register name="R19R18"/>
<register name="R21R20_"/>
<register name="R21R20"/>
<register name="R23R22_"/>
<register name="R23R22"/>
<register name="R25R24_"/>
<register name="R25R24"/>
</prefersplit>
<default_proto>
<prototype name="__stdcall" extrapop="0" stackshift="0">
<input>
<pentry minsize="1" maxsize="4">
<register name="R0"/>
</pentry>
<pentry minsize="1" maxsize="4">
<register name="R1"/>
</pentry>
<pentry minsize="5" maxsize="8">
<register name="R1R0"/>
</pentry>
<pentry minsize="1" maxsize="4">
<register name="R2"/>
</pentry>
<pentry minsize="1" maxsize="4">
<register name="R3"/>
</pentry>
<pentry minsize="5" maxsize="8">
<register name="R3R2"/>
</pentry>
<pentry minsize="1" maxsize="4">
<register name="R4"/>
</pentry>
<pentry minsize="1" maxsize="4">
<register name="R5"/>
</pentry>
<pentry minsize="5" maxsize="8">
<register name="R5R4"/>
</pentry>
<pentry minsize="1" maxsize="500" align="1"> <!-- unable to stipulate alignment properly - see ABI spec -->
<addr offset="0" space="stack"/>
</pentry>
</input>
<output>
<pentry minsize="1" maxsize="8">
<register name="R1R0"/>
</pentry>
</output>
<unaffected>
<register name="R16"/>
<register name="R17"/>
<register name="R18"/>
<register name="R19"/>
<register name="R20"/>
<register name="R21"/>
<register name="R22"/>
<register name="R23"/>
<register name="R24"/>
<register name="R25"/>
<register name="R26"/>
<register name="R27"/>
<register name="SP"/>
<register name="FP"/>
<register name="LC0"/>
<register name="LC1"/>
<register name="SA0"/>
<register name="SA1"/>
<register name="P3P0"/>
<register name="M0"/>
<register name="M1"/>
<register name="GP"/>
<register name="UGP"/>
<register name="FP"/>
</unaffected>
</prototype>
</default_proto>
<!-- Injections for various compiler helper functions -->
<callfixup name="prolog_save_regs">
<pcode><body>
<![CDATA[
ptr:4 = 0; # can't handle empty pcode
]]>
</body></pcode>
</callfixup>
<callfixup name="prolog_restore_regs">
<pcode><body>
<![CDATA[
ptr:4 = FP;
FP = *[ram]:4 ptr;
ptr = ptr + 4;
LR = *[ram]:4 ptr;
SP = ptr + 4;
]]>
</body></pcode>
</callfixup>
</compiler_spec>
@@ -0,0 +1,19 @@
<dwarf>
<register_mappings>
<register_mapping dwarf="0" ghidra="R0" auto_count="29"/> <!-- R0..R28 -->
<register_mapping dwarf="29" ghidra="SP" stackpointer="true"/> <!-- R29 -->
<register_mapping dwarf="30" ghidra="FP"/> <!-- R30 -->
<register_mapping dwarf="31" ghidra="LR"/> <!-- R31 -->
<register_mapping dwarf="32" ghidra="GP"/>
<register_mapping dwarf="33" ghidra="UGP"/>
<register_mapping dwarf="34" ghidra="SA0"/>
<register_mapping dwarf="35" ghidra="LC1"/>
<register_mapping dwarf="36" ghidra="M0"/>
<register_mapping dwarf="37" ghidra="M1"/>
<register_mapping dwarf="38" ghidra="P3P0"/>
<register_mapping dwarf="39" ghidra="PC"/>
<!-- <register_mapping dwarf="40" ghidra="CAUSE"/> **not implemented** -->
<!-- <register_mapping dwarf="41" ghidra="BADVA"/> **not implemented** -->
</register_mappings>
<call_frame_cfa value="0"/>
</dwarf>
+17
View File
@@ -0,0 +1,17 @@
<?xml version="1.0" encoding="UTF-8"?>
<language_definitions>
<language processor="Hexagon"
endian="little"
size="32"
variant="default"
version="2.4"
slafile="hexagon.sla"
processorspec="hexagon.pspec"
id="Hexagon:LE:32:default">
<description>Qualcomm Hexagon V69 processor (QDSP6) 32-bit little-endian</description>
<compiler name="default" spec="hexagon.cspec" id="default"/>
<external_name tool="gnu" name="0x18:0x5"/>
<external_name tool="DWARF.register.mapping.file" name="hexagon.dwarf"/>
</language>
</language_definitions>
+439
View File
@@ -0,0 +1,439 @@
<?xml version="1.0" encoding="UTF-8"?>
<processor_spec>
<properties>
<property key="parallelInstructionHelperClass" value="ghidra.app.util.viewer.field.HexagonParallelInstructionHelper"/>
<property key="emulateInstructionStateModifierClass" value="ghidra.program.emulation.HexagonEmulateInstructionStateModifier"/>
<property key="useropLibs" value="hexagon"/>
<property key="resetContextOnUpgrade" value="true" />
</properties>
<programcounter register="PC"/>
<volatile outputop="writeSReg" inputop="readSReg">
<range space="register" first="0x238" last="0x23f"/> <!-- Register: UPCYCLE -->
<range space="register" first="0x800" last="0x8ff"/> <!-- Registers: S0-S63 -->
</volatile>
<context_data>
<context_set space="ram">
<set name="packetOffset" val="0"/>
</context_set>
<tracked_set space="ram">
<set name="USR" val="0"/>
<set name="FRAMEKEY" val="0"/>
</tracked_set>
</context_data>
<register_data>
<register name="R1R0_" group="SHADOW" hidden="true"/>
<register name="R3R2_" group="SHADOW" hidden="true"/>
<register name="R5R4_" group="SHADOW" hidden="true"/>
<register name="R7R6_" group="SHADOW" hidden="true"/>
<register name="R9R8_" group="SHADOW" hidden="true"/>
<register name="R11R10_" group="SHADOW" hidden="true"/>
<register name="R13R12_" group="SHADOW" hidden="true"/>
<register name="R15R14_" group="SHADOW" hidden="true"/>
<register name="R17R16_" group="SHADOW" hidden="true"/>
<register name="R19R18_" group="SHADOW" hidden="true"/>
<register name="R21R20_" group="SHADOW" hidden="true"/>
<register name="R23R22_" group="SHADOW" hidden="true"/>
<register name="R25R24_" group="SHADOW" hidden="true"/>
<register name="R27R26_" group="SHADOW" hidden="true"/>
<register name="R29R28_" group="SHADOW" hidden="true"/>
<register name="R31R30_" group="SHADOW" hidden="true"/>
<register name="R0.new" group="SHADOW" hidden="true"/>
<register name="R1.new" group="SHADOW" hidden="true"/>
<register name="R2.new" group="SHADOW" hidden="true"/>
<register name="R3.new" group="SHADOW" hidden="true"/>
<register name="R4.new" group="SHADOW" hidden="true"/>
<register name="R5.new" group="SHADOW" hidden="true"/>
<register name="R6.new" group="SHADOW" hidden="true"/>
<register name="R7.new" group="SHADOW" hidden="true"/>
<register name="R8.new" group="SHADOW" hidden="true"/>
<register name="R9.new" group="SHADOW" hidden="true"/>
<register name="R10.new" group="SHADOW" hidden="true"/>
<register name="R11.new" group="SHADOW" hidden="true"/>
<register name="R12.new" group="SHADOW" hidden="true"/>
<register name="R13.new" group="SHADOW" hidden="true"/>
<register name="R14.new" group="SHADOW" hidden="true"/>
<register name="R15.new" group="SHADOW" hidden="true"/>
<register name="R16.new" group="SHADOW" hidden="true"/>
<register name="R17.new" group="SHADOW" hidden="true"/>
<register name="R18.new" group="SHADOW" hidden="true"/>
<register name="R19.new" group="SHADOW" hidden="true"/>
<register name="R20.new" group="SHADOW" hidden="true"/>
<register name="R21.new" group="SHADOW" hidden="true"/>
<register name="R22.new" group="SHADOW" hidden="true"/>
<register name="R23.new" group="SHADOW" hidden="true"/>
<register name="R24.new" group="SHADOW" hidden="true"/>
<register name="R25.new" group="SHADOW" hidden="true"/>
<register name="R26.new" group="SHADOW" hidden="true"/>
<register name="R27.new" group="SHADOW" hidden="true"/>
<register name="R28.new" group="SHADOW" hidden="true"/>
<register name="SP.new" group="SHADOW" hidden="true"/>
<register name="FP.new" group="SHADOW" hidden="true"/>
<register name="LR.new" group="SHADOW" hidden="true"/>
<register name="R0.L_" group="SHADOW" hidden="true"/>
<register name="R0.H_" group="SHADOW" hidden="true"/>
<register name="R1.L_" group="SHADOW" hidden="true"/>
<register name="R1.H_" group="SHADOW" hidden="true"/>
<register name="R2.L_" group="SHADOW" hidden="true"/>
<register name="R2.H_" group="SHADOW" hidden="true"/>
<register name="R3.L_" group="SHADOW" hidden="true"/>
<register name="R3.H_" group="SHADOW" hidden="true"/>
<register name="R4.L_" group="SHADOW" hidden="true"/>
<register name="R4.H_" group="SHADOW" hidden="true"/>
<register name="R5.L_" group="SHADOW" hidden="true"/>
<register name="R5.H_" group="SHADOW" hidden="true"/>
<register name="R6.L_" group="SHADOW" hidden="true"/>
<register name="R6.H_" group="SHADOW" hidden="true"/>
<register name="R7.L_" group="SHADOW" hidden="true"/>
<register name="R7.H_" group="SHADOW" hidden="true"/>
<register name="R8.L_" group="SHADOW" hidden="true"/>
<register name="R8.H_" group="SHADOW" hidden="true"/>
<register name="R9.L_" group="SHADOW" hidden="true"/>
<register name="R9.H_" group="SHADOW" hidden="true"/>
<register name="R10.L_" group="SHADOW" hidden="true"/>
<register name="R10.H_" group="SHADOW" hidden="true"/>
<register name="R11.L_" group="SHADOW" hidden="true"/>
<register name="R11.H_" group="SHADOW" hidden="true"/>
<register name="R12.L_" group="SHADOW" hidden="true"/>
<register name="R12.H_" group="SHADOW" hidden="true"/>
<register name="R13.L_" group="SHADOW" hidden="true"/>
<register name="R13.H_" group="SHADOW" hidden="true"/>
<register name="R14.L_" group="SHADOW" hidden="true"/>
<register name="R14.H_" group="SHADOW" hidden="true"/>
<register name="R15.L_" group="SHADOW" hidden="true"/>
<register name="R15.H_" group="SHADOW" hidden="true"/>
<register name="R16.L_" group="SHADOW" hidden="true"/>
<register name="R16.H_" group="SHADOW" hidden="true"/>
<register name="R17.L_" group="SHADOW" hidden="true"/>
<register name="R17.H_" group="SHADOW" hidden="true"/>
<register name="R18.L_" group="SHADOW" hidden="true"/>
<register name="R18.H_" group="SHADOW" hidden="true"/>
<register name="R19.L_" group="SHADOW" hidden="true"/>
<register name="R19.H_" group="SHADOW" hidden="true"/>
<register name="R20.L_" group="SHADOW" hidden="true"/>
<register name="R20.H_" group="SHADOW" hidden="true"/>
<register name="R21.L_" group="SHADOW" hidden="true"/>
<register name="R21.H_" group="SHADOW" hidden="true"/>
<register name="R22.L_" group="SHADOW" hidden="true"/>
<register name="R22.H_" group="SHADOW" hidden="true"/>
<register name="R23.L_" group="SHADOW" hidden="true"/>
<register name="R23.H_" group="SHADOW" hidden="true"/>
<register name="R24.L_" group="SHADOW" hidden="true"/>
<register name="R24.H_" group="SHADOW" hidden="true"/>
<register name="R25.L_" group="SHADOW" hidden="true"/>
<register name="R25.H_" group="SHADOW" hidden="true"/>
<register name="R26.L_" group="SHADOW" hidden="true"/>
<register name="R26.H_" group="SHADOW" hidden="true"/>
<register name="R27.L_" group="SHADOW" hidden="true"/>
<register name="R27.H_" group="SHADOW" hidden="true"/>
<register name="R28.L_" group="SHADOW" hidden="true"/>
<register name="R28.H_" group="SHADOW" hidden="true"/>
<register name="R29.L_" group="SHADOW" hidden="true"/>
<register name="R29.H_" group="SHADOW" hidden="true"/>
<register name="R30.L_" group="SHADOW" hidden="true"/>
<register name="R30.H_" group="SHADOW" hidden="true"/>
<register name="R31.L_" group="SHADOW" hidden="true"/>
<register name="R31.H_" group="SHADOW" hidden="true"/>
<register name="C1C0" group="Control" hidden="true"/>
<register name="C3C2" group="Control" hidden="true"/>
<register name="C5C4" group="Control" hidden="true"/>
<register name="C7C6" group="Control" hidden="true"/>
<register name="C9C8" group="Control" hidden="true"/>
<register name="C11C10" group="Control" hidden="true"/>
<register name="C13C12" group="Control" hidden="true"/>
<register name="UPCYCLE" group="Control"/>
<register name="C17C16" group="Control" hidden="true"/>
<register name="PKTCOUNT" group="Control"/>
<register name="C21C20" group="Control" hidden="true"/>
<register name="C23C22" group="Control" hidden="true"/>
<register name="C25C24" group="Control" hidden="true"/>
<register name="C27C26" group="Control" hidden="true"/>
<register name="C29C28" group="Control" hidden="true"/>
<register name="UTIMER" group="Control"/>
<register name="C1C0_" group="SHADOW" hidden="true"/>
<register name="C3C2_" group="SHADOW" hidden="true"/>
<register name="C5C4_" group="SHADOW" hidden="true"/>
<register name="C7C6_" group="SHADOW" hidden="true"/>
<register name="C9C8_" group="SHADOW" hidden="true"/>
<register name="C11C10_" group="SHADOW" hidden="true"/>
<register name="C13C12_" group="SHADOW" hidden="true"/>
<register name="UPCYCLE_" group="SHADOW" hidden="true"/>
<register name="C17C16_" group="SHADOW" hidden="true"/>
<register name="PKTCOUNT_" group="SHADOW" hidden="true"/>
<register name="C21C20_" group="SHADOW" hidden="true"/>
<register name="C23C22_" group="SHADOW" hidden="true"/>
<register name="C25C24_" group="SHADOW" hidden="true"/>
<register name="C27C26_" group="SHADOW" hidden="true"/>
<register name="C29C28_" group="SHADOW" hidden="true"/>
<register name="UTIMER_" group="SHADOW" hidden="true"/>
<register name="ReturnAddr" group="SHADOW" hidden="true"/>
<register name="SA0" group="Control"/>
<register name="LC0" group="Control"/>
<register name="SA1" group="Control"/>
<register name="LC1" group="Control"/>
<register name="P3P0" group="Control"/>
<register name="C5" group="Control" hidden="true"/>
<register name="M0" group="Control"/>
<register name="M1" group="Control"/>
<register name="USR" group="Control"/>
<register name="PC" group="Control"/>
<register name="UGP" group="Control"/>
<register name="GP" group="Control"/>
<register name="CS0" group="Control"/>
<register name="CS1" group="Control"/>
<register name="UPCYCLELO" group="Control"/>
<register name="UPCYCLEHI" group="Control"/>
<register name="FRAMELIMIT" group="Control"/>
<register name="FRAMEKEY" group="Control"/>
<register name="PKTCOUNTLO" group="Control"/>
<register name="PKTCOUNTHI" group="Control"/>
<register name="C20" group="Control" hidden="true"/>
<register name="C21" group="Control" hidden="true"/>
<register name="C22" group="Control" hidden="true"/>
<register name="C23" group="Control" hidden="true"/>
<register name="C24" group="Control" hidden="true"/>
<register name="C25" group="Control" hidden="true"/>
<register name="C26" group="Control" hidden="true"/>
<register name="C27" group="Control" hidden="true"/>
<register name="C28" group="Control" hidden="true"/>
<register name="C29" group="Control" hidden="true"/>
<register name="UTIMERLO" group="Control"/>
<register name="UTIMERHI" group="Control"/>
<register name="SA0_" group="SHADOW" hidden="true"/>
<register name="LC0_" group="SHADOW" hidden="true"/>
<register name="SA1_" group="SHADOW" hidden="true"/>
<register name="LC1_" group="SHADOW" hidden="true"/>
<register name="P3P0_" group="SHADOW" hidden="true"/>
<register name="M0_" group="SHADOW" hidden="true"/>
<register name="M1_" group="SHADOW" hidden="true"/>
<register name="USR_" group="SHADOW" hidden="true"/>
<register name="PC_" group="SHADOW" hidden="true"/>
<register name="UGP_" group="SHADOW" hidden="true"/>
<register name="GP_" group="SHADOW" hidden="true"/>
<register name="CS0_" group="SHADOW" hidden="true"/>
<register name="CS1_" group="SHADOW" hidden="true"/>
<register name="UPCYCLELO_" group="SHADOW" hidden="true"/>
<register name="UPCYCLEHI_" group="SHADOW" hidden="true"/>
<register name="FRAMELIMIT_" group="SHADOW" hidden="true"/>
<register name="FRAMEKEY_" group="SHADOW" hidden="true"/>
<register name="PKTCOUNTLO_" group="SHADOW" hidden="true"/>
<register name="PKTCOUNTHI_" group="SHADOW" hidden="true"/>
<register name="C20_" group="SHADOW" hidden="true"/>
<register name="C21_" group="SHADOW" hidden="true"/>
<register name="C22_" group="SHADOW" hidden="true"/>
<register name="C23_" group="SHADOW" hidden="true"/>
<register name="C24_" group="SHADOW" hidden="true"/>
<register name="C25_" group="SHADOW" hidden="true"/>
<register name="C26_" group="SHADOW" hidden="true"/>
<register name="C27_" group="SHADOW" hidden="true"/>
<register name="C28_" group="SHADOW" hidden="true"/>
<register name="C29_" group="SHADOW" hidden="true"/>
<register name="UTIMERLO_" group="SHADOW" hidden="true"/>
<register name="UTIMERHI_" group="SHADOW" hidden="true"/>
<register name="P3.new" group="SHADOW" hidden="true"/>
<register name="P2.new" group="SHADOW" hidden="true"/>
<register name="P1.new" group="SHADOW" hidden="true"/>
<register name="P0.new" group="SHADOW" hidden="true"/>
<register name="G1G0" group="Guest" hidden="true"/>
<register name="G3G2" group="Guest" hidden="true"/>
<register name="G5G4" group="Guest" hidden="true"/>
<register name="G7G6" group="Guest" hidden="true"/>
<register name="G9G8" group="Guest" hidden="true"/>
<register name="G11G10" group="Guest" hidden="true"/>
<register name="G13G12" group="Guest" hidden="true"/>
<register name="G15G14" group="Guest" hidden="true"/>
<register name="G17G16" group="Guest" hidden="true"/>
<register name="G19G18" group="Guest" hidden="true"/>
<register name="G21G20" group="Guest" hidden="true"/>
<register name="G23G22" group="Guest" hidden="true"/>
<register name="G25G24" group="Guest" hidden="true"/>
<register name="G27G26" group="Guest" hidden="true"/>
<register name="G29G28" group="Guest" hidden="true"/>
<register name="G31G30" group="Guest" hidden="true"/>
<register name="G0" group="Guest"/>
<register name="G1" group="Guest"/>
<register name="G2" group="Guest"/>
<register name="G3" group="Guest"/>
<register name="G4" group="Guest" hidden="true"/>
<register name="G5" group="Guest" hidden="true"/>
<register name="G6" group="Guest" hidden="true"/>
<register name="G7" group="Guest" hidden="true"/>
<register name="G8" group="Guest" hidden="true"/>
<register name="G9" group="Guest" hidden="true"/>
<register name="G10" group="Guest" hidden="true"/>
<register name="G11" group="Guest" hidden="true"/>
<register name="G12" group="Guest" hidden="true"/>
<register name="G13" group="Guest" hidden="true"/>
<register name="G14" group="Guest" hidden="true"/>
<register name="G15" group="Guest" hidden="true"/>
<!-- naming of G16-G19 inconsistent between LLVM and V62 ref manual -->
<register name="G16" rename="GPMUCNT4" group="Guest"/>
<register name="G17" rename="GPMUCNT5" group="Guest"/>
<register name="G18" rename="GPMUCNT6" group="Guest"/>
<register name="G19" rename="GPMUCNT7" group="Guest"/>
<register name="G20" group="Guest" hidden="true"/>
<register name="G21" group="Guest" hidden="true"/>
<register name="G22" group="Guest" hidden="true"/>
<register name="G23" group="Guest" hidden="true"/>
<register name="G24" rename="GPCYCLELO" group="Guest"/>
<register name="G25" rename="GPCYCLEHI" group="Guest"/>
<register name="G26" rename="GPMUCNT0" group="Guest"/>
<register name="G27" rename="GPMUCNT1" group="Guest"/>
<register name="G28" rename="GPMUCNT2" group="Guest"/>
<register name="G29" rename="GPMUCNT3" group="Guest"/>
<register name="G30" group="Guest" hidden="true"/>
<register name="G31" group="Guest" hidden="true"/>
<register name="S1S0" group="Supervisor" hidden="true"/>
<register name="S3S2" group="Supervisor" hidden="true"/>
<register name="S5S4" group="Supervisor" hidden="true"/>
<register name="S7S6" group="Supervisor" hidden="true"/>
<register name="S9S8" group="Supervisor" hidden="true"/>
<register name="S11S10" group="Supervisor" hidden="true"/>
<register name="S13S12" group="Supervisor" hidden="true"/>
<register name="S15S14" group="Supervisor" hidden="true"/>
<register name="S17S16" group="Supervisor" hidden="true"/>
<register name="S19S18" group="Supervisor" hidden="true"/>
<register name="S21S20" group="Supervisor" hidden="true"/>
<register name="S23S22" group="Supervisor" hidden="true"/>
<register name="S25S24" group="Supervisor" hidden="true"/>
<register name="S27S26" group="Supervisor" hidden="true"/>
<register name="S29S28" group="Supervisor" hidden="true"/>
<register name="S31S30" group="Supervisor" hidden="true"/>
<register name="S33S32" group="Supervisor" hidden="true"/>
<register name="S35S34" group="Supervisor" hidden="true"/>
<register name="S37S36" group="Supervisor" hidden="true"/>
<register name="S39S38" group="Supervisor" hidden="true"/>
<register name="S41S40" group="Supervisor" hidden="true"/>
<register name="S43S42" group="Supervisor" hidden="true"/>
<register name="S45S44" group="Supervisor" hidden="true"/>
<register name="S47S46" group="Supervisor" hidden="true"/>
<register name="S49S48" group="Supervisor" hidden="true"/>
<register name="S51S50" group="Supervisor" hidden="true"/>
<register name="S53S52" group="Supervisor" hidden="true"/>
<register name="S55S54" group="Supervisor" hidden="true"/>
<register name="S57S56" group="Supervisor" hidden="true"/>
<register name="S59S58" group="Supervisor" hidden="true"/>
<register name="S61S60" group="Supervisor" hidden="true"/>
<register name="S63S62" group="Supervisor" hidden="true"/>
<register name="S0" rename="SGP0" group="Supervisor"/>
<register name="S1" rename="SGP1" group="Supervisor"/>
<register name="S2" rename="STID" group="Supervisor"/>
<register name="S3" rename="ELR" group="Supervisor"/>
<register name="S4" rename="BADVA0" group="Supervisor"/>
<register name="S5" rename="BADVA1" group="Supervisor"/>
<register name="S6" rename="SSR" group="Supervisor"/>
<register name="S7" rename="CCR" group="Supervisor"/>
<register name="S8" rename="HTID" group="Supervisor"/>
<register name="S9" rename="BADVA" group="Supervisor"/>
<register name="S10" rename="IMASK" group="Supervisor"/>
<register name="S11" group="Supervisor" hidden="true"/>
<register name="S12" group="Supervisor" hidden="true"/>
<register name="S13" group="Supervisor" hidden="true"/>
<register name="S14" group="Supervisor" hidden="true"/>
<register name="S15" group="Supervisor" hidden="true"/>
<register name="S16" rename="EVB" group="Supervisor"/>
<register name="S17" rename="MODECTL" group="Supervisor"/>
<register name="S18" rename="SYSCFG" group="Supervisor"/>
<register name="S19" group="Supervisor"/>
<register name="S20" rename="IPEND" group="Supervisor"/>
<register name="S21" rename="VID" group="Supervisor"/>
<register name="S22" rename="IAD" group="Supervisor"/>
<register name="S23" group="Supervisor"/>
<register name="S24" rename="IEL" group="Supervisor"/>
<register name="S25" group="Supervisor"/>
<register name="S26" rename="IAHL" group="Supervisor"/>
<register name="S27" rename="CFGBASE" group="Supervisor"/>
<register name="S28" rename="DIAG" group="Supervisor"/>
<register name="S29" rename="REV" group="Supervisor"/>
<register name="S30" rename="PCYCLELO" group="Supervisor"/>
<register name="S31" rename="PCYCLEHI" group="Supervisor"/>
<register name="S32" rename="ISDBST" group="Supervisor"/>
<register name="S33" rename="ISDBCFG0" group="Supervisor"/>
<register name="S34" rename="ISDBCFG1" group="Supervisor"/>
<register name="S35" group="Supervisor" hidden="true"/>
<register name="S36" rename="BRKPTPC0" group="Supervisor"/>
<register name="S37" rename="BRKPTCFG0" group="Supervisor"/>
<register name="S38" rename="BRKPTPC1" group="Supervisor"/>
<register name="S39" rename="BRKPTCFG1" group="Supervisor"/>
<register name="S40" rename="ISDBMBXIN" group="Supervisor"/>
<register name="S41" rename="ISDBMBXOUT" group="Supervisor"/>
<register name="S42" rename="ISDBEN" group="Supervisor"/>
<register name="S43" rename="ISDBGPR" group="Supervisor"/>
<register name="S44" group="Supervisor" hidden="true"/>
<register name="S45" group="Supervisor"/>
<register name="S46" group="Supervisor" hidden="true"/>
<register name="S47" group="Supervisor" hidden="true"/>
<register name="S48" rename="PMUCNT0" group="Supervisor"/>
<register name="S49" rename="PMUCNT1" group="Supervisor"/>
<register name="S50" rename="PMUCNT2" group="Supervisor"/>
<register name="S51" rename="PMUCNT3" group="Supervisor"/>
<register name="S52" rename="PMUEVTCFG" group="Supervisor"/>
<register name="S53" rename="PMUCFG" group="Supervisor"/>
<register name="S54" group="Supervisor" hidden="true"/>
<register name="S55" group="Supervisor" hidden="true"/>
<register name="S56" group="Supervisor" hidden="true"/>
<register name="S57" group="Supervisor" hidden="true"/>
<register name="S58" group="Supervisor" hidden="true"/>
<register name="S59" group="Supervisor" hidden="true"/>
<register name="S60" group="Supervisor" hidden="true"/>
<!-- uncertain where the naming of S61-S63 originated -->
<register name="S61" rename="ACC0" group="Supervisor"/>
<register name="S62" rename="ACC1" group="Supervisor"/>
<register name="S63" rename="CHICKEN" group="Supervisor"/>
<!-- HVX Vector Registers - Lane sizes .b .h .w -->
<register name="V1V0" group="SVE" vector_lane_sizes="1,2,4"/>
<register name="V3V2" group="SVE" vector_lane_sizes="1,2,4"/>
<register name="V5V4" group="SVE" vector_lane_sizes="1,2,4"/>
<register name="V7V6" group="SVE" vector_lane_sizes="1,2,4"/>
<register name="V9V8" group="SVE" vector_lane_sizes="1,2,4"/>
<register name="V11V10" group="SVE" vector_lane_sizes="1,2,4"/>
<register name="V13V12" group="SVE" vector_lane_sizes="1,2,4"/>
<register name="V15V14" group="SVE" vector_lane_sizes="1,2,4"/>
<register name="V17V16" group="SVE" vector_lane_sizes="1,2,4"/>
<register name="V19V18" group="SVE" vector_lane_sizes="1,2,4"/>
<register name="V21V20" group="SVE" vector_lane_sizes="1,2,4"/>
<register name="V23V22" group="SVE" vector_lane_sizes="1,2,4"/>
<register name="V25V24" group="SVE" vector_lane_sizes="1,2,4"/>
<register name="V27V26" group="SVE" vector_lane_sizes="1,2,4"/>
<register name="V29V28" group="SVE" vector_lane_sizes="1,2,4"/>
<register name="V31V30" group="SVE" vector_lane_sizes="1,2,4"/>
<register name="V1V0_" group="SVE" vector_lane_sizes="1,2,4"/>
<register name="V3V2_" group="SVE" vector_lane_sizes="1,2,4"/>
<register name="V5V4_" group="SVE" vector_lane_sizes="1,2,4"/>
<register name="V7V6_" group="SVE" vector_lane_sizes="1,2,4"/>
<register name="V9V8_" group="SVE" vector_lane_sizes="1,2,4"/>
<register name="V11V10_" group="SVE" vector_lane_sizes="1,2,4"/>
<register name="V13V12_" group="SVE" vector_lane_sizes="1,2,4"/>
<register name="V15V14_" group="SVE" vector_lane_sizes="1,2,4"/>
<register name="V17V16_" group="SVE" vector_lane_sizes="1,2,4"/>
<register name="V19V18_" group="SVE" vector_lane_sizes="1,2,4"/>
<register name="V21V20_" group="SVE" vector_lane_sizes="1,2,4"/>
<register name="V23V22_" group="SVE" vector_lane_sizes="1,2,4"/>
<register name="V25V24_" group="SVE" vector_lane_sizes="1,2,4"/>
<register name="V27V26_" group="SVE" vector_lane_sizes="1,2,4"/>
<register name="V29V28_" group="SVE" vector_lane_sizes="1,2,4"/>
<register name="V31V30_" group="SVE" vector_lane_sizes="1,2,4"/>
</register_data>
</processor_spec>
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,72 @@
<patternlist>
<patternpairs>
<prepatterns>
<data>01000000 00111111 ........ 0.0..... </data> <!-- packed EE dealloc_return -->
<data>01000000 00011111 ........ 001..... </data> <!-- packed EE dealloc_return -->
<data>11000000 00111111 ........ 0.0..... </data> <!-- packed EE jumpr LR -->
<data>11000000 00011111 ........ 001..... </data> <!-- packed EE jumpr LR -->
<data>00011110 11000000 00011110 10010110 </data> <!-- PP dealloc_return, last -->
<data>00011110 01000000 00011110 10010110 ........ 11...... ........ ........ </data> <!-- PP dealloc_return, 2nd to last -->
<data>00011110 01000000 00011110 10010110 ........ 00...... ........ ........ </data> <!-- PP dealloc_return, 2nd to last -->
<data>00011110 01000000 00011110 10010110 ........ 01...... ........ ........ ........ 11...... ........ ........ </data> <!-- PP dealloc_return, 3rd to last -->
<data>00011110 01000000 00011110 10010110 ........ 01...... ........ ........ ........ 00...... ........ ........ </data> <!-- PP dealloc_return, 3rd to last -->
<data>00011110 01000000 00011110 10010110 ........ 01...... ........ ........ ........ 01...... ........ ........ ........ 11...... ........ ........ </data> <!-- PP dealloc_return 4th to last -->
<data>.......0 11...... ........ 0101100. </data> <!-- PP jump, last -->
<data>.......0 01...... ........ 0101100. ........ 11...... ........ ........ </data> <!-- PP jump, 2nd to last -->
<data>.......0 01...... ........ 0101100. ........ 00...... ........ ........ </data> <!-- PP jump, 2nd to last -->
<data>.......0 01...... ........ 0101100. ........ 01...... ........ ........ ........ 11...... ........ ........ </data> <!-- PP jump, 3rd to last -->
<data>.......0 01...... ........ 0101100. ........ 01...... ........ ........ ........ 00...... ........ ........ </data> <!-- PP jump, 3rd to last -->
<data>.......0 01...... ........ 0101100. ........ 01...... ........ ........ ........ 01...... ........ ........ ........ 11...... ........ ........ </data> <!-- PP jump 4th to last -->
<data>00000000 01000000 100..... 01010010 </data> <!-- PP jumpr, last -->
<data>00000000 01000000 100..... 01010010 ........ 11...... ........ ........ </data> <!-- PP jumpr, 2nd to last -->
<data>00000000 01000000 100..... 01010010 ........ 00...... ........ ........ </data> <!-- PP jumpr, 2nd to last -->
<data>00000000 01000000 100..... 01010010 ........ 01...... ........ ........ ........ 11...... ........ ........ </data> <!-- PP jumpr, 3rd to last -->
<data>00000000 01000000 100..... 01010010 ........ 01...... ........ ........ ........ 00...... ........ ........ </data> <!-- PP jumpr, 3rd to last -->
<data>00000000 01000000 100..... 01010010 ........ 01...... ........ ........ ........ 01...... ........ ........ ........ 11...... ........ ........ </data> <!-- PP jumpr 4th to last -->
</prepatterns>
<postpatterns>
<!-- First Instruction in Packet -->
<data>........ .1000... 10011101 10100000 </data> <!-- allocframe (v2,10) - 1st in packet -->
<data>....0000 0011110. ........ 011..... </data> <!-- allocframe (v4,right,6,7) - 1 of 1 in packet -->
<data>....0000 0011110. ........ 101..... </data> <!-- allocframe (v4,right,10,11) - 1 of 1 in packet -->
<data>....0000 00.1110. ........ 110..... </data> <!-- allocframe (v4,right,12,13) - 1 of 1 in packet -->
<data>....0000 0001110. ........ 111..... </data> <!-- allocframe (v4,right,14,15) - 1 of 1 in packet -->
<!-- Second Instruction in Packet -->
<data>........ 01...... ........ ........ ........ .1000... 10011101 10100000 </data> <!-- allocframe (v2,10) - 2nd in packet -->
<data>........ 01...... ........ ........ ....0000 0011110. ........ 011..... </data> <!-- allocframe (v4,right,6,7) - 2 of 2 in packet -->
<data>........ 01...... ........ ........ ....0000 0011110. ........ 101..... </data> <!-- allocframe (v4,right,10,11) - 2 of 2 in packet -->
<data>........ 01...... ........ ........ ....0000 00.1110. ........ 110..... </data> <!-- allocframe (v4,right,12,13) - 2 of 2 in packet -->
<data>........ 01...... ........ ........ ....0000 0001110. ........ 111..... </data> <!-- allocframe (v4,right,14,15) - 2 of 2 in packet -->
<!-- Third Instruction in Packet -->
<data>........ 01...... ........ ........ ........ 01...... ........ ........ ........ .1000... 10011101 10100000 </data> <!-- allocframe (v2,10) - 3rd in packet -->
<data>........ 01...... ........ ........ ........ 01...... ........ ........ ....0000 0011110. ........ 011..... </data> <!-- allocframe (v4,right,6,7) - 3 of 3 in packet -->
<data>........ 01...... ........ ........ ........ 01...... ........ ........ ....0000 0011110. ........ 101..... </data> <!-- allocframe (v4,right,10,11) - 3 of 3 in packet -->
<data>........ 01...... ........ ........ ........ 01...... ........ ........ ....0000 00.1110. ........ 110..... </data> <!-- allocframe (v4,right,12,13) - 3 of 3 in packet -->
<data>........ 01...... ........ ........ ........ 01...... ........ ........ ....0000 0001110. ........ 111..... </data> <!-- allocframe (v4,right,14,15) - 3 of 3 in packet -->
<!-- Fourth Instruction in Packet -->
<data>........ 01...... ........ ........ ........ 01...... ........ ........ ........ 01...... ........ ........ ........ 11000... 10011101 10100000 </data> <!-- allocframe (v2,10) - 4th in packet -->
<data>........ 01...... ........ ........ ........ 01...... ........ ........ ........ 01...... ........ ........ ....0000 0011110. ........ 011..... </data> <!-- allocframe (v4,right,6,7) - 4 of 4 in packet -->
<data>........ 01...... ........ ........ ........ 01...... ........ ........ ........ 01...... ........ ........ ....0000 0011110. ........ 101..... </data> <!-- allocframe (v4,right,10,11) - 4 of 4 in packet -->
<data>........ 01...... ........ ........ ........ 01...... ........ ........ ........ 01...... ........ ........ ....0000 00.1110. ........ 110..... </data> <!-- allocframe (v4,right,12,13) - 4 of 4 in packet -->
<data>........ 01...... ........ ........ ........ 01...... ........ ........ ........ 01...... ........ ........ ....0000 0001110. ........ 111..... </data> <!-- allocframe (v4,right,14,15) - 4 of 4 in packet -->
<funcstart validcode="8" />
</postpatterns>
</patternpairs>
</patternlist>
@@ -0,0 +1,5 @@
<patternconstraints>
<language id="Hexagon:LE:32:*">
<patternfile>Hexagon_patterns.xml</patternfile>
</language>
</patternconstraints>
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,226 @@
/* ###
* IP: GHIDRA
*
* 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.
*/
package ghidra.app.plugin.core.analysis;
import ghidra.app.services.AnalysisPriority;
import ghidra.app.util.viewer.field.HexagonParallelInstructionHelper;
import ghidra.program.model.address.*;
import ghidra.program.model.data.DataType;
import ghidra.program.model.lang.*;
import ghidra.program.model.listing.*;
import ghidra.program.model.pcode.Varnode;
import ghidra.program.model.scalar.Scalar;
import ghidra.program.model.symbol.*;
import ghidra.program.util.SymbolicPropogator;
import ghidra.program.util.VarnodeContext;
import ghidra.util.exception.CancelledException;
import ghidra.util.task.TaskMonitor;
public class HexagonAnalyzer extends ConstantPropagationAnalyzer {
private final static String PROCESSOR_NAME = "Hexagon";
private Register r25Register;
private Register lrRegister;
private Register lrNewRegister;
HexagonParallelInstructionHelper helper = new HexagonParallelInstructionHelper();
protected int pass;
public HexagonAnalyzer() {
super(PROCESSOR_NAME);
setPriority(AnalysisPriority.CODE_ANALYSIS.after());
}
@Override
public boolean canAnalyze(Program program) {
Language language = program.getLanguage();
r25Register = program.getRegister("R25");
lrRegister = program.getRegister("LR");
lrNewRegister = program.getRegister("LR.new");
if (language.getProcessor().equals(Processor.findOrPossiblyCreateProcessor("Hexagon")) &&
r25Register != null && lrRegister != null && lrNewRegister != null) {
return true;
}
return false;
}
@Override
public AddressSetView flowConstants(final Program program, Address flowStart,
AddressSetView flowSet, final SymbolicPropogator symEval, final TaskMonitor monitor)
throws CancelledException {
// follow all flows building up context
// use context to fill out addresses on certain instructions
ConstantPropagationContextEvaluator eval =
new ConstantPropagationContextEvaluator(monitor, trustWriteMemOption) {
@Override
public boolean evaluateContext(VarnodeContext context, Instruction instr) {
// if (instr.getMnemonicString().equals("assign")) {
// Register destReg = instr.getRegister(0);
// if (destReg.getBitLength() == 16) {
// String regName = destReg.getName();
// Register shadowDest =
// program.getRegister(regName.substring(0, regName.length() - 1));
// Scalar s = instr.getScalar(1);
// if (s != null) {
// context.setValue(shadowDest, s.getBigInteger());
// }
// context.propogateResults(true);
// BigInteger rval = context.getValue(program.getRegister("R0"), false);
// Msg.info(this, rval == null ? "NULL" : rval.toString(16));
// rval = context.getValue(program.getRegister("R0.L"), false);
// Msg.info(this, rval == null ? "NULL" : rval.toString(16));
// rval = context.getValue(program.getRegister("R0.H"), false);
// Msg.info(this, rval == null ? "NULL" : rval.toString(16));
// }
// }
FlowType ftype = instr.getFlowType();
if (ftype.isComputed() && ftype.isJump()) {
// TODO: MUST get the value... of the PC????
Varnode destVal = null; // context.getRegisterVarnodeValue(indirectFlowDestReg);
if (destVal != null) {
if (isLinkRegister(context, destVal)) {
// need to set the return override
instr.setFlowOverride(FlowOverride.RETURN);
}
}
}
return false;
}
private boolean isLinkRegister(VarnodeContext context, Varnode destVal) {
Address destAddr = destVal.getAddress();
if (destVal.isRegister()) {
return (destAddr.equals(lrRegister.getAddress()) ||
destAddr.equals(lrNewRegister.getAddress()));
}
else if (context.isSymbol(destVal) && destAddr.getOffset() == 0) {
String symbolSpaceName = destAddr.getAddressSpace().getName();
return (symbolSpaceName.equals(lrRegister.getName()) ||
symbolSpaceName.equals(lrNewRegister.getName()));
}
return false;
}
@Override
public boolean evaluateReference(VarnodeContext context, Instruction instr,
int pcodeop, Address address, int size, DataType dataType,
RefType refType) {
if (address.isExternalAddress()) {
return true;
}
// do super check, then do our own checks
if (!super.evaluateReference(context, instr, pcodeop, address, size, dataType,
refType)) {
return false;
}
if (refType.isData()) {
// // for instruction with more operands than two, will be a dual instruction
// // can only do this for single instructions.
// // Only way to tell if has a third operand and is not an empty string!
// List<Object> opRepList = instr.getDefaultOperandRepresentationList(2);
// if (opRepList != null && opRepList.size() != 0) {
// return true;
// }
// TODO: need to do this better.
// Maybe take a look at the register values to tag things on for read/write
// all Reads should be in (). Writes should be in () on the left side.
if (refType.isWrite()) {
// goes on first operand
instr.addOperandReference(0, address, refType, SourceType.ANALYSIS);
return false;
}
else if (refType.isRead()) {
// goes on second operand
instr.addOperandReference(1, address, refType, SourceType.ANALYSIS);
return false;
}
}
// look backward for a good assign instruction that has this as a constant
// want to markup there if we find one.
return markupParallelInstruction(instr, refType, address);
}
/**
* For parallel instruction effects, look back to see if there is a constant in the parallel chain
* to match this target address.
*
* @return true to just mark it up anywhere, false if we actually put the reference on here.
*/
private boolean markupParallelInstruction(Instruction instr, RefType refType,
Address address) {
Instruction prevInst = instr;
int count = 0;
while (helper.isParallelInstruction(prevInst) && count++ < 5) {
Address fallFrom = prevInst.getFallFrom();
if (fallFrom == null)
break;
prevInst = program.getListing().getInstructionAt(fallFrom);
if (prevInst == null)
break;
int numOps = prevInst.getNumOperands();
for (int i = 0; i < numOps; i++) {
Scalar scalar = prevInst.getScalar(i);
if (scalar == null)
continue;
long unsignedValue = scalar.getUnsignedValue();
if (unsignedValue == address.getOffset()) {
// found the value, mark it up
prevInst.addOperandReference(i, address, refType,
SourceType.ANALYSIS);
return false;
}
}
}
return true; // just go ahead and mark up the instruction
}
@Override
public boolean evaluateDestination(VarnodeContext context,
Instruction instruction) {
FlowType flowType = instruction.getFlowType();
if (!flowType.isJump()) {
return false;
}
// TODO: if this is a switch stmt, add to destSet
Reference[] refs = instruction.getReferencesFrom();
if (refs.length <= 0 ||
(refs.length == 1 && refs[0].getReferenceType().isData())) {
destSet.addRange(instruction.getMinAddress(), instruction.getMinAddress());
}
return false;
}
};
eval.setTrustWritableMemory(trustWriteMemOption)
.setMinSpeculativeOffset(minSpeculativeRefAddress)
.setMaxSpeculativeOffset(maxSpeculativeRefAddress)
.setMinStoreLoadOffset(minStoreLoadRefAddress)
.setCreateComplexDataFromPointers(createComplexDataFromPointers);
AddressSet resultSet = symEval.flowConstants(flowStart, flowSet, eval, true, monitor);
return resultSet;
}
}
@@ -0,0 +1,288 @@
/* ###
* IP: GHIDRA
* NOTE: Need to review if these patterns are any indicators of code/original binary, even the address examples
*
* 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.
*/
package ghidra.app.plugin.core.analysis;
import ghidra.app.cmd.function.CreateFunctionCmd;
import ghidra.app.services.*;
import ghidra.app.util.importer.MessageLog;
import ghidra.framework.options.Options;
import ghidra.program.model.address.Address;
import ghidra.program.model.address.AddressSetView;
import ghidra.program.model.lang.IncompatibleMaskException;
import ghidra.program.model.lang.MaskImpl;
import ghidra.program.model.listing.*;
import ghidra.program.model.mem.DumbMemBufferImpl;
import ghidra.program.model.symbol.SourceType;
import ghidra.util.Msg;
import ghidra.util.exception.*;
import ghidra.util.task.TaskMonitor;
public class HexagonPrologEpilogAnalyzer extends AbstractAnalyzer {
private static final String NAME = "Hexagon Prolog/Epilog Functions";
private static final String DESCRIPTION =
"Detects common Prolog/Epilog functions used within Hexagon code and marks them as inline";
private final static String PROCESSOR_NAME = "Hexagon";
private final static String OPTION_NAME_FIXUP_FUNCTIONS = "Prolog/Epilog Function Fixup";
private static final String OPTION_DESCRIPTION_FIXUP_FUNCTIONS =
"Select fixup type which should be applied to Prolog functions (save registers) and Epilog functions (restore registers and dealloc frame).";
public enum FIXUP_TYPES {
Name_Only, Inline, Call_Fixup
}
private FIXUP_TYPES fixupType = FIXUP_TYPES.Call_Fixup;
// Call fixup names as defined in cspec
private final static String CALL_FIXUP_PROLOG_NAME = "prolog_save_regs";
private final static String CALL_FIXUP_EPILOG_NAME = "prolog_restore_regs";
// TODO: These patterns may be incomplete
private static InstructionMaskValue NOP = new InstructionMaskValue(0xffff3fff, 0x7f000000); // nop - ignore parse bits
private static InstructionMaskValue JUMPR_LR = new InstructionMaskValue(0xffff3fff, 0x529f0000); // jumpr lr - ignore parse bits
private static InstructionMaskValue JUMP = new InstructionMaskValue(0xfe000001, 0x58000000); // jump - ignore parse bits
private static InstructionMaskValue MEMD_PUSH =
new InstructionMaskValue(0xfdff0000, 0xa5de0000); // memd (FP+#-nn),<rtt5> - ignore parse bits
private static InstructionMaskValue MEMD_POP = new InstructionMaskValue(0xfdff0000, 0x95de0000); // memd <rdd5>,(FP+#-nn) - ignore parse bits
private static InstructionMaskValue DEALLOCFRAME = new InstructionMaskValue(0xffff3fff,
0x901e001e); // deallocframe - ignore parse bits
private static InstructionMaskValue DEALLOC_RETURN = new InstructionMaskValue(0xffff3fff,
0x961e001e); // deallocreturn - ignore parse bits
public HexagonPrologEpilogAnalyzer() {
super(NAME, DESCRIPTION, AnalyzerType.FUNCTION_ANALYZER);
setDefaultEnablement(true);
setPriority(AnalysisPriority.CODE_ANALYSIS.before());
}
@Override
public boolean canAnalyze(Program program) {
if (!PROCESSOR_NAME.equals(program.getLanguage().getProcessor().toString())) {
return false;
}
return true;
}
private boolean setPrologEpilog(Program program, Address entryPoint, boolean isProlog,
TaskMonitor monitor) {
Listing listing = program.getListing();
Function function = listing.getFunctionAt(entryPoint);
if (function == null) {
CreateFunctionCmd cmd = new CreateFunctionCmd(entryPoint);
if (!cmd.applyTo(program, monitor)) {
return false;
}
function = cmd.getFunction();
}
else if (function.isInline()) {
return true;
}
setPrologEpilog(function, isProlog);
return true;
}
private void setPrologEpilog(Function function, boolean isProlog) {
if (fixupType == FIXUP_TYPES.Inline) {
function.setInline(true);
Msg.info(this, "Set inline " + (isProlog ? "prolog" : "epilog") + " function at " +
function.getEntryPoint());
}
else if (fixupType == FIXUP_TYPES.Call_Fixup) {
function.setCallFixup(isProlog ? CALL_FIXUP_PROLOG_NAME : CALL_FIXUP_EPILOG_NAME);
Msg.info(this, "Set call-fixup " + (isProlog ? "prolog" : "epilog") + " function at " +
function.getEntryPoint());
}
if (function.getSymbol().getSource() == SourceType.DEFAULT) {
String name = isProlog ? "prolog_save_regs@" : "epilog_restore_regs@";
try {
function.setName(name + function.getEntryPoint(), SourceType.ANALYSIS);
}
catch (DuplicateNameException e) {
// ignore
}
catch (InvalidInputException e) {
throw new AssertException(e);
}
}
}
@Override
public boolean added(Program program, AddressSetView set, TaskMonitor monitor, MessageLog log)
throws CancelledException {
monitor.setMessage("Find Prologs and Epilogs...");
monitor.initialize(set.getNumAddresses());
int cnt = 0;
for (Function function : program.getListing().getFunctions(set, true)) {
monitor.checkCancelled();
monitor.setProgress(++cnt);
if (function.isInline() || function.getCallFixup() != null) {
continue;
}
if (isProlog(program, function.getEntryPoint(), true, monitor)) {
setPrologEpilog(function, true);
}
else if (isEpilog(program, function.getEntryPoint(), true, monitor)) {
setPrologEpilog(function, false);
}
}
return true;
}
private boolean isProlog(Program program, Address entryPoint, boolean recurseOk,
TaskMonitor monitor) throws CancelledException {
DumbMemBufferImpl mem = new DumbMemBufferImpl(program.getMemory(), entryPoint);
int memdCnt = 0;
boolean returnPending = false;
byte[] bytes = new byte[4];
for (int i = 0; i < 5; i++) {
if (mem.getBytes(bytes, i * 4) != 4) {
return false;
}
if (NOP.isMatch(bytes)) {
// ignore
}
else if (JUMPR_LR.isMatch(bytes)) {
returnPending = true;
}
else if (JUMP.isMatch(bytes)) {
if (!recurseOk ||
!hasContinuationFunction(program, entryPoint.add(i * 4), true, monitor)) {
return false;
}
returnPending = true;
}
else if (MEMD_PUSH.isMatch(bytes)) {
++memdCnt;
}
else {
return false; // unexpected instruction for prolog
}
if (returnPending && ((bytes[1] & 0x0c0) == 0x0c0)) {
break; // return pending and at end of parallel group
}
}
return (memdCnt != 0);
}
private boolean isEpilog(Program program, Address entryPoint, boolean recurseOk,
TaskMonitor monitor) throws CancelledException {
DumbMemBufferImpl mem = new DumbMemBufferImpl(program.getMemory(), entryPoint);
int memdCnt = 0;
boolean returnPending = false;
byte[] bytes = new byte[4];
for (int i = 0; i < 5; i++) {
if (mem.getBytes(bytes, i * 4) != 4) {
return false;
}
if (NOP.isMatch(bytes)) {
// ignore
}
else if (JUMPR_LR.isMatch(bytes) || DEALLOC_RETURN.isMatch(bytes)) {
returnPending = true;
}
else if (JUMP.isMatch(bytes)) {
if (!recurseOk ||
!hasContinuationFunction(program, entryPoint.add(i * 4), false, monitor)) {
return false;
}
returnPending = true;
}
else if (MEMD_POP.isMatch(bytes)) {
++memdCnt;
}
else if (DEALLOCFRAME.isMatch(bytes)) {
// ignore
}
else {
return false; // unexpected instruction for prolog
}
if (returnPending && ((bytes[1] & 0x0c0) == 0x0c0)) {
break; // return pending and at end of parallel group
}
}
return (memdCnt != 0);
}
private boolean hasContinuationFunction(Program program, Address jumpFromAddr,
boolean checkProlog, TaskMonitor monitor) throws CancelledException {
Listing listing = program.getListing();
Instruction instr = listing.getInstructionAt(jumpFromAddr);
if (instr == null) {
// unable to continue without instruction at jumpFromAddr
return false;
}
Address destAddr = instr.getAddress(0);
if (destAddr == null) {
return false;
}
if (checkProlog) {
return (isProlog(program, destAddr, false, monitor) && setPrologEpilog(program,
destAddr, true, monitor));
}
return (isEpilog(program, destAddr, false, monitor) && setPrologEpilog(program, destAddr,
false, monitor));
}
@Override
public void registerOptions(Options options, Program program) {
options.registerOption(OPTION_NAME_FIXUP_FUNCTIONS, FIXUP_TYPES.Name_Only, null,
OPTION_DESCRIPTION_FIXUP_FUNCTIONS);
}
@Override
public void optionsChanged(Options options, Program program) {
fixupType = options.getEnum(OPTION_NAME_FIXUP_FUNCTIONS, FIXUP_TYPES.Name_Only);
}
private static class InstructionMaskValue {
private MaskImpl mask;
private byte[] valueBytes;
InstructionMaskValue(int maskValue, int value) {
mask = new MaskImpl(getBytes(maskValue));
valueBytes = getBytes(value);
}
public boolean isMatch(byte[] bytes) {
try {
return mask.equalMaskedValue(bytes, valueBytes);
}
catch (IncompatibleMaskException e) {
throw new AssertException(e);
}
}
}
private static byte[] getBytes(int value) {
byte[] bytes = new byte[4];
// TODO: Order may need to change !!
bytes[0] = (byte) value;
bytes[1] = (byte) (value >> 8);
bytes[2] = (byte) (value >> 16);
bytes[3] = (byte) (value >> 24);
return bytes;
}
}
@@ -0,0 +1,292 @@
/* ###
* IP: GHIDRA
* NOTE: Need to review if these patterns are any indicators of code/original binary, even the address examples
*
* 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.
*/
package ghidra.app.plugin.core.analysis;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
import ghidra.app.cmd.function.CreateFunctionCmd;
import ghidra.app.services.*;
import ghidra.app.util.importer.MessageLog;
import ghidra.program.model.address.*;
import ghidra.program.model.listing.*;
import ghidra.program.model.mem.MemoryBlock;
import ghidra.program.model.symbol.*;
import ghidra.program.util.SymbolicPropogator;
import ghidra.util.bytesearch.*;
import ghidra.util.exception.CancelledException;
import ghidra.util.task.TaskMonitor;
public class HexagonThunkAnalyzer extends AbstractAnalyzer {
private static final String NAME = "Hexagon Thunks";
private static final String DESCRIPTION =
"Detects common Thunk pattern used within Hexagon code";
/**
* <code>THUNK_PATTERN1</code>
* <pre>
* 1d 7f fd bf add SP,SP,#-0x8
* fe fc 9d a7 || memw (SP+#-0x8),R28
* aa ca bc 72 assign R28.H,#0x8aaa
* aa cb bc 71 assign R28.L,#0x8baa
* 1d 41 1d b0 add SP,SP,#0x8
* 00 40 9c 52 || jumpr R28
* 1c c0 9d 91 || memw R28,(SP)
* </pre>
*/
private static final String THUNK_PATTERN1 =
"0x1d7ffdbf 0xfefc9da7 " + "..................11110001110010 " // first assign .H
+ "..................11110001110001 " // second assign .L
+ "0x1d411db0 0x00409c52 0x1cc09d91";
private final static String PROCESSOR_NAME = "Hexagon";
private BulkPatternSearcher<Pattern> sequenceSearchState;
public HexagonThunkAnalyzer() {
super(NAME, DESCRIPTION, AnalyzerType.INSTRUCTION_ANALYZER);
setDefaultEnablement(true);
setPriority(AnalysisPriority.CODE_ANALYSIS.before());
}
@Override
public boolean canAnalyze(Program program) {
if (!PROCESSOR_NAME.equals(program.getLanguage().getProcessor().toString())) {
return false;
}
return true;
}
private BulkPatternSearcher<Pattern> getSequenceSearchState() {
if (sequenceSearchState == null) {
List<Pattern> thunkPatterns = new ArrayList<Pattern>();
thunkPatterns.add(new Pattern(new DittedBitSequence(THUNK_PATTERN1), 0,
new PostRule[0], new MatchAction[0]));
sequenceSearchState = new BulkPatternSearcher<Pattern>(thunkPatterns);
}
return sequenceSearchState;
}
@Override
public boolean added(Program program, AddressSetView set, TaskMonitor monitor, MessageLog log)
throws CancelledException {
monitor.setMessage("Search for Thunks...");
BulkPatternSearcher<Pattern> searchState = getSequenceSearchState();
long numAddrs = 0;
monitor.initialize(set.getNumAddresses());
MemoryBlock[] blocks = program.getMemory().getBlocks();
for (int i = 0; i < blocks.length; ++i) {
monitor.setProgress(numAddrs);
MemoryBlock block = blocks[i];
numAddrs += block.getSize();
try {
if (set.intersects(block.getStart(), block.getEnd())) {
searchBlock(searchState, program, block, set, monitor, log);
}
}
catch (IOException e) {
log.appendMsg("Unable to scan block " + block.getName() + " for function starts");
}
}
return true;
}
private void searchBlock(BulkPatternSearcher<Pattern> searchState, Program program,
MemoryBlock block,
AddressSetView restrictSet, TaskMonitor monitor, MessageLog log) throws IOException,
CancelledException {
// if no restricted set, make restrict set the full block
AddressSet doneSet = new AddressSet(restrictSet);
if (doneSet.isEmpty()) {
doneSet.addRange(block.getStart(), block.getEnd());
}
doneSet = doneSet.intersectRange(block.getStart(), block.getEnd());
long currentProgress = monitor.getProgress();
// pull each range off the restricted set
AddressRangeIterator addressRanges = doneSet.getAddressRanges();
while (addressRanges.hasNext()) {
monitor.checkCancelled();
AddressRange addressRange = addressRanges.next();
monitor.setProgress(currentProgress);
currentProgress += addressRange.getLength();
ArrayList<Match<Pattern>> mymatches = new ArrayList<>();
Address blockStartAddr = block.getStart();
long blockOffset = addressRange.getMinAddress().subtract(blockStartAddr);
if (blockOffset <= 0) {
// don't go before the block start
blockOffset = 0;
}
// compute number of bytes in the range + 1, and don't search more than that.
long maxBlockSearchLength =
addressRange.getMaxAddress().subtract(blockStartAddr) - blockOffset + 1;
InputStream data = block.getData();
data.skip(blockOffset);
searchState.search(data, maxBlockSearchLength, mymatches, monitor);
monitor.checkCancelled();
// TODO: DANGER there is much offset<-->address calculation here
// should be OK, since they are all relative to the block.
for (int i = 0; i < mymatches.size(); ++i) {
monitor.checkCancelled();
Match<Pattern> match = mymatches.get(i);
Pattern pattern = match.getPattern();
long offset = blockOffset + match.getStart() + pattern.getMarkOffset();
Address addr = blockStartAddr.add(offset);
createThunk(program, addr, monitor, log);
}
}
}
private Address getThunkDestination(Function thunk, AddressSetView body) {
Listing listing = thunk.getProgram().getListing();
Instruction lastInstr = listing.getInstructionContaining(body.getMaxAddress());
if (lastInstr == null) {
return null;
}
FlowType flowType = lastInstr.getFlowType();
if (!flowType.isCall() && !flowType.isJump()) {
return null;
}
Reference flowRef = null;
for (Reference ref : lastInstr.getReferencesFrom()) {
RefType refType = ref.getReferenceType();
if (!refType.isFlow()) {
continue;
}
if (flowRef != null) {
return null;
}
if (!refType.isCall() && !refType.isJump()) {
return null;
}
flowRef = ref;
}
return flowRef != null ? flowRef.getToAddress() : null;
}
private void createThunk(Program program, Address addr, TaskMonitor monitor, MessageLog log)
throws CancelledException {
// check existing function first
Function func = program.getFunctionManager().getFunctionAt(addr);
if (func != null && func.isThunk()) {
return;
}
// no instruction, ignore it
Instruction instruction = program.getListing().getInstructionAt(addr);
if (instruction == null) {
return;
}
// don't know a body, make a dummy
AddressSet body;
body = new AddressSet(addr, addr.add(27));
// first get function to destination
// use the symbolic propagator to lay down the reference (restricted to this body).
SymbolicPropogator symEval = new SymbolicPropogator(program);
symEval.flowConstants(addr, body, null, true, monitor);
// if the found snippet is fallen into, at least get the to ref, so if
// this is found to be a thunk later, the reference is already there.
// instruction falling into it, not a thunk
// instruction must not be a jump to this location either.
Address fallFrom = instruction.getFallFrom();
if (fallFrom != null) {
Instruction fromInstr = program.getListing().getInstructionAt(fallFrom);
if (fromInstr != null) {
FlowType flowType = fromInstr.getFlowType();
if (!flowType.isJump() || flowType.isConditional()) {
return;
}
Reference[] referencesFrom = fromInstr.getReferencesFrom();
for (int i = 0; i < referencesFrom.length; i++) {
if (!referencesFrom.equals(addr)) {
return;
}
}
}
}
// Then create the body.
if (func == null) {
// must create it
CreateFunctionCmd createFunctionCmd =
new CreateFunctionCmd(null, addr, body, SourceType.ANALYSIS);
createFunctionCmd.applyTo(program);
func = program.getFunctionManager().getFunctionAt(addr);
}
if (func == null) {
return;
}
Address thunkDest = getThunkDestination(func, body);
if (thunkDest == null) {
return;
}
Listing listing = func.getProgram().getListing();
FunctionManager funcMgr = func.getProgram().getFunctionManager();
Function thunkedFunc = funcMgr.getFunctionAt(thunkDest);
if (thunkedFunc == null) {
Instruction instr = listing.getInstructionAt(thunkDest);
if (instr == null) {
return;
}
CreateFunctionCmd cmd = new CreateFunctionCmd(thunkDest);
cmd.applyTo(func.getProgram());
thunkedFunc = funcMgr.getFunctionAt(thunkDest);
if (thunkedFunc == null) {
return;
}
}
func.setThunkedFunction(thunkedFunc);
}
}
@@ -0,0 +1,190 @@
/* ###
* IP: GHIDRA
*
* 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.
*/
package ghidra.app.plugin.core.analysis;
import ghidra.app.services.*;
import ghidra.app.util.importer.MessageLog;
import ghidra.program.model.address.*;
import ghidra.program.model.lang.Register;
import ghidra.program.model.listing.*;
import ghidra.program.model.pcode.PcodeOp;
import ghidra.program.model.pcode.Varnode;
import ghidra.util.exception.CancelledException;
import ghidra.util.task.TaskMonitor;
import java.math.BigInteger;
import java.util.Arrays;
import java.util.HashSet;
public class HexagonUnsupportSemanticAnalyzer extends AbstractAnalyzer {
private static final String NAME = "Hexagon Unsupported Semantic Check";
private static final String DESCRIPTION =
"Detects and bookmarks instruction packets which read a predicate register before it is written";
private final static String PROCESSOR_NAME = "Hexagon";
private final static String BOOKMARK_CATEGORY_NAME = "Unsupported Semantics";
private static final String[] predicateNames = new String[] { "P0", "P1", "P2", "P3" };
private Register packetOffsetRegister;
private HashSet<Register> pNewRegisters = new HashSet<Register>();
public HexagonUnsupportSemanticAnalyzer() {
super(NAME, DESCRIPTION, AnalyzerType.INSTRUCTION_ANALYZER);
setDefaultEnablement(true);
setSupportsOneTimeAnalysis();
setPriority(AnalysisPriority.CODE_ANALYSIS);
}
@Override
public boolean canAnalyze(Program program) {
if (!PROCESSOR_NAME.equals(program.getLanguage().getProcessor().toString())) {
return false;
}
packetOffsetRegister = program.getRegister("packetOffset");
for (int i = 0; i < predicateNames.length; i++) {
Register predReg = program.getRegister(predicateNames[i] + ".new");
pNewRegisters.add(predReg);
}
return true;
}
private boolean isStartOfPacket(Instruction instruction) {
BigInteger value = instruction.getValue(packetOffsetRegister, false);
return value == null || (value.intValue() == 0);
}
@Override
public boolean added(Program program, AddressSetView set, TaskMonitor monitor, MessageLog log)
throws CancelledException {
for (AddressRange range : set) {
added(program, range.getMinAddress(), range.getMaxAddress(), monitor, log);
}
return true;
}
private Address getStartOfPacket(Program program, Address instrAddr) {
Listing listing = program.getListing();
// assume we will only get aligned address
Instruction instr = listing.getInstructionAt(instrAddr);
try {
while (instr != null && !isStartOfPacket(instr)) {
Address prevAddr = instrAddr.subtractNoWrap(4);
instr = listing.getInstructionAt(prevAddr);
if (instr != null) {
instrAddr = instr.getAddress();
}
}
}
catch (AddressOverflowException e) {
// ignore
}
return instrAddr;
}
private int getPredicateNumber(Register preg) {
return preg.getName().charAt(1) - 0x30;
}
private void added(Program program, Address minAddr, Address maxAddr, TaskMonitor monitor,
MessageLog log) {
Listing listing = program.getListing();
boolean[] predWasWritten = new boolean[predicateNames.length];
Arrays.fill(predWasWritten, false);
Address instrAddr = getStartOfPacket(program, minAddr); // find start of packet
Instruction instr = listing.getInstructionAt(instrAddr);
// skip past empty regions
if (instr == null) {
instr = listing.getInstructionAfter(instrAddr);
if (instr == null) {
return;
}
}
instrAddr = instr.getAddress();
while (instr != null && (instrAddr.compareTo(maxAddr) <= 0 || !isStartOfPacket(instr))) {
if (isStartOfPacket(instr)) {
Arrays.fill(predWasWritten, false);
}
for (PcodeOp op : instr.getPcode()) {
for (Varnode in : op.getInputs()) {
if (in.isRegister() && in.getSize() == 1) {
Register reg = program.getRegister(in.getAddress(), 1);
if (pNewRegisters.contains(reg)) {
int index = getPredicateNumber(reg);
if (!predWasWritten[index]) {
markUnsupportPredicateRead(instr, reg);
}
}
}
}
Varnode out = op.getOutput();
if (out != null && out.isRegister() && out.getSize() == 1) {
Register reg = program.getRegister(out.getAddress(), 1);
if (pNewRegisters.contains(reg)) {
// We ignore write to P3P0_ since this should only occur for packet initialization
int index = getPredicateNumber(reg);
predWasWritten[index] = true;
}
}
}
try {
instrAddr = instrAddr.addNoWrap(4);
}
catch (AddressOverflowException e) {
break;
}
instr = listing.getInstructionAt(instrAddr);
if (instr == null) {
// skip past empty regions
instr = listing.getInstructionAfter(instrAddr);
if (instr != null) {
instrAddr = instr.getAddress();
Arrays.fill(predWasWritten, false);
}
}
}
}
private void markUnsupportPredicateRead(Instruction instr, Register predReg) {
instr.getProgram().getBookmarkManager().setBookmark(instr.getAddress(),
BookmarkType.WARNING, BOOKMARK_CATEGORY_NAME,
"Predicate " + predReg.getName() + " read before written");
}
@Override
public boolean removed(Program program, AddressSetView set, TaskMonitor monitor, MessageLog log)
throws CancelledException {
program.getBookmarkManager().removeBookmarks(set, BookmarkType.WARNING,
BOOKMARK_CATEGORY_NAME, monitor);
return true;
}
}
@@ -0,0 +1,71 @@
/* ###
* IP: GHIDRA
*
* 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.
*/
package ghidra.app.util.bin.format.elf;
public class Hexagon_ElfConstants {
// Hexagon-specific e_flags
// Object processor version flags, bits[11:0]
public static final int EF_HEXAGON_MACH_V2 = 0x00000001; // Hexagon V2
public static final int EF_HEXAGON_MACH_V3 = 0x00000002; // Hexagon V3
public static final int EF_HEXAGON_MACH_V4 = 0x00000003; // Hexagon V4
public static final int EF_HEXAGON_MACH_V5 = 0x00000004; // Hexagon V5
public static final int EF_HEXAGON_MACH_V55 = 0x00000005; // Hexagon V55
public static final int EF_HEXAGON_MACH_V60 = 0x00000060; // Hexagon V60
public static final int EF_HEXAGON_MACH_V62 = 0x00000062; // Hexagon V62
public static final int EF_HEXAGON_MACH_V65 = 0x00000065; // Hexagon V65
public static final int EF_HEXAGON_MACH_V66 = 0x00000066; // Hexagon V66
public static final int EF_HEXAGON_MACH_V67 = 0x00000067; // Hexagon V67
public static final int EF_HEXAGON_MACH_V67T = 0x00008067; // Hexagon V67T
public static final int EF_HEXAGON_MACH_V68 = 0x00000068; // Hexagon V68
public static final int EF_HEXAGON_MACH_V69 = 0x00000069; // Hexagon V69
public static final int EF_HEXAGON_MACH_V71 = 0x00000071; // Hexagon V71
public static final int EF_HEXAGON_MACH_V71T = 0x00008071; // Hexagon V71T
public static final int EF_HEXAGON_MACH_V73 = 0x00000073; // Hexagon V73
public static final int EF_HEXAGON_MACH = 0x000003ff; // Hexagon V..
// Highest ISA version flags
public static final int EF_HEXAGON_ISA_MACH = 0x00000000; // Same as specified in bits[11:0] of e_flags
public static final int EF_HEXAGON_ISA_V2 = 0x00000010; // Hexagon V2 ISA
public static final int EF_HEXAGON_ISA_V3 = 0x00000020; // Hexagon V3 ISA
public static final int EF_HEXAGON_ISA_V4 = 0x00000030; // Hexagon V4 ISA
public static final int EF_HEXAGON_ISA_V5 = 0x00000040; // Hexagon V5 ISA
public static final int EF_HEXAGON_ISA_V55 = 0x00000050; // Hexagon V55 ISA
public static final int EF_HEXAGON_ISA_V60 = 0x00000060; // Hexagon V60 ISA
public static final int EF_HEXAGON_ISA_V62 = 0x00000062; // Hexagon V62 ISA
public static final int EF_HEXAGON_ISA_V65 = 0x00000065; // Hexagon V65 ISA
public static final int EF_HEXAGON_ISA_V66 = 0x00000066; // Hexagon V66 ISA
public static final int EF_HEXAGON_ISA_V67 = 0x00000067; // Hexagon V67 ISA
public static final int EF_HEXAGON_ISA_V68 = 0x00000068; // Hexagon V68 ISA
public static final int EF_HEXAGON_ISA_V69 = 0x00000069; // Hexagon V69 ISA
public static final int EF_HEXAGON_ISA_V71 = 0x00000071; // Hexagon V71 ISA
public static final int EF_HEXAGON_ISA_V73 = 0x00000073; // Hexagon V73 ISA
public static final int EF_HEXAGON_ISA_V75 = 0x00000075; // Hexagon V75 ISA
public static final int EF_HEXAGON_ISA = 0x000003ff; // Hexagon V.. ISA
// Hexagon-specific section indexes for common small data
public static final int SHN_HEXAGON_SCOMMON = 0xff00; // Other access sizes
public static final int SHN_HEXAGON_SCOMMON_1 = 0xff01; // Byte-sized access
public static final int SHN_HEXAGON_SCOMMON_2 = 0xff02; // Half-word-sized access
public static final int SHN_HEXAGON_SCOMMON_4 = 0xff03; // Word-sized access
public static final int SHN_HEXAGON_SCOMMON_8 = 0xff04; // Double-word-size access
private Hexagon_ElfConstants() {
// no construct
}
}
@@ -0,0 +1,74 @@
/* ###
* IP: GHIDRA
*
* 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.
*/
package ghidra.app.util.bin.format.elf.extend;
import ghidra.app.util.bin.format.elf.*;
import ghidra.app.util.bin.format.elf.ElfDynamicType.ElfDynamicValueType;
import ghidra.program.model.lang.Language;
public class Hexagon_ElfExtension extends ElfExtension {
// Elf Program Header Extensions
public static final ElfProgramHeaderType PT_ARM_EXIDX =
new ElfProgramHeaderType(0x70000000, "PT_ARM_EXIDX", "Frame unwind information");
// Elf Section Header Extensions
public static final ElfSectionHeaderType SHT_ARM_EXIDX =
new ElfSectionHeaderType(0x70000001, "SHT_ARM_EXIDX", "Exception Index table");
public static final ElfSectionHeaderType SHT_ARM_PREEMPTMAP = new ElfSectionHeaderType(
0x70000002, "SHT_ARM_PREEMPTMAP", "BPABI DLL dynamic linking preemption map");
public static final ElfSectionHeaderType SHT_ARM_ATTRIBUTES = new ElfSectionHeaderType(
0x70000003, "SHT_ARM_ATTRIBUTES", "Object file compatibility attributes");
public static final ElfSectionHeaderType SHT_ARM_DEBUGOVERLAY =
new ElfSectionHeaderType(0x70000004, "SHT_ARM_DEBUGOVERLAY", "See DBGOVL for details");
public static final ElfSectionHeaderType SHT_ARM_OVERLAYSECTION =
new ElfSectionHeaderType(0x70000005, "SHT_ARM_OVERLAYSECTION",
"See Debugging Overlaid Programs (DBGOVL) for details");
// Elf Dynamic Type Extensions
// DT_HEXAGON_SYMSZ: This value is equivalent to the value of DT_SYMENT multiplied by the value
// field "nchain" in the hash table pointed to by DT_HASH.
public static final ElfDynamicType DT_HEXAGON_SYMSZ =
new ElfDynamicType(0x70000000, "DT_HEXAGON_SYMSZ",
"Size in bytes of the DT_SYMTAB symbol table ", ElfDynamicValueType.VALUE);
// DT_HEXAGON_VER: Currently can be a value of 2 or 3. Hexagon ABI requires a value of 3
// although the default is 2.
public static final ElfDynamicType DT_HEXAGON_VER = new ElfDynamicType(0x70000001,
"DT_HEXAGON_VER", "Version of interface with dynamic linker", ElfDynamicValueType.VALUE);
public static final ElfDynamicType DT_HEXAGON_PLT = new ElfDynamicType(0x70000002,
"DT_HEXAGON_PLT", "Image offset of the PLT", ElfDynamicValueType.VALUE);
@Override
public boolean canHandle(ElfHeader elf) {
return elf.e_machine() == ElfConstants.EM_HEXAGON;
}
@Override
public boolean canHandle(ElfLoadHelper elfLoadHelper) {
Language language = elfLoadHelper.getProgram().getLanguage();
return canHandle(elfLoadHelper.getElfHeader()) &&
"Hexagon".equals(language.getProcessor().toString());
}
@Override
public String getDataTypeSuffix() {
return "_Hexagon";
}
}
@@ -0,0 +1,34 @@
/* ###
* IP: GHIDRA
*
* 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.
*/
package ghidra.app.util.bin.format.elf.extend;
public class Hexagon_ElfProgramHeaderConstants {
public static final int EF_HEXAGON_MACH_V4 = 0x3; // Hexagon V4
public static final int EF_HEXAGON_MACH_V5 = 0x4; // Hexagon V5
public static final int EF_HEXAGON_MACH_V55 = 0x5; // Hexagon V55
public static final int EF_HEXAGON_MACH_V60 = 0x60; // Hexagon V60
public static final int EF_HEXAGON_MACH_V61 = 0x61; // Hexagon V61
public static final int EF_HEXAGON_MACH_V62 = 0x62; // Hexagon V62
public static final int EF_HEXAGON_MACH_V65 = 0x65; // Hexagon V65
public static final int EF_HEXAGON_MACH_V66 = 0x66; // Hexagon V66
public static final int EF_HEXAGON_MACH_V67 = 0x67; // Hexagon V67
public static final int EF_HEXAGON_MACH_V67T = 0x8067; // Hexagon V67 Small Core (V67t)
public static final int EF_HEXAGON_MACH_V68 = 0x68; // Hexagon V68
public static final int EF_HEXAGON_MACH_V69 = 0x69; // Hexagon V69
public static final int EF_HEXAGON_MACH_V71 = 0x71; // Hexagon V71
}
@@ -0,0 +1,219 @@
/* ###
* IP: GHIDRA
*
* 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.
*/
package ghidra.app.util.bin.format.elf.relocation;
import ghidra.app.util.bin.format.elf.*;
import ghidra.app.util.importer.MessageLog;
import ghidra.program.model.address.Address;
import ghidra.program.model.listing.Program;
import ghidra.program.model.mem.Memory;
import ghidra.program.model.mem.MemoryAccessException;
import ghidra.program.model.reloc.Relocation.Status;
import ghidra.program.model.reloc.RelocationResult;
public class Hexagon_ElfRelocationHandler
extends AbstractElfRelocationHandler<Hexagon_ElfRelocationType, ElfRelocationContext<?>> {
/**
* Constructor
*/
public Hexagon_ElfRelocationHandler() {
super(Hexagon_ElfRelocationType.class);
}
@Override
public boolean canRelocate(ElfHeader elf) {
return elf.e_machine() == ElfConstants.EM_HEXAGON;
}
@Override
public int getRelrRelocationType() {
return Hexagon_ElfRelocationType.R_HEXAGON_RELATIVE.typeId;
}
@Override
protected RelocationResult relocate(ElfRelocationContext<?> elfRelocationContext,
ElfRelocation relocation, Hexagon_ElfRelocationType type, Address relocationAddress,
ElfSymbol elfSymbol, Address symbolAddr, long symbolValue, String symbolName)
throws MemoryAccessException {
Program program = elfRelocationContext.getProgram();
Memory memory = program.getMemory();
MessageLog log = elfRelocationContext.getLog();
long addend = relocation.getAddend();
long offset = (int) relocationAddress.getOffset();
int symbolIndex = relocation.getSymbolIndex();
int byteLength = 4; // applied relocation length
// Handle relative relocations that do not require symbolAddr or symbolValue
switch (type) {
case R_HEXAGON_RELATIVE:
long imageBaseAdjustment = elfRelocationContext.getImageBaseWordAdjustmentOffset();
int value = (int) (addend + imageBaseAdjustment);
memory.setInt(relocationAddress, value);
return new RelocationResult(Status.APPLIED, byteLength);
case R_HEXAGON_COPY:
markAsUnsupportedCopy(program, relocationAddress, type, symbolName, symbolIndex,
elfSymbol.getSize(), elfRelocationContext.getLog());
return RelocationResult.UNSUPPORTED;
default:
break;
}
// Check for unresolved symbolAddr and symbolValue required by remaining relocation types handled below
if (handleUnresolvedSymbol(elfRelocationContext, relocation, relocationAddress)) {
return RelocationResult.FAILURE;
}
int value = (int) (symbolValue + addend);
int memValue = memory.getInt(relocationAddress);
switch (type) {
case R_HEXAGON_B22_PCREL:
int dist =
(int) (Integer.toUnsignedLong(value) - Integer.toUnsignedLong((int) offset));
if ((dist < -0x00800000) || (dist >= 0x00800000)) {
return RelocationResult.FAILURE;
}
memValue &= ~0x01ff3fff;
memValue |= 0x00003fff & dist;
memValue |= 0x01ff0000 & (dist << 2);
memory.setInt(relocationAddress, memValue);
break;
// break;
// case R_HEXAGON_B15_PCREL:
// break;
// case R_HEXAGON_B7_PCREL:
// break;
case R_HEXAGON_HI16:
value = (value >> 16) & 0xffff;
/* fallthrough */
case R_HEXAGON_LO16:
memValue &= ~0x00c03fff;
memValue |= value & 0x3fff;
memValue |= (value & 0xc000) << 8;
memory.setInt(relocationAddress, memValue);
break;
case R_HEXAGON_32:
memory.setInt(relocationAddress, value);
if (symbolIndex != 0 && addend != 0 && !elfSymbol.isSection()) {
warnExternalOffsetRelocation(program, relocationAddress, symbolAddr, symbolName,
addend, elfRelocationContext.getLog());
applyComponentOffsetPointer(program, relocationAddress, addend);
}
break;
case R_HEXAGON_16:
memory.setShort(relocationAddress, (short) value);
byteLength = 2;
break;
case R_HEXAGON_8:
memory.setByte(relocationAddress, (byte) value);
byteLength = 1;
break;
// case R_HEXAGON_GPREL16_0:
// break;
// case R_HEXAGON_GPREL16_1:
// break;
// case R_HEXAGON_GPREL16_2:
// break;
// case R_HEXAGON_GPREL16_3:
// break;
// case R_HEXAGON_HL16:
// break;
// case R_HEXAGON_B13_PCREL:
// break;
// case R_HEXAGON_B9_PCREL:
// break;
// case R_HEXAGON_B32_PCREL_X:
// break;
// case R_HEXAGON_32_6_X:
// break;
// case R_HEXAGON_B22_PCREL_X:
// break;
// case R_HEXAGON_B15_PCREL_X:
// break;
// case R_HEXAGON_B13_PCREL_X:
// break;
// case R_HEXAGON_B9_PCREL_X:
// break;
// case R_HEXAGON_B7_PCREL_X:
// break;
// case R_HEXAGON_16_X:
// break;
// case R_HEXAGON_12_X:
// break;
// case R_HEXAGON_11_X:
// break;
// case R_HEXAGON_10_X:
// break;
// case R_HEXAGON_9_X:
// break;
// case R_HEXAGON_8_X:
// break;
// case R_HEXAGON_7_X:
// break;
// case R_HEXAGON_6_X:
// break;
case R_HEXAGON_32_PCREL:
dist = (int) (Integer.toUnsignedLong(value) - Integer.toUnsignedLong((int) offset));
memory.setInt(relocationAddress, dist);
break;
case R_HEXAGON_GLOB_DAT:
case R_HEXAGON_JMP_SLOT: {
memory.setInt(relocationAddress, value);
break;
}
// case R_HEXAGON_PLT_B22_PCREL:
// break;
// case R_HEXAGON_GOTOFF_LO16:
// break;
// case R_HEXAGON_GOTOFF_HI16:
// break;
// case R_HEXAGON_GOTOFF_32:
// break;
// case R_HEXAGON_GOT_LO16:
// break; // TODO: See MIPS for similar HI/LO approach
// case R_HEXAGON_GOT_HI16:
// break; // TODO: See MIPS for similar HI/LO approach
// case R_HEXAGON_GOT_32:
// break;
// case R_HEXAGON_GOT_16:
// break;
default:
markAsUnhandled(program, relocationAddress, type, symbolIndex, symbolName, log);
return RelocationResult.UNSUPPORTED;
}
return new RelocationResult(Status.APPLIED, byteLength);
}
}
@@ -0,0 +1,151 @@
/* ###
* IP: GHIDRA
*
* 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.
*/
package ghidra.app.util.bin.format.elf.relocation;
public enum Hexagon_ElfRelocationType implements ElfRelocationType {
/**
* NOTES:
* 1. The GP register is set to the starting address of the process's small data area,
* as referenced by the program symbol, "_SDA_BASE_".
*
*
*/
/* V2 */
R_HEXAGON_NONE(0),
R_HEXAGON_B22_PCREL(1),
R_HEXAGON_B15_PCREL(2),
R_HEXAGON_B7_PCREL(3),
R_HEXAGON_LO16(4),
R_HEXAGON_HI16(5),
R_HEXAGON_32(6),
R_HEXAGON_16(7),
R_HEXAGON_8(8),
R_HEXAGON_GPREL16_0(9),
R_HEXAGON_GPREL16_1(10),
R_HEXAGON_GPREL16_2(11),
R_HEXAGON_GPREL16_3(12),
R_HEXAGON_HL16(13),
/* V3 */
R_HEXAGON_B13_PCREL(14),
/* V4 */
R_HEXAGON_B9_PCREL(15),
/* V4 (extenders) */
R_HEXAGON_B32_PCREL_X(16),
R_HEXAGON_32_6_X(17),
/* V4 (extended) */
R_HEXAGON_B22_PCREL_X(18),
R_HEXAGON_B15_PCREL_X(19),
R_HEXAGON_B13_PCREL_X(20),
R_HEXAGON_B9_PCREL_X(21),
R_HEXAGON_B7_PCREL_X(22),
R_HEXAGON_16_X(23),
R_HEXAGON_12_X(24),
R_HEXAGON_11_X(25),
R_HEXAGON_10_X(26),
R_HEXAGON_9_X(27),
R_HEXAGON_8_X(28),
R_HEXAGON_7_X(29),
R_HEXAGON_6_X(30),
/* V2 PIC */
R_HEXAGON_32_PCREL(31),
R_HEXAGON_COPY(32),
R_HEXAGON_GLOB_DAT(33),
R_HEXAGON_JMP_SLOT(34),
R_HEXAGON_RELATIVE(35),
R_HEXAGON_PLT_B22_PCREL(36),
R_HEXAGON_GOTOFF_LO16(37),
R_HEXAGON_GOTOFF_HI16(38),
R_HEXAGON_GOTOFF_32(39),
R_HEXAGON_GOT_LO16(40),
R_HEXAGON_GOT_HI16(41),
R_HEXAGON_GOT_32(42),
R_HEXAGON_GOT_16(43),
R_HEXAGON_DTPMOD_32(44),
R_HEXAGON_DTPREL_LO16(45),
R_HEXAGON_DTPREL_HI16(46),
R_HEXAGON_DTPREL_32(47),
R_HEXAGON_DTPREL_16(48),
R_HEXAGON_GD_PLT_B22_PCREL(49),
R_HEXAGON_GD_GOT_LO16(50),
R_HEXAGON_GD_GOT_HI16(51),
R_HEXAGON_GD_GOT_32(52),
R_HEXAGON_GD_GOT_16(53),
R_HEXAGON_IE_LO16(54),
R_HEXAGON_IE_HI16(55),
R_HEXAGON_IE_32(56),
R_HEXAGON_IE_GOT_LO16(57),
R_HEXAGON_IE_GOT_HI16(58),
R_HEXAGON_IE_GOT_32(59),
R_HEXAGON_IE_GOT_16(60),
R_HEXAGON_TPREL_LO16(61),
R_HEXAGON_TPREL_HI16(62),
R_HEXAGON_TPREL_32(63),
R_HEXAGON_TPREL_16(64),
R_HEXAGON_6_PCREL_X(65),
R_HEXAGON_GOTREL_32_6_X(66),
R_HEXAGON_GOTREL_16_X(67),
R_HEXAGON_GOTREL_11_X(68),
R_HEXAGON_GOT_32_6_X(69),
R_HEXAGON_GOT_16_X(70),
R_HEXAGON_GOT_11_X(71),
R_HEXAGON_DTPREL_32_6_X(72),
R_HEXAGON_DTPREL_16_X(73),
R_HEXAGON_DTPREL_11_X(74),
R_HEXAGON_GD_GOT_32_6_X(75),
R_HEXAGON_GD_GOT_16_X(76),
R_HEXAGON_GD_GOT_11_X(77),
R_HEXAGON_IE_32_6_X(78),
R_HEXAGON_IE_16_X(79),
R_HEXAGON_IE_GOT_32_6_X(80),
R_HEXAGON_IE_GOT_16_X(81),
R_HEXAGON_IE_GOT_11_X(82),
R_HEXAGON_TPREL_32_6_X(83),
R_HEXAGON_TPREL_16_X(84),
R_HEXAGON_TPREL_11_X(85),
R_HEXAGON_LD_PLT_B22_PCREL(86),
R_HEXAGON_LD_GOT_LO16(87),
R_HEXAGON_LD_GOT_HI16(88),
R_HEXAGON_LD_GOT_32(89),
R_HEXAGON_LD_GOT_16(90),
R_HEXAGON_LD_GOT_32_6_X(91),
R_HEXAGON_LD_GOT_16_X(92),
R_HEXAGON_LD_GOT_11_X(93),
R_HEXAGON_23_REG(94),
R_HEXAGON_GD_PLT_B22_PCREL_X(95),
R_HEXAGON_GD_PLT_B32_PCREL_X(96),
R_HEXAGON_LD_PLT_B22_PCREL_X(97),
R_HEXAGON_LD_PLT_B32_PCREL_X(98),
R_HEXAGON_27_REG(99);
public final int typeId;
private Hexagon_ElfRelocationType(int typeId) {
this.typeId = typeId;
}
@Override
public int typeId() {
return typeId;
}
}
@@ -0,0 +1,63 @@
/* ###
* IP: GHIDRA
*
* 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.
*/
package ghidra.app.util.viewer.field;
import ghidra.program.model.lang.ParallelInstructionLanguageHelper;
import ghidra.program.model.lang.Register;
import ghidra.program.model.listing.Instruction;
import java.math.BigInteger;
public class HexagonParallelInstructionHelper implements ParallelInstructionLanguageHelper {
public HexagonParallelInstructionHelper() {
}
@Override
public String getMnemonicPrefix(Instruction instr) {
if (isParallelInstruction(instr)) {
return "||";
}
return null;
}
@Override
public boolean isParallelInstruction(Instruction instruction) {
Register packetOffsetReg = instruction.getRegister("packetOffset");
if (packetOffsetReg == null) {
return false;
}
BigInteger value = instruction.getValue(packetOffsetReg, false);
return value.intValue() != 0;
}
@Override
public boolean isEndOfParallelInstructionGroup(Instruction instruction) {
try {
byte[] bytes = instruction.getBytes();
// assume little endian'
// End of packet instruction will have PP='11' or EE='00'
int bits = (bytes[1] & 0xC0) >> 6;
return (bits == 0 || bits == 3);
}
catch (Exception e) {
// ignore
}
return true;
}
}
@@ -0,0 +1,56 @@
/* ###
* IP: GHIDRA
*
* 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.
*/
package ghidra.program.emulation;
public enum HexagonFp32 {
;
public static final int FP32_FRAC_POS = 0;
public static final int FP32_FRAC_SIZE = 23;
public static final int FP32_FRAC_MASK = ((1 << FP32_FRAC_SIZE) - 1) << FP32_FRAC_POS;
public static final int FP32_EXP_POS = FP32_FRAC_POS + FP32_FRAC_SIZE;
public static final int FP32_EXP_SIZE = 8;
public static final int FP32_EXP_MASK = ((1 << FP32_EXP_SIZE) - 1) << FP32_EXP_POS;
public static final int FP32_SIGN_POS = FP32_EXP_POS + FP32_EXP_SIZE;
public static final int FP32_BIAS = (1 << FP32_EXP_SIZE - 1) - 1;
static int maskFp32Exponent(int valueBits) {
return FP32_EXP_MASK & valueBits;
}
static int maskFp32Fraction(int valueBits) {
return FP32_FRAC_MASK & valueBits;
}
static boolean isFp32Zero(int exp, int frac) {
return exp == 0 && frac == 0;
}
static boolean isFp32Normal(int exp, int frac) {
return exp != 0 && exp != FP32_EXP_MASK;
}
static boolean isFp32Subnormal(int exp, int frac) {
return exp == 0 && frac != 0;
}
static boolean isFp32Infinite(int exp, int frac) {
return exp == FP32_EXP_MASK && frac == 0;
}
static boolean isFp32Nan(int exp, int frac) {
return exp == FP32_EXP_MASK && frac != 0;
}
}
@@ -0,0 +1,229 @@
/* ###
* IP: GHIDRA
*
* 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.
*/
package ghidra.program.emulation;
public enum HexagonFp64 {
;
public static final int FP64_FRAC_POS = 0;
public static final int FP64_FRAC_SIZE = 52;
public static final long FP64_FRAC_MASK = ((1L << FP64_FRAC_SIZE) - 1) << FP64_FRAC_POS;
public static final int FP64_EXP_POS = FP64_FRAC_POS + FP64_FRAC_SIZE;
public static final int FP64_EXP_SIZE = 11;
public static final long FP64_EXP_MASK = ((1L << FP64_EXP_SIZE) - 1) << FP64_EXP_POS;
public static final int FP64_SIGN_POS = FP64_EXP_POS + FP64_EXP_SIZE;
public static final int FP64_BIAS = (1 << FP64_EXP_SIZE - 1) - 1;
public static final int FP64_EXP_INF = (int) (FP64_EXP_MASK >>> FP64_EXP_POS);
static long maskFp64Exponent(long valueBits) {
return FP64_EXP_MASK & valueBits;
}
static long maskFp64Fraction(long valueBits) {
return FP64_FRAC_MASK & valueBits;
}
static boolean isFp64Zero(long exp, long frac) {
return exp == 0 && frac == 0;
}
static boolean isFp64Normal(long exp, long frac) {
return exp != 0 && exp != FP64_EXP_MASK;
}
static boolean isFp64Subnormal(long exp, long frac) {
return exp == 0 && frac != 0;
}
static boolean isFp64Infinite(long exp, long frac) {
return exp == FP64_EXP_MASK && frac == 0;
}
static boolean isFp64Nan(long exp, long frac) {
return exp == FP64_EXP_MASK && frac != 0;
}
static boolean isFp64Negative(long bits) {
return bits < 0;
}
static long getFp64Fraction(long exp, long frac) {
// Note: No additional shifting of frac necessary, as FP64_FRAC_POS = 0
if (isFp64Normal(exp, frac)) {
return frac | (1L << FP64_FRAC_SIZE);
}
if (isFp64Zero(exp, frac)) {
return 0L;
}
if (!isFp64Subnormal(exp, frac)) {
return -1L;
}
return frac;
}
static int getFp64Exponent(long exp, long frac) {
if (isFp64Normal(exp, frac)) {
return (int) (exp >>> FP64_EXP_POS);
}
if (isFp64Subnormal(exp, frac)) {
return (int) (exp >>> FP64_EXP_POS) + 1;
}
return -1;
}
static long encSign(boolean negative) {
return negative ? Long.MIN_VALUE : 0;
}
static long encExp(int exp, long mantUpper) {
if ((mantUpper >>> (FP64_FRAC_SIZE - 32)) == 0) {
return 0;
}
return Integer.toUnsignedLong(exp) << FP64_EXP_POS;
}
static long encFrac(long mantUpper, int mantLower) {
return ((mantUpper << 32) | Integer.toUnsignedLong(mantLower)) & FP64_FRAC_MASK;
}
public static long dfmpyhh(long rdd, long rss, long rtt) {
long expRss = maskFp64Exponent(rss);
long fracRss = maskFp64Fraction(rss);
long expRtt = maskFp64Exponent(rtt);
long fracRtt = maskFp64Fraction(rtt);
if (isFp64Zero(expRss, fracRss) || isFp64Nan(expRss, fracRss) ||
isFp64Infinite(expRss, fracRss) ||
isFp64Zero(expRtt, fracRtt) || isFp64Nan(expRtt, fracRtt) ||
isFp64Infinite(expRtt, fracRtt)) {
return Double.doubleToRawLongBits(
Double.longBitsToDouble(rss) * Double.longBitsToDouble(rtt));
}
// Read Accumulated from rdd
boolean sticky = (rdd & 1) != 0;
int mantLower = (int) (rdd >> 1);
long mantUpper = rdd >> 33;
long prod = (getFp64Fraction(expRss, fracRss) >>> 32) *
(getFp64Fraction(expRtt, fracRtt) >>> 32);
mantUpper += prod;
int exp = getFp64Exponent(expRss, fracRss) + getFp64Exponent(expRtt, fracRtt) -
FP64_BIAS - 20;
if (!isFp64Normal(expRss, fracRss) || !isFp64Normal(expRtt, fracRtt)) {
// Crush to inexact 0
sticky = true;
exp = -4096;
}
boolean negative = isFp64Negative(rss) ^ isFp64Negative(rtt);
// round
boolean round = false;
boolean guard = false;
if (sticky && mantLower == 0 && mantUpper == 0) {
return Double.doubleToRawLongBits(0.0);
}
// normalize right for fraction
// 32 is size of mantLower
for (; mantUpper >>> (FP64_FRAC_SIZE + 1 - 32) != 0; exp++) {
sticky |= round;
round = guard;
guard = (mantLower & 1) != 0;
mantLower >>>= 1;
mantLower |= (mantUpper << 63) >>> 32;
mantUpper >>>= 1;
}
// (else) normalize left for fraction
for (; (mantUpper & (1L << FP64_FRAC_SIZE - 32)) == 0; exp--) {
mantUpper <<= 1;
mantUpper |= mantLower >>> 31;
mantLower <<= 1;
mantLower |= guard ? 1 : 0;
guard = round;
round = sticky;
}
// normalize right for exponent
if (1 - exp > 130) { // if (exp < -129)
sticky |= round | guard | (mantLower == 0 && mantUpper == 0);
guard = false;
round = false;
exp = 1;
}
for (; 1 - exp >= 64; exp += 64) { // while (exp <= -63)
// Can this be re-specialized to this 64|32-bit split?
sticky |= round | guard | (mantLower == 0 && (mantUpper & 0x0_ffff_ffffL) == 0);
guard = (mantUpper >>> 31) != 0;
round = (mantUpper >>> 30) != 0;
/**
* effective shift right 64 bits
*
* | ----- long upper ---- | int lower |
*
* |BB:AA:99:88:77:66:55:44|33:22:11:00|
*
* |00:00:00:00:00:00:00:00|BB:AA:99:88|
*/
mantLower = (int) (mantUpper >>> 32);
mantUpper = 0;
}
for (; 1 - exp >= 0; exp++) {
sticky |= round;
round = guard;
guard = (mantLower & 1) != 0;
mantLower >>>= 1;
mantLower |= (mantUpper << 63) >>> 32;
mantUpper >>>= 1;
}
// one more normalize right for fraction
if (mantUpper >>> (FP64_FRAC_SIZE + 1 - 32) != 0) {
sticky |= round;
round = guard;
guard = (mantLower & 1) != 0;
mantLower >>>= 1;
mantLower |= (mantUpper << 63) >>> 32;
mantUpper >>>= 1;
exp++;
}
if (exp >= FP64_EXP_INF) {
return Double.doubleToRawLongBits(negative
? Double.NEGATIVE_INFINITY
: Double.POSITIVE_INFINITY);
}
return encSign(negative) | encExp(exp, mantUpper) | encFrac(mantUpper, mantLower);
}
public static long dfmpyfix(long rss, long rtt) {
long expRss = maskFp64Exponent(rss);
long fracRss = maskFp64Fraction(rss);
long expRtt = maskFp64Exponent(rtt);
long fracRtt = maskFp64Exponent(rtt);
if (!isFp64Normal(expRss, fracRss) && isFp64Normal(expRtt, fracRtt) &&
expRtt >= (512 << FP64_EXP_POS)) {
return Double.doubleToRawLongBits(Double.longBitsToDouble(rss) * 0x1.0p52);
}
if (!isFp64Normal(expRtt, fracRtt) && isFp64Normal(expRss, fracRss) &&
expRss >= (512 << FP64_EXP_POS)) {
return Double.doubleToRawLongBits(Double.longBitsToDouble(rss) * 0x1.0p-52);
}
return rss;
}
}
@@ -0,0 +1,210 @@
/* ###
* IP: GHIDRA
*
* 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.
*/
package ghidra.program.emulation;
import java.util.function.Function;
import ghidra.app.plugin.processors.sleigh.SleighLanguage;
import ghidra.pcode.error.LowlevelError;
import ghidra.pcode.exec.*;
import ghidra.pcode.exec.PcodeUseropLibraryFactory.UseropLibrary;
import ghidra.program.model.pcode.Varnode;
@UseropLibrary("hexagon")
public class HexagonPcodeUseropLibraryFactory implements PcodeUseropLibraryFactory {
@Override
public <T> PcodeUseropLibrary<T> create(SleighLanguage language,
PcodeArithmetic<T> arithmetic) {
return new HexagonPcodeUseropLibrary<T>(language);
}
public static class HexagonPcodeUseropLibrary<T> extends AnnotatedPcodeUseropLibrary<T> {
private static final int FP_ZERO_CLASS_MASK = 0x01;
private static final int FP_NORMAL_CLASS_MASK = 0x02;
private static final int FP_SUBNORMAL_CLASS_MASK = 0x04;
private static final int FP_INFINITE_CLASS_MASK = 0x08;
private static final int FP_NAN_CLASS_MASK = 0x10;
public HexagonPcodeUseropLibrary(SleighLanguage language) {
SleighPcodeUseropDefinition.Factory factory =
new SleighPcodeUseropDefinition.Factory(language);
putOp(factory.define("min").params("a", "b").body(args -> """
if (a s<= b) goto <take_a>;
__op_output = b;
goto <done>;
<take_a>
__op_output = a;
<done>
""").build());
putOp(factory.define("vlslh")
.params("source", "shift")
.body(args -> genVecShift(args.get(0), 16, "<<", ">>"))
.build());
putOp(factory.define("vlsrh")
.params("source", "shift")
.body(args -> genVecShift(args.get(0), 16, ">>", "<<"))
.build());
putOp(factory.define("vlslw")
.params("source", "shift")
.body(args -> genVecShift(args.get(0), 32, "<<", ">>"))
.build());
putOp(factory.define("vlsrw")
.params("source", "shift")
.body(args -> genVecShift(args.get(0), 32, ">>", "<<"))
.build());
putOp(factory.define("vmux").params("sel", "a", "b").body(args -> """
local s:1;
local result:8;
""" + genVec(0, 8, 1, i -> """
s = ((sel >> %d) & 1) * 0xff;
result[%d,8] = (a[%d,8] & s) | (b[%d,8] & ~s);
""".formatted(i, 8 * i, 8 * i, 8 * i)) + """
__op_output = result;
""").build());
putOp(factory.define("vabsh").params("n").body(args -> genVecAbs(16)).build());
putOp(factory.define("vabsw").params("n").body(args -> genVecAbs(32)).build());
putOp(factory.define("dfmpylh").params("rdd", "rss", "rtt").body(args -> """
rss_lo:8 = rss & 0xffffffff;
rtt_hi:8 = rtt >> 32;
prod:8 = (rss_lo * (0x00100000 | (rtt_hi & 0xfffff))) << 1;
__op_output = rdd + prod;
""").build());
putOp(factory.define("dfmpyll").params("rss", "rtt").body(args -> """
rss_lo:8 = rss & 0xffffffff;
rtt_lo:8 = rtt & 0xffffffff;
prod:8 = rss_lo * rtt_lo;
result:8 = (prod >> 32) << 1;
if ((prod & 0xffffffff) == 0) goto <done>;
result = result + 1;
<done>
__op_output = result;
""").build());
putOp(factory.define("isClassifiedFloat")
.params("bits", "cls")
.body(args -> switch (args.get(1).getSize()) {
case 4 -> "__op_output = __isClassifiedFloat32(bits, cls);";
case 8 -> "__op_output = __isClassifiedFloat64(bits, cls);";
default -> throw new LowlevelError(
"isClassifiedFloat: invalid float size of " + args.get(0).getSize());
})
.build());
}
protected String genVec(int start, int stop, int step, Function<Integer, String> slot) {
StringBuffer buf = new StringBuffer();
for (int i = start; i < stop; i += step) {
buf.append(slot.apply(i));
}
return buf.toString();
}
protected String genVecShift(Varnode source, int slotSize, String posOp, String negOp) {
int regSize = source.getSize() * 8;
return """
s:1 = (shift[0,8] << 1) s>> 1;
if (s s< 0) goto <shift_neg>;
""" + genVec(0, regSize, slotSize, slot -> """
__op_output[%d,%d] = source[%d,%d] %s s;
""".formatted(slot, slotSize, slot, slotSize, posOp)) + """
goto <done>;
<shift_neg>
""" + genVec(0, regSize, slotSize, slot -> """
__op_output[%d,%d] = source[%d,%d] %s s;
""".formatted(slot, slotSize, slot, slotSize, negOp)) + """
<done>
""";
}
protected String genVecAbs(int slotSize) {
long signMask = Long.MIN_VALUE;
for (int i = 32; i >= slotSize; i >>>= 1) {
signMask |= (signMask >>> i);
}
long sm = signMask;
long mult = -1L >>> (64 - slotSize);
return """
s = n & 0x%x;
ones = s >> %d;
mask = ones * 0x%x;
inv = n ^ mask;
""".formatted(sm, slotSize - 1, mult) + genVec(0, 64, slotSize, slot -> """
__op_output[%d,%d] = inv[%d,%d] + ones[%d,%d];
""".formatted(slot, slotSize, slot, slotSize, slot, slotSize));
}
@PcodeUserop(functional = true)
public static int __isClassifiedFloat32(int valueBits, int cls) {
int exp = HexagonFp32.maskFp32Exponent(valueBits);
int frac = HexagonFp32.maskFp32Fraction(valueBits);
if ((cls & FP_ZERO_CLASS_MASK) != 0 && HexagonFp32.isFp32Zero(exp, frac)) {
return 0xff;
}
if ((cls & FP_NORMAL_CLASS_MASK) != 0 && HexagonFp32.isFp32Normal(exp, frac)) {
return 0xff;
}
if ((cls & FP_SUBNORMAL_CLASS_MASK) != 0 && HexagonFp32.isFp32Subnormal(exp, frac)) {
return 0xff;
}
if ((cls & FP_INFINITE_CLASS_MASK) != 0 && HexagonFp32.isFp32Infinite(exp, frac)) {
return 0xff;
}
if ((cls & FP_NAN_CLASS_MASK) != 0 && HexagonFp32.isFp32Nan(exp, frac)) {
return 0xff;
}
return 0;
}
@PcodeUserop(functional = true)
public static int __isClassifiedFloat64(long valueBits, int cls) {
long exp = HexagonFp64.maskFp64Exponent(valueBits);
long frac = HexagonFp64.maskFp64Fraction(valueBits);
if ((cls & FP_ZERO_CLASS_MASK) != 0 && HexagonFp64.isFp64Zero(exp, frac)) {
return 0xff;
}
if ((cls & FP_NORMAL_CLASS_MASK) != 0 && HexagonFp64.isFp64Normal(exp, frac)) {
return 0xff;
}
if ((cls & FP_SUBNORMAL_CLASS_MASK) != 0 && HexagonFp64.isFp64Subnormal(exp, frac)) {
return 0xff;
}
if ((cls & FP_INFINITE_CLASS_MASK) != 0 && HexagonFp64.isFp64Infinite(exp, frac)) {
return 0xff;
}
if ((cls & FP_NAN_CLASS_MASK) != 0 && HexagonFp64.isFp64Nan(exp, frac)) {
return 0xff;
}
return 0;
}
// LATER: Could/should this be done in Sleigh instead?
@PcodeUserop(functional = true)
public static long dfmpyfix(long rss, long rtt) {
return HexagonFp64.dfmpyfix(rss, rtt);
}
// LATER: Could/should this be done in Sleigh instead?
@PcodeUserop(functional = true)
public static long dfmpyhh(long rdd, long rss, long rtt) {
return HexagonFp64.dfmpyhh(rdd, rss, rtt);
}
}
}
@@ -0,0 +1,115 @@
/* ###
* IP: GHIDRA
*
* 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.
*/
package ghidra.test.processors;
import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.fail;
import org.junit.Test;
import ghidra.app.util.PseudoInstruction;
import ghidra.pcode.emu.*;
import ghidra.pcode.exec.*;
import ghidra.pcode.exec.PcodeExecutorStatePiece.Reason;
import ghidra.program.model.address.Address;
import ghidra.program.model.address.AddressSpace;
import ghidra.program.model.lang.LanguageID;
import ghidra.program.model.lang.RegisterValue;
import ghidra.program.model.pcode.PcodeOp;
import ghidra.test.AbstractGhidraHeadlessIntegrationTest;
import ghidra.util.NumericUtilities;
public class HexagonPcodeEmulatorTest extends AbstractGhidraHeadlessIntegrationTest {
@Test
public void testCunitSample() throws Throwable {
PcodeEmulator emu = new PcodeEmulator(
getLanguageService().getLanguage(new LanguageID("Hexagon:LE:32:default"))) {
@Override
protected BytesPcodeThread createThread(String name) {
return new BytesPcodeThread(name, this) {
@Override
protected PcodeThreadExecutor<byte[]> createExecutor() {
return new PcodeThreadExecutor<>(this) {
@Override
public void stepOp(PcodeOp op, PcodeFrame frame,
PcodeUseropLibrary<byte[]> library) {
//System.err.println(" StepOp: " + op);
super.stepOp(op, frame, library);
}
};
}
@Override
protected SleighInstructionDecoder createInstructionDecoder(
PcodeExecutorState<byte[]> sharedState) {
return new SleighInstructionDecoder(language, sharedState) {
@Override
public PseudoInstruction decodeInstruction(Address address,
RegisterValue context) {
PseudoInstruction instruction =
super.decodeInstruction(address, context);
//System.err.println("Decoded " + address + ": " + instruction);
return instruction;
}
};
}
};
}
};
PcodeThread<byte[]> thread = emu.newThread();
AddressSpace as = emu.getLanguage().getDefaultSpace();
byte[] code_db54 = NumericUtilities.convertStringToBytes("""
09c09da0284a000042c300782e4a000003c0007841e7007800c06270f9e29ea702c06370f8e39ea784c
e035a20c0c049ffe0dea742c0c049fee2dea7e2ffde97c4ffde97fbe0dea700c203f502c405f5f8c100
5afde0dea7a4ffde9702c07d7060ffde9700c0c2a121e8007802c0007820ff9e97f5e29ea7fcc9035a6
0c0c049f9e0dea722ffde97dcc1005a02c07d7004c1c04900c4c2a142e8007823ff9e97f8e0dea700c0
637001c06270a2fe9e9704ffde97dec9035a81e8007820ff9e9702ff9e972ace035a1ec01e96"""
.replaceAll("\\s+", ""));
emu.getSharedState().setVar(as, 0xdb54, code_db54.length, false, code_db54);
byte[] code_27a00 = NumericUtilities.convertStringToBytes("""
00478185004780850440c14326c0c1432e40205c004882754840c1416ac0c1412640005c00448275004
4c04408c6c04401458275024682758c40c141aec8c1430248c0a103cac0a100527f53204cc04029cec0
4000478275c440c191e6c0c14300409f520644c0a138c6c0401aefff59"""
.replaceAll("\\s+", ""));
emu.getSharedState().setVar(as, 0x27a00, code_27a00.length, false, code_27a00);
byte[] src = new byte[64];
for (int i = 0; i < src.length; i++) {
src[i] = (byte) (31 * i + 5);
}
emu.getSharedState().setVar(as, 0x10002000, src.length, false, src);
emu.addBreakpoint(as.getAddress(0xDEADBEEFL), "1:1");
//thread.getExecutor().executeSleigh("PC=0xdb54; SP=0x40000000;");
thread.getExecutor()
.executeSleigh("PC=0x27a00; SP=0x4000000; R0=0x10001000; R1=0x10002000; R2=" +
src.length + "; LR=0xDEADBEEF;");
thread.reInitialize();
try {
thread.run();
fail();
}
catch (InterruptPcodeExecutionException e) {
// We hit the breakpoint. Good.
}
byte[] dst = emu.getSharedState().getVar(as, 0x10001000, src.length, false, Reason.INSPECT);
assertArrayEquals(src, dst);
}
}
@@ -0,0 +1,74 @@
/* ###
* IP: GHIDRA
*
* 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.
*/
package ghidra.test.processors;
import ghidra.program.model.listing.Program;
import ghidra.program.model.symbol.Symbol;
import ghidra.program.model.symbol.SymbolUtilities;
import ghidra.test.processors.support.EmulatorTestRunner;
import ghidra.test.processors.support.ProcessorEmulatorTestAdapter;
import junit.framework.Test;
public class Hexagon_O0_EmulatorTest extends ProcessorEmulatorTestAdapter {
/**
* Known Failures:
* - All nalign_i2,4,8 tests are known to fail since the llvm compiler for Hexagon
* produces code which handles reads and writes inconsistently and does not
* attempt to force use of byte read/write for non-aligned accesses. The processor
* H/W will throw an exception for unaligned accesses.
*/
private static final String LANGUAGE_ID = "Hexagon:LE:32:default";
private static final String COMPILER_SPEC_ID = "default";
private static final String[] REG_DUMP_SET = new String[] {};
public Hexagon_O0_EmulatorTest(String name) throws Exception {
super(name, LANGUAGE_ID, COMPILER_SPEC_ID, REG_DUMP_SET);
// Ignore known issues with alignment tests
addIgnoredTests(
// Alignment tests need to declare the char array with proper alignment
// since Hexagon will access char array in a char-aligned fashion for
// the various size.
"nalign_i2_Main",
"nalign_i4_Main",
"nalign_i8_Main");
}
@Override
protected void initializeState(EmulatorTestRunner testRunner, Program program)
throws Exception {
super.initializeState(testRunner, program);
testRunner.setRegister("SP", 0x40000000L); // stack, unused location
Symbol globalDataSym = SymbolUtilities.getLabelOrFunctionSymbol(program, "GLOBAL",
m -> {
/* ignore */ });
assertNotNull("GLOBAL data symbol not found", globalDataSym);
testRunner.setRegister("GP", globalDataSym.getAddress().getOffset());
}
@Override
protected String getProcessorDesignator() {
return "Hexagon_CLANG_LLVM_O0";
}
public static Test suite() {
return ProcessorEmulatorTestAdapter
.buildEmulatorTestSuite(Hexagon_O0_EmulatorTest.class);
}
}
@@ -0,0 +1,62 @@
/* ###
* IP: GHIDRA
*
* 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.
*/
package ghidra.test.processors;
import ghidra.program.model.listing.Program;
import ghidra.program.model.symbol.Symbol;
import ghidra.program.model.symbol.SymbolUtilities;
import ghidra.test.processors.support.EmulatorTestRunner;
import ghidra.test.processors.support.ProcessorEmulatorTestAdapter;
import junit.framework.Test;
public class Hexagon_O3_EmulatorTest extends ProcessorEmulatorTestAdapter {
private static final String LANGUAGE_ID = "Hexagon:LE:32:default";
private static final String COMPILER_SPEC_ID = "default";
private static final String[] REG_DUMP_SET = new String[] {};
public Hexagon_O3_EmulatorTest(String name) throws Exception {
super(name, LANGUAGE_ID, COMPILER_SPEC_ID, REG_DUMP_SET);
addIgnoredTests(
// Hexagon Tools 8.5.10 LLVM compiler produces incorrect O3 optimized do/while loop code
"pcode_RolledDoWhileLoop_Main",
"pcode_Unrolled2DoWhileLoop_Main");
}
@Override
protected void initializeState(EmulatorTestRunner testRunner, Program program)
throws Exception {
super.initializeState(testRunner, program);
testRunner.setRegister("SP", 0x40000000L); // stack, unused location
Symbol globalDataSym = SymbolUtilities.getLabelOrFunctionSymbol(program, "GLOBAL",
m -> {
/* ignore */ });
assertNotNull("GLOBAL data symbol not found", globalDataSym);
testRunner.setRegister("GP", globalDataSym.getAddress().getOffset());
}
@Override
protected String getProcessorDesignator() {
return "Hexagon_CLANG_LLVM_O3";
}
public static Test suite() {
return ProcessorEmulatorTestAdapter
.buildEmulatorTestSuite(Hexagon_O3_EmulatorTest.class);
}
}
@@ -0,0 +1,70 @@
/* ###
* IP: GHIDRA
*
* 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.
*/
package ghidra.app.plugin.assembler.sleigh;
import java.math.BigInteger;
import org.junit.Test;
import ghidra.app.plugin.assembler.sleigh.sem.AssemblyPatternBlock;
import ghidra.program.model.lang.LanguageID;
import ghidra.program.model.lang.RegisterValue;
public class HexagonAssemblyTest extends AbstractAssemblyTest {
@Override
protected LanguageID getLanguageID() {
return new LanguageID("Hexagon:LE:32:default");
}
String makeCtx(int packetOffset, long packetBits) {
RegisterValue ctxVal = new RegisterValue(lang.getContextBaseRegister());
ctxVal = ctxVal.assign(lang.getRegister("packetOffset"), BigInteger.valueOf(packetOffset));
ctxVal = ctxVal.assign(lang.getRegister("packetBits"), BigInteger.valueOf(packetBits));
return AssemblyPatternBlock.fromRegisterValue(ctxVal).fillMask().toString();
}
@Test
public void testAssemble_memb_R0_mR1() {
assertOneCompatRestExact("memb R0,(R1)", "00:40:01:91", 0x000c0000);
}
@Test
public void testAssemble_jump_if_t_cmp_eq_mR0new_n0_0xc0010() {
assertOneCompatRestExact("jump.if:t cmp.eq(R0.new,#0x0),0x000c0010", "0b:e0:02:24",
makeCtx(1, 0x40000000), 0x000c0000,
"jump.if:t cmp.eq(R0.new,#0x0),0x000c0010");
}
@Test
public void testAssemble_assign_R0_P0() {
assertOneCompatRestExact("assign R0,P0", "00:40:40:89", 0x000c0000);
}
@Test
public void testAssemble_cmp_gtu_P0_R1_n0x9__jump_if_P0new_t_0xc0010() {
assertOneCompatRestExact("cmp.gtu P0,R1,#0x9 ; jump.if(P0.new):t 0x000c0010", "0b:69:01:11",
makeCtx(1, 0x40000000), 0x000c0000,
"cmp.gtu P0,R1,#0x9 ; jump.if(P0.new):t 0x000c0010");
}
@Test
public void testAssemble_memw_mSP_n0x4_R0new() {
assertOneCompatRestExact("memw (SP+#0x4),R0.new", "01:d4:bd:a1",
makeCtx(2, 0x50000000), 0x000c0000,
"memw (SP+#0x4),R0.new");
}
}
@@ -0,0 +1,237 @@
/* ###
* IP: GHIDRA
*
* 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.
*/
package ghidra.program.emulation;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.junit.Assert.assertNotNull;
import java.util.Map;
import org.hamcrest.Matchers;
import org.junit.*;
import ghidra.app.plugin.processors.sleigh.SleighLanguage;
import ghidra.pcode.exec.*;
import ghidra.program.emulation.HexagonPcodeUseropLibraryFactory.HexagonPcodeUseropLibrary;
import ghidra.program.model.lang.LanguageID;
import ghidra.program.util.DefaultLanguageService;
public class HexagonPcodeUseropLibraryTest extends AbstractEmulationEquivalenceTest {
static final LanguageID LANGI_ID_HEXAGON = new LanguageID("Hexagon:LE:32:default");
static SleighLanguage HEXAGON;
@Before
public void setupHexagon() throws Exception {
if (HEXAGON == null) {
HEXAGON = (SleighLanguage) DefaultLanguageService.getLanguageService()
.getLanguage(LANGI_ID_HEXAGON);
}
}
@Test
public void testFoundById() {
PcodeUseropLibrary<byte[]> lib = PcodeUseropLibraryFactory
.createUseropLibraryFromId("hexagon", HEXAGON,
BytesPcodeArithmetic.forLanguage(HEXAGON));
assertThat(lib, Matchers.instanceOf(HexagonPcodeUseropLibrary.class));
}
@Test
public void testFoundByLang() {
PcodeUseropLibrary<byte[]> lib = PcodeUseropLibraryFactory
.createUseropLibraryForLanguage(HEXAGON, BytesPcodeArithmetic.forLanguage(HEXAGON));
assertNotNull(lib.getUserops().get("dfmpyfix"));
assertNotNull(lib.getUserops().get("dfmpyhh"));
}
@Test
public void testDfClass() throws Exception {
doTestEquiv(HEXAGON,
Map.ofEntries(
Map.entry("P3", "ffff"), // Kind of hacky, but Pd2 &= result
Map.entry("R1R0", "3ff0000000000000")),
buf -> buf.assemble("dfclass P3,R1R0,#0x2"), 1,
Map.ofEntries(
Map.entry("P3", "ff"),
Map.entry("PC", "400004"),
Map.entry("P0.new", "ff"),
Map.entry("P1.new", "ff"),
Map.entry("P2.new", "ff"),
Map.entry("P3.new", "ff"),
Map.entry("R1R0", "3ff0000000000000")));
}
@Test
public void testVMux() throws Exception {
doTestEquiv(HEXAGON,
Map.ofEntries(
Map.entry("P0", "96"),
Map.entry("R1R0", "aaaaaaaaaaaaaaaa"),
Map.entry("R9R8", "bbbbbbbbbbbbbbbb")),
buf -> buf.assemble("vmux R1R0,P0,R1R0,R9R8"), 1,
Map.ofEntries(
Map.entry("R1R0_", "aabbbbaabbaaaabb"),
Map.entry("P0", "96"),
Map.entry("PC", "400004"),
Map.entry("P0.new", "ff"),
Map.entry("P1.new", "ff"),
Map.entry("P2.new", "ff"),
Map.entry("P3.new", "ff"),
Map.entry("R1R0", "aaaaaaaaaaaaaaaa"),
Map.entry("R9R8", "bbbbbbbbbbbbbbbb")));
}
static final long DF_ANY = 0x3f80_0000_0000_0000L;
static final long DF_HEX_NAN = -1L;
static final long DF_MAX = Double.doubleToRawLongBits(Double.MAX_VALUE);
static final long DF_MIN = Double.doubleToRawLongBits(Double.MIN_NORMAL);
static final long DF_NEG_ONE = Double.doubleToRawLongBits(-1.0);
static final long DF_NEG_ZERO = Double.doubleToRawLongBits(-0.0);
static final long DF_ONE = Double.doubleToRawLongBits(1.0);
static final long DF_ONE_HH = 0x3ff0_01ff_8000_0000L;
static final long DF_QNAN = 0x7ff8_0000_0000_0000L;
static final long DF_SNAN = 0x7ff7_0000_0000_0000L;
static final long DF_ZERO = Double.doubleToRawLongBits(0.0);
protected void runTestDfmpyhh(long accNew, long accInit, long a, long b)
throws Exception {
doTestEquiv(HEXAGON,
Map.ofEntries(
Map.entry("R1R0", Long.toHexString(accInit)),
Map.entry("R3R2", Long.toHexString(a)),
Map.entry("R9R8", Long.toHexString(b))),
buf -> buf.assemble("dfmpyhh+= R1R0,R3R2,R9R8"), 1,
Map.ofEntries(
Map.entry("R1R0_", Long.toHexString(accNew)),
Map.entry("PC", "400004"),
Map.entry("P0.new", "ff"),
Map.entry("P1.new", "ff"),
Map.entry("P2.new", "ff"),
Map.entry("P3.new", "ff"),
Map.entry("R1R0", Long.toHexString(accInit)),
Map.entry("R3R2", Long.toHexString(a)),
Map.entry("R9R8", Long.toHexString(b))));
}
protected void runTestDfmpylh(long accNew, long accInit, long a, long b)
throws Exception {
doTestEquiv(HEXAGON,
Map.ofEntries(
Map.entry("R1R0", Long.toHexString(accInit)),
Map.entry("R3R2", Long.toHexString(a)),
Map.entry("R9R8", Long.toHexString(b))),
buf -> buf.assemble("dfmpylh+= R1R0,R3R2,R9R8"), 1,
Map.ofEntries(
Map.entry("R1R0_", Long.toHexString(accNew)),
Map.entry("PC", "400004"),
Map.entry("P0.new", "ff"),
Map.entry("P1.new", "ff"),
Map.entry("P2.new", "ff"),
Map.entry("P3.new", "ff"),
Map.entry("R1R0", Long.toHexString(accInit)),
Map.entry("R3R2", Long.toHexString(a)),
Map.entry("R9R8", Long.toHexString(b))));
}
protected void runTestDfmpyll(long accNew, long accInit, long a, long b)
throws Exception {
doTestEquiv(HEXAGON,
Map.ofEntries(
Map.entry("R1R0", Long.toHexString(accInit)),
Map.entry("R3R2", Long.toHexString(a)),
Map.entry("R9R8", Long.toHexString(b))),
buf -> buf.assemble("dfmpyll R1R0,R3R2,R9R8"), 1,
Map.ofEntries(
Map.entry("R1R0_", Long.toHexString(accNew)),
Map.entry("PC", "400004"),
Map.entry("P0.new", "ff"),
Map.entry("P1.new", "ff"),
Map.entry("P2.new", "ff"),
Map.entry("P3.new", "ff"),
Map.entry("R1R0", Long.toHexString(accInit)),
Map.entry("R3R2", Long.toHexString(a)),
Map.entry("R9R8", Long.toHexString(b))));
}
@Test
public void testDfmpyhhOnes() throws Exception {
runTestDfmpyhh(DF_ONE_HH, DF_ONE, DF_ONE, DF_ONE);
}
@Test
@Ignore
public void testDfmpyhhZeroAnyQNan() throws Exception {
runTestDfmpyhh(DF_HEX_NAN, DF_ZERO, DF_ANY, DF_QNAN);
}
@Test
@Ignore
public void testDfmpyhhZeroAnySNan() throws Exception {
runTestDfmpyhh(DF_HEX_NAN, DF_ZERO, DF_ANY, DF_SNAN);
}
@Test
@Ignore
public void testDfmpyhhZeroQNanSNan() throws Exception {
runTestDfmpyhh(DF_HEX_NAN, DF_ZERO, DF_QNAN, DF_SNAN);
}
@Test
@Ignore
public void testDfmpyhhZeroSNanQNan() throws Exception {
runTestDfmpyhh(DF_HEX_NAN, DF_ZERO, DF_SNAN, DF_QNAN);
}
@Test
public void testDfmpyhhMain() throws Exception {
runTestDfmpyhh(
0x4023_b81d_7dbf_4880L,
0x0020_2752_200f_06f7L,
0x4009_1eb8_51eb_851fL,
0x4009_1eb8_51eb_851fL);
}
@Test
public void testDfmpylhMins() throws Exception {
runTestDfmpylh(0x10_0000_0000_0000L, DF_MIN, DF_MIN, DF_MIN);
}
@Test
public void testDfmpylhNegOneMaxMin() throws Exception {
runTestDfmpylh(0xc00f_ffff_ffe0_0000L, DF_NEG_ONE, DF_MAX, DF_MIN);
}
@Test
public void testDfmpylhMaxZeroNegOne() throws Exception {
runTestDfmpylh(0x7fef_ffff_ffff_ffffL, DF_MAX, DF_ZERO, DF_NEG_ONE);
}
@Test
public void testDfmpyllMins() throws Exception {
runTestDfmpyll(0, -1L, DF_MIN, DF_MIN);
}
@Test
public void testDfmpyllNegOneMin() throws Exception {
runTestDfmpyll(0, -1L, DF_NEG_ONE, DF_MIN);
}
@Test
public void testDfmpyllMaxes() throws Exception {
runTestDfmpyll(0x1_ffff_fffdL, -1L, DF_MAX, DF_MAX);
}
}
+30
View File
@@ -253,12 +253,42 @@ ext.deps = [
sha256: "21546210748ba52e839e52112124b16ffab7d7fb68096493165fbc249e9023ad",
destination: file("${DEPS_DIR}/Debugger-agent-dbgeng/")
],
[
name: "pywin32-311-cp314-cp314-win_amd64.whl",
url: "https://files.pythonhosted.org/packages/90/4b/07c77d8ba0e01349358082713400435347df8426208171ce297da32c313d/pywin32-311-cp314-cp314-win_amd64.whl",
sha256: "3aca44c046bd2ed8c90de9cb8427f581c479e594e99b5c0bb19b29c10fd6cb87",
destination: file("${DEPS_DIR}/Debugger-agent-dbgeng/")
],
[
name: "pywin32-311-cp313-cp313-win_amd64.whl",
url: "https://files.pythonhosted.org/packages/e3/28/e0a1909523c6890208295a29e05c2adb2126364e289826c0a8bc7297bd5c/pywin32-311-cp313-cp313-win_amd64.whl",
sha256: "718a38f7e5b058e76aee1c56ddd06908116d35147e133427e59a3983f703a20d",
destination: file("${DEPS_DIR}/Debugger-agent-dbgeng/")
],
[
name: "pywin32-311-cp312-cp312-win_amd64.whl",
url: "https://files.pythonhosted.org/packages/d1/a8/a0e8d07d4d051ec7502cd58b291ec98dcc0c3fff027caad0470b72cfcc2f/pywin32-311-cp312-cp312-win_amd64.whl",
sha256: "b8c095edad5c211ff31c05223658e71bf7116daa0ecf3ad85f3201ea3190d067",
destination: file("${DEPS_DIR}/Debugger-agent-dbgeng/")
],
[
name: "pywin32-311-cp311-cp311-win_amd64.whl",
url: "https://files.pythonhosted.org/packages/51/8f/9bb81dd5bb77d22243d33c8397f09377056d5c687aa6d4042bea7fbf8364/pywin32-311-cp311-cp311-win_amd64.whl",
sha256: "3ce80b34b22b17ccbd937a6e78e7225d80c52f5ab9940fe0506a1a16f3dab503",
destination: file("${DEPS_DIR}/Debugger-agent-dbgeng/")
],
[
name: "pywin32-311-cp310-cp310-win_amd64.whl",
url: "https://files.pythonhosted.org/packages/5e/bf/360243b1e953bd254a82f12653974be395ba880e7ec23e3731d9f73921cc/pywin32-311-cp310-cp310-win_amd64.whl",
sha256: "797c2772017851984b97180b0bebe4b620bb86328e8a884bb626156295a63b3b",
destination: file("${DEPS_DIR}/Debugger-agent-dbgeng/")
],
[
name: "pywin32-311-cp39-cp39-win_amd64.whl",
url: "https://files.pythonhosted.org/packages/9f/8a/1403d0353f8c5a2f0829d2b1c4becbf9da2f0a4d040886404fc4a5431e4d/pywin32-311-cp39-cp39-win_amd64.whl",
sha256: "e0c4cfb0621281fe40387df582097fd796e80430597cb9944f0ae70447bacd91",
destination: file("${DEPS_DIR}/Debugger-agent-dbgeng/")
],
[
name: "win32more-0.7.0-py3-none-any.whl",
url: "https://files.pythonhosted.org/packages/92/3a/658eb3ba88f067662be280f8f1aec07a70c96bac77e9edc48b1be38e446b/win32more-0.7.0-py3-none-any.whl",