Compare commits

...

63 Commits

Author SHA1 Message Date
Timothée COCAULT
38625ed9e1
Merge 21c42371f2 into ac58d20693 2024-11-20 18:09:45 -08:00
ghidra1
ac58d20693 GP-0 Corrected test failures and fixed cspec encoding bug 2024-11-20 10:04:56 -05:00
Ryan Kurtz
22ddbc3f4b Merge remote-tracking branch 'origin/GP-5137_dev747368_delete_duplicate_processor_list_plugin' 2024-11-20 06:15:14 -05:00
Ryan Kurtz
55b2016b16 Merge remote-tracking branch 'origin/GP-5136_ghidra1_SarifStructureComponents' 2024-11-20 06:13:59 -05:00
Ryan Kurtz
4d96514f1b Merge remote-tracking branch 'origin/GP-1-dragonmacher-go-to-bug-fix' 2024-11-20 06:12:50 -05:00
ghidra1
79b008d7e4 Merge remote-tracking branch 'origin/GP-0-dragonmacher-test-fixes-11-19-24' 2024-11-19 18:53:52 -05:00
dragonmacher
ac22ed69f2 Test fixes 2024-11-19 18:07:54 -05:00
dragonmacher
68bb1e182a Fixed Go To for functions with default names so that a table of choices
is not shown
2024-11-19 15:09:12 -05:00
Ryan Kurtz
9421ec0ab0 Merge remote-tracking branch 'origin/GP-4885-dragonmacher-gnu-demangler-keep-raw-demangled--SQUASHED' 2024-11-19 13:11:55 -05:00
Ryan Kurtz
650c5d8756 Merge remote-tracking branch 'origin/GP-1-dragonmacher-focus-fix' 2024-11-19 12:47:54 -05:00
Ryan Kurtz
58e48456de Merge remote-tracking branch 'origin/GP-1-dragonmacher-dialog-escape-bug' 2024-11-19 12:47:36 -05:00
Ryan Kurtz
a7351baba4 Merge remote-tracking branch 'origin/GP-4202_James_msp430_cspec_improvements--SQUASHED' 2024-11-19 12:43:45 -05:00
Ryan Kurtz
329f8b4a19 Merge remote-tracking branch 'origin/patch' 2024-11-19 12:41:27 -05:00
Ryan Kurtz
fc7b0ef327 Merge remote-tracking branch 'origin/GP-0_d-millar_accidental_reversion_in_GP-4686' into patch 2024-11-19 12:37:29 -05:00
d-millar
454d57d754 GP-0: reversion for GP-4686 2024-11-19 12:21:39 -05:00
James
8abe4d76f0 GP-4202 msp430 cspec improvements 2024-11-19 09:57:12 -05:00
dragonmacher
8f08f2730d GP-4885 - Gnu Demangler - Save the raw demangled string 2024-11-19 09:21:42 -05:00
dragonmacher
b67fab8b51 Fix for Escape action not working for some dialogs 2024-11-18 18:45:17 -05:00
ghidra1
058ecb5eef GP-0 Revert GP-4886 change pending further review and rework 2024-11-18 11:43:17 -05:00
Ryan Kurtz
81432f75c7 GP-5132: PyGhidra launchers for VSCode (message for previous 'init' commit) 2024-11-18 11:05:12 -05:00
Ryan Kurtz
69d6495b60 init 2024-11-18 11:00:47 -05:00
dev747368
dc17dcd639 GP-5137 delete duplicate / unneeded processorlist plugin 2024-11-18 15:23:42 +00:00
Ryan Kurtz
4cbc94d960 Merge remote-tracking branch 'origin/GP-2470_EnumVariants' (#2581) 2024-11-18 06:26:59 -05:00
Ryan Kurtz
b12d39ee3f Merge remote-tracking branch 'origin/GP-5127_MultiSlotAlignment' 2024-11-18 06:22:59 -05:00
Ryan Kurtz
294f81dfc2 Merge remote-tracking branch 'origin/patch' 2024-11-18 06:20:49 -05:00
Ryan Kurtz
0411db7e88 Merge remote-tracking branch 'origin/GP-5130_HeapSequenceIndex' into patch 2024-11-18 06:18:32 -05:00
Ryan Kurtz
600c02703a Merge remote-tracking branch 'origin/GP-0_d-millar_fix_for_5120' (#7176) 2024-11-18 06:11:58 -05:00
dragonmacher
7712224ff1 Fixed focus issue that caused new dialogs to sometimes have focus taken
away
2024-11-15 20:52:34 -05:00
ghidra1
2390546961 GP-5136 Changed SARIF export to only include defined-components when
outputing a structure definition
2024-11-15 16:18:46 -05:00
caheckman
55a026b3ba GP-2470 Support for partial enums 2024-11-15 20:54:17 +00:00
caheckman
ab7684a230 GP-5127 Alignment fix for MultiSlotAssign 2024-11-15 20:31:06 +00:00
d-millar
eced291c6e GP-0: broken in 5120 2024-11-15 20:27:17 +00:00
caheckman
306e15a33d GP-5130 Negative offsets in HeapSequence 2024-11-15 19:09:46 +00:00
Ryan Kurtz
c9a51029bb Merge remote-tracking branch
'origin/GP-5120_d-millar_inferior_thread--SQUASHED' (Closes #7176)
2024-11-15 13:34:13 -05:00
Ryan Kurtz
a7c192c58e Merge remote-tracking branch
'origin/GP-5119_d-millar_possible_putreg_errors' (Closes #7174)
2024-11-15 13:32:52 -05:00
Ryan Kurtz
b536b99e60 Merge remote-tracking branch
'origin/GP-5105_d-millar_better_labels--SQUASHED' (Closes #7167)
2024-11-15 13:30:35 -05:00
Ryan Kurtz
83d38b8368 Merge remote-tracking branch 'origin/GP-4886_ghidra1_UnassignedStorageForDefaultDatatype' 2024-11-15 13:24:39 -05:00
Ryan Kurtz
a9c2c6efc7 Merge remote-tracking branch
'origin/GP-5135_dragonmacher_PR-7193_gemesa_listing-highlight-color'
(Closes #7193)
2024-11-15 13:23:07 -05:00
Ryan Kurtz
f7b21f5ea3 Merge remote-tracking branch 'origin/GP-0-dragonmacher-test-fixes-11-15-24' 2024-11-15 13:19:28 -05:00
dragonmacher
2ac3fe7b1b test fixes 2024-11-15 13:09:38 -05:00
Andras Gemes
bd9959730f Gui: Rework listing highlighter colors (dark theme) 2024-11-15 12:50:38 -05:00
d-millar
6be0884f18 GP-5120: single pattern for regions
GP-5120: single pattern for regions
GP-5120: mismatched errors
GP-5120: fix for inferior_thread is None
2024-11-15 11:54:05 -05:00
d-millar
8e6d269b8e GP-5105: same for ttd
GP-5105: better labeling
2024-11-15 11:53:45 -05:00
Ryan Kurtz
3fb7d914f5 Merge remote-tracking branch
'origin/GP-5114-dragonmacher-escape-action--SQUASHED' (#7136)
2024-11-15 10:00:45 -05:00
dragonmacher
aaf23cf096 GP-5114 - Updated component providers to close on Escape when they are the only provider in a window 2024-11-14 17:32:01 -05:00
d-millar
54cd023fc9 GP-5119: get_register_by_index can fail 2024-11-11 21:37:43 +00:00
caheckman
33646bbcdc Move UNASSIGNED check into LocalSymbolMap 2024-10-09 23:06:43 +00:00
ghidra1
38445e387b GP-4886 Do not assign storage for DEFAULT/unassigned datatype and create
undefined-typedef instead of DWORD-typedef as a default named type when
demangling.
2024-08-30 15:01:43 -04:00
Timothée COCAULT
21c42371f2 [NDS32] Add baseline v3 2020-12-11 01:34:23 +01:00
Timothée COCAULT
2e7dd784dc [NDS32] Fix divr and divsr instructions 2020-12-08 21:09:08 +01:00
Timothée COCAULT
00a899eba4 [NDS32] Add pcodeTest for little-endian variant 2020-12-08 21:08:12 +01:00
Timothée COCAULT
020d9a837a [NDS32] Add gp recovery from ELF symbol 2020-12-08 21:06:31 +01:00
Timothée COCAULT
319fc387a0 [NDS32] Add DWARF register mapping 2020-12-07 01:24:41 +01:00
Timothée COCAULT
85756ca9c8 [NDS32] Implement basic ELF relocation 2020-12-07 01:04:52 +01:00
Timothée COCAULT
83745acb3e Merge remote-tracking branch 'origin/master' into tim/add_nds32_processor 2020-12-06 20:51:17 +01:00
Timothée COCAULT
adc677cbf6
[NDS32] Fix typo in XOR instruction 2020-06-08 22:09:17 +02:00
Timothée COCAULT
6c45eb95c2 [NDS32] Fix clip signed comparison 2020-04-18 18:23:24 +02:00
Timothée COCAULT
75048cc19b [NDS32] Fix dpref* 2020-04-18 18:14:43 +02:00
Timothée COCAULT
37ef612a0f [NDS32] Implement tlbop 2020-04-18 18:05:55 +02:00
Timothée COCAULT
57a8ca011b [NDS32] Ignore llw/scw atomicity 2020-04-18 17:56:06 +02:00
Timothée COCAULT
a6e497159c [NDS32] Add clip* instructions 2020-04-18 17:50:29 +02:00
Timothée COCAULT
f1c61221a8 [NDS32] Add pbsad* instructions 2020-04-18 17:44:22 +02:00
Timothée COCAULT
f23433dd60 Add support for the NDS32 Processor 2020-04-16 18:58:10 +02:00
97 changed files with 4440 additions and 1631 deletions

View File

@ -10,8 +10,8 @@
::@icon icon.debugger
::@help TraceRmiLauncherServicePlugin#dbgeng_attach
::@env OPT_PYTHON_EXE:file!="python" "Python command" "The path to the Python 3 interpreter. Omit the full path to resolve using the system PATH."
::@env OPT_TARGET_PID:int="" "Process id" "The target process id"
::@env OPT_ATTACH_FLAGS:int="0" "Attach flags" "Attach flags"
::@env OPT_TARGET_PID:int=0 "Process id" "The target process id"
::@env OPT_ATTACH_FLAGS:int=0 "Attach flags" "Attach flags"
::@env OPT_USE_DBGMODEL:bool=true "Use dbgmodel" "Load and use dbgmodel.dll if it is available."
::@env WINDBG_DIR:dir="" "Path to dbgeng.dll directory" "Path containing dbgeng and associated DLLS (if not Windows Kits)."

View File

@ -208,16 +208,11 @@ class DefaultMemoryMapper(object):
self.defaultSpace = defaultSpace
def map(self, proc: int, offset: int):
if proc == 0:
space = self.defaultSpace
else:
space = f'{self.defaultSpace}{proc}'
space = self.defaultSpace
return self.defaultSpace, Address(space, offset)
def map_back(self, proc: int, address: Address) -> int:
if address.space == self.defaultSpace and proc == 0:
return address.offset
if address.space == f'{self.defaultSpace}{proc}':
if address.space == self.defaultSpace:
return address.offset
raise ValueError(f"Address {address} is not in process {proc}")

View File

@ -591,8 +591,8 @@ def putreg():
regs = util.dbg._base.reg
for i in range(0, len(regs)):
name = regs._reg.GetDescription(i)[0]
value = regs._get_register_by_index(i)
try:
value = regs._get_register_by_index(i)
values.append(mapper.map_value(nproc, name, value))
robj.set_value(name, hex(value))
except Exception:

View File

@ -1,17 +1,17 @@
## ###
# 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.
# 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.
##
from concurrent.futures import Future, ThreadPoolExecutor
from contextlib import redirect_stdout
@ -199,9 +199,11 @@ def execute(cmd: str, to_string: bool=False):
exec(cmd, shared_globals)
@REGISTRY.method
@REGISTRY.method(action='evaluate', display='Evaluate')
# @util.dbg.eng_thread
def evaluate(expr: str):
def evaluate(
session: sch.Schema('Session'),
expr: ParamDesc(str, display='Expr')):
"""Evaluate a Python3 expression."""
return str(eval(expr, shared_globals))
@ -323,15 +325,16 @@ def remove_process(process: sch.Schema('Process')):
dbg().detach_proc()
@REGISTRY.method(action='connect')
@REGISTRY.method(action='connect', display='Connect')
@util.dbg.eng_thread
def target(process: sch.Schema('Process'), spec: str):
def target(
session: sch.Schema('Session'),
cmd: ParamDesc(str, display='Command')):
"""Connect to a target machine or process."""
find_proc_by_obj(process)
dbg().attach_kernel(spec)
dbg().attach_kernel(cmd)
@REGISTRY.method(action='attach')
@REGISTRY.method(action='attach', display='Attach')
@util.dbg.eng_thread
def attach_obj(target: sch.Schema('Attachable')):
"""Attach the process to the given target."""
@ -339,29 +342,34 @@ def attach_obj(target: sch.Schema('Attachable')):
dbg().attach_proc(pid)
@REGISTRY.method(action='attach')
@REGISTRY.method(action='attach', display='Attach by pid')
@util.dbg.eng_thread
def attach_pid(pid: int):
def attach_pid(
session: sch.Schema('Session'),
pid: ParamDesc(str, display='PID')):
"""Attach the process to the given target."""
dbg().attach_proc(pid)
dbg().attach_proc(int(pid))
@REGISTRY.method(action='attach')
@REGISTRY.method(action='attach', display='Attach by name')
@util.dbg.eng_thread
def attach_name(process: sch.Schema('Process'), name: str):
def attach_name(
session: sch.Schema('Session'),
name: ParamDesc(str, display='Name')):
"""Attach the process to the given target."""
dbg().attach_proc(name)
@REGISTRY.method
@REGISTRY.method(action='detach', display='Detach')
@util.dbg.eng_thread
def detach(process: sch.Schema('Process')):
"""Detach the process's target."""
dbg().detach_proc()
@REGISTRY.method(action='launch')
@REGISTRY.method(action='launch', display='Launch')
def launch_loader(
session: sch.Schema('Session'),
file: ParamDesc(str, display='File'),
args: ParamDesc(str, display='Arguments')=''):
"""
@ -373,8 +381,9 @@ def launch_loader(
commands.ghidra_trace_create(command=file, start_trace=False)
@REGISTRY.method(action='launch')
@REGISTRY.method(action='launch', display='LaunchEx')
def launch(
session: sch.Schema('Session'),
file: ParamDesc(str, display='File'),
args: ParamDesc(str, display='Arguments')='',
initial_break: ParamDesc(bool, display='Initial Break')=True,
@ -431,7 +440,7 @@ def step_out(thread: sch.Schema('Thread')):
util.dbg.run_async(lambda: dbg().stepout())
@REGISTRY.method(action='step_to')
@REGISTRY.method(action='step_to', display='Step To')
def step_to(thread: sch.Schema('Thread'), address: Address, max=None):
"""Continue execution up to the given address."""
find_thread_by_obj(thread)

View File

@ -1,17 +1,17 @@
## ###
# 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.
# 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.
##
from concurrent.futures import Future, ThreadPoolExecutor
import re
@ -196,8 +196,10 @@ def execute(cmd: str, to_string: bool=False):
exec("{}".format(cmd), shared_globals)
@REGISTRY.method
def evaluate(expr: str):
@REGISTRY.method(action='evaluate', display='Evaluate')
def evaluate(
session: sch.Schema('Session'),
expr: ParamDesc(str, display='Expr')):
"""Execute a CLI command."""
return str(eval("{}".format(expr), shared_globals))
@ -311,40 +313,51 @@ def remove_process(process: sch.Schema('Process')):
dbg().detach()
@REGISTRY.method(action='connect')
def target(process: sch.Schema('Process'), spec: str):
@REGISTRY.method(action='connect', display='Connect')
@util.dbg.eng_thread
def target(
session: sch.Schema('Session'),
cmd: ParamDesc(str, display='Command')):
"""Connect to a target machine or process."""
find_proc_by_obj(process)
dbg().attach(spec)
dbg().attach_kernel(cmd)
@REGISTRY.method(action='attach')
@REGISTRY.method(action='attach', display='Attach')
@util.dbg.eng_thread
def attach_obj(target: sch.Schema('Attachable')):
"""Attach the process to the given target."""
pid = find_availpid_by_obj(target)
dbg().attach(pid)
@REGISTRY.method(action='attach')
def attach_pid(pid: int):
@REGISTRY.method(action='attach', display='Attach by pid')
@util.dbg.eng_thread
def attach_pid(
session: sch.Schema('Session'),
pid: ParamDesc(str, display='PID')):
"""Attach the process to the given target."""
dbg().attach(pid)
dbg().attach_proc(int(pid))
@REGISTRY.method(action='attach')
def attach_name(process: sch.Schema('Process'), name: str):
@REGISTRY.method(action='attach', display='Attach by name')
@util.dbg.eng_thread
def attach_name(
session: sch.Schema('Session'),
name: ParamDesc(str, display='Name')):
"""Attach the process to the given target."""
dbg().atach(name)
dbg().attach_proc(name)
@REGISTRY.method
@REGISTRY.method(action='detach', display='Detach')
@util.dbg.eng_thread
def detach(process: sch.Schema('Process')):
"""Detach the process's target."""
dbg().detach()
@REGISTRY.method(action='launch')
@REGISTRY.method(action='launch', display='Launch')
def launch_loader(
session: sch.Schema('Session'),
file: ParamDesc(str, display='File'),
args: ParamDesc(str, display='Arguments')=''):
"""
@ -356,11 +369,13 @@ def launch_loader(
commands.ghidra_trace_create(command=file, start_trace=False)
@REGISTRY.method(action='launch')
@REGISTRY.method(action='launch', display='LaunchEx')
def launch(
timeout: ParamDesc(int, display='Timeout'),
session: sch.Schema('Session'),
file: ParamDesc(str, display='File'),
args: ParamDesc(str, display='Arguments')=''):
args: ParamDesc(str, display='Arguments')='',
initial_break: ParamDesc(bool, display='Initial Break')=True,
timeout: ParamDesc(int, display='Timeout')=-1):
"""
Run a native process with the given command line.
"""
@ -368,7 +383,7 @@ def launch(
if args != None:
command += " "+args
commands.ghidra_trace_create(
command, initial_break=False, timeout=timeout, start_trace=False)
command, initial_break=initial_break, timeout=timeout, start_trace=False)
@REGISTRY.method
@ -413,7 +428,7 @@ def step_out(thread: sch.Schema('Thread')):
hooks.on_stop()
@REGISTRY.method(action='step_to')
@REGISTRY.method(action='step_to', display='Step To')
def step_to(thread: sch.Schema('Thread'), address: Address, max=None):
"""Continue execution up to the given address."""
find_thread_by_obj(thread)

View File

@ -98,11 +98,11 @@ class InferiorState(object):
frame, util.get_register_descs(frame.architecture(), 'general'))
try:
commands.putmem("$pc", "1", from_tty=False)
except MemoryError as e:
except gdb.MemoryError as e:
print(f"Couldn't record page with PC: {e}")
try:
commands.putmem("$sp", "1", from_tty=False)
except MemoryError as e:
except gdb.MemoryError as e:
print(f"Couldn't record page with SP: {e}")
self.visited.add(hashable_frame)
# NB: These commands (put_modules/put_regions) will fail if the process is running
@ -281,6 +281,11 @@ def on_register_changed(event):
@log_errors
def on_cont(event):
if gdb.selected_thread() is None:
# thread-based state computed in record_continued will
# fail in some versions of gdb because the current_thread is None
# and gdb fails to test for None before switching
return
if (HOOK_STATE.check_skip_continue()):
return
inf = gdb.selected_inferior()

View File

@ -196,18 +196,12 @@ MODULE_INFO_READER = _choose_module_info_reader()
REGIONS_CMD = 'info proc mappings'
REGION_PATTERN_V8 = re.compile("\\s*" +
"0x(?P<start>[0-9,A-F,a-f]+)\\s+" +
"0x(?P<end>[0-9,A-F,a-f]+)\\s+" +
"0x(?P<size>[0-9,A-F,a-f]+)\\s+" +
"0x(?P<offset>[0-9,A-F,a-f]+)\\s+" +
"(?P<objfile>.*)")
REGION_PATTERN_V12 = re.compile("\\s*" +
REGION_PATTERN = re.compile("\\s*" +
"0x(?P<start>[0-9,A-F,a-f]+)\\s+" +
"0x(?P<end>[0-9,A-F,a-f]+)\\s+" +
"0x(?P<size>[0-9,A-F,a-f]+)\\s+" +
"0x(?P<offset>[0-9,A-F,a-f]+)\\s+" +
"(?P<perms>[rwsxp\\-]+)\\s+" +
"((?P<perms>[rwsxp\\-]+)?\\s+)?" +
"(?P<objfile>.*)")
@ -216,6 +210,9 @@ class Region(namedtuple('BaseRegion', ['start', 'end', 'offset', 'perms', 'objfi
class RegionInfoReader(object):
cmd = REGIONS_CMD
region_pattern = REGION_PATTERN
def region_from_line(self, line):
mat = self.region_pattern.fullmatch(line)
if mat is None:
@ -253,28 +250,13 @@ class RegionInfoReader(object):
return False, None
return True, new_regions
class RegionInfoReaderV8(RegionInfoReader):
cmd = REGIONS_CMD
region_pattern = REGION_PATTERN_V8
def get_region_perms(self, mat):
return None
class RegionInfoReaderV12(RegionInfoReader):
cmd = REGIONS_CMD
region_pattern = REGION_PATTERN_V12
def get_region_perms(self, mat):
return mat['perms']
def _choose_region_info_reader():
if 8 <= GDB_VERSION.major < 12:
return RegionInfoReaderV8()
elif GDB_VERSION.major >= 12:
return RegionInfoReaderV12()
if 8 <= GDB_VERSION.major:
return RegionInfoReader()
else:
raise gdb.GdbError(
"GDB version not recognized by ghidragdb: " + GDB_VERSION.full)

View File

@ -4,9 +4,9 @@
* 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.
@ -27,17 +27,13 @@ public class IsfComposite extends AbstractIsfObject {
public String kind;
public Integer size;
public JsonObject fields;
public IsfComposite(Composite composite, IsfDataTypeWriter writer, TaskMonitor monitor) {
super(composite);
size = composite.getLength();
size = composite.isZeroLength() ? 0 : composite.getLength();
kind = composite instanceof Structure ? "struct" : "union";
DataTypeComponent[] components = composite.getComponents();
if (components.length == 0) {
// NB: composite.getLength always returns > 0
size = 0;
}
DataTypeComponent[] components = composite.getDefinedComponents();
fields = new JsonObject();
for (DataTypeComponent component : components) {
if (monitor.isCancelled()) {

View File

@ -821,7 +821,6 @@ src/main/resources/images/field.header.up.png||GHIDRA||||END|
src/main/resources/images/fingerPointer.png||GHIDRA||||END|
src/main/resources/images/flag-green.png||Oxygen Icons - LGPL 3.0|||Oxygen icon theme (dual license; LGPL or CC-SA-3.0)|END|
src/main/resources/images/flag-yellow.png||Oxygen Icons - LGPL 3.0|||Oxygen icon theme (dual license; LGPL or CC-SA-3.0)|END|
src/main/resources/images/folder-downloads-32.png||Oxygen Icons - LGPL 3.0|||Oxygen icon theme (dual license; LGPL or CC-SA-3.0)|END|
src/main/resources/images/format-text-bold.png||Tango Icons - Public Domain|||tango icon set|END|
src/main/resources/images/functionDef.png||GHIDRA||||END|
src/main/resources/images/function_graph.png||FAMFAMFAM Icons - CC 2.5|||famfamfam silk icon set|END|

View File

@ -115,9 +115,8 @@ font.listing.header = SansSerif-PLAIN-11
color.bg.highlight.listing.diff = #4D4D2A
// non-palette colors; these are currently ugly, but bright enough for easy scanning
color.bg.listing.highlighter.default = yellow
color.bg.listing.highlighter.scoped.read = darkorange
color.bg.listing.highlighter.scoped.write = lime
color.bg.listing.highlighter.default = #666600
color.bg.listing.highlighter.scoped.read = #996600
color.bg.listing.highlighter.scoped.write = #009900

View File

@ -107,6 +107,7 @@ public class VSCodeProjectScript extends GhidraScript {
File settingsFile = new File(vscodeDir, "settings.json");
String gradleVersion = Application
.getApplicationProperty(ApplicationProperties.APPLICATION_GRADLE_MIN_PROPERTY);
String pythonInterpreterPath = System.getProperty("pyghidra.sys.prefix", null);
// Build settings json object
JsonObject json = new JsonObject();
@ -138,6 +139,9 @@ public class VSCodeProjectScript extends GhidraScript {
json.addProperty("python.analysis.stubPath",
new File(installDir, "docs/ghidra_stubs/typestubs").getAbsolutePath());
if (pythonInterpreterPath != null) {
json.addProperty("python.defaultInterpreterPath", pythonInterpreterPath);
}
// Write settings json object
if (!FileUtilities.mkdirs(settingsFile.getParentFile())) {
@ -183,6 +187,8 @@ public class VSCodeProjectScript extends GhidraScript {
json.addProperty("version", "0.2.0");
JsonArray configurationsArray = new JsonArray();
json.add("configurations", configurationsArray);
// Ghidra launcher
JsonObject ghidraConfigObject = new JsonObject();
configurationsArray.add(ghidraConfigObject);
ghidraConfigObject.addProperty("type", "java");
@ -198,6 +204,33 @@ public class VSCodeProjectScript extends GhidraScript {
vmArgsArray.add("-Dghidra.external.modules=${workspaceFolder}");
vmArgs.forEach(vmArgsArray::add);
// PyGhidra launcher
JsonObject pyghidraConfigObject = new JsonObject();
configurationsArray.add(pyghidraConfigObject);
pyghidraConfigObject.addProperty("type", "debugpy");
pyghidraConfigObject.addProperty("name", "PyGhidra");
pyghidraConfigObject.addProperty("request", "launch");
pyghidraConfigObject.addProperty("module", "pyghidra.ghidra_launch");
pyghidraConfigObject.addProperty("args", GhidraRun.class.getName());
JsonArray argsArray = new JsonArray();
pyghidraConfigObject.add("args", argsArray);
argsArray.add("--install-dir");
argsArray.add(installDir.getAbsolutePath());
argsArray.add("-g");
argsArray.add(GhidraRun.class.getName());
JsonObject envObject = new JsonObject();
pyghidraConfigObject.add("env", envObject);
envObject.addProperty("PYGHIDRA_DEBUG", "1");
// PyGhidra Java Attach
JsonObject pyghidraAttachObject = new JsonObject();
configurationsArray.add(pyghidraAttachObject);
pyghidraAttachObject.addProperty("type", "java");
pyghidraAttachObject.addProperty("name", "PyGhidra Java Attach");
pyghidraAttachObject.addProperty("request", "attach");
pyghidraAttachObject.addProperty("hostName", "localhost");
pyghidraAttachObject.addProperty("port", 18001);
// Write launch json object
if (!FileUtilities.mkdirs(launchFile.getParentFile())) {
throw new IOException("Failed to create: " + launchFile.getParentFile());

View File

@ -4,9 +4,9 @@
* 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.
@ -62,6 +62,10 @@ public class AnalysisOptionsDialog extends DialogComponentProvider
addCancelButton();
addApplyButton();
setOkButtonText("Analyze");
// This allows user to press Enter to launch analysis when the dialog is shown. Without
// this, the table takes focus, which consumes Enter key presses.
setFocusComponent(okButton);
okButton.setMnemonic('A');
setOkEnabled(true);
setPreferredSize(1000, 600);

View File

@ -1,293 +0,0 @@
/* ###
* 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.help;
import java.awt.datatransfer.Clipboard;
import java.awt.datatransfer.Transferable;
import java.util.*;
import javax.swing.*;
import docking.ActionContext;
import docking.ReusableDialogComponentProvider;
import docking.action.DockingAction;
import docking.action.MenuData;
import docking.dnd.GClipboard;
import docking.dnd.StringTransferable;
import docking.tool.ToolConstants;
import docking.widgets.table.AbstractSortedTableModel;
import docking.widgets.table.GTable;
import ghidra.app.CorePluginPackage;
import ghidra.app.plugin.PluginCategoryNames;
import ghidra.app.util.HelpTopics;
import ghidra.framework.main.ApplicationLevelPlugin;
import ghidra.framework.plugintool.*;
import ghidra.framework.plugintool.util.PluginStatus;
import ghidra.program.model.lang.*;
import ghidra.program.util.DefaultLanguageService;
import ghidra.util.HelpLocation;
import ghidra.util.SystemUtilities;
//@formatter:off
@PluginInfo(
status = PluginStatus.RELEASED,
packageName = CorePluginPackage.NAME,
category = PluginCategoryNames.COMMON,
shortDescription = "Displays list of installed processor modules",
description = "This plugin provides a Help action that displays a list of installed processor modules"
)
//@formatter:on
public class ProcessorListPlugin extends Plugin implements ApplicationLevelPlugin {
private DockingAction processorListAction;
private ProcessorListDialogProvider dialogProvider;
public ProcessorListPlugin(PluginTool tool) {
super(tool);
}
@Override
protected void init() {
setupActions();
}
@Override
public void dispose() {
tool.removeAction(processorListAction);
processorListAction.dispose();
if (dialogProvider != null) {
dialogProvider.dispose();
}
super.dispose();
}
private void setupActions() {
processorListAction = new DockingAction("Installed Processors", this.getName()) {
@Override
public void actionPerformed(ActionContext context) {
showProcessorList();
}
};
processorListAction.setEnabled(true);
processorListAction.setMenuBarData(new MenuData(
new String[] { ToolConstants.MENU_HELP, processorListAction.getName() }, null, "AAAZ"));
processorListAction
.setHelpLocation(new HelpLocation(HelpTopics.RUNTIME_INFO, "InstalledProcessors"));
processorListAction.setDescription(getPluginDescription().getDescription());
tool.addAction(processorListAction);
}
private void dialogClosed() {
dialogProvider = null;
}
private void showProcessorList() {
if (dialogProvider == null) {
dialogProvider = new ProcessorListDialogProvider();
}
tool.showDialog(dialogProvider);
}
private void copy(boolean asHtml) {
Clipboard systemClipboard = GClipboard.getSystemClipboard();
Transferable transferable = new StringTransferable(getProcessorList(asHtml));
systemClipboard.setContents(transferable, null);
}
private Set<Processor> getProcessors() {
TreeSet<Processor> processors = new TreeSet<>();
LanguageService languageService = DefaultLanguageService.getLanguageService();
for (LanguageDescription languageDescription : languageService
.getLanguageDescriptions(true)) {
processors.add(languageDescription.getProcessor());
}
return processors;
}
private String getProcessorList(boolean asHtml) {
StringBuilder strBuilder = new StringBuilder();
if (asHtml) {
strBuilder.append("<html><BODY>\n");
strBuilder.append("<table width=\"100%\" cellpadding=\"0\" cellspacing=\"0\">\n<tr>");
}
Set<Processor> processors = getProcessors();
int itemsPerColum = (processors.size() + 2) / 3;
int colCnt = 0;
for (Processor processor : processors) {
if (asHtml) {
if ((colCnt % itemsPerColum) == 0) {
if (colCnt != 0) {
strBuilder.append("</ul>\n</td>");
}
strBuilder.append("<td width=\"33%\">\n<ul>");
}
strBuilder.append("<li>");
}
++colCnt;
strBuilder.append(processor.toString());
if (asHtml) {
strBuilder.append("</li>");
}
strBuilder.append("\n");
}
if (asHtml) {
strBuilder.append("</ul>\n</td></tr>\n</table>");
strBuilder.append("</BODY></html>");
}
return strBuilder.toString();
}
private class ProcessorListDialogProvider extends ReusableDialogComponentProvider {
ProcessorListDialogProvider() {
super("Installed Processor Modules", false, false, true, false);
ProcessorListTableProvider tableProvider =
new ProcessorListTableProvider(tool, getName());
setRememberLocation(true);
addWorkPanel(tableProvider.getComponent());
setHelpLocation(new HelpLocation(HelpTopics.ABOUT, "ProcessorList"));
if (SystemUtilities.isInDevelopmentMode()) {
JButton copyButton = new JButton("Copy");
copyButton.addActionListener(e -> copy(false));
addButton(copyButton);
JButton copyHtmlButton = new JButton("Copy as HTML");
copyHtmlButton.addActionListener(e -> copy(true));
addButton(copyHtmlButton);
}
JButton closeButton = new JButton("Close");
closeButton.addActionListener(e -> close());
addButton(closeButton);
}
@Override
protected void dialogClosed() {
super.dialogClosed();
ProcessorListPlugin.this.dialogClosed();
}
}
public class ProcessorListTableProvider extends ComponentProviderAdapter {
GTable table;
private ProcessorListTableModel processorTableModel;
private JScrollPane scrollPane;
public ProcessorListTableProvider(PluginTool tool, String owner) {
super(tool, "Processor Table", owner);
buildTable();
}
@Override
public JComponent getComponent() {
return scrollPane;
}
private void buildTable() {
TreeSet<Processor> processors = new TreeSet<>();
LanguageService languageService = DefaultLanguageService.getLanguageService();
for (LanguageDescription languageDescription : languageService
.getLanguageDescriptions(true)) {
processors.add(languageDescription.getProcessor());
}
processorTableModel = new ProcessorListTableModel(new ArrayList<>(processors));
table = new GTable(processorTableModel);
scrollPane = new JScrollPane(table);
table.getSelectionManager().setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
}
}
public class ProcessorListTableModel extends AbstractSortedTableModel<Processor> {
private static final int PROCESSOR_COL = 0;
private List<Processor> processors;
public ProcessorListTableModel(List<Processor> processors) {
this.processors = processors;
}
@Override
public Object getColumnValueForRow(Processor p, int columnIndex) {
switch (columnIndex) {
case PROCESSOR_COL:
return p.toString();
}
return null;
}
@Override
public String getName() {
return "Processors";
}
@Override
public List<Processor> getModelData() {
return processors;
}
@Override
public boolean isSortable(int columnIndex) {
return false; // maybe later when we add more columns
}
@Override
public int getColumnCount() {
return 1;
}
@Override
public int getRowCount() {
return processors.size();
}
@Override
public String getColumnName(int column) {
switch (column) {
case PROCESSOR_COL:
return "Processor";
}
return null;
}
@Override
public Class<?> getColumnClass(int columnIndex) {
switch (columnIndex) {
case PROCESSOR_COL:
return String.class;
}
return Object.class;
}
}
}

View File

@ -4,9 +4,9 @@
* 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.
@ -61,7 +61,7 @@ public class LabelMgrPlugin extends Plugin {
// Setup list of actions
setupActions();
addEditDialog = new AddEditDialog("", tool);
addEditDialog = new AddEditDialog("Add/Edit Label", tool);
addEditDialog.setReusable(true);
}
@ -278,7 +278,7 @@ public class LabelMgrPlugin extends Plugin {
addr = loc.getAddress();
}
else if (location instanceof OperandFieldLocation) {
Address a = ((OperandFieldLocation) location).getRefAddress();
Address a = location.getRefAddress();
addr = (a == null) ? addr : a;
}

View File

@ -44,41 +44,48 @@ public abstract class DemangledObject implements Demangled {
/*
The following names probably need to be refactored. Until then, this is how the following
fields are used.
mangled -
mangled -
Source: The original mangled string as seen in the program
Usage: Can be used to see if a program symbol has already been demangled
originalDemangled -
rawDemangled -
Source: The raw demangled string returned from the demangler
Usage: for debugging
originalDemangled -
Source: The starting demangled string. This will usually be the same as the raw
demangled string. This may have simplifications applied.
Usage: for display
demangledName -
demangledName -
Source: The name as created by the parser which may transform or even replace the
string returned from the demangler
Usage: for display
name -
name -
Source: This is derived from the 'demangledName' This is updated to be suitable
for use as a symbol name. This may be null while building, but is
expected to be non-null when applyTo() is called
Usage: The name that will be applied when applyTo() is called.
Future: These variables should be refactored and renamed to be clearer and more cohesive,
something like:
mangled
rawDemangled
escapedDemangled
simplifiedDemangled --| These two could be combined into 'transformedDemangled'
escapedDemangled --|
symbolName
*/
protected MangledContext mangledContext; // the mangled context, which includes mangled string
protected final String mangled; // original mangled string
protected String originalDemangled; // raw demangled string
private String demangledName; // updated demangled string
protected String rawDemangled; // demangled string from the demangler without any simplifications
protected String originalDemangled; // starting demangled string that may have been simplified
private String demangledName; // updated demangled string, possibly with changes made while building
private String name; // version of demangled name suitable for symbols
protected String specialPrefix;
@ -120,6 +127,7 @@ public abstract class DemangledObject implements Demangled {
DemangledObject(String mangled, String originalDemangled) {
this.mangled = mangled;
this.originalDemangled = originalDemangled;
this.rawDemangled = originalDemangled;
}
/**
@ -132,6 +140,7 @@ public abstract class DemangledObject implements Demangled {
this.mangledContext = mangledContext;
this.mangled = mangledContext.getMangled();
this.originalDemangled = originalDemangled;
this.rawDemangled = originalDemangled;
}
@Override
@ -280,6 +289,24 @@ public abstract class DemangledObject implements Demangled {
this.originalDemangled = originalDemangled;
}
/**
* Returns the raw demangled string. This is the value returned from the demangler before any
* simplifications or transformations have been made.
* @return the string
*/
public String getRawDemangled() {
return rawDemangled;
}
/**
* Sets the raw demangled string. This is the value returned from the demangler before any
* simplifications or transformations have been made.
* @param s the string
*/
public void setRawDemangledString(String s) {
this.rawDemangled = s;
}
@Override
public Demangled getNamespace() {
return namespace;

View File

@ -184,7 +184,9 @@ public class SymbolSearcher {
return;
}
Symbol s = program.getSymbolTable().getPrimarySymbol(address);
addSymbolIfMatches(s, locations);
if (s.isDynamic()) { // non-dynamic symbols have already been searched (ex, FUN_12345678)
addSymbolIfMatches(s, locations);
}
}
private void searchDefinedSymbols(Program program, List<ProgramLocation> locations) {

View File

@ -4,9 +4,9 @@
* 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.
@ -237,6 +237,7 @@ public abstract class AbstractScreenShotGenerator extends AbstractGhidraHeadedIn
public void performAction(String actionName, String owner, ComponentProvider contextProvider,
boolean wait) {
DockingActionIf action = getAction(tool, owner, actionName);
assertNotNull("Could not find action: " + actionName + " for owner " + owner, action);
performAction(action, contextProvider, wait);
}

View File

@ -4,9 +4,9 @@
* 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.
@ -225,7 +225,7 @@ public abstract class GhidraScreenShotGenerator extends AbstractScreenShotGenera
showDialog(dialog);
}
private void showDialog(final DialogComponentProvider dialogComponent) {
private void showDialog(DialogComponentProvider dialogComponent) {
runSwing(() -> {
DockingDialog dialog = DockingDialog.createDialog(null, dialogComponent, null);
dialog.setLocation(WindowUtilities.centerOnScreen(dialog.getSize()));

View File

@ -4,9 +4,9 @@
* 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.
@ -207,8 +207,7 @@ public class StructureEditorUnlockedCellEdit2Test extends AbstractStructureEdito
assertEquals(model.getDataTypeColumn(), model.getColumn());
// Bad value allows escape.
escape();
escape();
escape(); // cancel editing
waitForSwing();
assertTrue(!model.isEditingField());
assertEquals(1, model.getNumSelectedRows());

View File

@ -4,9 +4,9 @@
* 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.
@ -630,7 +630,7 @@ public class AutoTableDisassemblerTest extends AbstractGhidraHeadedIntegrationTe
}
private JButton getActionButton(String actionName) {
Map<?, ?> actionMap = (Map<?, ?>) getInstanceField("actionMap", dialog);
Map<?, ?> actionMap = (Map<?, ?>) getInstanceField("toolbarButtonsByAction", dialog);
Set<?> entrySet = actionMap.entrySet();
for (Object entry : entrySet) {
Map.Entry<?, ?> mapEntry = (Map.Entry<?, ?>) entry;

View File

@ -4,9 +4,9 @@
* 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.
@ -19,7 +19,6 @@ import static org.junit.Assert.*;
import java.awt.*;
import java.awt.event.MouseEvent;
import java.util.Set;
import javax.swing.JTable;
import javax.swing.JTextField;
@ -27,8 +26,6 @@ import javax.swing.table.TableModel;
import org.junit.*;
import docking.ActionContext;
import docking.DefaultActionContext;
import docking.action.DockingActionIf;
import ghidra.app.cmd.memory.*;
import ghidra.app.plugin.core.codebrowser.CodeBrowserPlugin;
@ -93,58 +90,6 @@ public class MemoryMapPluginTest extends AbstractGhidraHeadedIntegrationTest {
assertTrue(action.isEnabled());
}
@Test
public void testOpenProgram() throws Exception {
env.close(program);
program = buildProgram("sdk");
env.open(program);
Set<DockingActionIf> actions = getActionsByOwner(tool, plugin.getName());
for (DockingActionIf action : actions) {
String name = action.getName();
if (name.equals("Add Block") || name.equals("Set Image Base") ||
name.equals("Memory Map") || name.equals("Close Window") ||
name.contains("Table")) {
assertActionEnabled(action, getActionContext(), true);
}
else {
assertActionEnabled(action, getActionContext(), false);
}
}
}
@Test
public void testCloseProgram() {
env.close(program);
JTable table = provider.getTable();
assertEquals(0, table.getModel().getRowCount());
Set<DockingActionIf> actions = getActionsByOwner(tool, plugin.getName());
for (DockingActionIf action : actions) {
String name = action.getName();
if (name.equals("Memory Map") || name.equals("Close Window") ||
name.equals("Local Menu")) {
continue;
}
assertActionEnabled(action, getActionContext(), false);
}
}
private void assertActionEnabled(DockingActionIf action, ActionContext context,
boolean shouldBeEnabled) {
String text = shouldBeEnabled ? "should be enabled" : "should be disabled";
assertEquals("Action " + text + ", but is not: '" + action.getFullName() + "'",
shouldBeEnabled, action.isEnabledForContext(context));
}
private ActionContext getActionContext() {
ActionContext context = provider.getActionContext(null);
if (context == null) {
return new DefaultActionContext();
}
return context;
}
@Test
public void testBlockNameChanged() throws Exception {
MemoryBlock block = memory.getBlock(program.getMinAddress());

View File

@ -4,9 +4,9 @@
* 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.
@ -124,29 +124,6 @@ public class MemoryMapProvider1Test extends AbstractGhidraHeadedIntegrationTest
}
}
@Test
public void testMultiSelection() {
table.addRowSelectionInterval(0, 1);
assertEquals(2, table.getSelectedRowCount());
Set<DockingActionIf> actions = getActionsByOwner(tool, plugin.getName());
for (DockingActionIf action : actions) {
String name = action.getName();
if (name.equals("Add Block") || name.equals("Merge Blocks") ||
name.equals("Delete Block") || name.equals("Set Image Base") ||
name.equals("Memory Map") || name.equals("Close Window") ||
name.equals("Make Selection")) {
assertTrue("Action should be enabled for a multi-row selection - '" + name + "'",
action.isEnabled());
}
else {
assertFalse(
"Action should not be enabled for a multi-row selection - '" + name + "'",
action.isEnabled());
}
}
}
@Test
public void testGoToAddress() {
Rectangle rect = table.getCellRect(2, MemoryMapModel.START, true);

View File

@ -4,9 +4,9 @@
* 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.
@ -25,7 +25,7 @@ import javax.swing.*;
import org.junit.After;
import org.junit.Test;
import docking.DockingDialog;
import docking.DockingWindowManager;
import docking.options.editor.OptionsDialog;
import docking.options.editor.StringWithChoicesEditor;
import docking.widgets.tree.GTree;
@ -34,26 +34,22 @@ import ghidra.test.AbstractGhidraHeadedIntegrationTest;
public class PropertyEditorTest extends AbstractGhidraHeadedIntegrationTest {
private DockingDialog dialog;
private OptionsDialog dialog;
@After
public void tearDown() throws Exception {
if (dialog != null) {
dialog.setVisible(false);
dialog.dispose();
close(dialog);
}
waitForSwing();
}
private DockingDialog showEditor(Options options) {
private OptionsDialog showEditor(Options options) {
OptionsDialog dialogComponent =
new OptionsDialog("Test Properties", "Properties", new Options[] { options }, null);
final DockingDialog editorDialog =
runSwing(() -> DockingDialog.createDialog(null, dialogComponent, null));
SwingUtilities.invokeLater(() -> editorDialog.setVisible(true));
runSwing(() -> DockingWindowManager.showDialog(dialogComponent), false);
waitForJDialog("Test Properties");
assertNotNull("Dialog failed to launch", editorDialog);
OptionsDialog editorDialog = waitForDialogComponent(OptionsDialog.class);
waitForSwing();
waitForOptionsTree(dialogComponent);
return editorDialog;
@ -65,10 +61,9 @@ public class PropertyEditorTest extends AbstractGhidraHeadedIntegrationTest {
waitForTree(tree);
}
private Component findPairedComponent(final Container container, final String labelText) {
final Component[] box = new Component[1];
runSwing(() -> box[0] = doFindPairedComponent(container, labelText));
return box[0];
private Component findPairedComponent(final String labelText) {
JComponent component = dialog.getComponent();
return runSwing(() -> doFindPairedComponent(component, labelText));
}
private Component doFindPairedComponent(Container container, String labelText) {
@ -102,7 +97,7 @@ public class PropertyEditorTest extends AbstractGhidraHeadedIntegrationTest {
dialog = showEditor(options);
Component editor = findPairedComponent(dialog, "TestInt");
Component editor = findPairedComponent("TestInt");
assertNotNull("Could not find editor component", editor);
assertEquals(PropertyText.class, editor.getClass());
final PropertyText textField = (PropertyText) editor;
@ -125,7 +120,7 @@ public class PropertyEditorTest extends AbstractGhidraHeadedIntegrationTest {
dialog = showEditor(options);
Component editor = findPairedComponent(dialog, "TestLong");
Component editor = findPairedComponent("TestLong");
assertNotNull("Could not find editor component", editor);
assertEquals(PropertyText.class, editor.getClass());
final PropertyText textField = (PropertyText) editor;
@ -148,7 +143,7 @@ public class PropertyEditorTest extends AbstractGhidraHeadedIntegrationTest {
dialog = showEditor(options);
Component editor = findPairedComponent(dialog, "TestFloat");
Component editor = findPairedComponent("TestFloat");
assertNotNull("Could not find editor component", editor);
assertEquals(PropertyText.class, editor.getClass());
final PropertyText textField = (PropertyText) editor;
@ -173,7 +168,7 @@ public class PropertyEditorTest extends AbstractGhidraHeadedIntegrationTest {
dialog = showEditor(options);
Component editor = findPairedComponent(dialog, "TestDouble");
Component editor = findPairedComponent("TestDouble");
assertNotNull("Could not find editor component", editor);
assertEquals(PropertyText.class, editor.getClass());
final PropertyText textField = (PropertyText) editor;
@ -197,7 +192,7 @@ public class PropertyEditorTest extends AbstractGhidraHeadedIntegrationTest {
dialog = showEditor(options);
Component editor = findPairedComponent(dialog, "TestString");
Component editor = findPairedComponent("TestString");
assertNotNull("Could not find editor component", editor);
assertEquals(PropertyText.class, editor.getClass());
final PropertyText textField = (PropertyText) editor;
@ -222,7 +217,7 @@ public class PropertyEditorTest extends AbstractGhidraHeadedIntegrationTest {
dialog = showEditor(options);
Component editor = findPairedComponent(dialog, "TestStringWithChoices");
Component editor = findPairedComponent("TestStringWithChoices");
assertNotNull("Could not find editor component", editor);
assertEquals(PropertySelector.class, editor.getClass());
final PropertySelector textSelector = (PropertySelector) editor;

View File

@ -25,6 +25,7 @@ src/decompile/datatests/divopt.xml||GHIDRA||||END|
src/decompile/datatests/doublemove.xml||GHIDRA||||END|
src/decompile/datatests/dupptr.xml||GHIDRA||||END|
src/decompile/datatests/elseif.xml||GHIDRA||||END|
src/decompile/datatests/enum.xml||GHIDRA||||END|
src/decompile/datatests/floatcast.xml||GHIDRA||||END|
src/decompile/datatests/floatconv.xml||GHIDRA||||END|
src/decompile/datatests/floatprint.xml||GHIDRA||||END|

View File

@ -19,6 +19,7 @@
namespace ghidra {
const int4 ArraySequence::MINIMUM_SEQUENCE_LENGTH = 4;
const int4 ArraySequence::MAXIMUM_SEQUENCE_LENGTH = 0x20000;
/// Initialize the sequence with the \b root operation which writes the earliest character in the memory region.
/// \param fdata is the function containing the sequence
@ -112,7 +113,7 @@ int4 ArraySequence::formByteArray(int4 sz,int4 slot,uint8 rootOff,bool bigEndian
int4 elSize = charType->getSize();
for(int4 i=0;i<moveOps.size();++i) {
int4 bytePos = moveOps[i].offset - rootOff;
if (bytePos + elSize > sz) continue;
if (bytePos < 0 || bytePos + elSize > sz) continue;
uint8 val = moveOps[i].op->getIn(slot)->getOffset();
used[bytePos] = (val == 0) ? 2 : 1; // Mark byte as used, a 2 indicates a null terminator
if (bigEndian) {
@ -470,7 +471,7 @@ void HeapSequence::findBasePointer(Varnode *initPtr)
OpCode opc = op->code();
if (opc == CPUI_PTRADD) {
int8 sz = op->getIn(2)->getOffset();
if (sz != charType->getAlignSize()) break;
if (sz != ptrAddMult) break;
}
else if (opc != CPUI_COPY)
break;
@ -546,7 +547,6 @@ void HeapSequence::findInitialStores(vector<PcodeOp *> &stores)
vector<Varnode *> ptradds;
findDuplicateBases(ptradds);
int4 pos = 0;
int4 alignSize = charType->getAlignSize();
while(pos < ptradds.size()) {
Varnode *vn = ptradds[pos];
pos += 1;
@ -558,7 +558,7 @@ void HeapSequence::findInitialStores(vector<PcodeOp *> &stores)
if (op->getIn(0) != vn) continue;
// We only check array element size here, if we checked the data-type, we would
// need to take into account different pointer styles to the same element data-type
if (op->getIn(2)->getOffset() != alignSize) continue;
if (op->getIn(2)->getOffset() != ptrAddMult) continue;
ptradds.push_back(op->getOut());
}
else if (opc == CPUI_COPY) {
@ -594,13 +594,13 @@ uint8 HeapSequence::calcAddElements(Varnode *vn,vector<Varnode *> &nonConst,int4
return res;
}
/// \brief Calculate the offset and any non-constant additive elements between the given Varnode and the \b basePointer
/// \brief Calculate the byte offset and any non-constant additive elements between the given Varnode and the \b basePointer
///
/// Walk backward from the given Varnode thru PTRADDs and COPYs, summing any offsets encountered.
/// Any non-constant Varnodes encountered in the path, that are not themselves a pointer, are passed back in a list.
/// \param vn is the given Varnode to trace back to the \b basePointer
/// \param nonConst will hold the list of non-constant Varnodes being passed back
/// \return the sum off constant offsets on the path
/// \return the sum off constant offsets on the path in byte units
uint8 HeapSequence::calcPtraddOffset(Varnode *vn,vector<Varnode *> &nonConst)
{
@ -610,7 +610,7 @@ uint8 HeapSequence::calcPtraddOffset(Varnode *vn,vector<Varnode *> &nonConst)
OpCode opc = op->code();
if (opc == CPUI_PTRADD) {
uint8 mult = op->getIn(2)->getOffset();
if (mult != charType->getAlignSize())
if (mult != ptrAddMult)
break;
uint8 off = calcAddElements(op->getIn(1),nonConst,3);
off *= mult;
@ -623,7 +623,7 @@ uint8 HeapSequence::calcPtraddOffset(Varnode *vn,vector<Varnode *> &nonConst)
else
break;
}
return res;
return AddrSpace::addressToByteInt(res, storeSpace->getWordSize());
}
/// \brief Determine if two sets of Varnodes are equal
@ -667,18 +667,21 @@ bool HeapSequence::collectStoreOps(void)
findInitialStores(initStores);
if (initStores.size() + 1 < MINIMUM_SEQUENCE_LENGTH)
return false;
uint8 maxSize = MAXIMUM_SEQUENCE_LENGTH * charType->getAlignSize(); // Maximum bytes
uint8 wrapMask = calc_mask(storeSpace->getAddrSize());
baseOffset = calcPtraddOffset(rootOp->getIn(1), nonConstAdds);
vector<Varnode *> nonConstComp;
for(int4 i=0;i<initStores.size();++i) {
PcodeOp *op = initStores[i];
nonConstComp.clear();
uint8 curOffset = calcPtraddOffset(op->getIn(1), nonConstComp);
uint8 diff = (curOffset - baseOffset) & wrapMask; // Allow wrapping relative to base pointer
if (setsEqual(nonConstAdds, nonConstComp)) {
if (curOffset < baseOffset)
return false; // Root is not the earliest STORE
if (diff >= maxSize)
return false; // Root is not the earliest STORE, or offsets span range larger then maxSize
if (!testValue(op))
return false;
moveOps.emplace_back(curOffset - baseOffset,op,-1);
moveOps.emplace_back(diff,op,-1);
}
}
moveOps.emplace_back(0,rootOp,-1);
@ -721,6 +724,7 @@ PcodeOp *HeapSequence::buildStringCopy(void)
if (baseOffset != 0) { // Add in any non-zero constant
uint8 numEl = baseOffset / charType->getAlignSize();
Varnode *cvn = data.newConstant(basePointer->getSize(), numEl);
cvn->updateType(intType, false, false);
if (indexVn == (Varnode *)0)
indexVn = cvn;
else {
@ -875,13 +879,15 @@ HeapSequence::HeapSequence(Funcdata &fdata,Datatype *ct,PcodeOp *root)
: ArraySequence(fdata,ct,root)
{
baseOffset = 0;
storeSpace = root->getIn(0)->getSpaceFromConst();
ptrAddMult = AddrSpace::byteToAddressInt(charType->getAlignSize(), storeSpace->getWordSize());
findBasePointer(rootOp->getIn(1));
if (!collectStoreOps())
return;
if (!checkInterference())
return;
int4 arrSize = moveOps.size() * charType->getAlignSize();
bool bigEndian = moveOps[0].op->getIn(0)->getSpaceFromConst()->isBigEndian();
bool bigEndian = storeSpace->isBigEndian();
numElements = formByteArray(arrSize, 2, 0, bigEndian);
}

View File

@ -29,6 +29,7 @@ namespace ghidra {
class ArraySequence {
public:
static const int4 MINIMUM_SEQUENCE_LENGTH; ///< Minimum number of sequential characters to trigger replacement with CALLOTHER
static const int4 MAXIMUM_SEQUENCE_LENGTH; ///< Maximum number of characters in replacement string
/// \brief Helper class holding a data-flow edge and optionally a memory offset being COPYed into or from
class WriteNode {
public:
@ -38,8 +39,6 @@ public:
WriteNode(uint8 off,PcodeOp *o,int4 sl) { offset = off; op = o; slot = sl; } ///< Constructor
/// \brief Compare two nodes by their order within a basic block
bool operator<(const WriteNode &node2) const { return op->getSeqNum().getOrder() < node2.op->getSeqNum().getOrder(); }
/// \brief Compare two PcodeOps based on the position of the element they copy within the sequence
static bool compareOffset(const WriteNode &a,const WriteNode &b) { return a.offset < b.offset; }
};
protected:
Funcdata &data; ///< The function containing the sequence
@ -87,6 +86,8 @@ public:
class HeapSequence : public ArraySequence {
Varnode *basePointer; ///< Pointer that sequence is stored to
uint8 baseOffset; ///< Offset relative to pointer to root STORE
AddrSpace *storeSpace; ///< Address space being STOREed to
int4 ptrAddMult; ///< Required multiplier for PTRADD ops
vector<Varnode *> nonConstAdds; ///< non-constant Varnodes being added into pointer calculation
void findBasePointer(Varnode *initPtr); ///< Find the base pointer for the sequence
void findDuplicateBases(vector<Varnode *> &duplist); ///< Find any duplicates of \b basePointer

View File

@ -5600,6 +5600,7 @@ void ActionDatabase::universalAction(Architecture *conf)
actcleanup->addRule( new Rule2Comp2Sub("cleanup") );
actcleanup->addRule( new RuleSubRight("cleanup") );
actcleanup->addRule( new RuleFloatSignCleanup("cleanup") );
actcleanup->addRule( new RuleExpandLoad("cleanup") );
actcleanup->addRule( new RulePtrsubCharConstant("cleanup") );
actcleanup->addRule( new RuleExtensionPush("cleanup") );
actcleanup->addRule( new RulePieceStructure("cleanup") );

View File

@ -3112,7 +3112,7 @@ int grammarerror(const char *str)
Datatype *parse_type(istream &s,string &name,Architecture *glb)
{
CParse parser(glb,1000);
CParse parser(glb,4096);
if (!parser.parseStream(s,CParse::doc_parameter_declaration))
throw ParseError(parser.getError());
@ -3131,7 +3131,7 @@ Datatype *parse_type(istream &s,string &name,Architecture *glb)
void parse_protopieces(PrototypePieces &pieces,
istream &s,Architecture *glb)
{
CParse parser(glb,1000);
CParse parser(glb,4096);
if (!parser.parseStream(s,CParse::doc_declaration))
throw ParseError(parser.getError());
@ -3151,7 +3151,7 @@ void parse_protopieces(PrototypePieces &pieces,
void parse_C(Architecture *glb,istream &s)
{ // Load type data straight into datastructures
CParse parser(glb,1000);
CParse parser(glb,4096);
if (!parser.parseStream(s,CParse::doc_declaration))
throw ParseError(parser.getError());

View File

@ -1366,7 +1366,7 @@ int grammarerror(const char *str)
Datatype *parse_type(istream &s,string &name,Architecture *glb)
{
CParse parser(glb,1000);
CParse parser(glb,4096);
if (!parser.parseStream(s,CParse::doc_parameter_declaration))
throw ParseError(parser.getError());
@ -1385,7 +1385,7 @@ Datatype *parse_type(istream &s,string &name,Architecture *glb)
void parse_protopieces(PrototypePieces &pieces,
istream &s,Architecture *glb)
{
CParse parser(glb,1000);
CParse parser(glb,4096);
if (!parser.parseStream(s,CParse::doc_declaration))
throw ParseError(parser.getError());
@ -1405,7 +1405,7 @@ void parse_protopieces(PrototypePieces &pieces,
void parse_C(Architecture *glb,istream &s)
{ // Load type data straight into datastructures
CParse parser(glb,1000);
CParse parser(glb,4096);
if (!parser.parseStream(s,CParse::doc_declaration))
throw ParseError(parser.getError());

View File

@ -4,9 +4,9 @@
* 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.
@ -1252,8 +1252,9 @@ AttributeId ATTRIB_VAL = AttributeId("val",24);
AttributeId ATTRIB_VALUE = AttributeId("value",25);
AttributeId ATTRIB_WORDSIZE = AttributeId("wordsize",26);
AttributeId ATTRIB_STORAGE = AttributeId("storage",149);
AttributeId ATTRIB_STACKSPILL = AttributeId("stackspill",150);
AttributeId ATTRIB_UNKNOWN = AttributeId("XMLunknown",150); // Number serves as next open index
AttributeId ATTRIB_UNKNOWN = AttributeId("XMLunknown",151); // Number serves as next open index
ElementId ELEM_DATA = ElementId("data",1);
ElementId ELEM_INPUT = ElementId("input",2);

View File

@ -4,9 +4,9 @@
* 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.
@ -736,6 +736,7 @@ extern AttributeId ATTRIB_VAL; ///< Marshaling attribute "val"
extern AttributeId ATTRIB_VALUE; ///< Marshaling attribute "value"
extern AttributeId ATTRIB_WORDSIZE; ///< Marshaling attribute "wordsize"
extern AttributeId ATTRIB_STORAGE; ///< Marshaling attribute "storage"
extern AttributeId ATTRIB_STACKSPILL; ///< Marshaling attribute "stackspill"
extern ElementId ELEM_DATA; ///< Marshaling element \<data>
extern ElementId ELEM_INPUT; ///< Marshaling element \<input>

View File

@ -4,9 +4,9 @@
* 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.
@ -689,6 +689,7 @@ uint4 MultiSlotAssign::assignAddress(Datatype *dt,const PrototypePieces &proto,i
vector<int4> tmpStatus = status;
vector<VarnodeData> pieces;
int4 sizeLeft = dt->getSize();
int4 align = dt->getAlignment();
list<ParamEntry>::const_iterator iter = firstIter;
list<ParamEntry>::const_iterator endIter = resource->getEntry().end();
if (enforceAlignment) {
@ -699,7 +700,6 @@ uint4 MultiSlotAssign::assignAddress(Datatype *dt,const PrototypePieces &proto,i
break; // Reached end of resource list
if (entry.getType() == resourceType && entry.getAllGroups().size() == 1) { // Single register
if (tmpStatus[entry.getGroup()] == 0) { // Not consumed
int4 align = dt->getAlignment();
int4 regSize = entry.getSize();
if (align <= regSize || (resourcesConsumed % align) == 0)
break;
@ -720,19 +720,20 @@ uint4 MultiSlotAssign::assignAddress(Datatype *dt,const PrototypePieces &proto,i
if (tmpStatus[entry.getGroup()] != 0)
continue; // Already consumed
int4 trialSize = entry.getSize();
Address addr = entry.getAddrBySlot(tmpStatus[entry.getGroup()], trialSize,1);
Address addr = entry.getAddrBySlot(tmpStatus[entry.getGroup()], trialSize,align);
tmpStatus[entry.getGroup()] = -1; // Consume the register
pieces.push_back(VarnodeData());
pieces.back().space = addr.getSpace();
pieces.back().offset = addr.getOffset();
pieces.back().size = trialSize;
sizeLeft -= trialSize;
align = 1; // Treat remaining partial pieces as having no alignment requirement
}
if (sizeLeft > 0) { // Have to use stack to get enough bytes
if (!consumeFromStack)
return fail;
int4 grp = stackEntry->getGroup();
Address addr = stackEntry->getAddrBySlot(tmpStatus[grp],sizeLeft,1); // Consume all the space we need
Address addr = stackEntry->getAddrBySlot(tmpStatus[grp],sizeLeft,align); // Consume all the space we need
if (addr.isInvalid())
return fail;
pieces.push_back(VarnodeData());
@ -841,6 +842,9 @@ void MultiSlotAssign::decode(Decoder &decoder)
else if (attribId == ATTRIB_ALIGN) {
enforceAlignment = decoder.readBool();
}
else if (attribId == ATTRIB_STACKSPILL) {
consumeFromStack = decoder.readBool();
}
}
decoder.closeElement(elemId);
initializeEntries(); // Need new firstIter

View File

@ -959,7 +959,7 @@ void PrintC::opPtrsub(const PcodeOp *op)
if (ct->getMetatype() == TYPE_STRUCT || ct->getMetatype() == TYPE_UNION) {
int8 suboff = (int4)in1const; // How far into container
if (ptrel != (TypePointerRel *)0) {
suboff += ptrel->getPointerOffset();
suboff += ptrel->getAddressOffset();
suboff &= calc_mask(ptype->getSize());
if (suboff == 0) {
// Special case where we do not print a field
@ -1666,22 +1666,23 @@ void PrintC::pushCharConstant(uintb val,const Datatype *ct,tagtype tag,const Var
void PrintC::pushEnumConstant(uintb val,const TypeEnum *ct,tagtype tag,
const Varnode *vn,const PcodeOp *op)
{
vector<string> valnames;
TypeEnum::Representation rep;
bool complement = ct->getMatches(val,valnames);
if (valnames.size() > 0) {
if (complement)
ct->getMatches(val,rep);
if (rep.matchname.size() > 0) {
if (rep.shiftAmount != 0)
pushOp(&shift_right,op);
if (rep.complement)
pushOp(&bitwise_not,op);
for(int4 i=valnames.size()-1;i>0;--i)
for(int4 i=rep.matchname.size()-1;i>0;--i)
pushOp(&enum_cat,op);
for(int4 i=0;i<valnames.size();++i)
pushAtom(Atom(valnames[i],tag,EmitMarkup::const_color,op,vn,val));
for(int4 i=0;i<rep.matchname.size();++i)
pushAtom(Atom(rep.matchname[i],tag,EmitMarkup::const_color,op,vn,val));
if (rep.shiftAmount != 0)
push_integer(rep.shiftAmount,4,false,tag,vn,op);
}
else {
push_integer(val,ct->getSize(),false,tag,vn,op);
// ostringstream s;
// s << "BAD_ENUM(0x" << hex << val << ")";
// pushAtom(Atom(s.str(),vartoken,EmitMarkup::const_color,op,vn));
}
}
@ -1793,8 +1794,11 @@ void PrintC::pushConstant(uintb val,const Datatype *ct,tagtype tag,
case TYPE_SPACEBASE:
case TYPE_CODE:
case TYPE_ARRAY:
case TYPE_ENUM_INT:
case TYPE_ENUM_UINT:
case TYPE_STRUCT:
case TYPE_UNION:
case TYPE_PARTIALENUM:
case TYPE_PARTIALSTRUCT:
case TYPE_PARTIALUNION:
break;

View File

@ -15,7 +15,6 @@
*/
#include "ruleaction.hh"
#include "coreaction.hh"
#include "subflow.hh"
#include "rangeutil.hh"
#include "multiprecision.hh"
@ -5679,7 +5678,7 @@ void AddTreeState::clear(void)
nonmultsum = 0;
biggestNonMultCoeff = 0;
if (pRelType != (const TypePointerRel *)0) {
nonmultsum = ((TypePointerRel *)ct)->getPointerOffset();
nonmultsum = ((TypePointerRel *)ct)->getAddressOffset();
nonmultsum &= ptrmask;
}
multiple.clear();
@ -5733,7 +5732,7 @@ AddTreeState::AddTreeState(Funcdata &d,PcodeOp *op,int4 slot)
if (ct->isFormalPointerRel()) {
pRelType = (const TypePointerRel *)ct;
baseType = pRelType->getParent();
nonmultsum = pRelType->getPointerOffset();
nonmultsum = pRelType->getAddressOffset();
nonmultsum &= ptrmask;
}
if (baseType->isVariableLength())
@ -6012,7 +6011,7 @@ void AddTreeState::calcSubtype(void)
extra = AddrSpace::byteToAddressInt(extra, ct->getWordSize()); // Convert back to address units
offset = (offset - extra) & ptrmask;
correct = (correct - extra) & ptrmask;
if (pRelType != (TypePointerRel *)0 && offset == pRelType->getPointerOffset()) {
if (pRelType != (TypePointerRel *)0 && offset == pRelType->getAddressOffset()) {
// offset falls within basic ptrto
if (!pRelType->evaluateThruParent(0)) { // If we are not representing offset 0 through parent
valid = false; // Use basic (alternate) form
@ -6031,7 +6030,7 @@ void AddTreeState::calcSubtype(void)
valid = false; // There is substructure we don't know about
}
if (pRelType != (const TypePointerRel *)0) {
int4 ptrOff = ((TypePointerRel *)ct)->getPointerOffset();
int4 ptrOff = ((TypePointerRel *)ct)->getAddressOffset();
offset = (offset - ptrOff) & ptrmask;
correct = (correct - ptrOff) & ptrmask;
}
@ -6398,8 +6397,7 @@ int4 RuleStructOffset0::applyOp(PcodeOp *op,Funcdata &data)
baseType = ptRel->getParent();
if (baseType->getMetatype() != TYPE_STRUCT)
return 0;
int8 iOff = ptRel->getPointerOffset();
iOff = AddrSpace::addressToByteInt(iOff, ptRel->getWordSize());
int8 iOff = ptRel->getByteOffset();
if (iOff >= baseType->getSize())
return 0;
offset = iOff;
@ -6864,7 +6862,6 @@ int4 RuleAddUnsigned::applyOp(PcodeOp *op,Funcdata &data)
Datatype *dt = constvn->getTypeReadFacing(op);
if (dt->getMetatype() != TYPE_UINT) return 0;
if (dt->isCharPrint()) return 0; // Only change integer forms
if (dt->isEnumType()) return 0;
uintb val = constvn->getOffset();
uintb mask = calc_mask(constvn->getSize());
int4 sa = constvn->getSize() * 6; // 1/4 less than full bitsize
@ -6877,8 +6874,14 @@ int4 RuleAddUnsigned::applyOp(PcodeOp *op,Funcdata &data)
return 0; // Dont transform a named equate
}
}
uintb negatedVal = (-val) & mask;
if (dt->isEnumType()) {
TypeEnum *enumType = (TypeEnum *)dt;
if (!enumType->hasNamedValue(negatedVal) && enumType->hasNamedValue((~val)&mask))
return 0;
}
data.opSetOpcode(op,CPUI_INT_SUB);
Varnode *cvn = data.newConstant(constvn->getSize(), (-val) & mask);
Varnode *cvn = data.newConstant(constvn->getSize(), negatedVal);
cvn->copySymbol(constvn);
data.opSetInput(op,cvn,1);
return 1;
@ -7369,86 +7372,6 @@ int4 RulePieceStructure::applyOp(PcodeOp *op,Funcdata &data)
return 1;
}
/// \class RuleSplitCopy
/// \brief Split COPY ops based on TypePartialStruct
///
/// If more than one logical component of a structure or array is copied at once,
/// rewrite the COPY operator as multiple COPYs.
void RuleSplitCopy::getOpList(vector<uint4> &oplist) const
{
oplist.push_back(CPUI_COPY);
}
int4 RuleSplitCopy::applyOp(PcodeOp *op,Funcdata &data)
{
Datatype *inType = op->getIn(0)->getTypeReadFacing(op);
Datatype *outType = op->getOut()->getTypeDefFacing();
type_metatype metain = inType->getMetatype();
type_metatype metaout = outType->getMetatype();
if (metain != TYPE_PARTIALSTRUCT && metaout != TYPE_PARTIALSTRUCT &&
metain != TYPE_ARRAY && metaout != TYPE_ARRAY &&
metain != TYPE_STRUCT && metaout != TYPE_STRUCT)
return false;
SplitDatatype splitter(data);
if (splitter.splitCopy(op, inType, outType))
return 1;
return 0;
}
/// \class RuleSplitLoad
/// \brief Split LOAD ops based on TypePartialStruct
///
/// If more than one logical component of a structure or array is loaded at once,
/// rewrite the LOAD operator as multiple LOADs.
void RuleSplitLoad::getOpList(vector<uint4> &oplist) const
{
oplist.push_back(CPUI_LOAD);
}
int4 RuleSplitLoad::applyOp(PcodeOp *op,Funcdata &data)
{
Datatype *inType = SplitDatatype::getValueDatatype(op, op->getOut()->getSize(), data.getArch()->types);
if (inType == (Datatype *)0)
return 0;
type_metatype metain = inType->getMetatype();
if (metain != TYPE_STRUCT && metain != TYPE_ARRAY && metain != TYPE_PARTIALSTRUCT)
return 0;
SplitDatatype splitter(data);
if (splitter.splitLoad(op, inType))
return 1;
return 0;
}
/// \class RuleSplitStore
/// \brief Split STORE ops based on TypePartialStruct
///
/// If more than one logical component of a structure or array is stored at once,
/// rewrite the STORE operator as multiple STOREs.
void RuleSplitStore::getOpList(vector<uint4> &oplist) const
{
oplist.push_back(CPUI_STORE);
}
int4 RuleSplitStore::applyOp(PcodeOp *op,Funcdata &data)
{
Datatype *outType = SplitDatatype::getValueDatatype(op, op->getIn(2)->getSize(), data.getArch()->types);
if (outType == (Datatype *)0)
return 0;
type_metatype metain = outType->getMetatype();
if (metain != TYPE_STRUCT && metain != TYPE_ARRAY && metain != TYPE_PARTIALSTRUCT)
return 0;
SplitDatatype splitter(data);
if (splitter.splitStore(op, outType))
return 1;
return 0;
}
/// \class RuleSubNormal
/// \brief Pull-back SUBPIECE through INT_RIGHT and INT_SRIGHT
///
@ -8779,138 +8702,6 @@ int4 RuleSegment::applyOp(PcodeOp *op,Funcdata &data)
return 0;
}
/// \class RuleSubvarAnd
/// \brief Perform SubVariableFlow analysis triggered by INT_AND
void RuleSubvarAnd::getOpList(vector<uint4> &oplist) const
{
oplist.push_back(CPUI_INT_AND);
}
int4 RuleSubvarAnd::applyOp(PcodeOp *op,Funcdata &data)
{
if (!op->getIn(1)->isConstant()) return 0;
Varnode *vn = op->getIn(0);
Varnode *outvn = op->getOut();
// if (vn->getSize() != 1) return 0; // Only for bitsize variables
if (outvn->getConsume() != op->getIn(1)->getOffset()) return 0;
if ((outvn->getConsume() & 1)==0) return 0;
uintb cmask;
if (outvn->getConsume() == (uintb)1)
cmask = (uintb)1;
else {
cmask = calc_mask(vn->getSize());
cmask >>=8;
while(cmask != 0) {
if (cmask == outvn->getConsume()) break;
cmask >>=8;
}
}
if (cmask == 0) return 0;
// if (vn->getConsume() == 0) return 0;
// if ((vn->getConsume() & 0xff)==0xff) return 0;
// if (op->getIn(1)->getOffset() != (uintb)1) return 0;
if (op->getOut()->hasNoDescend()) return 0;
SubvariableFlow subflow(&data,vn,cmask,false,false,false);
if (!subflow.doTrace()) return 0;
subflow.doReplacement();
return 1;
}
/// \class RuleSubvarSubpiece
/// \brief Perform SubVariableFlow analysis triggered by SUBPIECE
void RuleSubvarSubpiece::getOpList(vector<uint4> &oplist) const
{
oplist.push_back(CPUI_SUBPIECE);
}
int4 RuleSubvarSubpiece::applyOp(PcodeOp *op,Funcdata &data)
{
Varnode *vn = op->getIn(0);
Varnode *outvn = op->getOut();
int4 flowsize = outvn->getSize();
uintb mask = calc_mask( flowsize );
mask <<= 8*((int4)op->getIn(1)->getOffset());
bool aggressive = outvn->isPtrFlow();
if (!aggressive) {
if ((vn->getConsume() & mask) != vn->getConsume()) return 0;
if (op->getOut()->hasNoDescend()) return 0;
}
bool big = false;
if (flowsize >= 8 && vn->isInput()) {
// Vector register inputs getting truncated to what actually gets used
// happens occasionally. We let SubvariableFlow deal with this special case
// to avoid overlapping inputs
// TODO: ActionLaneDivide should be handling this
if (vn->loneDescend() == op)
big = true;
}
SubvariableFlow subflow(&data,vn,mask,aggressive,false,big);
if (!subflow.doTrace()) return 0;
subflow.doReplacement();
return 1;
}
/// \class RuleSplitFlow
/// \brief Try to detect and split artificially joined Varnodes
///
/// Look for SUBPIECE coming from a PIECE that has come through INDIRECTs and/or MULTIEQUAL
/// Then: check if the input to SUBPIECE can be viewed as two independent pieces
/// If so: split the pieces into independent data-flows
void RuleSplitFlow::getOpList(vector<uint4> &oplist) const
{
oplist.push_back(CPUI_SUBPIECE);
}
int4 RuleSplitFlow::applyOp(PcodeOp *op,Funcdata &data)
{
int4 loSize = (int4)op->getIn(1)->getOffset();
if (loSize == 0) // Make sure SUBPIECE doesn't take least significant part
return 0;
Varnode *vn = op->getIn(0);
if (!vn->isWritten())
return 0;
if (vn->isPrecisLo() || vn->isPrecisHi())
return 0;
if (op->getOut()->getSize() + loSize != vn->getSize())
return 0; // Make sure SUBPIECE is taking most significant part
PcodeOp *concatOp = (PcodeOp *)0;
PcodeOp *multiOp = vn->getDef();
while(multiOp->code() == CPUI_INDIRECT) { // PIECE may come through INDIRECT
Varnode *tmpvn = multiOp->getIn(0);
if (!tmpvn->isWritten()) return 0;
multiOp = tmpvn->getDef();
}
if (multiOp->code() == CPUI_PIECE) {
if (vn->getDef() != multiOp)
concatOp = multiOp;
}
else if (multiOp->code() == CPUI_MULTIEQUAL) { // Otherwise PIECE comes through MULTIEQUAL
for(int4 i=0;i<multiOp->numInput();++i) {
Varnode *invn = multiOp->getIn(i);
if (!invn->isWritten()) continue;
PcodeOp *tmpOp = invn->getDef();
if (tmpOp->code() == CPUI_PIECE) {
concatOp = tmpOp;
break;
}
}
}
if (concatOp == (PcodeOp *)0) // Didn't find the concatenate
return 0;
if (concatOp->getIn(1)->getSize() != loSize)
return 0;
SplitFlow splitFlow(&data,vn,loSize);
if (!splitFlow.doTrace()) return 0;
splitFlow.apply();
return 1;
}
/// \class RulePtrFlow
/// \brief Mark Varnode and PcodeOp objects that are carrying or operating on pointers
///
@ -9111,178 +8902,6 @@ int4 RulePtrFlow::applyOp(PcodeOp *op,Funcdata &data)
return madeChange;
}
/// \class RuleSubvarCompZero
/// \brief Perform SubvariableFlow analysis triggered by testing of a single bit
///
/// Given a comparison (INT_EQUAL or INT_NOTEEQUAL_ to a constant,
/// check that input has only 1 bit that can possibly be non-zero
/// and that the constant is testing this. This then triggers
/// the full SubvariableFlow analysis.
void RuleSubvarCompZero::getOpList(vector<uint4> &oplist) const
{
oplist.push_back(CPUI_INT_NOTEQUAL);
oplist.push_back(CPUI_INT_EQUAL);
}
int4 RuleSubvarCompZero::applyOp(PcodeOp *op,Funcdata &data)
{
if (!op->getIn(1)->isConstant()) return 0;
Varnode *vn = op->getIn(0);
uintb mask = vn->getNZMask();
int4 bitnum = leastsigbit_set(mask);
if (bitnum == -1) return 0;
if ((mask >> bitnum) != 1) return 0; // Check if only one bit active
// Check if the active bit is getting tested
if ((op->getIn(1)->getOffset()!=mask)&&
(op->getIn(1)->getOffset()!=0))
return 0;
if (op->getOut()->hasNoDescend()) return 0;
// We do a basic check that the stream from which it looks like
// the bit is getting pulled is not fully consumed
if (vn->isWritten()) {
PcodeOp *andop = vn->getDef();
if (andop->numInput()==0) return 0;
Varnode *vn0 = andop->getIn(0);
switch(andop->code()) {
case CPUI_INT_AND:
case CPUI_INT_OR:
case CPUI_INT_RIGHT:
{
if (vn0->isConstant()) return 0;
uintb mask0 = vn0->getConsume() & vn0->getNZMask();
uintb wholemask = calc_mask(vn0->getSize()) & mask0;
// We really need a popcnt here
// We want: if the number of bits that are both consumed
// and not known to be zero are "big" then don't continue
// because it doesn't look like a few bits getting manipulated
// within a status register
if ((wholemask & 0xff)==0xff) return 0;
if ((wholemask & 0xff00)==0xff00) return 0;
}
break;
default:
break;
}
}
SubvariableFlow subflow(&data,vn,mask,false,false,false);
if (!subflow.doTrace()) {
return 0;
}
subflow.doReplacement();
return 1;
}
/// \class RuleSubvarShift
/// \brief Perform SubvariableFlow analysis triggered by INT_RIGHT
///
/// If the INT_RIGHT input has only 1 bit that can possibly be non-zero
/// and it is getting shifted into the least significant bit position,
/// trigger the full SubvariableFlow analysis.
void RuleSubvarShift::getOpList(vector<uint4> &oplist) const
{
oplist.push_back(CPUI_INT_RIGHT);
}
int4 RuleSubvarShift::applyOp(PcodeOp *op,Funcdata &data)
{
Varnode *vn = op->getIn(0);
if (vn->getSize() != 1) return 0;
if (!op->getIn(1)->isConstant()) return 0;
int4 sa = (int4)op->getIn(1)->getOffset();
uintb mask = vn->getNZMask();
if ((mask >> sa) != (uintb)1) return 0; // Pulling out a single bit
mask = (mask >> sa) << sa;
if (op->getOut()->hasNoDescend()) return 0;
SubvariableFlow subflow(&data,vn,mask,false,false,false);
if (!subflow.doTrace()) return 0;
subflow.doReplacement();
return 1;
}
/// \class RuleSubvarZext
/// \brief Perform SubvariableFlow analysis triggered by INT_ZEXT
void RuleSubvarZext::getOpList(vector<uint4> &oplist) const
{
oplist.push_back(CPUI_INT_ZEXT);
}
int4 RuleSubvarZext::applyOp(PcodeOp *op,Funcdata &data)
{
Varnode *vn = op->getOut();
Varnode *invn = op->getIn(0);
uintb mask = calc_mask(invn->getSize());
SubvariableFlow subflow(&data,vn,mask,invn->isPtrFlow(),false,false);
if (!subflow.doTrace()) return 0;
subflow.doReplacement();
return 1;
}
/// \class RuleSubvarSext
/// \brief Perform SubvariableFlow analysis triggered by INT_SEXT
void RuleSubvarSext::getOpList(vector<uint4> &oplist) const
{
oplist.push_back(CPUI_INT_SEXT);
}
int4 RuleSubvarSext::applyOp(PcodeOp *op,Funcdata &data)
{
Varnode *vn = op->getOut();
Varnode *invn = op->getIn(0);
uintb mask = calc_mask(invn->getSize());
SubvariableFlow subflow(&data,vn,mask,isaggressive,true,false);
if (!subflow.doTrace()) return 0;
subflow.doReplacement();
return 1;
}
void RuleSubvarSext::reset(Funcdata &data)
{
isaggressive = data.getArch()->aggressive_ext_trim;
}
/// \class RuleSubfloatConvert
/// \brief Perform SubfloatFlow analysis triggered by FLOAT_FLOAT2FLOAT
void RuleSubfloatConvert::getOpList(vector<uint4> &oplist) const
{
oplist.push_back(CPUI_FLOAT_FLOAT2FLOAT);
}
int4 RuleSubfloatConvert::applyOp(PcodeOp *op,Funcdata &data)
{
Varnode *invn = op->getIn(0);
Varnode *outvn = op->getOut();
int4 insize = invn->getSize();
int4 outsize = outvn->getSize();
if (outsize > insize) {
SubfloatFlow subflow(&data,outvn,insize);
if (!subflow.doTrace()) return 0;
subflow.apply();
}
else {
SubfloatFlow subflow(&data,invn,outsize);
if (!subflow.doTrace()) return 0;
subflow.apply();
}
return 1;
}
/// \class RuleNegateNegate
/// \brief Simplify INT_NEGATE chains: `~~V => V`
void RuleNegateNegate::getOpList(vector<uint4> &oplist) const
@ -10926,4 +10545,145 @@ int4 RuleOrCompare::applyOp(PcodeOp *op,Funcdata &data)
return 1;
}
/// \brief Check that all uses of given Varnode are of the form `(V & C) == D`
///
/// \param vn is the given Varnode
/// \return \b true if all uses match the INT_AND form
bool RuleExpandLoad::checkAndComparison(Varnode *vn)
{
list<PcodeOp *>::const_iterator iter;
for(iter=vn->beginDescend();iter!=vn->endDescend();++iter) {
PcodeOp *op = *iter;
if (op->code() != CPUI_INT_AND) return false;
if (!op->getIn(1)->isConstant()) return false;
PcodeOp *compOp = op->getOut()->loneDescend();
if (compOp == (PcodeOp *)0) return false;
OpCode opc = compOp->code();
if (opc != CPUI_INT_EQUAL && opc != CPUI_INT_NOTEQUAL) return false;
if (!compOp->getIn(1)->isConstant()) return false;
}
return true;
}
/// \brief Expand the constants in the previously scanned forms: `(V & C) == D`
///
/// The method checkAndComparison() must have returned \b true for \b oldVn. Change the size and
/// data-type of all the constants in these expressions.
/// \param data is the function containing the expressions
/// \param oldVn is incoming variable in all the expressions
/// \param newVn is the new bigger variable
/// \param dt is the data-type to associate with the constants
/// \param offset is the number of least significant (zero) bytes to add to each constant
void RuleExpandLoad::modifyAndComparison(Funcdata &data,Varnode *oldVn,Varnode *newVn,Datatype *dt,int4 offset)
{
offset = 8*offset; // Convert to shift amount
list<PcodeOp *>::const_iterator iter = oldVn->beginDescend();
while(iter != oldVn->endDescend()) {
PcodeOp *andOp = *iter;
++iter; // Advance iterator before modifying op
PcodeOp *compOp = andOp->getOut()->loneDescend();
uintb newOff = andOp->getIn(1)->getOffset();
newOff <<= offset;
Varnode *vn = data.newConstant(dt->getSize(), newOff);
vn->updateType(dt, false, false);
data.opSetInput(andOp, newVn, 0);
data.opSetInput(andOp, vn, 1);
newOff = compOp->getIn(1)->getOffset();
newOff <<= offset;
vn = data.newConstant(dt->getSize(), newOff);
vn->updateType(dt, false, false);
data.opSetInput(compOp,vn,1);
}
}
/// \class RuleExpandLoad
/// \brief Convert LOAD size to match pointer data-type
///
/// Change LOAD output to a larger size if used for INT_AND comparisons or if a truncation is natural
void RuleExpandLoad::getOpList(vector<uint4> &oplist) const
{
oplist.push_back(CPUI_LOAD);
}
int4 RuleExpandLoad::applyOp(PcodeOp *op,Funcdata &data)
{
Varnode *outVn = op->getOut();
int4 outSize = outVn->getSize();
Varnode *rootPtr = op->getIn(1);
PcodeOp *addOp = (PcodeOp *)0;
int4 offset = 0;
Datatype *elType;
if (rootPtr->isWritten()) {
PcodeOp *defOp = rootPtr->getDef();
if (defOp->code() == CPUI_INT_ADD && defOp->getIn(1)->isConstant()) {
addOp = defOp;
rootPtr = defOp->getIn(0);
offset = defOp->getIn(1)->getOffset();
if (offset > 16) return 0; // INT_ADD offset must be small
if (defOp->getOut()->loneDescend() == (PcodeOp *)0) return 0; // INT_ADD must be used only once
elType = rootPtr->getTypeReadFacing(defOp);
}
else
elType = rootPtr->getTypeReadFacing(op);
}
else
elType = rootPtr->getTypeReadFacing(op);
if (elType->getMetatype() != TYPE_PTR) return 0;
elType = ((TypePointer *)elType)->getPtrTo();
if (elType->getSize() <= outSize) return 0; // Pointer data-type must be bigger than LOAD
if (elType->getSize() < outSize + offset) return 0;
type_metatype meta = elType->getMetatype();
if (meta == TYPE_UNKNOWN) return 0;
bool addForm = checkAndComparison(outVn);
AddrSpace *spc = op->getIn(0)->getSpaceFromConst();
int4 lsbCut = 0;
if (addForm) {
if (spc->isBigEndian()) {
lsbCut = elType->getSize() - outSize - offset;
}
else
lsbCut = offset;
}
else {
// Check for natural integer truncation
if (meta != TYPE_INT && meta != TYPE_UINT) return 0;
type_metatype outMeta = outVn->getTypeDefFacing()->getMetatype();
if (outMeta != TYPE_INT && outMeta != TYPE_UINT && outMeta != TYPE_UNKNOWN && outMeta != TYPE_BOOL)
return false;
// Check that LOAD is grabbing least significant bytes
if (spc->isBigEndian()) {
if (outSize + offset != elType->getSize()) return 0;
}
else {
if (offset != 0) return 0;
}
}
// Modify the LOAD
Varnode *newOut = data.newUnique(elType->getSize(), elType);
data.opSetOutput(op, newOut);
if (addOp != (PcodeOp *)0) {
data.opSetInput(op, rootPtr, 1);
data.opDestroy(addOp);
}
if (addForm) {
if (meta != TYPE_INT && meta != TYPE_UINT)
elType = data.getArch()->types->getBase(elType->getSize(), TYPE_UINT);
modifyAndComparison(data, outVn, newOut, elType, lsbCut);
}
else {
PcodeOp *subOp = data.newOp(2,op->getAddr());
data.opSetOpcode(subOp, CPUI_SUBPIECE);
data.opSetInput(subOp,newOut,0); // Truncate new bigger LOAD output
data.opSetInput(subOp, data.newConstant(4, 0), 1);
data.opSetOutput(subOp, outVn); // Original LOAD output is now defined by SUBPIECE
data.opInsertAfter(subOp, op);
}
return 1;
}
} // End namespace ghidra

View File

@ -1181,39 +1181,6 @@ public:
virtual int4 applyOp(PcodeOp *op,Funcdata &data);
};
class RuleSplitCopy : public Rule {
public:
RuleSplitCopy(const string &g) : Rule( g, 0, "splitcopy") {} ///< Constructor
virtual Rule *clone(const ActionGroupList &grouplist) const {
if (!grouplist.contains(getGroup())) return (Rule *)0;
return new RuleSplitCopy(getGroup());
}
virtual void getOpList(vector<uint4> &oplist) const;
virtual int4 applyOp(PcodeOp *op,Funcdata &data);
};
class RuleSplitLoad : public Rule {
public:
RuleSplitLoad(const string &g) : Rule( g, 0, "splitload") {} ///< Constructor
virtual Rule *clone(const ActionGroupList &grouplist) const {
if (!grouplist.contains(getGroup())) return (Rule *)0;
return new RuleSplitLoad(getGroup());
}
virtual void getOpList(vector<uint4> &oplist) const;
virtual int4 applyOp(PcodeOp *op,Funcdata &data);
};
class RuleSplitStore : public Rule {
public:
RuleSplitStore(const string &g) : Rule( g, 0, "splitstore") {} ///< Constructor
virtual Rule *clone(const ActionGroupList &grouplist) const {
if (!grouplist.contains(getGroup())) return (Rule *)0;
return new RuleSplitStore(getGroup());
}
virtual void getOpList(vector<uint4> &oplist) const;
virtual int4 applyOp(PcodeOp *op,Funcdata &data);
};
class RuleSubNormal : public Rule {
public:
RuleSubNormal(const string &g) : Rule( g, 0, "subnormal") {} ///< Constructor
@ -1398,39 +1365,6 @@ public:
virtual int4 applyOp(PcodeOp *op,Funcdata &data);
};
class RuleSubvarAnd : public Rule {
public:
RuleSubvarAnd(const string &g) : Rule( g, 0, "subvar_and") {} ///< Constructor
virtual Rule *clone(const ActionGroupList &grouplist) const {
if (!grouplist.contains(getGroup())) return (Rule *)0;
return new RuleSubvarAnd(getGroup());
}
virtual void getOpList(vector<uint4> &oplist) const;
virtual int4 applyOp(PcodeOp *op,Funcdata &data);
};
class RuleSubvarSubpiece : public Rule {
public:
RuleSubvarSubpiece(const string &g) : Rule( g, 0, "subvar_subpiece") {} ///< Constructor
virtual Rule *clone(const ActionGroupList &grouplist) const {
if (!grouplist.contains(getGroup())) return (Rule *)0;
return new RuleSubvarSubpiece(getGroup());
}
virtual void getOpList(vector<uint4> &oplist) const;
virtual int4 applyOp(PcodeOp *op,Funcdata &data);
};
class RuleSplitFlow : public Rule {
public:
RuleSplitFlow(const string &g) : Rule( g, 0, "splitflow") {} ///< Constructor
virtual Rule *clone(const ActionGroupList &grouplist) const {
if (!grouplist.contains(getGroup())) return (Rule *)0;
return new RuleSplitFlow(getGroup());
}
virtual void getOpList(vector<uint4> &oplist) const;
virtual int4 applyOp(PcodeOp *op,Funcdata &data);
};
class RulePtrFlow : public Rule {
Architecture *glb; ///< The address space manager
bool hasTruncations; ///< \b true if this architecture needs truncated pointers
@ -1448,63 +1382,6 @@ public:
virtual int4 applyOp(PcodeOp *op,Funcdata &data);
};
class RuleSubvarCompZero : public Rule {
public:
RuleSubvarCompZero(const string &g) : Rule( g, 0, "subvar_compzero") {} ///< Constructor
virtual Rule *clone(const ActionGroupList &grouplist) const {
if (!grouplist.contains(getGroup())) return (Rule *)0;
return new RuleSubvarCompZero(getGroup());
}
virtual void getOpList(vector<uint4> &oplist) const;
virtual int4 applyOp(PcodeOp *op,Funcdata &data);
};
class RuleSubvarShift : public Rule {
public:
RuleSubvarShift(const string &g) : Rule( g, 0, "subvar_shift") {} ///< Constructor
virtual Rule *clone(const ActionGroupList &grouplist) const {
if (!grouplist.contains(getGroup())) return (Rule *)0;
return new RuleSubvarShift(getGroup());
}
virtual void getOpList(vector<uint4> &oplist) const;
virtual int4 applyOp(PcodeOp *op,Funcdata &data);
};
class RuleSubvarZext : public Rule {
public:
RuleSubvarZext(const string &g) : Rule( g, 0, "subvar_zext") {} ///< Constructor
virtual Rule *clone(const ActionGroupList &grouplist) const {
if (!grouplist.contains(getGroup())) return (Rule *)0;
return new RuleSubvarZext(getGroup());
}
virtual void getOpList(vector<uint4> &oplist) const;
virtual int4 applyOp(PcodeOp *op,Funcdata &data);
};
class RuleSubvarSext : public Rule {
int4 isaggressive; ///< Is it guaranteed the root is a sub-variable needing to be trimmed
public:
RuleSubvarSext(const string &g) : Rule( g, 0, "subvar_sext") { isaggressive = false; } ///< Constructor
virtual Rule *clone(const ActionGroupList &grouplist) const {
if (!grouplist.contains(getGroup())) return (Rule *)0;
return new RuleSubvarSext(getGroup());
}
virtual void getOpList(vector<uint4> &oplist) const;
virtual int4 applyOp(PcodeOp *op,Funcdata &data);
virtual void reset(Funcdata &data);
};
class RuleSubfloatConvert : public Rule {
public:
RuleSubfloatConvert(const string &g) : Rule( g, 0, "subfloat_convert") {} ///< Constructor
virtual Rule *clone(const ActionGroupList &grouplist) const {
if (!grouplist.contains(getGroup())) return (Rule *)0;
return new RuleSubfloatConvert(getGroup());
}
virtual void getOpList(vector<uint4> &oplist) const;
virtual int4 applyOp(PcodeOp *op,Funcdata &data);
};
class RuleNegateNegate : public Rule {
public:
RuleNegateNegate(const string &g) : Rule( g, 0, "negatenegate") {} ///< Constructor
@ -1695,5 +1572,18 @@ public:
virtual int4 applyOp(PcodeOp *op,Funcdata &data);
};
class RuleExpandLoad : public Rule {
static bool checkAndComparison(Varnode *vn);
static void modifyAndComparison(Funcdata &data,Varnode *oldVn,Varnode *newVn,Datatype *dt,int4 offset);
public:
RuleExpandLoad(const string &g) : Rule( g, 0, "expandload") {} ///< Constructor
virtual Rule *clone(const ActionGroupList &grouplist) const {
if (!grouplist.contains(getGroup())) return (Rule *)0;
return new RuleExpandLoad(getGroup());
}
virtual void getOpList(vector<uint4> &oplist) const;
virtual int4 applyOp(PcodeOp *op,Funcdata &data);
};
} // End namespace ghidra
#endif

View File

@ -14,6 +14,7 @@
* limitations under the License.
*/
#include "subflow.hh"
#include "funcdata.hh"
namespace ghidra {
@ -1506,6 +1507,204 @@ void SubvariableFlow::doReplacement(void)
}
}
void RuleSubvarAnd::getOpList(vector<uint4> &oplist) const
{
oplist.push_back(CPUI_INT_AND);
}
int4 RuleSubvarAnd::applyOp(PcodeOp *op,Funcdata &data)
{
if (!op->getIn(1)->isConstant()) return 0;
Varnode *vn = op->getIn(0);
Varnode *outvn = op->getOut();
// if (vn->getSize() != 1) return 0; // Only for bitsize variables
if (outvn->getConsume() != op->getIn(1)->getOffset()) return 0;
if ((outvn->getConsume() & 1)==0) return 0;
uintb cmask;
if (outvn->getConsume() == (uintb)1)
cmask = (uintb)1;
else {
cmask = calc_mask(vn->getSize());
cmask >>=8;
while(cmask != 0) {
if (cmask == outvn->getConsume()) break;
cmask >>=8;
}
}
if (cmask == 0) return 0;
// if (vn->getConsume() == 0) return 0;
// if ((vn->getConsume() & 0xff)==0xff) return 0;
// if (op->getIn(1)->getOffset() != (uintb)1) return 0;
if (op->getOut()->hasNoDescend()) return 0;
SubvariableFlow subflow(&data,vn,cmask,false,false,false);
if (!subflow.doTrace()) return 0;
subflow.doReplacement();
return 1;
}
void RuleSubvarSubpiece::getOpList(vector<uint4> &oplist) const
{
oplist.push_back(CPUI_SUBPIECE);
}
int4 RuleSubvarSubpiece::applyOp(PcodeOp *op,Funcdata &data)
{
Varnode *vn = op->getIn(0);
Varnode *outvn = op->getOut();
int4 flowsize = outvn->getSize();
uintb mask = calc_mask( flowsize );
mask <<= 8*((int4)op->getIn(1)->getOffset());
bool aggressive = outvn->isPtrFlow();
if (!aggressive) {
if ((vn->getConsume() & mask) != vn->getConsume()) return 0;
if (op->getOut()->hasNoDescend()) return 0;
}
bool big = false;
if (flowsize >= 8 && vn->isInput()) {
// Vector register inputs getting truncated to what actually gets used
// happens occasionally. We let SubvariableFlow deal with this special case
// to avoid overlapping inputs
// TODO: ActionLaneDivide should be handling this
if (vn->loneDescend() == op)
big = true;
}
SubvariableFlow subflow(&data,vn,mask,aggressive,false,big);
if (!subflow.doTrace()) return 0;
subflow.doReplacement();
return 1;
}
void RuleSubvarCompZero::getOpList(vector<uint4> &oplist) const
{
oplist.push_back(CPUI_INT_NOTEQUAL);
oplist.push_back(CPUI_INT_EQUAL);
}
int4 RuleSubvarCompZero::applyOp(PcodeOp *op,Funcdata &data)
{
if (!op->getIn(1)->isConstant()) return 0;
Varnode *vn = op->getIn(0);
uintb mask = vn->getNZMask();
int4 bitnum = leastsigbit_set(mask);
if (bitnum == -1) return 0;
if ((mask >> bitnum) != 1) return 0; // Check if only one bit active
// Check if the active bit is getting tested
if ((op->getIn(1)->getOffset()!=mask)&&
(op->getIn(1)->getOffset()!=0))
return 0;
if (op->getOut()->hasNoDescend()) return 0;
// We do a basic check that the stream from which it looks like
// the bit is getting pulled is not fully consumed
if (vn->isWritten()) {
PcodeOp *andop = vn->getDef();
if (andop->numInput()==0) return 0;
Varnode *vn0 = andop->getIn(0);
switch(andop->code()) {
case CPUI_INT_AND:
case CPUI_INT_OR:
case CPUI_INT_RIGHT:
{
if (vn0->isConstant()) return 0;
uintb mask0 = vn0->getConsume() & vn0->getNZMask();
uintb wholemask = calc_mask(vn0->getSize()) & mask0;
// We really need a popcnt here
// We want: if the number of bits that are both consumed
// and not known to be zero are "big" then don't continue
// because it doesn't look like a few bits getting manipulated
// within a status register
if ((wholemask & 0xff)==0xff) return 0;
if ((wholemask & 0xff00)==0xff00) return 0;
}
break;
default:
break;
}
}
SubvariableFlow subflow(&data,vn,mask,false,false,false);
if (!subflow.doTrace()) {
return 0;
}
subflow.doReplacement();
return 1;
}
void RuleSubvarShift::getOpList(vector<uint4> &oplist) const
{
oplist.push_back(CPUI_INT_RIGHT);
}
int4 RuleSubvarShift::applyOp(PcodeOp *op,Funcdata &data)
{
Varnode *vn = op->getIn(0);
if (vn->getSize() != 1) return 0;
if (!op->getIn(1)->isConstant()) return 0;
int4 sa = (int4)op->getIn(1)->getOffset();
uintb mask = vn->getNZMask();
if ((mask >> sa) != (uintb)1) return 0; // Pulling out a single bit
mask = (mask >> sa) << sa;
if (op->getOut()->hasNoDescend()) return 0;
SubvariableFlow subflow(&data,vn,mask,false,false,false);
if (!subflow.doTrace()) return 0;
subflow.doReplacement();
return 1;
}
void RuleSubvarZext::getOpList(vector<uint4> &oplist) const
{
oplist.push_back(CPUI_INT_ZEXT);
}
int4 RuleSubvarZext::applyOp(PcodeOp *op,Funcdata &data)
{
Varnode *vn = op->getOut();
Varnode *invn = op->getIn(0);
uintb mask = calc_mask(invn->getSize());
SubvariableFlow subflow(&data,vn,mask,invn->isPtrFlow(),false,false);
if (!subflow.doTrace()) return 0;
subflow.doReplacement();
return 1;
}
void RuleSubvarSext::getOpList(vector<uint4> &oplist) const
{
oplist.push_back(CPUI_INT_SEXT);
}
int4 RuleSubvarSext::applyOp(PcodeOp *op,Funcdata &data)
{
Varnode *vn = op->getOut();
Varnode *invn = op->getIn(0);
uintb mask = calc_mask(invn->getSize());
SubvariableFlow subflow(&data,vn,mask,isaggressive,true,false);
if (!subflow.doTrace()) return 0;
subflow.doReplacement();
return 1;
}
void RuleSubvarSext::reset(Funcdata &data)
{
isaggressive = data.getArch()->aggressive_ext_trim;
}
/// \brief Find or build the placeholder objects for a Varnode that needs to be split
///
/// Mark the Varnode so it doesn't get revisited.
@ -1797,6 +1996,57 @@ bool SplitFlow::doTrace(void)
return true;
}
void RuleSplitFlow::getOpList(vector<uint4> &oplist) const
{
oplist.push_back(CPUI_SUBPIECE);
}
int4 RuleSplitFlow::applyOp(PcodeOp *op,Funcdata &data)
{
int4 loSize = (int4)op->getIn(1)->getOffset();
if (loSize == 0) // Make sure SUBPIECE doesn't take least significant part
return 0;
Varnode *vn = op->getIn(0);
if (!vn->isWritten())
return 0;
if (vn->isPrecisLo() || vn->isPrecisHi())
return 0;
if (op->getOut()->getSize() + loSize != vn->getSize())
return 0; // Make sure SUBPIECE is taking most significant part
PcodeOp *concatOp = (PcodeOp *)0;
PcodeOp *multiOp = vn->getDef();
while(multiOp->code() == CPUI_INDIRECT) { // PIECE may come through INDIRECT
Varnode *tmpvn = multiOp->getIn(0);
if (!tmpvn->isWritten()) return 0;
multiOp = tmpvn->getDef();
}
if (multiOp->code() == CPUI_PIECE) {
if (vn->getDef() != multiOp)
concatOp = multiOp;
}
else if (multiOp->code() == CPUI_MULTIEQUAL) { // Otherwise PIECE comes through MULTIEQUAL
for(int4 i=0;i<multiOp->numInput();++i) {
Varnode *invn = multiOp->getIn(i);
if (!invn->isWritten()) continue;
PcodeOp *tmpOp = invn->getDef();
if (tmpOp->code() == CPUI_PIECE) {
concatOp = tmpOp;
break;
}
}
}
if (concatOp == (PcodeOp *)0) // Didn't find the concatenate
return 0;
if (concatOp->getIn(1)->getSize() != loSize)
return 0;
SplitFlow splitFlow(&data,vn,loSize);
if (!splitFlow.doTrace()) return 0;
splitFlow.apply();
return 1;
}
/// If \b pointer Varnode is written by a COPY, INT_ADD, PTRSUB, or PTRADD from another pointer to a
/// - structure
/// - array OR
@ -2628,8 +2878,7 @@ Datatype *SplitDatatype::getValueDatatype(PcodeOp *loadStore,int4 size,TypeFacto
if (ptrType->isPointerRel()) {
TypePointerRel *ptrRel = (TypePointerRel *)ptrType;
resType = ptrRel->getParent();
baseOffset = ptrRel->getPointerOffset();
baseOffset = AddrSpace::addressToByteInt(baseOffset, ptrRel->getWordSize());
baseOffset = ptrRel->getByteOffset();
}
else {
resType = ((TypePointer *)ptrType)->getPtrTo();
@ -2649,6 +2898,71 @@ Datatype *SplitDatatype::getValueDatatype(PcodeOp *loadStore,int4 size,TypeFacto
return (Datatype *)0;
}
void RuleSplitCopy::getOpList(vector<uint4> &oplist) const
{
oplist.push_back(CPUI_COPY);
}
int4 RuleSplitCopy::applyOp(PcodeOp *op,Funcdata &data)
{
Datatype *inType = op->getIn(0)->getTypeReadFacing(op);
Datatype *outType = op->getOut()->getTypeDefFacing();
type_metatype metain = inType->getMetatype();
type_metatype metaout = outType->getMetatype();
if (metain != TYPE_PARTIALSTRUCT && metaout != TYPE_PARTIALSTRUCT &&
metain != TYPE_ARRAY && metaout != TYPE_ARRAY &&
metain != TYPE_STRUCT && metaout != TYPE_STRUCT)
return false;
SplitDatatype splitter(data);
if (splitter.splitCopy(op, inType, outType))
return 1;
return 0;
}
void RuleSplitLoad::getOpList(vector<uint4> &oplist) const
{
oplist.push_back(CPUI_LOAD);
}
int4 RuleSplitLoad::applyOp(PcodeOp *op,Funcdata &data)
{
Datatype *inType = SplitDatatype::getValueDatatype(op, op->getOut()->getSize(), data.getArch()->types);
if (inType == (Datatype *)0)
return 0;
type_metatype metain = inType->getMetatype();
if (metain != TYPE_STRUCT && metain != TYPE_ARRAY && metain != TYPE_PARTIALSTRUCT)
return 0;
SplitDatatype splitter(data);
if (splitter.splitLoad(op, inType))
return 1;
return 0;
}
void RuleSplitStore::getOpList(vector<uint4> &oplist) const
{
oplist.push_back(CPUI_STORE);
}
int4 RuleSplitStore::applyOp(PcodeOp *op,Funcdata &data)
{
Datatype *outType = SplitDatatype::getValueDatatype(op, op->getIn(2)->getSize(), data.getArch()->types);
if (outType == (Datatype *)0)
return 0;
type_metatype metain = outType->getMetatype();
if (metain != TYPE_STRUCT && metain != TYPE_ARRAY && metain != TYPE_PARTIALSTRUCT)
return 0;
SplitDatatype splitter(data);
if (splitter.splitStore(op, outType))
return 1;
return 0;
}
/// This method distinguishes between a floating-point variable with \e full precision, where all the
/// storage can vary (or is unknown), versus a value that is extended from a floating-point variable with
/// smaller storage. Within the data-flow above the given Varnode, we search for the maximum
@ -3062,6 +3376,32 @@ bool SubfloatFlow::doTrace(void)
return true;
}
void RuleSubfloatConvert::getOpList(vector<uint4> &oplist) const
{
oplist.push_back(CPUI_FLOAT_FLOAT2FLOAT);
}
int4 RuleSubfloatConvert::applyOp(PcodeOp *op,Funcdata &data)
{
Varnode *invn = op->getIn(0);
Varnode *outvn = op->getOut();
int4 insize = invn->getSize();
int4 outsize = outvn->getSize();
if (outsize > insize) {
SubfloatFlow subflow(&data,outvn,insize);
if (!subflow.doTrace()) return 0;
subflow.apply();
}
else {
SubfloatFlow subflow(&data,invn,outsize);
if (!subflow.doTrace()) return 0;
subflow.apply();
}
return 1;
}
/// \brief Find or build the placeholder objects for a Varnode that needs to be split into lanes
///
/// The Varnode is split based on the given subset of the lane description.

View File

@ -18,7 +18,8 @@
#ifndef __SUBFLOW_HH__
#define __SUBFLOW_HH__
#include "funcdata.hh"
#include "ruleaction.hh"
#include "transform.hh"
namespace ghidra {
@ -128,6 +129,89 @@ public:
void doReplacement(void); ///< Perform the discovered transform, making logical values explicit
};
/// \brief Perform SubVariableFlow analysis triggered by INT_AND
class RuleSubvarAnd : public Rule {
public:
RuleSubvarAnd(const string &g) : Rule( g, 0, "subvar_and") {} ///< Constructor
virtual Rule *clone(const ActionGroupList &grouplist) const {
if (!grouplist.contains(getGroup())) return (Rule *)0;
return new RuleSubvarAnd(getGroup());
}
virtual void getOpList(vector<uint4> &oplist) const;
virtual int4 applyOp(PcodeOp *op,Funcdata &data);
};
/// \brief Perform SubVariableFlow analysis triggered by SUBPIECE
class RuleSubvarSubpiece : public Rule {
public:
RuleSubvarSubpiece(const string &g) : Rule( g, 0, "subvar_subpiece") {} ///< Constructor
virtual Rule *clone(const ActionGroupList &grouplist) const {
if (!grouplist.contains(getGroup())) return (Rule *)0;
return new RuleSubvarSubpiece(getGroup());
}
virtual void getOpList(vector<uint4> &oplist) const;
virtual int4 applyOp(PcodeOp *op,Funcdata &data);
};
/// \brief Perform SubvariableFlow analysis triggered by testing of a single bit
///
/// Given a comparison (INT_EQUAL or INT_NOTEEQUAL_ to a constant,
/// check that input has only 1 bit that can possibly be non-zero
/// and that the constant is testing this. This then triggers
/// the full SubvariableFlow analysis.
class RuleSubvarCompZero : public Rule {
public:
RuleSubvarCompZero(const string &g) : Rule( g, 0, "subvar_compzero") {} ///< Constructor
virtual Rule *clone(const ActionGroupList &grouplist) const {
if (!grouplist.contains(getGroup())) return (Rule *)0;
return new RuleSubvarCompZero(getGroup());
}
virtual void getOpList(vector<uint4> &oplist) const;
virtual int4 applyOp(PcodeOp *op,Funcdata &data);
};
/// \brief Perform SubvariableFlow analysis triggered by INT_RIGHT
///
/// If the INT_RIGHT input has only 1 bit that can possibly be non-zero
/// and it is getting shifted into the least significant bit position,
/// trigger the full SubvariableFlow analysis.
class RuleSubvarShift : public Rule {
public:
RuleSubvarShift(const string &g) : Rule( g, 0, "subvar_shift") {} ///< Constructor
virtual Rule *clone(const ActionGroupList &grouplist) const {
if (!grouplist.contains(getGroup())) return (Rule *)0;
return new RuleSubvarShift(getGroup());
}
virtual void getOpList(vector<uint4> &oplist) const;
virtual int4 applyOp(PcodeOp *op,Funcdata &data);
};
/// \brief Perform SubvariableFlow analysis triggered by INT_ZEXT
class RuleSubvarZext : public Rule {
public:
RuleSubvarZext(const string &g) : Rule( g, 0, "subvar_zext") {} ///< Constructor
virtual Rule *clone(const ActionGroupList &grouplist) const {
if (!grouplist.contains(getGroup())) return (Rule *)0;
return new RuleSubvarZext(getGroup());
}
virtual void getOpList(vector<uint4> &oplist) const;
virtual int4 applyOp(PcodeOp *op,Funcdata &data);
};
/// \brief Perform SubvariableFlow analysis triggered by INT_SEXT
class RuleSubvarSext : public Rule {
int4 isaggressive; ///< Is it guaranteed the root is a sub-variable needing to be trimmed
public:
RuleSubvarSext(const string &g) : Rule( g, 0, "subvar_sext") { isaggressive = false; } ///< Constructor
virtual Rule *clone(const ActionGroupList &grouplist) const {
if (!grouplist.contains(getGroup())) return (Rule *)0;
return new RuleSubvarSext(getGroup());
}
virtual void getOpList(vector<uint4> &oplist) const;
virtual int4 applyOp(PcodeOp *op,Funcdata &data);
virtual void reset(Funcdata &data);
};
/// \brief Class for splitting up Varnodes that hold 2 logical variables
///
/// Starting from a \e root Varnode provided to the constructor, \b this class looks for data-flow
@ -147,6 +231,22 @@ public:
bool doTrace(void); ///< Trace split through data-flow, constructing transform
};
/// \brief Try to detect and split artificially joined Varnodes
///
/// Look for SUBPIECE coming from a PIECE that has come through INDIRECTs and/or MULTIEQUAL
/// Then: check if the input to SUBPIECE can be viewed as two independent pieces
/// If so: split the pieces into independent data-flows
class RuleSplitFlow : public Rule {
public:
RuleSplitFlow(const string &g) : Rule( g, 0, "splitflow") {} ///< Constructor
virtual Rule *clone(const ActionGroupList &grouplist) const {
if (!grouplist.contains(getGroup())) return (Rule *)0;
return new RuleSplitFlow(getGroup());
}
virtual void getOpList(vector<uint4> &oplist) const;
virtual int4 applyOp(PcodeOp *op,Funcdata &data);
};
/// \brief Split a p-code COPY, LOAD, or STORE op based on underlying composite data-type
///
/// During the cleanup phase, if a COPY, LOAD, or STORE occurs on a partial structure or array
@ -208,6 +308,51 @@ public:
static Datatype *getValueDatatype(PcodeOp *loadStore,int4 size,TypeFactory *tlst);
};
/// \brief Split COPY ops based on TypePartialStruct
///
/// If more than one logical component of a structure or array is copied at once,
/// rewrite the COPY operator as multiple COPYs.
class RuleSplitCopy : public Rule {
public:
RuleSplitCopy(const string &g) : Rule( g, 0, "splitcopy") {} ///< Constructor
virtual Rule *clone(const ActionGroupList &grouplist) const {
if (!grouplist.contains(getGroup())) return (Rule *)0;
return new RuleSplitCopy(getGroup());
}
virtual void getOpList(vector<uint4> &oplist) const;
virtual int4 applyOp(PcodeOp *op,Funcdata &data);
};
/// \brief Split LOAD ops based on TypePartialStruct
///
/// If more than one logical component of a structure or array is loaded at once,
/// rewrite the LOAD operator as multiple LOADs.
class RuleSplitLoad : public Rule {
public:
RuleSplitLoad(const string &g) : Rule( g, 0, "splitload") {} ///< Constructor
virtual Rule *clone(const ActionGroupList &grouplist) const {
if (!grouplist.contains(getGroup())) return (Rule *)0;
return new RuleSplitLoad(getGroup());
}
virtual void getOpList(vector<uint4> &oplist) const;
virtual int4 applyOp(PcodeOp *op,Funcdata &data);
};
/// \brief Split STORE ops based on TypePartialStruct
///
/// If more than one logical component of a structure or array is stored at once,
/// rewrite the STORE operator as multiple STOREs.
class RuleSplitStore : public Rule {
public:
RuleSplitStore(const string &g) : Rule( g, 0, "splitstore") {} ///< Constructor
virtual Rule *clone(const ActionGroupList &grouplist) const {
if (!grouplist.contains(getGroup())) return (Rule *)0;
return new RuleSplitStore(getGroup());
}
virtual void getOpList(vector<uint4> &oplist) const;
virtual int4 applyOp(PcodeOp *op,Funcdata &data);
};
/// \brief Class for tracing changes of precision in floating point variables
///
/// It follows the flow of a logical lower precision value stored in higher precision locations
@ -242,6 +387,18 @@ public:
bool doTrace(void); ///< Trace logical value as far as possible
};
/// \brief Perform SubfloatFlow analysis triggered by FLOAT_FLOAT2FLOAT
class RuleSubfloatConvert : public Rule {
public:
RuleSubfloatConvert(const string &g) : Rule( g, 0, "subfloat_convert") {} ///< Constructor
virtual Rule *clone(const ActionGroupList &grouplist) const {
if (!grouplist.contains(getGroup())) return (Rule *)0;
return new RuleSubfloatConvert(getGroup());
}
virtual void getOpList(vector<uint4> &oplist) const;
virtual int4 applyOp(PcodeOp *op,Funcdata &data);
};
/// \brief Class for splitting data-flow on \e laned registers
///
/// From a root Varnode and a description of its \e lanes, trace data-flow as far as

View File

@ -113,6 +113,24 @@ void FunctionTestCollection::clear(void)
console->reset();
}
/// Remove any carriage return character as well.
/// \param ref is the string to strip
/// \return the stripped string
string FunctionTestCollection::stripNewlines(const string &ref)
{
string res;
for(int4 i=0;i<ref.size();++i) {
char c = ref[i];
if (c == '\r') continue; // Remove carriage return
if (c == '\n')
c = ' '; // Convert newline to space
res.push_back(c);
}
return res;
}
/// \param el is the root \<script> tag
void FunctionTestCollection::restoreXmlCommands(const Element *el)
@ -122,7 +140,7 @@ void FunctionTestCollection::restoreXmlCommands(const Element *el)
for(iter=list.begin();iter!=list.end();++iter) {
const Element *subel = *iter;
commands.push_back(subel->getContent());
commands.push_back(stripNewlines(subel->getContent()));
}
}

View File

@ -4,9 +4,9 @@
* 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.
@ -77,6 +77,7 @@ class FunctionTestCollection {
mutable int4 numTestsApplied; ///< Count of tests that were executed
mutable int4 numTestsSucceeded; ///< Count of tests that passed
void clear(void); ///< Clear any previous architecture and function
static string stripNewlines(const string &ref); ///< Convert any \e newline character to a \e space
void restoreXmlCommands(const Element *el); ///< Reconstruct commands from an XML tag
void buildProgram(DocumentStorage &store); ///< Build program (Architecture) from \<binaryimage> tag
void startTests(void) const; ///< Initialize each FunctionTestProperty

View File

@ -20,16 +20,17 @@ namespace ghidra {
/// The base propagation ordering associated with each meta-type.
/// The array elements correspond to the ordering of #type_metatype.
sub_metatype Datatype::base2sub[15] = {
SUB_PARTIALUNION, SUB_PARTIALSTRUCT, SUB_UNION, SUB_STRUCT, SUB_ARRAY, SUB_PTRREL, SUB_PTR, SUB_FLOAT, SUB_CODE,
SUB_BOOL, SUB_UINT_PLAIN, SUB_INT_PLAIN, SUB_UNKNOWN, SUB_SPACEBASE, SUB_VOID
sub_metatype Datatype::base2sub[18] = {
SUB_PARTIALUNION, SUB_PARTIALSTRUCT, SUB_UINT_ENUM, SUB_UNION, SUB_STRUCT, SUB_INT_ENUM, SUB_UINT_ENUM,
SUB_ARRAY, SUB_PTRREL, SUB_PTR, SUB_FLOAT, SUB_CODE, SUB_BOOL, SUB_UINT_PLAIN, SUB_INT_PLAIN, SUB_UNKNOWN,
SUB_SPACEBASE, SUB_VOID
};
AttributeId ATTRIB_ALIGNMENT = AttributeId("alignment",47);
AttributeId ATTRIB_ARRAYSIZE = AttributeId("arraysize",48);
AttributeId ATTRIB_CHAR = AttributeId("char",49);
AttributeId ATTRIB_CORE = AttributeId("core",50);
AttributeId ATTRIB_ENUM = AttributeId("enum",51);
//AttributeId ATTRIB_ENUM = AttributeId("enum",51); // deprecated
AttributeId ATTRIB_INCOMPLETE = AttributeId("incomplete",52);
//AttributeId ATTRIB_ENUMSIZE = AttributeId("enumsize",53); // deprecated
//AttributeId ATTRIB_INTSIZE = AttributeId("intsize",54); // deprecated
@ -250,12 +251,21 @@ void metatype2string(type_metatype metatype,string &res)
case TYPE_ARRAY:
res = "array";
break;
case TYPE_PARTIALENUM:
res = "partenum";
break;
case TYPE_PARTIALSTRUCT:
res = "partstruct";
break;
case TYPE_PARTIALUNION:
res = "partunion";
break;
case TYPE_ENUM_INT:
res = "enum_int";
break;
case TYPE_ENUM_UINT:
res = "enum_uint";
break;
case TYPE_STRUCT:
res = "struct";
break;
@ -309,6 +319,12 @@ type_metatype string2metatype(const string &metastring)
if (metastring=="array")
return TYPE_ARRAY;
break;
case 'e':
if (metastring=="enum_int")
return TYPE_ENUM_INT;
else if (metastring == "enum_uint")
return TYPE_ENUM_UINT;
break;
case 's':
if (metastring=="struct")
return TYPE_STRUCT;
@ -1083,6 +1099,12 @@ TypePointer *TypePointer::downChain(int8 &off,TypePointer *&par,int8 &parOff,boo
}
}
if (ptrto->isEnumType()) {
// Go "into" the enumeration
Datatype *tmp = typegrp.getBase(1, TYPE_UINT);
off = 0;
return typegrp.getTypePointer(size,tmp,wordsize);
}
type_metatype meta = ptrto->getMetatype();
bool isArray = (meta == TYPE_ARRAY);
if (isArray || meta == TYPE_STRUCT) {
@ -1325,81 +1347,22 @@ TypeEnum::TypeEnum(const TypeEnum &op) : TypeBase(op)
{
namemap = op.namemap;
masklist = op.masklist;
flags |= (op.flags&poweroftwo)|enumtype;
}
/// Set the map. Calculate the independent bit-fields within the named values of the enumeration
/// Two bits are in the same bit-field if there is a name in the map whose value
/// has those two bits set. Bit-fields must be a contiguous range of bits.
void TypeEnum::setNameMap(const map<uintb,string> &nmap)
/// \param val is the given value to test
/// \return \b true if \b this enumeration has a name with the value
bool TypeEnum::hasNamedValue(uintb val) const
{
map<uintb,string>::const_iterator iter;
uintb curmask,lastmask;
int4 maxbit;
int4 curmaxbit;
bool fieldisempty;
namemap = nmap;
masklist.clear();
flags &= ~((uint4)poweroftwo);
maxbit = 8 * size - 1;
curmaxbit = 0;
while(curmaxbit <= maxbit) {
curmask = 1;
curmask <<= curmaxbit;
lastmask = 0;
fieldisempty = true;
while(curmask != lastmask) { // Repeat until there is no change in the current mask
lastmask = curmask; // Note changes from last time through
for(iter=namemap.begin();iter!=namemap.end();++iter) { // For every named enumeration value
uintb val = (*iter).first;
if ((val & curmask) != 0) { // If the value shares ANY bits in common with the current mask
curmask |= val; // Absorb ALL defined bits of the value into the current mask
fieldisempty = false;
}
}
// Fill in any holes in the mask (bit field must consist of contiguous bits
int4 lsb = leastsigbit_set(curmask);
int4 msb = mostsigbit_set(curmask);
if (msb > curmaxbit)
curmaxbit = msb;
uintb mask1 = 1;
mask1 = (mask1 << lsb) - 1; // every bit below lsb is set to 1
uintb mask2 = 1;
mask2 <<= msb;
mask2 <<= 1;
mask2 -= 1; // every bit below or equal to msb is set to 1
curmask = mask1 ^ mask2;
}
if (fieldisempty) { // If no value hits this bit
if (!masklist.empty())
masklist.back() |= curmask; // Include the bit with the previous mask
else
masklist.push_back(curmask);
}
else
masklist.push_back(curmask);
curmaxbit += 1;
}
if (masklist.size() > 1)
flags |= poweroftwo;
return (namemap.find(val) != namemap.end());
}
/// Given a specific value of the enumeration, calculate the named representation of that value.
/// The representation is returned as a list of names that must logically ORed and possibly complemented.
/// If no representation is possible, no names will be returned.
/// \param val is the value to find the representation for
/// \param valnames will hold the returned list of names
/// \return true if the representation needs to be complemented
bool TypeEnum::getMatches(uintb val,vector<string> &valnames) const
/// \param rep will contain the individual names in the representation and other transforms
void TypeEnum::getMatches(uintb val,Representation &rep) const
{
map<uintb,string>::const_iterator iter;
@ -1407,33 +1370,47 @@ bool TypeEnum::getMatches(uintb val,vector<string> &valnames) const
for(count=0;count<2;++count) {
bool allmatch = true;
if (val == 0) { // Zero handled specially, it crosses all masks
if (val == 0) { // Zero handled specially
iter = namemap.find(val);
if (iter != namemap.end())
valnames.push_back( (*iter).second );
rep.matchname.push_back( (*iter).second );
else
allmatch = false;
}
else {
for(int4 i=0;i<masklist.size();++i) {
uintb maskedval = val & masklist[i];
if (maskedval == 0) // No component of -val- in this mask
continue; // print nothing
iter = namemap.find(maskedval);
if (iter != namemap.end())
valnames.push_back( (*iter).second ); // Found name for this component
else { // If no name for this component
allmatch = false; // Give up on representation
break; // Stop searching for other components
uintb bitsleft = val;
uintb target = val;
while(target != 0) {
// Find named value that matches the largest number of most significant bits in bitsleft
iter = namemap.upper_bound(target);
if (iter == namemap.begin()) break; // All named values are greater than target
--iter; // Biggest named value less than or equal to target
uintb curval = (*iter).first;
uintb diff = coveringmask(bitsleft ^ curval);
if (diff >= bitsleft) break; // Could not match most significant bit of bitsleft
if ((curval & diff) == 0) {
// Found a named value that matches at least most significant bit of bitsleft
rep.matchname.push_back( (*iter).second ); // Accept the name
bitsleft ^= curval; // Remove the bits from bitsleft
target = bitsleft; // Continue searching for named value that match the new bitsleft
}
else {
// Not all the (one) bits of curval match into bitsleft, but we can restrict a further search.
// Bits above diff in curval are the maximum we can hope to match with one named value.
// Zero out bits below this and prepare to search at or below this value
target = curval & ~diff;
}
}
allmatch = (bitsleft == 0);
}
if (allmatch) { // If we have a complete representation
rep.complement = (count==1); // Set whether we represented original value or complement
return;
}
if (allmatch) // If we have a complete representation
return (count==1); // Return whether we represented original value or complement
val = val ^ calc_mask(size); // Switch value we are trying to represent (to complement)
valnames.clear(); // Clear out old attempt
rep.matchname.clear(); // Clear out old attempt
}
return false; // If we reach here, no representation was possible, -valnames- is empty
// If we reach here, no representation was possible, -matchname- is empty
}
int4 TypeEnum::compare(const Datatype &op,int4 level) const
@ -1475,8 +1452,7 @@ void TypeEnum::encode(Encoder &encoder) const
return;
}
encoder.openElement(ELEM_TYPE);
encodeBasic(metatype,-1,encoder);
encoder.writeString(ATTRIB_ENUM, "true");
encodeBasic((metatype == TYPE_INT) ? TYPE_ENUM_INT : TYPE_ENUM_UINT,-1,encoder);
map<uintb,string>::const_iterator iter;
for(iter=namemap.begin();iter!=namemap.end();++iter) {
encoder.openElement(ELEM_VAL);
@ -1496,7 +1472,7 @@ string TypeEnum::decode(Decoder &decoder,TypeFactory &typegrp)
{
// uint4 elemId = decoder.openElement();
decodeBasic(decoder);
submeta = (metatype == TYPE_INT) ? SUB_INT_ENUM : SUB_UINT_ENUM;
metatype = (metatype == TYPE_ENUM_INT) ? TYPE_INT : TYPE_UINT; // Use TYPE_INT or TYPE_UINT internally
map<uintb,string> nmap;
string warning;
@ -2265,6 +2241,81 @@ void TypeUnion::assignFieldOffsets(vector<TypeField> &list,int4 &newSize,int4 &n
}
}
TypePartialEnum::TypePartialEnum(const TypePartialEnum &op)
: TypeEnum(op)
{
stripped = op.stripped;
parent = op.parent;
offset = op.offset;
}
TypePartialEnum::TypePartialEnum(TypeEnum *par,int4 off,int4 sz,Datatype *strip)
: TypeEnum(sz, TYPE_PARTIALENUM)
{
flags |= has_stripped;
stripped = strip;
parent = par;
offset = off;
}
void TypePartialEnum::printRaw(ostream &s) const
{
parent->printRaw(s);
s << "[off=" << dec << offset << ",sz=" << size << ']';
}
bool TypePartialEnum::hasNamedValue(uintb val) const
{
val <<= 8*offset;
return parent->hasNamedValue(val);
}
void TypePartialEnum::getMatches(uintb val,Representation &rep) const
{
val <<= 8*offset;
rep.shiftAmount = offset * 8;
parent->getMatches(val,rep);
}
int4 TypePartialEnum::compare(const Datatype &op,int4 level) const
{
int4 res = Datatype::compare(op,level);
if (res != 0) return res;
// Both must be partial
TypePartialEnum *tp = (TypePartialEnum *) &op;
if (offset != tp->offset) return (offset < tp->offset) ? -1 : 1;
level -= 1;
if (level < 0) {
if (id == op.getId()) return 0;
return (id < op.getId()) ? -1 : 1;
}
return parent->compare(*tp->parent,level); // Compare the underlying union
}
int4 TypePartialEnum::compareDependency(const Datatype &op) const
{
if (submeta != op.getSubMeta()) return (submeta < op.getSubMeta()) ? -1 : 1;
TypePartialEnum *tp = (TypePartialEnum *) &op; // Both must be partial
if (parent != tp->parent) return (parent < tp->parent) ? -1 : 1; // Compare absolute pointers
if (offset != tp->offset) return (offset < tp->offset) ? -1 : 1;
return (op.getSize()-size);
}
void TypePartialEnum::encode(Encoder &encoder) const
{
encoder.openElement(ELEM_TYPE);
encodeBasic(TYPE_PARTIALENUM,-1,encoder);
encoder.writeSignedInteger(ATTRIB_OFFSET, offset);
parent->encodeRef(encoder);
encoder.closeElement(ELEM_TYPE);
}
TypePartialStruct::TypePartialStruct(const TypePartialStruct &op)
: Datatype(op)
{
@ -3111,7 +3162,7 @@ void TypeFactory::setupSizes(void)
setDefaultAlignmentMap();
if (enumsize == 0) {
enumsize = glb->getDefaultSize();
enumtype = TYPE_UINT;
enumtype = TYPE_ENUM_UINT;
}
}
@ -3866,6 +3917,11 @@ TypeStruct *TypeFactory::getTypeStruct(const string &n)
return (TypeStruct *) findAdd(tmp);
}
/// Create a data-type representing storage of part of an \e array or \e structure.
/// \param contain is the parent \e array or \e structure data-type that we are taking a part of.
/// \param off is the offset (in bytes) within the parent that the partial data-type starts at
/// \param sz is the number of bytes in the partial data-type
/// \return the TypePartialStruct object
TypePartialStruct *TypeFactory::getTypePartialStruct(Datatype *contain,int4 off,int4 sz)
{
@ -3887,6 +3943,11 @@ TypeUnion *TypeFactory::getTypeUnion(const string &n)
return (TypeUnion *) findAdd(tmp);
}
/// Create a data-type representing storage of part of a \e union data-type.
/// \param contain is the parent \e union data-type that we are taking a part of.
/// \param off is the offset (in bytes) within the parent that the partial data-type starts at
/// \param sz is the number of bytes in the partial data-type
/// \return the TypePartialUnion object
TypePartialUnion *TypeFactory::getTypePartialUnion(TypeUnion *contain,int4 off,int4 sz)
{
@ -3907,6 +3968,19 @@ TypeEnum *TypeFactory::getTypeEnum(const string &n)
return (TypeEnum *) findAdd(tmp);
}
/// Create a data-type representing storage of part of an \e enumeration.
/// \param contain is the parent \e enumeration data-type that we are taking a part of.
/// \param off is the offset (in bytes) within the parent that the partial data-type starts at
/// \param sz is the number of bytes in the partial data-type
/// \return the TypePartialEnum object
TypePartialEnum *TypeFactory::getTypePartialEnum(TypeEnum *contain,int4 off,int4 sz)
{
Datatype *strip = getBase(sz, TYPE_UNKNOWN);
TypePartialEnum tpe(contain,off,sz,strip);
return (TypePartialEnum *) findAdd(tpe);
}
/// Creates the special TypeSpacebase with an associated address space and scope
/// \param id is the address space
/// \param addr specifies the function scope, or isInvalid() for global scope
@ -4032,6 +4106,8 @@ Datatype *TypeFactory::getExactPiece(Datatype *ct,int4 offset,int4 size)
// If we reach here, lastType is bigger than size
if (lastType->getMetatype() == TYPE_STRUCT || lastType->getMetatype() == TYPE_ARRAY)
return getTypePartialStruct(lastType, lastOff, size);
else if (lastType->isEnumType() && !lastType->hasStripped())
return getTypePartialEnum((TypeEnum *)lastType, lastOff, size);
}
return (Datatype *)0;
}
@ -4238,7 +4314,7 @@ Datatype *TypeFactory::decodeTypedef(Decoder &decoder)
Datatype *TypeFactory::decodeEnum(Decoder &decoder,bool forcecore)
{
TypeEnum te(1,TYPE_INT); // size and metatype are replaced
TypeEnum te(1,TYPE_ENUM_INT); // metatype and size are replaced
string warning = te.decode(decoder,*this);
if (forcecore)
te.flags |= Datatype::coretype;
@ -4399,6 +4475,10 @@ Datatype *TypeFactory::decodeTypeNoRef(Decoder &decoder,bool forcecore)
ct = findAdd(ta);
}
break;
case TYPE_ENUM_INT:
case TYPE_ENUM_UINT:
ct = decodeEnum(decoder,forcecore);
break;
case TYPE_STRUCT:
ct = decodeStruct(decoder,forcecore);
break;
@ -4438,12 +4518,6 @@ Datatype *TypeFactory::decodeTypeNoRef(Decoder &decoder,bool forcecore)
decoder.closeElement(elemId);
return ct;
}
else if (attribId == ATTRIB_ENUM && decoder.readBool()) {
decoder.rewindAttributes();
ct = decodeEnum(decoder, forcecore);
decoder.closeElement(elemId);
return ct;
}
else if (attribId == ATTRIB_UTF && decoder.readBool()) {
TypeUnicode tu;
decoder.rewindAttributes();
@ -4587,9 +4661,9 @@ void TypeFactory::parseEnumConfig(Decoder &decoder)
uint4 elemId = decoder.openElement(ELEM_ENUM);
enumsize = decoder.readSignedInteger(ATTRIB_SIZE);
if (decoder.readBool(ATTRIB_SIGNED))
enumtype = TYPE_INT;
enumtype = TYPE_ENUM_INT;
else
enumtype = TYPE_UINT;
enumtype = TYPE_ENUM_UINT;
decoder.closeElement(elemId);
}

View File

@ -27,7 +27,7 @@ extern AttributeId ATTRIB_ALIGNMENT; ///< Marshaling attribute "alignment"
extern AttributeId ATTRIB_ARRAYSIZE; ///< Marshaling attribute "arraysize"
extern AttributeId ATTRIB_CHAR; ///< Marshaling attribute "char"
extern AttributeId ATTRIB_CORE; ///< Marshaling attribute "core"
extern AttributeId ATTRIB_ENUM; ///< Marshaling attribute "enum"
//extern AttributeId ATTRIB_ENUM; ///< Marshaling attribute "enum" deprecated
extern AttributeId ATTRIB_INCOMPLETE; ///< Marshaling attribute "incomplete"
//extern AttributeId ATTRIB_ENUMSIZE; ///< Marshaling attribute "enumsize" deprecated
//extern AttributeId ATTRIB_INTSIZE; ///< Marshaling attribute "intsize" deprecated
@ -77,20 +77,23 @@ extern void print_data(ostream &s,uint1 *buffer,int4 size,const Address &baseadd
/// The core meta-types supported by the decompiler. These are sizeless templates
/// for the elements making up the type algebra. Index is important for Datatype::base2sub array.
enum type_metatype {
TYPE_VOID = 14, ///< Standard "void" type, absence of type
TYPE_SPACEBASE = 13, ///< Placeholder for symbol/type look-up calculations
TYPE_UNKNOWN = 12, ///< An unknown low-level type. Treated as an unsigned integer.
TYPE_INT = 11, ///< Signed integer. Signed is considered less specific than unsigned in C
TYPE_UINT = 10, ///< Unsigned integer
TYPE_BOOL = 9, ///< Boolean
TYPE_CODE = 8, ///< Data is actual executable code
TYPE_FLOAT = 7, ///< Floating-point
TYPE_VOID = 17, ///< Standard "void" type, absence of type
TYPE_SPACEBASE = 16, ///< Placeholder for symbol/type look-up calculations
TYPE_UNKNOWN = 15, ///< An unknown low-level type. Treated as an unsigned integer.
TYPE_INT = 14, ///< Signed integer. Signed is considered less specific than unsigned in C
TYPE_UINT = 13, ///< Unsigned integer
TYPE_BOOL = 12, ///< Boolean
TYPE_CODE = 11, ///< Data is actual executable code
TYPE_FLOAT = 10, ///< Floating-point
TYPE_PTR = 6, ///< Pointer data-type
TYPE_PTRREL = 5, ///< Pointer relative to another data-type (specialization of TYPE_PTR)
TYPE_ARRAY = 4, ///< Array data-type, made up of a sequence of "element" datatype
TYPE_STRUCT = 3, ///< Structure data-type, made up of component datatypes
TYPE_UNION = 2, ///< An overlapping union of multiple datatypes
TYPE_PTR = 9, ///< Pointer data-type
TYPE_PTRREL = 8, ///< Pointer relative to another data-type (specialization of TYPE_PTR)
TYPE_ARRAY = 7, ///< Array data-type, made up of a sequence of "element" datatype
TYPE_ENUM_UINT = 6, ///< Unsigned enumeration data-type (specialization of TYPE_UINT)
TYPE_ENUM_INT = 5, ///< Signed enumeration data-type (specialization of TYPE_INT)
TYPE_STRUCT = 4, ///< Structure data-type, made up of component datatypes
TYPE_UNION = 3, ///< An overlapping union of multiple datatypes
TYPE_PARTIALENUM = 2, ///< Part of an enumerated value (specialization of TYPE_UINT)
TYPE_PARTIALSTRUCT = 1, ///< Part of a structure, stored separately from the whole
TYPE_PARTIALUNION = 0 ///< Part of a union
};
@ -160,7 +163,7 @@ struct DatatypeCompare;
/// Used for symbols, function prototypes, type propagation etc.
class Datatype {
protected:
static sub_metatype base2sub[15];
static sub_metatype base2sub[18];
/// Boolean properties of datatypes
enum {
coretype = 1, ///< This is a basic type which will never be redefined
@ -213,7 +216,6 @@ public:
bool isCoreType(void) const { return ((flags&coretype)!=0); } ///< Is this a core data-type
bool isCharPrint(void) const { return ((flags&(chartype|utf16|utf32|opaque_string))!=0); } ///< Does this print as a 'char'
bool isEnumType(void) const { return ((flags&enumtype)!=0); } ///< Is this an enumerated type
bool isPowerOfTwo(void) const { return ((flags&poweroftwo)!=0); } ///< Is this a flag-based enumeration
bool isASCII(void) const { return ((flags&chartype)!=0); } ///< Does this print as an ASCII 'char'
bool isUTF16(void) const { return ((flags&utf16)!=0); } ///< Does this print as UTF16 'wchar'
bool isUTF32(void) const { return ((flags&utf32)!=0); } ///< Does this print as UTF32 'wchar'
@ -466,24 +468,33 @@ public:
/// This supports combinations of the enumeration values (using logical OR and bit-wise complement)
/// by defining independent \b bit-fields.
class TypeEnum : public TypeBase {
public:
/// \brief Class describing how a particular enumeration value is constructed using tokens
class Representation {
public:
vector<string> matchname; ///< Name tokens that are ORed together
bool complement; ///< If \b true, bitwise complement value after ORing
int4 shiftAmount; ///< Number of bits to left-shift final value
Representation(void) { complement = false; shiftAmount = 0; } ///< Constructor
};
protected:
friend class TypeFactory;
map<uintb,string> namemap; ///< Map from integer to name
vector<uintb> masklist; ///< Masks for each bitfield within the enum
void setNameMap(const map<uintb,string> &nmap); ///< Establish the value -> name map
void setNameMap(const map<uintb,string> &nmap) { namemap = nmap; } ///< Establish the value -> name map
string decode(Decoder &decoder,TypeFactory &typegrp); ///< Restore \b this enum data-type from a stream
public:
/// Construct from another TypeEnum
TypeEnum(const TypeEnum &op);
/// Construct from a size and meta-type (TYPE_INT or TYPE_UINT)
TypeEnum(int4 s,type_metatype m) : TypeBase(s,m) {
flags |= enumtype; submeta = (m==TYPE_INT) ? SUB_INT_ENUM : SUB_UINT_ENUM; }
flags |= enumtype; metatype = (m==TYPE_ENUM_INT) ? TYPE_INT : TYPE_UINT; }
/// Construct from a size, meta-type, and name
TypeEnum(int4 s,type_metatype m,const string &nm) : TypeBase(s,m,nm) {
flags |= enumtype; submeta = (m==TYPE_INT) ? SUB_INT_ENUM : SUB_UINT_ENUM; }
flags |= enumtype; metatype = (m==TYPE_ENUM_INT) ? TYPE_INT : TYPE_UINT; }
map<uintb,string>::const_iterator beginEnum(void) const { return namemap.begin(); } ///< Beginning of name map
map<uintb,string>::const_iterator endEnum(void) const { return namemap.end(); } ///< End of name map
bool getMatches(uintb val,vector<string> &matchname) const; ///< Recover the named representation
virtual bool hasNamedValue(uintb val) const; ///< Does \b this have a (single) name for the given value
virtual void getMatches(uintb val,Representation &rep) const; ///< Recover the named representation
virtual int4 compare(const Datatype &op,int4 level) const;
virtual int4 compareDependency(const Datatype &op) const;
virtual Datatype *clone(void) const { return new TypeEnum(*this); }
@ -553,6 +564,27 @@ public:
static void assignFieldOffsets(vector<TypeField> &list,int4 &newSize,int4 &newAlign,TypeUnion *tu); ///< Assign field offsets
};
/// \brief A data-type thats holds part of a TypeEnum and possible additional padding
class TypePartialEnum : public TypeEnum {
friend class TypeFactory;
Datatype *stripped; ///< The \e undefined data-type to use if a formal data-type is required.
TypeEnum *parent; ///< The enumeration data-type \b this is based on
int4 offset; ///< Byte offset with the parent enum where \b this starts
public:
TypePartialEnum(const TypePartialEnum &op); ///< Construct from another TypePartialEnum
TypePartialEnum(TypeEnum *par,int4 off,int4 sz,Datatype *strip); ///< Constructor
int4 getOffset(void) const { return offset; } ///< Get the byte offset into the containing data-type
Datatype *getParent(void) const { return parent; } ///< Get the enumeration containing \b this piece
virtual void printRaw(ostream &s) const;
virtual bool hasNamedValue(uintb val) const;
virtual void getMatches(uintb val,Representation &rep) const;
virtual int4 compare(const Datatype &op,int4 level) const;
virtual int4 compareDependency(const Datatype &op) const;
virtual Datatype *clone(void) const { return new TypePartialEnum(*this); }
virtual void encode(Encoder &encoder) const;
virtual Datatype *getStripped(void) const { return stripped; }
};
/// \brief A data-type that holds \e part of a TypeStruct or TypeArray
class TypePartialStruct : public Datatype {
friend class TypeFactory;
@ -634,7 +666,12 @@ public:
/// \brief Get offset of \b this pointer relative to start of the containing data-type
///
/// \return the offset value in \e address \e units
int4 getPointerOffset(void) const { return AddrSpace::byteToAddressInt(offset, wordsize); }
int4 getAddressOffset(void) const { return AddrSpace::byteToAddressInt(offset, wordsize); }
/// \brief Get offset of \b this pointer relative to start of the containing data-type
///
/// \return the offset value in \e byte units
int4 getByteOffset(void) const { return offset; }
virtual void printRaw(ostream &s) const;
virtual int4 compare(const Datatype &op,int4 level) const;
virtual int4 compareDependency(const Datatype &op) const;
@ -803,6 +840,7 @@ public:
TypeUnion *getTypeUnion(const string &n); ///< Create an (empty) union
TypePartialUnion *getTypePartialUnion(TypeUnion *contain,int4 off,int4 sz); ///< Create a partial union
TypeEnum *getTypeEnum(const string &n); ///< Create an (empty) enumeration
TypePartialEnum *getTypePartialEnum(TypeEnum *contain,int4 off,int4 sz); ///< Create a partial enumeration
TypeSpacebase *getTypeSpacebase(AddrSpace *id,const Address &addr); ///< Create a "spacebase" type
TypeCode *getTypeCode(const PrototypePieces &proto); ///< Create a "function" datatype
Datatype *getTypedef(Datatype *ct,const string &name,uint8 id,uint4 format); ///< Create a new \e typedef data-type

View File

@ -175,10 +175,11 @@ OpCode TypeOp::floatSignManipulation(PcodeOp *op)
return CPUI_MAX;
}
/// \brief Propagate a dereferenced data-type up to its pointer data-type
/// \brief Propagate a dereferenced data-type up to its pointer data-type through a LOAD or STORE
///
/// Don't create more than a depth of 1, i.e. ptr->ptr
/// \param pt is the pointed-to data-type
/// \param t is the TypeFactory containing the data-types
/// \param dt is the pointed-to data-type
/// \param sz is the size of the pointer
/// \param wordsz is the wordsize associated with the pointer
/// \return the TypePointer object
@ -196,6 +197,36 @@ Datatype *TypeOp::propagateToPointer(TypeFactory *t,Datatype *dt,int4 sz,int4 wo
return t->getTypePointer(sz,dt,wordsz);
}
/// \brief Propagate a pointer data-type down to its element data-type through a LOAD or STORE
///
/// \param t is the TypeFactory containing the data-types
/// \param dt is the pointer data-type
/// \param sz is the size of the dereferenced pointer
/// \return the dereferenced data-type
Datatype *TypeOp::propagateFromPointer(TypeFactory *t,Datatype *dt,int4 sz)
{
if (dt->getMetatype() != TYPE_PTR)
return (Datatype *)0;
Datatype *ptrto = ((TypePointer *)dt)->getPtrTo();
if (ptrto->isVariableLength())
return (Datatype *)0;
if (ptrto->getSize() == sz)
return ptrto;
// If we reach here, there is a size mismatch between the pointer data-type and the dereferenced value.
// We only propagate (partial) enumerations in this case.
if (dt->isPointerRel()) {
TypePointerRel *ptrrel = (TypePointerRel *)dt;
Datatype *res = t->getExactPiece(ptrrel->getParent(), ptrrel->getByteOffset(), sz);
if (res != (Datatype *)0 && res->isEnumType())
return res;
}
else if (ptrto->isEnumType() && !ptrto->hasStripped()) {
return t->getTypePartialEnum((TypeEnum *)ptrto, 0, sz);
}
return (Datatype *)0;
}
/// \param t is the TypeFactory used to construct data-types
/// \param opc is the op-code value the new object will represent
/// \param n is the display name that will represent the op-code
@ -463,13 +494,8 @@ Datatype *TypeOpLoad::propagateType(Datatype *alttype,PcodeOp *op,Varnode *invn,
AddrSpace *spc = op->getIn(0)->getSpaceFromConst();
newtype = propagateToPointer(tlst,alttype,outvn->getSize(),spc->getWordSize());
}
else if (alttype->getMetatype()==TYPE_PTR) {
newtype = ((TypePointer *)alttype)->getPtrTo();
if (newtype->getSize() != outvn->getSize() || newtype->isVariableLength()) // Size must be appropriate
newtype = (Datatype *)0;
}
else
newtype = (Datatype *)0; // Don't propagate anything
newtype = propagateFromPointer(tlst, alttype, outvn->getSize());
return newtype;
}
@ -538,13 +564,8 @@ Datatype *TypeOpStore::propagateType(Datatype *alttype,PcodeOp *op,Varnode *invn
AddrSpace *spc = op->getIn(0)->getSpaceFromConst();
newtype = propagateToPointer(tlst,alttype,outvn->getSize(),spc->getWordSize());
}
else if (alttype->getMetatype()==TYPE_PTR) {
newtype = ((TypePointer *)alttype)->getPtrTo();
if (newtype->getSize() != outvn->getSize() || newtype->isVariableLength())
newtype = (Datatype *)0;
}
else
newtype = (Datatype *)0; // Don't propagate anything
newtype = propagateFromPointer(tlst, alttype, outvn->getSize());
return newtype;
}
@ -933,7 +954,7 @@ Datatype *TypeOpEqual::propagateAcrossCompare(Datatype *alttype,TypeFactory *typ
}
else if (alttype->isPointerRel() && !outvn->isConstant()) {
TypePointerRel *relPtr = (TypePointerRel *)alttype;
if (relPtr->getParent()->getMetatype() == TYPE_STRUCT && relPtr->getPointerOffset() >= 0) {
if (relPtr->getParent()->getMetatype() == TYPE_STRUCT && relPtr->getByteOffset() >= 0) {
// If we know the pointer is in the middle of a structure, don't propagate across comparison operators
// as the two sides of the operator are likely to be different types , and the other side can also
// get data-type information from the structure pointer
@ -1383,7 +1404,7 @@ Datatype *TypeOpIntXor::getOutputToken(const PcodeOp *op,CastStrategy *castStrat
Datatype *TypeOpIntXor::propagateType(Datatype *alttype,PcodeOp *op,Varnode *invn,Varnode *outvn,
int4 inslot,int4 outslot)
{
if (!alttype->isPowerOfTwo()) {
if (!alttype->isEnumType()) {
if (alttype->getMetatype() != TYPE_FLOAT)
return (Datatype *)0;
if (floatSignManipulation(op) == CPUI_MAX)
@ -1416,7 +1437,7 @@ Datatype *TypeOpIntAnd::getOutputToken(const PcodeOp *op,CastStrategy *castStrat
Datatype *TypeOpIntAnd::propagateType(Datatype *alttype,PcodeOp *op,Varnode *invn,Varnode *outvn,
int4 inslot,int4 outslot)
{
if (!alttype->isPowerOfTwo()) {
if (!alttype->isEnumType()) {
if (alttype->getMetatype() != TYPE_FLOAT)
return (Datatype *)0;
if (floatSignManipulation(op) == CPUI_MAX)
@ -1449,7 +1470,7 @@ Datatype *TypeOpIntOr::getOutputToken(const PcodeOp *op,CastStrategy *castStrate
Datatype *TypeOpIntOr::propagateType(Datatype *alttype,PcodeOp *op,Varnode *invn,Varnode *outvn,
int4 inslot,int4 outslot)
{
if (!alttype->isPowerOfTwo()) return (Datatype *)0; // Only propagate flag enums
if (!alttype->isEnumType()) return (Datatype *)0; // Only propagate enums
Datatype *newtype;
if (invn->isSpacebase()) {
AddrSpace *spc = tlst->getArch()->getDefaultDataSpace();

View File

@ -181,6 +181,7 @@ public:
/// \brief Return the floating-point operation associated with the \e sign bit manipulation by the given PcodeOp
static OpCode floatSignManipulation(PcodeOp *op);
static Datatype *propagateToPointer(TypeFactory *t,Datatype *dt,int4 sz,int4 wordsz);
static Datatype *propagateFromPointer(TypeFactory *t,Datatype *dt,int4 sz);
};
// Major classes of operations

View File

@ -297,6 +297,27 @@ void HighVariable::transferPiece(HighVariable *tv2)
tv2->highflags &= ~(uint4)(intersectdirty | extendcoverdirty);
}
/// Except in specific circumstances, convert \b type into its stripped form.
void HighVariable::stripType(void) const
{
if (!type->hasStripped())
return;
if (type->getMetatype() == TYPE_PARTIALUNION) {
if (symbol != (Symbol *)0 && symboloffset != -1) {
type_metatype meta = symbol->getType()->getMetatype();
if (meta != TYPE_STRUCT && meta != TYPE_UNION) // If partial union does not have a bigger backing symbol
type = type->getStripped(); // strip the partial union
}
}
else if (type->isEnumType()) {
if (inst.size() != 1 || !inst[0]->isConstant()) // Only preserve partial enum on a constant
type = type->getStripped();
}
else
type = type->getStripped();
}
/// Only update if the cover is marked as \e dirty.
/// Merge the covers of all Varnode instances.
void HighVariable::updateInternalCover(void) const
@ -386,17 +407,7 @@ void HighVariable::updateType(void) const
vn = getTypeRepresentative();
type = vn->getType();
if (type->hasStripped()) {
if (type->getMetatype() == TYPE_PARTIALUNION) {
if (symbol != (Symbol *)0 && symboloffset != -1) {
type_metatype meta = symbol->getType()->getMetatype();
if (meta != TYPE_STRUCT && meta != TYPE_UNION) // If partial union does not have a bigger backing symbol
type = type->getStripped(); // strip the partial union
}
}
else
type = type->getStripped();
}
stripType();
// Update lock flags
flags &= ~Varnode::typelock;
if (vn->isTypeLock())
@ -549,17 +560,7 @@ void HighVariable::finalizeDatatype(TypeFactory *typeFactory)
if (tp == (Datatype *)0 || tp->getMetatype() == TYPE_UNKNOWN)
return;
type = tp;
if (type->hasStripped()) {
if (type->getMetatype() == TYPE_PARTIALUNION) {
if (symboloffset != -1) {
type_metatype meta = symbol->getType()->getMetatype();
if (meta != TYPE_STRUCT && meta != TYPE_UNION) // If partial union does not have a bigger backing symbol
type = type->getStripped(); // strip the partial union
}
}
else
type = type->getStripped();
}
stripType();
highflags |= type_finalized;
}

View File

@ -4,9 +4,9 @@
* 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.
@ -167,6 +167,7 @@ private:
void symbolDirty(void) const { highflags |= symboldirty; } ///< Mark the symbol as \e dirty
void setUnmerged(void) const { highflags |= unmerged; } ///< Mark \b this as having merge problems
bool isCoverDirty(void) const; ///< Is the cover returned by getCover() up-to-date
void stripType(void) const; ///< Take the stripped form of the current data-type.
public:
HighVariable(Varnode *vn); ///< Construct a HighVariable with a single member Varnode
~HighVariable(void); ///< Destructor

View File

@ -0,0 +1,108 @@
<decompilertest>
<binaryimage arch="x86:LE:64:default:gcc">
<!--
Functions that read enum values and compare with constant values that should be printed by name.
-->
<bytechunk space="ram" offset="0x100000" readonly="true">
4883ec184889e7e8f40f0000f6442408
4175054883c418c3bf00000000e8e60f
0000ebef4883ec184889e7e8d00f0000
f744240c0003000075054883c418c3bf
00000000e8bf0f0000ebef
</bytechunk>
<bytechunk space="ram" offset="0x100065" readonly="true">
f647082c7501c34883ec08
bf02000000e88e0f00004883c408c3f7
470c571300007501c34883ec08bf0300
0000e8710f00004883c408c3
</bytechunk>
<bytechunk space="ram" offset="0x1000d3" readonly="true">
48817f08000810007401c34883
ec08bf06000000e81c0f00004883c408
c3
</bytechunk>
<symbol space="ram" offset="0x100000" name="stackenumlow"/>
<symbol space="ram" offset="0x100024" name="stackenumhigh"/>
<symbol space="ram" offset="0x100065" name="ptrenumlow"/>
<symbol space="ram" offset="0x10007f" name="ptrenumhigh"/>
<symbol space="ram" offset="0x1000d3" name="ptrenumequal"/>
<symbol space="ram" offset="0x101000" name="setStruct"/>
</binaryimage>
<script>
<com>parse line enum flags {
FLAG_1=1,
FLAG_2 = 2,
FLAG_4 = 4,
FLAG_8 = 8,
FLAG_10 = 0x10,
FLAG_20 = 0x20,
FLAG_40 = 0x40,
FLAG_80 = 0x80,
FLAG_100 = 0x100,
FLAG_200 = 0x200,
FLAG_400 = 0x400,
FLAG_800 = 0x800,
FLAG_1000 = 0x1000,
FLAG_2000 = 0x2000,
FLAG_4000 = 0x4000,
FLAG_8000 = 0x8000,
FLAG_10000 = 0x10000,
FLAG_20000 = 0x20000,
FLAG_40000 = 0x40000,
FLAG_80000 = 0x80000,
FLAG_100000 = 0x100000,
FLAG_200000 = 0x200000,
FLAG_400000 = 0x400000,
FLAG_800000 = 0x800000,
HIGH_1 = 0x100000000,
HIGH_2 = 0x200000000,
HIGH_4 = 0x400000000,
HIGH_8 = 0x800000000,
HIGH_10 = 0x1000000000,
HIGH_20 = 0x2000000000,
HIGH_40 = 0x4000000000,
HIGH_80 = 0x8000000000,
HIGH_100 = 0x10000000000,
HIGH_200 = 0x20000000000,
HIGH_400 = 0x40000000000,
HIGH_800 = 0x80000000000,
HIGH_1000 = 0x100000000000,
HIGH_2000 = 0x200000000000,
HIGH_4000 = 0x400000000000,
HIGH_8000 = 0x800000000000,
HIGH_10000 = 0x1000000000000,
HIGH_20000 = 0x2000000000000,
HIGH_40000 = 0x4000000000000,
HIGH_80000 = 0x8000000000000,
HIGH_100000 = 0x10000000000000,
HIGH_200000 = 0x20000000000000,
HIGH_400000 = 0x40000000000000,
HIGH_800000 = 0x80000000000000 };</com>
<com>parse line struct enumstruct { int4 a; int4 b; flags flagfield; };</com>
<com>parse line extern void setStruct(enumstruct *ptr);</com>
<com>parse line extern void ptrenumlow(enumstruct *ptr);</com>
<com>parse line extern void ptrenumhigh(enumstruct *ptrhigh);</com>
<com>parse line extern void ptrenumequal(enumstruct *ptrequal);</com>
<com>lo fu stackenumlow</com>
<com>decompile</com>
<com>print C</com>
<com>lo fu stackenumhigh</com>
<com>decompile</com>
<com>print C</com>
<com>lo fu ptrenumlow</com>
<com>decompile</com>
<com>print C</com>
<com>lo fu ptrenumhigh</com>
<com>decompile</com>
<com>print C</com>
<com>lo fu ptrenumequal</com>
<com>decompile</com>
<com>print C</com>
<com>quit</com>
</script>
<stringmatch name="Enum Reading #1" min="1" max="1">Stack_18\.flagfield &amp; \(FLAG_40\|FLAG_1\)\) .= 0\)</stringmatch>
<stringmatch name="Enum Reading #2" min="1" max="1">Stack_18\.flagfield\._4_4_ &amp; \(HIGH_200\|HIGH_100\) &gt;&gt; 0x20\) .= 0\)</stringmatch>
<stringmatch name="Enum Reading #3" min="1" max="1">ptr-&gt;flagfield &amp; \(FLAG_20\|FLAG_8\|FLAG_4\)\) .= 0\)</stringmatch>
<stringmatch name="Enum Reading #4" min="1" max="1">if \(\(ptrhigh-&gt;flagfield &amp; \(HIGH_1000\|HIGH_200\|HIGH_100\|HIGH_40\|HIGH_10\|HIGH_4\|HIGH_2\|HIGH_1\)\) .= 0</stringmatch>
<stringmatch name="Enum Reading #5" min="1" max="1">if \(ptrequal-&gt;flagfield .= \(FLAG_100000\|FLAG_800\)\)</stringmatch>
</decompilertest>

View File

@ -22,7 +22,8 @@ f30f1efa488b0748ba454c4556454e54
<bytechunk space="ram" offset="0x1000c5" readonly="true">
488b0748ba770061007200
6e0048891048ba69006e006700210048
895008c3
895008c348b84e454741544956454889
47f9c3
</bytechunk>
<bytechunk space="ram" offset="0x100140" readonly="true">
546865206e756d626572206973205858
@ -31,6 +32,7 @@ f30f1efa488b0748ba454c4556454e54
<symbol space="ram" offset="0x100040" name="fillin_edit"/>
<symbol space="ram" offset="0x1000a0" name="overlap"/>
<symbol space="ram" offset="0x1000c5" name="fillin_wide"/>
<symbol space="ram" offset="0x1000e4" name="negative_ptr"/>
</binaryimage>
<script>
<com>option readonly on</com>
@ -40,6 +42,7 @@ f30f1efa488b0748ba454c4556454e54
<com>parse line extern void fillin_edit(mystring *ptr,int4 extra,int8 pos);</com>
<com>parse line extern void overlap(mystring *ptr);</com>
<com>parse line extern void fillin_wide(mywide *ptr);</com>
<com>parse line extern void negative_ptr(char *negptr);</com>
<com>lo fu fillin</com>
<com>decompile</com>
<com>print C</com>
@ -52,6 +55,9 @@ f30f1efa488b0748ba454c4556454e54
<com>lo fu fillin_wide</com>
<com>decompile</com>
<com>print C</com>
<com>lo fu negative_ptr</com>
<com>decompile</com>
<com>print C</com>
<com>quit</com>
</script>
<stringmatch name="Heap string #1" min="1" max="1">builtin_strncpy\(ptr-\>val,"Message: ",9\);</stringmatch>
@ -60,4 +66,5 @@ f30f1efa488b0748ba454c4556454e54
<stringmatch name="Heap string #4" min="1" max="1">builtin_strncpy\(ptr-\>val \+ pos \+ 0xf,"FOUR",4\);</stringmatch>
<stringmatch name="Heap string #5" min="1" max="1">builtin_strncpy\(ptr-\>val,"ELEVENTWELVE",0xc\);</stringmatch>
<stringmatch name="Heap string #6" min="1" max="1">builtin_memcpy\(ptr-\>wval,L"warning!",0x10\);</stringmatch>
<stringmatch name="Heap string #7" min="1" max="1">builtin_strncpy\(negptr \+ -7,"NEGATIVE",8\);</stringmatch>
</decompilertest>

View File

@ -4,9 +4,9 @@
* 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.
@ -212,4 +212,52 @@ TEST(cast_integertoken) {
ASSERT(!longPrinted(CPUI_INT_RIGHT,parse("uint8"),0x100000000));
}
TEST(enum_matching) {
TypeTestEnvironment::build();
TypeEnum *enum3 = (TypeEnum *)parse("enum enum3 { ZERO=0, ONE=1, TWO=2, FOUR=4, EIGHT=8 }");
TypeEnum::Representation rep;
enum3->getMatches(5, rep);
ASSERT(rep.matchname.size() == 2);
ASSERT(rep.matchname[0] == "FOUR");
ASSERT(rep.matchname[1] == "ONE");
ASSERT(!rep.complement);
rep.matchname.clear();
enum3->getMatches(0xfffffffffffffff7,rep);
ASSERT(rep.matchname.size() == 1);
ASSERT(rep.matchname[0] == "EIGHT");
ASSERT(rep.complement);
rep.matchname.clear();
rep.complement = false;
enum3->getMatches(0,rep);
ASSERT(rep.matchname.size() == 1);
ASSERT(rep.matchname[0] == "ZERO");
ASSERT(!rep.complement);
rep.matchname.clear();
enum3->getMatches(0x10, rep);
ASSERT(rep.matchname.size() == 0);
ASSERT(!rep.complement);
}
TEST(enum_matching2) {
TypeTestEnvironment::build();
TypeEnum *enum4 = (TypeEnum *)parse("enum enum4 { ZERO=0, ONE=1, TWO=2, FOUR=4, SIX=6, EIGHT=8, ELEVEN=11 }");
TypeEnum::Representation rep;
enum4->getMatches(12,rep);
ASSERT(rep.matchname.size()==2);
ASSERT(rep.matchname[0] == "EIGHT");
ASSERT(rep.matchname[1] == "FOUR");
ASSERT(!rep.complement);
rep.matchname.clear();
enum4->getMatches(7,rep);
ASSERT(rep.matchname.size()==2);
ASSERT(rep.matchname[0] == "SIX");
ASSERT(rep.matchname[1] == "ONE");
ASSERT(!rep.complement);
rep.matchname.clear();
enum4->getMatches(11,rep);
ASSERT(rep.matchname.size()==1);
ASSERT(rep.matchname[0] == "ELEVEN");
ASSERT(!rep.complement);
}
} // End namespace ghidra

View File

@ -412,6 +412,7 @@ public class GnuDemanglerParser {
demangled = cleanupRustLegacySymbol(demangled);
String rawDemangled = demangled;
if (simplify) {
demangled = replaceStdLibraryTypes(demangled);
}
@ -421,10 +422,16 @@ public class GnuDemanglerParser {
DemangledObjectBuilder builder = getSpecializedBuilder(demangled);
if (builder != null) {
return builder.build();
DemangledObject dobj = builder.build();
// note: the raw demangled is before any simplifications
dobj.setRawDemangledString(rawDemangled);
return dobj;
}
return parseFunctionOrVariable(demangled);
DemangledObject dobj = parseFunctionOrVariable(demangled);
// note: the raw demangled is before any simplifications
dobj.setRawDemangledString(rawDemangled);
return dobj;
}
private DemangledObjectBuilder getSpecializedBuilder(String demangled) {

View File

@ -115,6 +115,10 @@ public class GnuDemanglerTest extends AbstractGenericTest {
"virtual thunk to undefined __thiscall std::ostringstream::~ostringstream(void)",
signature);
assertEquals(
"virtual thunk to std::basic_ostringstream<char, std::char_traits<char>, pool_allocator<char> >::~basic_ostringstream()",
dobj.getRawDemangled());
//
// Now disable demangled string replacement
//

View File

@ -35,8 +35,6 @@ import docking.widgets.fieldpanel.FieldPanel;
import docking.widgets.fieldpanel.support.FieldLocation;
import docking.widgets.tab.GTabPanel;
import ghidra.app.cmd.data.CreateDataCmd;
import ghidra.app.events.ProgramLocationPluginEvent;
import ghidra.app.events.ProgramSelectionPluginEvent;
import ghidra.app.plugin.core.progmgr.MultiTabPlugin;
import ghidra.app.util.viewer.field.OpenCloseField;
import ghidra.app.util.viewer.listingpanel.ListingModel;
@ -208,8 +206,7 @@ public class DiffTest extends DiffTestAdapter {
assertNotNull(nextDiff);
assertTrue(nextDiff.isEnabled());
tool.firePluginEvent(new ProgramLocationPluginEvent("test",
new ProgramLocation(program, addr("1004c61")), program));
goTo(tool, program, "1004c61");
assertEquals(addr("1004c61"), getDiffAddress());
assertEquals(cb.getCurrentSelection(), new ProgramSelection());
@ -230,8 +227,7 @@ public class DiffTest extends DiffTestAdapter {
assertNotNull(nextDiff);
assertTrue(nextDiff.isEnabled());
tool.firePluginEvent(new ProgramLocationPluginEvent("test",
new ProgramLocation(program, addr("100f3ff")), program));
goTo(tool, program, "100f3ff");
assertEquals(addr("100f3ff"), getDiffAddress());
assertEquals(cb.getCurrentSelection(), new ProgramSelection());
@ -252,8 +248,7 @@ public class DiffTest extends DiffTestAdapter {
assertNotNull(nextDiff);
assertTrue(nextDiff.isEnabled());
tool.firePluginEvent(new ProgramLocationPluginEvent("test",
new ProgramLocation(program, addr("1004c61")), program));
goTo(tool, program, "1004c61");
assertEquals(addr("1004c61"), getDiffAddress());
assertEquals(cb.getCurrentSelection(), new ProgramSelection());
@ -263,8 +258,7 @@ public class DiffTest extends DiffTestAdapter {
assertEquals(cb.getCurrentSelection(),
new ProgramSelection(addr("100415a"), addr("100415a")));
tool.firePluginEvent(new ProgramLocationPluginEvent("test",
new ProgramLocation(program, addr("1002055")), program));
goTo(tool, program, "1002055");
assertEquals(addr("1002055"), getDiffAddress());
invokeLater(prevDiff);
@ -284,8 +278,7 @@ public class DiffTest extends DiffTestAdapter {
assertNotNull(diffDetails);
assertTrue(diffDetails.isEnabled());
tool.firePluginEvent(new ProgramLocationPluginEvent("test",
new ProgramLocation(program, addr("1004c61")), program));
goTo(tool, program, "1004c61");
assertEquals(addr("1004c61"), getDiffAddress());
assertEquals(cb.getCurrentSelection(), new ProgramSelection());
@ -335,8 +328,7 @@ public class DiffTest extends DiffTestAdapter {
assertNotNull(diffDetails);
assertTrue(diffDetails.isEnabled());
tool.firePluginEvent(new ProgramLocationPluginEvent("test",
new ProgramLocation(program, addr("100")), program));
goTo(tool, program, "100");
assertEquals(addr("100"), getDiffAddress());
invokeLater(diffDetails);
@ -353,11 +345,8 @@ public class DiffTest extends DiffTestAdapter {
assertTrue(info.indexOf("Bookmark Diffs") == -1);
assertEquals(addr("100"), getDiffAddress());
tool.firePluginEvent(new ProgramLocationPluginEvent("test",
new ProgramLocation(program, addr("1001014")), program));
goTo(tool, program, "1001014");
assertEquals(addr("1001014"), getDiffAddress());
invokeLater(diffDetails);
waitForSwing();
assertEquals(true, isDiffDetailsDisplayed());
// Check where there are no differences
@ -406,10 +395,8 @@ public class DiffTest extends DiffTestAdapter {
diffAs.addRange(addr("1002304"), addr("1002304"));
diffAs.addRange(addr("1002306"), addr("1002306"));
tool.firePluginEvent(
new ProgramSelectionPluginEvent("test", new ProgramSelection(as), program));
tool.firePluginEvent(new ProgramLocationPluginEvent("test",
new ProgramLocation(program, addr("1001000")), program));
makeSelection(tool, program, as);
goTo(tool, program, "1001000");
assertTrue(setPgm2Selection.isEnabled());
invokeLater(setPgm2Selection);

View File

@ -216,14 +216,19 @@ class PyGhidraLauncher:
raise Exception("org.eclipse.jdt.launching.VM_ARGUMENTS not found")
def _jvm_args(self) -> List[str]:
properties = [
f"-Dpyghidra.sys.prefix={sys.prefix}",
f"-Dpyghidra.sys.executable={sys.executable}"
]
if self._dev_mode and self._java_home:
return self._parse_dev_args()
return properties + self._parse_dev_args()
suffix = "_" + platform.system().upper()
if suffix == "_DARWIN":
suffix = "_MACOS"
option_pattern: re.Pattern = re.compile(fr"VMARGS(?:{suffix})?=(.+)")
properties = []
root = self._install_dir

View File

@ -4,9 +4,9 @@
* 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.
@ -15,29 +15,12 @@
*/
package sarif;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.*;
import org.junit.Test;
import ghidra.program.model.address.AddressSetView;
import ghidra.program.model.data.Array;
import ghidra.program.model.data.ArrayDataType;
import ghidra.program.model.data.ByteDataType;
import ghidra.program.model.data.CategoryPath;
import ghidra.program.model.data.FunctionDefinition;
import ghidra.program.model.data.FunctionDefinitionDataType;
import ghidra.program.model.data.Pointer;
import ghidra.program.model.data.Pointer32DataType;
import ghidra.program.model.data.PointerDataType;
import ghidra.program.model.data.ProgramBasedDataTypeManager;
import ghidra.program.model.data.Structure;
import ghidra.program.model.data.StructureDataType;
import ghidra.program.model.data.TypeDef;
import ghidra.program.model.data.TypedefDataType;
import ghidra.program.model.data.Union;
import ghidra.program.model.data.UnionDataType;
import ghidra.program.model.data.*;
import ghidra.program.util.ProgramDiff;
public class DataTypesSarifTest extends AbstractSarifTest {
@ -63,11 +46,11 @@ public class DataTypesSarifTest extends AbstractSarifTest {
cp = new CategoryPath("/A/B/C/D/E/F/G/H");
dataMgr.createCategory(cp);
assertTrue(dataMgr.containsCategory(cp));
ProgramDiff programDiff = readWriteCompare();
AddressSetView differences = programDiff.getDifferences(monitor);
assert(differences.isEmpty());
assert (differences.isEmpty());
}
@Test
@ -78,9 +61,9 @@ public class DataTypesSarifTest extends AbstractSarifTest {
assertNotNull(array);
ProgramDiff programDiff = readWriteCompare();
AddressSetView differences = programDiff.getDifferences(monitor);
assert(differences.isEmpty());
assert (differences.isEmpty());
}
@Test
@ -93,9 +76,9 @@ public class DataTypesSarifTest extends AbstractSarifTest {
assertNotNull(td);
ProgramDiff programDiff = readWriteCompare();
AddressSetView differences = programDiff.getDifferences(monitor);
assert(differences.isEmpty());
assert (differences.isEmpty());
}
@Test
@ -110,9 +93,9 @@ public class DataTypesSarifTest extends AbstractSarifTest {
assertNotNull(ptr);
ProgramDiff programDiff = readWriteCompare();
AddressSetView differences = programDiff.getDifferences(monitor);
assert(differences.isEmpty());
assert (differences.isEmpty());
}
@Test
@ -130,24 +113,24 @@ public class DataTypesSarifTest extends AbstractSarifTest {
p = new Pointer32DataType(null);
ptr = (Pointer) dataMgr.resolve(p, null);
assertNotNull(ptr);
ProgramDiff programDiff = readWriteCompare();
AddressSetView differences = programDiff.getDifferences(monitor);
assert(differences.isEmpty());
assert (differences.isEmpty());
}
@Test
public void testCreateStructure() throws Exception {
ProgramBasedDataTypeManager dataMgr = program.getDataTypeManager();
StructureDataType sdt = new StructureDataType("test", 0);
Structure sdt = createComplexStructureDataType(dataMgr);
Structure struct = (Structure) dataMgr.addDataType(sdt, null);
assertNotNull(struct);
ProgramDiff programDiff = readWriteCompare();
AddressSetView differences = programDiff.getDifferences(monitor);
assert(differences.isEmpty());
assert (differences.isEmpty());
}
@Test
@ -158,9 +141,9 @@ public class DataTypesSarifTest extends AbstractSarifTest {
assertNotNull(union);
ProgramDiff programDiff = readWriteCompare();
AddressSetView differences = programDiff.getDifferences(monitor);
assert(differences.isEmpty());
assert (differences.isEmpty());
}
@Test
@ -172,9 +155,75 @@ public class DataTypesSarifTest extends AbstractSarifTest {
assertNotNull(funcDef);
ProgramDiff programDiff = readWriteCompare();
AddressSetView differences = programDiff.getDifferences(monitor);
assert(differences.isEmpty());
assert (differences.isEmpty());
}
static Structure createComplexStructureDataType(DataTypeManager dtm) throws Exception {
/**
* /structA
* aligned(8) pack(disabled)
* Structure structA {
* 0 char 1 a0 ""
* 4 int 4 a1 ""
* 16 int[4] 16 a3 ""
* 32 char[0] 0 az ""
* 40 short 2 a4 ""
* 48 int[0] 0 aflex ""
* }
* Length: 48 Alignment: 8
*/
Structure structA = new StructureDataType("structA", 0);
structA.insertAtOffset(0, CharDataType.dataType, -1, "a0", null);
structA.insertAtOffset(4, IntegerDataType.dataType, -1, "a1", null);
structA.insertAtOffset(0x10, new ArrayDataType(CharDataType.dataType, 0, -1), -1, "az",
null);
structA.insertAtOffset(0x10, new ArrayDataType(IntegerDataType.dataType, 4, -1), -1, "a3",
null);
structA.insertAtOffset(0x28, ShortDataType.dataType, -1, "a4", null);
structA.insertAtOffset(0x30, new ArrayDataType(IntegerDataType.dataType, 0, -1), -1,
"aflex", null);
structA.setExplicitMinimumAlignment(8);
/**
* /structB
* pack()
* Structure structB {
* 0 short 2 b0 ""
* 2 byte[0] 0 bfs ""
* 2 int:4(0) 1 bf1 ""
* 2 int:6(4) 2 bf2 ""
* 3 int:2(2) 1 bf3 ""
* 8 structA 48 b1 ""
* }
* Length: 56 Alignment: 8
*/
Structure structB = new StructureDataType("structB", 0);
structB.setPackingEnabled(true);
structB.add(ShortDataType.dataType, "b0", null);
structB.add(new ArrayDataType(ByteDataType.dataType, 0, -1), "bfs", null);
structB.addBitField(IntegerDataType.dataType, 4, "bf1", null);
structB.addBitField(IntegerDataType.dataType, 6, "bf2", null);
structB.addBitField(IntegerDataType.dataType, 2, "bf3", null);
structB.add(structA, "b1", null);
/**
* /structC
* pack()
* Structure structC {
* 0 char 1 c0 ""
* 8 structB 56 c1 ""
* }
* Length: 64 Alignment: 8
*/
Structure structC = new StructureDataType("structC", 0);
structC.setPackingEnabled(true);
structC.add(CharDataType.dataType, "c0", null);
structC.add(structB, "c1", null);
return structC;
}
}

View File

@ -4,9 +4,9 @@
* 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.
@ -18,15 +18,8 @@ package sarif;
import org.junit.Test;
import ghidra.program.model.address.AddressSetView;
import ghidra.program.model.data.ArrayDataType;
import ghidra.program.model.data.ByteDataType;
import ghidra.program.model.data.CharDataType;
import ghidra.program.model.data.DataType;
import ghidra.program.model.data.IntegerDataType;
import ghidra.program.model.data.ProgramBasedDataTypeManager;
import ghidra.program.model.data.ShortDataType;
import ghidra.program.model.data.Structure;
import ghidra.program.model.data.StructureDataType;
import ghidra.program.util.ProgramDiff;
public class DefinedDataSarifTest extends AbstractSarifTest {
@ -37,58 +30,16 @@ public class DefinedDataSarifTest extends AbstractSarifTest {
@Test
public void testDefinedData() throws Exception {
Structure structA = new StructureDataType("structA", 0);
structA.add(IntegerDataType.dataType, "a0", null);
structA.add(new ArrayDataType(CharDataType.dataType, 0, -1), "az", null);
structA.add(DataType.DEFAULT);
structA.add(ByteDataType.dataType, "a1", null);
structA.add(new ArrayDataType(IntegerDataType.dataType, 0, -1), "aflex", null);
/**
* /structB
* pack()
* Structure structB {
* 0 short 2 b0 ""
* 2 byte[0] 0 bfs ""
* 4 int:4(0) 1 bf1 ""
* 4 int:6(4) 2 bf2 ""
* 5 int:2(2) 1 bf3 ""
* 6 structA 6 b1 ""
* }
* Size = 12 Actual Alignment = 4
*/
Structure structB = new StructureDataType("structB", 0);
structB.setPackingEnabled(true);
structB.add(ShortDataType.dataType, "b0", null);
structB.add(new ArrayDataType(ByteDataType.dataType, 0, -1), "bfs", null);
structB.addBitField(IntegerDataType.dataType, 4, "bf1", null);
structB.addBitField(IntegerDataType.dataType, 6, "bf2", null);
structB.addBitField(IntegerDataType.dataType, 2, "bf3", null);
structB.add(structA, "b1", null);
/**
* /structC
* pack()
* Structure structC {
* 0 char 1 c0 ""
* 4 structB 12 c1 ""
* }
* Size = 16 Actual Alignment = 4
*/
Structure structC = new StructureDataType("structC", 0);
structC.setPackingEnabled(true);
structC.add(CharDataType.dataType, "c0", null);
structC.add(structB, "c1", null);
ProgramBasedDataTypeManager dtm = program.getDataTypeManager();
structC = (Structure) dtm.resolve(structC, null);
Structure sdt = DataTypesSarifTest.createComplexStructureDataType(dtm);
Structure struct = (Structure) dtm.resolve(sdt, null);
program.getListing().createData(addr(0x100), structC);
program.getListing().createData(addr(0x100), struct);
ProgramDiff programDiff = readWriteCompare();
AddressSetView differences = programDiff.getDifferences(monitor);
assert(differences.isEmpty());
assert (differences.isEmpty());
}
}

View File

@ -227,8 +227,12 @@ class ComponentNode extends Node {
}
}
@Override
int getComponentCount() {
return windowPlaceholders.size();
// we may be a single component or in a tabbed pane of components
List<ComponentPlaceholder> activeComponents = new ArrayList<>();
populateActiveComponents(activeComponents);
return activeComponents.size();
}
@Override

View File

@ -4,9 +4,9 @@
* 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.
@ -101,6 +101,11 @@ class DetachedWindowNode extends WindowNode {
}
}
@Override
int getComponentCount() {
return child.getComponentCount();
}
@Override
String getTitle() {
if (window instanceof JDialog) {

View File

@ -4,9 +4,9 @@
* 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.
@ -27,13 +27,14 @@ import org.jdesktop.animation.timing.Animator;
import org.jdesktop.animation.timing.TimingTargetAdapter;
import docking.action.*;
import docking.actions.KeyBindingUtils;
import docking.action.builder.ActionBuilder;
import docking.event.mouse.GMouseListenerAdapter;
import docking.menu.DialogToolbarButton;
import docking.util.AnimationUtils;
import docking.widgets.label.GDHtmlLabel;
import generic.theme.GColor;
import generic.theme.GThemeDefaults.Colors.Messages;
import generic.util.WindowUtilities;
import ghidra.util.*;
import ghidra.util.exception.AssertException;
import ghidra.util.task.*;
@ -81,6 +82,7 @@ public class DialogComponentProvider
private TaskMonitorComponent taskMonitorComponent;
private static final KeyStroke ESC_KEYSTROKE = KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0);
private DockingAction closeAction;
private CardLayout progressCardLayout;
private JButton defaultButton;
@ -89,11 +91,14 @@ public class DialogComponentProvider
private Component focusComponent;
private JPanel toolbar;
private final Map<DockingActionIf, DialogToolbarButton> actionMap = new HashMap<>();
private final DialogComponentProviderPopupActionManager popupManager =
private Map<DockingActionIf, DialogToolbarButton> toolbarButtonsByAction = new HashMap<>();
private DialogComponentProviderPopupActionManager popupManager =
new DialogComponentProviderPopupActionManager(this);
private final PopupHandler popupHandler = new PopupHandler();
private final Set<DockingActionIf> dialogActions = new HashSet<>();
private PopupHandler popupHandler = new PopupHandler();
private Set<DockingActionIf> dialogActions = new HashSet<>();
// we track these separately so that we can remove them on dispose
private Set<DialogActionProxy> keyBindingProxyActions = new HashSet<>();
private Point initialLocation;
private boolean resizeable = true;
@ -104,6 +109,7 @@ public class DialogComponentProvider
private Dimension defaultSize;
private String accessibleDescription;
private Tool tool;
/**
* Constructor for a DialogComponentProvider that will be modal and will include a status line and
@ -175,21 +181,37 @@ public class DialogComponentProvider
panel.add(buttonPanel);
rootPanel.add(panel, BorderLayout.SOUTH);
}
installEscapeAction();
doInitialize();
}
private void installEscapeAction() {
Action escAction = new AbstractAction("ESCAPE") {
@Override
public void actionPerformed(ActionEvent ev) {
escapeCallback();
}
};
closeAction = new ActionBuilder("Close Dialog", title)
.sharedKeyBinding()
.keyBinding(ESC_KEYSTROKE)
.enabledWhen(this::isMyDialog)
.onAction(c -> escapeCallback())
.build();
KeyBindingUtils.registerAction(rootPanel, ESC_KEYSTROKE, escAction,
JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT);
addAction(closeAction);
}
private boolean isMyDialog(ActionContext c) {
//
// Each dialog registers a shared action bound to Escape. If all dialog actions are
// enabled, then the user will get prompted to pick which dialog to close when pressing
// Escape. Thus, we limit the enablement of each action to be the dialog that contains the
// focused component. We use the action context to find out if this dialog is the active
// dialog.
//
Window window = WindowUtilities.windowForComponent(c.getSourceComponent());
if (!(window instanceof DockingDialog dockingDialog)) {
return false;
}
return dockingDialog.containsProvider(DialogComponentProvider.this);
}
/** a callback mechanism for children to do work */
@ -197,6 +219,16 @@ public class DialogComponentProvider
// may be overridden by subclasses
}
/**
* Returns true if the given keystroke is the trigger for this dialog's close action.
* @param ks the keystroke
* @return true if the given keystroke is the trigger for this dialog's close action
*/
public boolean isCloseKeyStroke(KeyStroke ks) {
KeyStroke currentCloseKs = closeAction.getKeyBinding();
return Objects.equals(ks, currentCloseKs);
}
public int getId() {
return id;
}
@ -905,11 +937,16 @@ public class DialogComponentProvider
closeDialog();
if (tool != null) {
keyBindingProxyActions.forEach(a -> tool.removeAction(a));
}
keyBindingProxyActions.clear();
popupManager.dispose();
dialogActions.forEach(DockingActionIf::dispose);
actionMap.clear();
toolbarButtonsByAction.clear();
dialogActions.clear();
}
@ -1125,6 +1162,38 @@ public class DialogComponentProvider
return ((dialog != null) && dialog.isShowing());
}
/**
* Called each time the dialog is show. The given tool is the parent tool of the dialog.
* @param t the tool
*/
void dialogShown(Tool t) {
setTool(t);
dialogShown();
}
private void setTool(Tool tool) {
if (this.tool != null) {
return;
}
// initialize the first time we are shown
this.tool = tool;
if (tool == null) {
// The tool can be null for dialogs shown before the framework is initialized, like
// dialogs shown over the splash screen. Without a tool, we cannot add key binding
// actions.
return;
}
// Any actions in this list already were added before we had a tool. Add them now. Any
// future calls to addKeyBindingAction() will get added to the tool at that time.
for (DockingActionIf proxy : keyBindingProxyActions) {
tool.addAction(proxy);
}
}
/**
* Override this method if you want to do something when the dialog is made visible
*/
@ -1204,7 +1273,7 @@ public class DialogComponentProvider
if (context == null) {
context = new DefaultActionContext();
}
Set<DockingActionIf> keySet = actionMap.keySet();
Set<DockingActionIf> keySet = toolbarButtonsByAction.keySet();
for (DockingActionIf action : keySet) {
action.setEnabled(action.isEnabledForContext(context));
}
@ -1227,7 +1296,7 @@ public class DialogComponentProvider
DialogToolbarButton button = new DialogToolbarButton(action, this);
toolbar.add(button);
actionMap.put(action, button);
toolbarButtonsByAction.put(action, button);
}
/**
@ -1236,7 +1305,7 @@ public class DialogComponentProvider
* the tool, as this dialog will do that for you.
* @param action the action
*/
public void addAction(final DockingActionIf action) {
public void addAction(DockingActionIf action) {
dialogActions.add(action);
addToolbarAction(action);
popupManager.addAction(action);
@ -1245,25 +1314,49 @@ public class DialogComponentProvider
private void addKeyBindingAction(DockingActionIf action) {
// add the action to the tool in order get key event management (key bindings
// options and key event processing)
DockingWindowManager dwm = DockingWindowManager.getActiveInstance();
if (dwm == null) {
// This implies the client dialog has been shown outside of the plugin framework. In
// that case, the client will not get key event processing for dialog actions.
return;
}
DialogActionProxy proxy = new DialogActionProxy(action);
keyBindingProxyActions.add(proxy);
Tool tool = dwm.getTool();
tool.addAction(new DialogActionProxy(action));
// The tool will be null when clients add actions to this dialog before it has been shown.
// This is different than ComponentProviders, which require a Tool at construction. The
// DialogComponentProvider did not originally require a Tool at construction. Rather than
// refactor the dialog to require a Tool, it was easier to simply delay adding actions until
// the Tool is set when the dialog is first shown.
if (tool != null) {
tool.addAction(proxy);
}
}
public void removeAction(DockingActionIf action) {
dialogActions.remove(action);
JButton button = actionMap.remove(action);
JButton button = toolbarButtonsByAction.remove(action);
if (button != null && toolbar != null) {
toolbar.remove(button);
}
popupManager.removeAction(action);
removeKeyBindingAction(action);
}
private void removeKeyBindingAction(DockingActionIf action) {
DialogActionProxy proxy = null;
for (DialogActionProxy actionProxy : keyBindingProxyActions) {
if (action == actionProxy.getAction()) {
proxy = actionProxy;
break;
}
}
if (proxy == null) {
return;
}
keyBindingProxyActions.remove(proxy);
if (tool != null) {
tool.removeAction(proxy);
}
}
/**

View File

@ -4,9 +4,9 @@
* 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.
@ -49,6 +49,10 @@ public class DialogComponentProviderPopupActionManager {
popupActions.add(action);
}
void removeAction(DockingActionIf action) {
popupActions.remove(action);
}
void popupMenu(ActionContext actionContext, MouseEvent e) {
if (e.isConsumed()) {
return;

View File

@ -4,9 +4,9 @@
* 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.
@ -75,12 +75,15 @@ class DockableToolBarManager {
ToolBarCloseAction closeAction = new ToolBarCloseAction(owner);
closeButtonManager = new ToolBarItemManager(closeAction, winMgr);
CloseLastProviderAction closeLastProviderAction = new CloseLastProviderAction(owner);
ToolBarMenuAction dropDownAction = new ToolBarMenuAction(owner);
menuButtonManager = new ToolBarItemManager(dropDownAction, winMgr);
// we need to add this action to the tool in order to use key bindings
Tool tool = winMgr.getTool();
tool.addLocalAction(provider, closeAction);
tool.addLocalAction(provider, closeLastProviderAction);
tool.addLocalAction(provider, dropDownAction);
}
@ -216,6 +219,42 @@ class DockableToolBarManager {
}
}
/**
* An action to close the provider on Escape if the provider is the last in the window. This
* allows users to close transient providers (like search results) easily.
*/
private class CloseLastProviderAction extends DockingAction {
CloseLastProviderAction(String owner) {
super("Close Window for Last Provider", owner, KeyBindingType.SHARED);
setKeyBindingData(new KeyBindingData("ESCAPE"));
setDescription("Close the window if this provider is the last provider in the window");
markHelpUnnecessary();
}
@Override
public void actionPerformed(ActionContext context) {
ComponentPlaceholder placeholder = dockableComponent.getComponentWindowingPlaceholder();
if (placeholder != null) {
placeholder.close();
}
}
@Override
public boolean isEnabledForContext(ActionContext context) {
DockingWindowManager dwm = DockingWindowManager.getActiveInstance();
ComponentProvider provider = context.getComponentProvider();
if (provider == null) {
// Some context providers do not specify the provider when creating a contexts
provider = dwm.getActiveComponentProvider();
}
if (provider != dockableComponent.getComponentProvider()) {
return false; // not my provider
}
return dwm.isLastProviderInDetachedWindow(provider);
}
}
/**
* Actions added to toolbar for displaying the drop-down menu.
*/

View File

@ -4,9 +4,9 @@
* 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.
@ -62,10 +62,9 @@ public class DockingDialog extends JDialog implements HelpDescriptor {
* only happens during tests and one-off main methods that are not part of a
* running tool.
*
* @param componentProvider the dialog content for this dialog
* @return the hidden frame
*/
private static JFrame createHiddenParentFrame(DialogComponentProvider componentProvider) {
private static JFrame createHiddenParentFrame() {
//
// Note: we expect to only get here when there is no parent window found. This usually
@ -118,7 +117,7 @@ public class DockingDialog extends JDialog implements HelpDescriptor {
}
private DockingDialog(DialogComponentProvider comp, Component centeredOnComponent) {
super(createHiddenParentFrame(comp), comp.getTitle(), comp.isModal());
super(createHiddenParentFrame(), comp.getTitle(), comp.isModal());
init(comp);
initializeLocationAndSize(centeredOnComponent);
}
@ -211,7 +210,11 @@ public class DockingDialog extends JDialog implements HelpDescriptor {
@Override
public void windowOpened(WindowEvent e) {
component.dialogShown();
Tool tool = null;
if (owningWindowManager != null) {
tool = owningWindowManager.getTool();
}
component.dialogShown(tool);
}
@Override
@ -299,6 +302,15 @@ public class DockingDialog extends JDialog implements HelpDescriptor {
return component;
}
/**
* Returns true if the given provider is the provider owned by this dialog.
* @param dcp the provider to check
* @return true if the given provider is the provider owned by this dialog
*/
public boolean containsProvider(DialogComponentProvider dcp) {
return component == dcp;
}
/**
* Centers the dialog on the given component.
* @param c the component to center over.

View File

@ -461,6 +461,23 @@ public class DockingWindowManager implements PropertyChangeListener, Placeholder
return isActiveWindowManager && isFocusedProvider;
}
/**
* Returns true if the given provider is in a non-main window (a {@link DetachedWindowNode})
* and is the last component provider in that window.
* @param provider the provider
* @return true if the last provider in a non-main window
*/
public boolean isLastProviderInDetachedWindow(ComponentProvider provider) {
Window providerWindow = getProviderWindow(provider);
WindowNode providerNode = root.getNodeForWindow(providerWindow);
if (!(providerNode instanceof DetachedWindowNode windowNode)) {
return false;
}
return windowNode.getComponentCount() == 1;
}
/**
* Sets the visible state of the set of docking windows.
*
@ -944,7 +961,7 @@ public class DockingWindowManager implements PropertyChangeListener, Placeholder
if (visibleState) {
movePlaceholderToFront(placeholder, false);
if (placeholder.getNode() == null) {
root.add(placeholder);
root.addToNewWindow(placeholder);
}
if (requestFocus) {
setNextFocusPlaceholder(placeholder);
@ -1142,7 +1159,7 @@ public class DockingWindowManager implements PropertyChangeListener, Placeholder
void movePlaceholder(ComponentPlaceholder source, Point p) {
ComponentNode sourceNode = source.getNode();
sourceNode.remove(source);
root.add(source, p);
root.addToNewWindow(source, p);
scheduleUpdate();
}
@ -1368,6 +1385,7 @@ public class DockingWindowManager implements PropertyChangeListener, Placeholder
}
private synchronized ComponentPlaceholder maybeGetPlaceholderToFocus() {
if (nextFocusedPlaceholder != null) {
ComponentPlaceholder temp = nextFocusedPlaceholder;
setNextFocusPlaceholder(null);
@ -1375,8 +1393,12 @@ public class DockingWindowManager implements PropertyChangeListener, Placeholder
}
KeyboardFocusManager kfm = KeyboardFocusManager.getCurrentKeyboardFocusManager();
Component permanentFocusOwner = kfm.getPermanentFocusOwner();
Component focusOwner = kfm.getFocusOwner();
if (focusOwner == null) {
// A null focus owner and a null permanent focus owner imply that Java did not know who
// should get focus. Make sure one of our widgets gets focus.
if (focusOwner == null && permanentFocusOwner == null) {
return findNextFocusedComponent();
}
return null;
@ -1446,6 +1468,7 @@ public class DockingWindowManager implements PropertyChangeListener, Placeholder
}
private ComponentPlaceholder findNextFocusedComponent() {
Iterator<ComponentPlaceholder> iterator = lastFocusedPlaceholders.iterator();
while (iterator.hasNext()) {
ComponentPlaceholder placeholder = iterator.next();
@ -1454,7 +1477,6 @@ public class DockingWindowManager implements PropertyChangeListener, Placeholder
}
iterator.remove();
}
return getActivePlaceholder(defaultProvider);
}
@ -1797,7 +1819,8 @@ public class DockingWindowManager implements PropertyChangeListener, Placeholder
bestCenter = centeredOnComponent;
}
DockingDialog dialog = DockingDialog.createDialog(bestParent, provider, bestCenter);
DockingDialog dialog =
DockingDialog.createDialog(bestParent, provider, bestCenter);
dialog.setVisible(true);
};

View File

@ -216,8 +216,9 @@ public class KeyBindingOverrideKeyEventDispatcher implements KeyEventDispatcher
KeyStroke keyStroke = KeyStroke.getKeyStrokeForEvent(event);
// note: this call has no effect if 'action' is null
SwingUtilities.notifyAction(action, keyStroke, event, event.getSource(),
event.getModifiersEx());
Object source = event.getSource();
int modifiersEx = event.getModifiersEx();
SwingUtilities.notifyAction(action, keyStroke, event, source, modifiersEx);
}
return wasInProgress;
@ -240,7 +241,16 @@ public class KeyBindingOverrideKeyEventDispatcher implements KeyEventDispatcher
// processed with modal dialogs open. For now, do not let key bindings get processed
// for modal dialogs. This can be changed in the future if needed.
DockingDialog dialog = (DockingDialog) activeWindow;
return !dialog.isModal();
if (!dialog.isModal()) {
return true;
}
// Allow modal dialogs to process close keystrokes (e.g., ESCAPE) so they can be closed
DialogComponentProvider provider = dialog.getComponent();
if (provider.isCloseKeyStroke(keyStroke)) {
return true;
}
return false; // modal dialog; non-escape key
}
return true; // default case; allow it through
}
@ -275,6 +285,15 @@ public class KeyBindingOverrideKeyEventDispatcher implements KeyEventDispatcher
// return false;
// }
// Special Case: We allow Escape to go through. This doesn't seem useful to text widgets
// but does allow for closing of windows. If we find text widgets that need Escape, then
// we will have to update how we make this decision, such as by having the concerned text
// widgets register actions for Escape and then check for that action.
int code = event.getKeyCode();
if (code == KeyEvent.VK_ESCAPE) {
return false;
}
// We've made the executive decision to allow all keys to go through to the text component
// unless they are modified with the 'Alt'/'Ctrl'/etc keys, unless they directly used
// by the text component

View File

@ -4,9 +4,9 @@
* 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.
@ -52,6 +52,12 @@ abstract class Node {
*/
abstract List<Node> getChildren();
/**
* Returns the number of visible components in this node.
* @return the number of visible components in this node.
*/
abstract int getComponentCount();
/**
* Recursively closes all nodes.
*/

View File

@ -213,19 +213,19 @@ class RootNode extends WindowNode {
}
}
void add(ComponentPlaceholder info) {
add(info, (Point) null);
void addToNewWindow(ComponentPlaceholder placeholder) {
addToNewWindow(placeholder, (Point) null);
}
/**
* Creates a new sub-window for the given component a positions it at the given location.
*
* @param info the component to be put in its own window.
* @param placeholder the component to be put in its own window.
* @param loc the location for the new window.
*/
void add(ComponentPlaceholder info, Point loc) {
void addToNewWindow(ComponentPlaceholder placeholder, Point loc) {
ComponentNode node = new ComponentNode(winMgr);
info.setNode(node);
placeholder.setNode(node);
node.parent = this;
DetachedWindowNode windowNode =
new DetachedWindowNode(winMgr, this, node, dropTargetFactory);
@ -233,18 +233,18 @@ class RootNode extends WindowNode {
windowNode.setInitialLocation(loc.x, loc.y);
}
detachedWindows.add(windowNode);
info.getNode().add(info);
info.requestFocusWhenReady();
placeholder.getNode().add(placeholder);
placeholder.requestFocusWhenReady();
notifyWindowAdded(windowNode);
}
void add(ComponentPlaceholder info, WindowPosition initialPosition) {
void add(ComponentPlaceholder placeholder, WindowPosition initialPosition) {
if (initialPosition == WindowPosition.WINDOW) {
add(info);
addToNewWindow(placeholder);
return;
}
ComponentNode node = new ComponentNode(winMgr);
info.setNode(node);
placeholder.setNode(node);
if (child == null) {
node.parent = this;
child = node;
@ -266,7 +266,7 @@ class RootNode extends WindowNode {
}
child.parent = this;
}
info.getNode().add(info);
placeholder.getNode().add(placeholder);
}
/**
@ -635,6 +635,11 @@ class RootNode extends WindowNode {
return windowWrapper.getWindow();
}
@Override
int getComponentCount() {
return child.getComponentCount();
}
//==================================================================================================
// Inner Classes
//==================================================================================================

View File

@ -4,9 +4,9 @@
* 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.
@ -205,6 +205,18 @@ class SplitNode extends Node {
return list;
}
@Override
int getComponentCount() {
int n = 0;
if (child1 != null) {
n += child1.getComponentCount();
}
if (child2 != null) {
n += child2.getComponentCount();
}
return n;
}
@Override
public String toString() {
return printTree();

View File

@ -350,7 +350,6 @@ public abstract class DockingAction implements DockingActionIf {
@Override
public void setKeyBindingData(KeyBindingData newKeyBindingData) {
if (!supportsKeyBinding(newKeyBindingData)) {
return;
}
@ -365,6 +364,11 @@ public abstract class DockingAction implements DockingActionIf {
firePropertyChanged(KEYBINDING_DATA_PROPERTY, oldData, keyBindingData);
}
// this allows framework classes to directly set the default value
protected void setDefaultKeyBindingData(KeyBindingData kbd) {
defaultKeyBindingData = kbd;
}
private boolean supportsKeyBinding(KeyBindingData kbData) {
KeyBindingType type = getKeyBindingType();

View File

@ -4,9 +4,9 @@
* 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.
@ -363,9 +363,14 @@ public class KeyBindings {
return;
}
// 1) update the options with the new value
ActionTrigger newTrigger = keyBinding.getActionTrigger();
String fullName = getFullName();
keyStrokeOptions.setActionTrigger(fullName, newTrigger);
// 2) update our state so the UI shows the new value
currentKeyStroke = newTrigger.getKeyStroke();
currentMouseBinding = newTrigger.getMouseBinding();
}
private boolean hasChanged() {
@ -409,11 +414,11 @@ public class KeyBindings {
DockingActionIf action = getRepresentativeAction();
KeyBindingData defaultBinding = action.getDefaultKeyBindingData();
cancelChanges();
if (!matches(defaultBinding)) {
apply(options, defaultBinding);
}
cancelChanges();
}
}

View File

@ -4,9 +4,9 @@
* 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.
@ -120,14 +120,21 @@ public class SharedStubKeyBindingAction extends DockingAction implements Options
void addClientAction(DockingActionIf action) {
// 1) Validate new action keystroke against existing actions
ActionTrigger defaultKs = validateActionsHaveTheSameDefaultKeyStroke(action);
ActionTrigger defaultTrigger = validateActionsHaveTheSameDefaultKeyStroke(action);
// 2) Add the action and the validated keystroke, as this is the default keystroke
clientActions.put(action, defaultKs);
clientActions.put(action, defaultTrigger);
// 3) Update the given action with the current option value. This allows clients to
// add and remove actions after the tool has been initialized.
updateActionKeyStrokeFromOptions(action, defaultKs);
updateActionKeyStrokeFromOptions(action, defaultTrigger);
// 4) Store the default value for this stub so later requests to Restore Defaults will have
// the correct value.
if (defaultTrigger != null) {
KeyBindingData defaultKbd = new KeyBindingData(defaultTrigger);
setDefaultKeyBindingData(defaultKbd);
}
}
@Override

View File

@ -4,9 +4,9 @@
* 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.
@ -48,7 +48,7 @@ public class OptionsDialog extends ReusableDialogComponentProvider {
public OptionsDialog(String title, String rootNodeName, Options[] options,
OptionsEditorListener listener, boolean showRestoreDefaultsButton) {
super("OptionsDialog.Foofoo", true, false, true, false);
super("Options Dialog", true, false, true, false);
this.listener = listener;
panel = new OptionsPanel(rootNodeName, options, showRestoreDefaultsButton,
new OptionsPropertyChangeListener());

View File

@ -4,9 +4,9 @@
* 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.
@ -177,79 +177,6 @@ public class DropDownTextField<T> extends JTextField implements GComponent {
return previewLabel;
}
// overridden to grab the Escape and enter key events before our parent window gets them
@Override
protected boolean processKeyBinding(KeyStroke ks, KeyEvent e, int condition, boolean pressed) {
if (handleEscapeKey(ks, e, condition, pressed)) {
return true;
}
if (handleEnterKey(ks, e, condition, pressed)) {
return true;
}
return super.processKeyBinding(ks, e, condition, pressed);
}
private boolean handleEscapeKey(KeyStroke ks, KeyEvent e, int condition, boolean pressed) {
if ((condition == JComponent.WHEN_FOCUSED) && (ks.getKeyCode() == KeyEvent.VK_ESCAPE)) {
if (getMatchingWindow().isShowing()) {
hideMatchingWindow();
e.consume();
return true;
}
else if (pressed) {
// do not return after this call so that the event will continue to be processed
fireEditingCancelled();
}
}
return false;
}
private boolean handleEnterKey(KeyStroke ks, KeyEvent e, int condition, boolean pressed) {
if ((condition != JComponent.WHEN_FOCUSED) || (ks.getKeyCode() != KeyEvent.VK_ENTER)) {
return false; // enter key not pressed!
}
if (ignoreEnterKeyPress) {
return false;
}
// O.K., if we are consuming key presses, then we only want to do so when the selection
// window is showing. This will close the selection window and not send the Enter event up
// to our parent component.
boolean listShowing = isMatchingListShowing();
if (consumeEnterKeyPress) {
if (listShowing) {
setTextFromListOnEnterPress();
validateChosenItemAgainstText(true);
e.consume();
return true; // don't let our parent see the event
}
else if (pressed) {
validateChosenItemAgainstText(false);
fireEditingStopped();
}
// Return false, even though 'consumeEnterKeyPress' is set, so that our
// parent can process the event.
return false;
}
// When we aren't consuming Enter key presses, then we just take the user's selection
// and signal that editing is finished, while letting our parent component handle the event
if (pressed) {
setTextFromListOnEnterPress();
validateChosenItemAgainstText(listShowing);
fireEditingStopped();
return true;
}
return false;
}
private void validateChosenItemAgainstText(boolean isListShowing) {
//
// If the text differs from that of the chosen item, then the implication is the user has
@ -884,62 +811,117 @@ public class DropDownTextField<T> extends JTextField implements GComponent {
KeyEvent.VK_KP_DOWN)) {
//@formatter:on
if (!getMatchingWindow().isShowing()) {
updateDisplayContents(getText());
event.consume();
}
else { // update the window if it is showing
if (keyCode == KeyEvent.VK_UP || keyCode == KeyEvent.VK_KP_UP) {
decrementListSelection();
}
else {
incrementListSelection();
}
event.consume();
setTextFromSelectedListItemAndKeepMatchingWindowOpen();
}
handleArrowKey(event);
}
else if (keyCode == KeyEvent.VK_ENTER) {
handleEnterKey(event);
}
else if (keyCode == KeyEvent.VK_ESCAPE) {
handleEscapeKey(event);
}
setToolTipText(getToolTipText());
}
private void incrementListSelection() {
int index = list.getSelectedIndex();
int listSize = list.getModel().getSize();
if (index < 0) { // no selection
index = 0;
private void handleEscapeKey(KeyEvent event) {
if (getMatchingWindow().isShowing()) {
hideMatchingWindow();
}
else if (index == listSize - 1) { // last element selected - wrap
index = 0;
else {
fireEditingCancelled();
}
else { // just increment
index++;
}
list.setSelectedIndex(index);
list.ensureIndexIsVisible(index);
event.consume();
}
private void decrementListSelection() {
int index = list.getSelectedIndex();
int listSize = list.getModel().getSize();
private void handleEnterKey(KeyEvent event) {
if (index < 0) { // no selection
index = 0;
}
else if (index == 0) { // first element - wrap
index = listSize - 1;
}
else { // just decrement
index--;
if (ignoreEnterKeyPress) {
return;
}
list.setSelectedIndex(index);
list.ensureIndexIsVisible(index);
// O.K., if we are consuming key presses, then we only want to do so when the selection
// window is showing. This will close the selection window and not send the Enter event up
// to our parent component.
boolean listShowing = isMatchingListShowing();
if (consumeEnterKeyPress) {
if (listShowing) {
setTextFromListOnEnterPress();
validateChosenItemAgainstText(true);
event.consume();
return; // don't let our parent see the event
}
validateChosenItemAgainstText(false);
fireEditingStopped();
// Even though 'consumeEnterKeyPress' is set, do not consume the event so that our
// parent can process the event.
return;
}
// When we aren't consuming Enter key presses, then just take the user's selection and
// signal that editing is finished, while letting our parent component handle the event
setTextFromListOnEnterPress();
validateChosenItemAgainstText(listShowing);
fireEditingStopped();
}
}
private void handleArrowKey(KeyEvent event) {
int keyCode = event.getKeyCode();
if (!getMatchingWindow().isShowing()) {
updateDisplayContents(getText());
event.consume();
}
else { // update the window if it is showing
if (keyCode == KeyEvent.VK_UP || keyCode == KeyEvent.VK_KP_UP) {
decrementListSelection();
}
else {
incrementListSelection();
}
event.consume();
setTextFromSelectedListItemAndKeepMatchingWindowOpen();
}
}
private void incrementListSelection() {
int index = list.getSelectedIndex();
int listSize = list.getModel().getSize();
if (index < 0) { // no selection
index = 0;
}
else if (index == listSize - 1) { // last element selected - wrap
index = 0;
}
else { // just increment
index++;
}
list.setSelectedIndex(index);
list.ensureIndexIsVisible(index);
}
private void decrementListSelection() {
int index = list.getSelectedIndex();
int listSize = list.getModel().getSize();
if (index < 0) { // no selection
index = 0;
}
else if (index == 0) { // first element - wrap
index = listSize - 1;
}
else { // just decrement
index--;
}
list.setSelectedIndex(index);
list.ensureIndexIsVisible(index);
}
// we know the cast is safe because we put the items in the list
protected void setTextFromSelectedListItemAndKeepMatchingWindowOpen() {
T selectedItem = list.getSelectedValue();

View File

@ -4,9 +4,9 @@
* 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.
@ -245,10 +245,12 @@ public abstract class AbstractSortedTableModel<T> extends AbstractGTableModel<T>
protected TableSortingContext<T> createSortingContext(TableSortState newSortState) {
if (!isValidSortState(newSortState)) {
Msg.error(this, """
"Table '%s' sort is invalid. Assuming columns have been removed. \
Setting unsorted.""".formatted(getName()));
newSortState = TableSortState.createUnsortedSortState();
if (!isDisposed) {
Msg.error(this, """
"Table '%s' sort is invalid. Assuming columns have been removed. \
Setting unsorted.""".formatted(getName()));
}
}
return new TableSortingContext<>(newSortState, getComparatorChain(newSortState));

View File

@ -396,6 +396,9 @@
<optional>
<attribute name="storage"/>
</optional>
<optional>
<attribute name="stackspill"/>
</optional>
</element>
<element name="hidden_return">
<optional>

View File

@ -4,9 +4,9 @@
* 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.
@ -150,6 +150,7 @@ public class MultiSlotAssign extends AssignAction {
ArrayList<Varnode> pieces = new ArrayList<>();
ParameterPieces param = new ParameterPieces();
int sizeLeft = dt.getLength();
int align = dt.getAlignment();
int iter = firstIter;
int endIter = resource.getNumParamEntry();
if (enforceAlignment) {
@ -161,7 +162,6 @@ public class MultiSlotAssign extends AssignAction {
} // Reached end of resource list
if (entry.getType() == resourceType && entry.getAllGroups().length == 1) { // Single register
if (tmpStatus[entry.getGroup()] == 0) { // Not consumed
int align = dt.getAlignment();
int regSize = entry.getSize();
if (align <= regSize || (resourcesConsumed % align) == 0) {
break;
@ -186,11 +186,12 @@ public class MultiSlotAssign extends AssignAction {
continue;
} // Already consumed
int trialSize = entry.getSize();
entry.getAddrBySlot(tmpStatus[entry.getGroup()], trialSize, 1, param);
entry.getAddrBySlot(tmpStatus[entry.getGroup()], trialSize, align, param);
tmpStatus[entry.getGroup()] = -1; // Consume the register
Varnode vn = new Varnode(param.address, trialSize);
pieces.add(vn);
sizeLeft -= trialSize;
align = 1; // Treat remaining partial pieces as having no alignment requirement
}
boolean onePieceJoin = false;
if (sizeLeft > 0) { // Have to use stack to get enough bytes
@ -198,7 +199,7 @@ public class MultiSlotAssign extends AssignAction {
return FAIL;
}
int grp = stackEntry.getGroup();
tmpStatus[grp] = stackEntry.getAddrBySlot(tmpStatus[grp], sizeLeft, 1, param); // Consume all the space we need
tmpStatus[grp] = stackEntry.getAddrBySlot(tmpStatus[grp], sizeLeft, align, param); // Consume all the space we need
if (param.address == null) {
return FAIL;
}
@ -257,6 +258,7 @@ public class MultiSlotAssign extends AssignAction {
encoder.writeString(ATTRIB_STORAGE, resourceType.toString());
}
encoder.writeBool(ATTRIB_ALIGN, enforceAlignment);
encoder.writeBool(ATTRIB_STACKSPILL, consumeFromStack);
encoder.closeElement(ELEM_JOIN);
}
@ -276,6 +278,9 @@ public class MultiSlotAssign extends AssignAction {
else if (name.equals(ATTRIB_ALIGN.name())) {
enforceAlignment = SpecXmlUtils.decodeBoolean(attrib.getValue());
}
else if (name.equals(ATTRIB_STACKSPILL.name())) {
consumeFromStack = SpecXmlUtils.decodeBoolean(attrib.getValue());
}
}
parser.end(elem);
try {

View File

@ -114,7 +114,7 @@ public record AttributeId(String name, int id) {
public static final AttributeId ATTRIB_ARRAYSIZE = new AttributeId("arraysize", 48);
public static final AttributeId ATTRIB_CHAR = new AttributeId("char", 49);
public static final AttributeId ATTRIB_CORE = new AttributeId("core", 50);
public static final AttributeId ATTRIB_ENUM = new AttributeId("enum", 51);
// public static final AttributeId ATTRIB_ENUM = new AttributeId("enum", 51); // deprecated
public static final AttributeId ATTRIB_INCOMPLETE = new AttributeId("incomplete", 52);
// public static final AttributeId ATTRIB_ENUMSIZE = new AttributeId("enumsize", 53); // deprecated
// public static final AttributeId ATTRIB_INTSIZE = new AttributeId("intsize", 54); // deprecated
@ -242,6 +242,7 @@ public record AttributeId(String name, int id) {
// public static final AttributeId ATTRIB_ADDRESS = new AttributeId("address", 148);
public static final AttributeId ATTRIB_STORAGE = new AttributeId("storage", 149);
public static final AttributeId ATTRIB_STACKSPILL = new AttributeId("stackspill", 150);
public static final AttributeId ATTRIB_UNKNOWN = new AttributeId("XMLunknown", 150);
public static final AttributeId ATTRIB_UNKNOWN = new AttributeId("XMLunknown", 151);
}

View File

@ -278,6 +278,13 @@ public class PcodeDataTypeManager {
decoder.closeElement(el);
return new PartialUnion(progDataTypes, dt, offset, size);
}
else if (meta.equals("partenum")) {
int size = (int) decoder.readSignedInteger(ATTRIB_SIZE);
// int offset = (int) decoder.readSignedInteger(ATTRIB_OFFSET);
// DataType dt = decodeDataType(decoder);
decoder.closeElementSkipping(el);
return AbstractIntegerDataType.getUnsignedDataType(size, progDataTypes);
}
else { // We typically reach here if the decompiler invents a new type
// probably an unknown with a non-standard size
int size = (int) decoder.readSignedInteger(ATTRIB_SIZE);
@ -541,11 +548,10 @@ public class PcodeDataTypeManager {
private void encodeEnum(Encoder encoder, Enum type, int size) throws IOException {
encoder.openElement(ELEM_TYPE);
encodeNameIdAttributes(encoder, type);
String metatype = type.isSigned() ? "int" : "uint";
String metatype = type.isSigned() ? "enum_int" : "enum_uint";
String[] names = type.getNames();
encoder.writeString(ATTRIB_METATYPE, metatype);
encoder.writeSignedInteger(ATTRIB_SIZE, type.getLength());
encoder.writeBool(ATTRIB_ENUM, true);
for (String name : names) {
encoder.openElement(ELEM_VAL);
encoder.writeString(ATTRIB_NAME, name);

View File

View File

@ -0,0 +1,15 @@
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 NDS32'
dependencies {
compile project(':Base')
// Temporary dependency so that pcodeTests can use the Decompiler switch recovery
compile project(':Decompiler')
}

View File

@ -0,0 +1,50 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
+ Compile sleigh languages within this module.
+ Sleigh compiler options are read from the sleighArgs.txt file.
+ Eclipse: right-click on this file and choose menu item "Run As->Ant Build"
-->
<project name="privateBuildDeveloper" default="sleighCompile">
<property name="sleigh.compile.class" value="ghidra.pcodeCPort.slgh_compile.SleighCompile"/>
<!--Import optional ant properties. GhidraDev Eclipse plugin produces this so this file can find the Ghidra installation-->
<import file="../.antProperties.xml" optional="false" />
<target name="sleighCompile">
<!-- If language module is detached from installation, get Ghidra installation directory path from imported properties -->
<property name="framework.path" value="${ghidra.install.dir}/Ghidra/Framework"/>
<path id="sleigh.class.path">
<fileset dir="${framework.path}/SoftwareModeling/lib">
<include name="*.jar"/>
</fileset>
<fileset dir="${framework.path}/Generic/lib">
<include name="*.jar"/>
</fileset>
<fileset dir="${framework.path}/Utility/lib">
<include name="*.jar"/>
</fileset>
</path>
<available classname="${sleigh.compile.class}" classpathref="sleigh.class.path" property="sleigh.compile.exists"/>
<fail unless="sleigh.compile.exists" />
<java classname="${sleigh.compile.class}"
classpathref="sleigh.class.path"
fork="true"
failonerror="true">
<jvmarg value="-Xmx2048M"/>
<arg value="-i"/>
<arg value="sleighArgs.txt"/>
<arg value="-a"/>
<arg value="./languages"/>
</java>
</target>
</project>

View File

@ -0,0 +1,576 @@
macro Lmwbi(reg) {
reg = *mult_addr;
mult_addr = mult_addr + 4;
}
macro Lmwbd(reg) {
reg = *mult_addr;
mult_addr = mult_addr - 4;
}
macro Lmwai(reg) {
mult_addr = mult_addr + 4;
reg = *mult_addr;
}
macro Lmwad(reg) {
mult_addr = mult_addr - 4;
reg = *mult_addr;
}
macro Smwbi(reg) {
*mult_addr = reg;
mult_addr = mult_addr + 4;
}
macro Smwbd(reg) {
*mult_addr = reg;
mult_addr = mult_addr - 4;
}
macro Smwai(reg) {
mult_addr = mult_addr + 4;
*mult_addr = reg;
}
macro Smwad(reg) {
mult_addr = mult_addr - 4;
*mult_addr = reg;
}
Lmwbi.a0: a0 is LsmwRb_<=0 & LsmwRe_>=0 & a0 { Lmwbi(a0); }
Lmwbi.a0: is LsmwRb_ & LsmwRe_ { }
Lmwbi.a1: a1 is LsmwRb_<=1 & LsmwRe_>=1 & a1 { Lmwbi(a1); }
Lmwbi.a1: is LsmwRb_ & LsmwRe_ { }
Lmwbi.a2: a2 is LsmwRb_<=2 & LsmwRe_>=2 & a2 { Lmwbi(a2); }
Lmwbi.a2: is LsmwRb_ & LsmwRe_ { }
Lmwbi.a3: a3 is LsmwRb_<=3 & LsmwRe_>=3 & a3 { Lmwbi(a3); }
Lmwbi.a3: is LsmwRb_ & LsmwRe_ { }
Lmwbi.a4: a4 is LsmwRb_<=4 & LsmwRe_>=4 & a4 { Lmwbi(a4); }
Lmwbi.a4: is LsmwRb_ & LsmwRe_ { }
Lmwbi.a5: a5 is LsmwRb_<=5 & LsmwRe_>=5 & a5 { Lmwbi(a5); }
Lmwbi.a5: is LsmwRb_ & LsmwRe_ { }
Lmwbi.s0: s0 is LsmwRb_<=6 & LsmwRe_>=6 & s0 { Lmwbi(s0); }
Lmwbi.s0: is LsmwRb_ & LsmwRe_ { }
Lmwbi.s1: s1 is LsmwRb_<=7 & LsmwRe_>=7 & s1 { Lmwbi(s1); }
Lmwbi.s1: is LsmwRb_ & LsmwRe_ { }
Lmwbi.s2: s2 is LsmwRb_<=8 & LsmwRe_>=8 & s2 { Lmwbi(s2); }
Lmwbi.s2: is LsmwRb_ & LsmwRe_ { }
Lmwbi.s3: s3 is LsmwRb_<=9 & LsmwRe_>=9 & s3 { Lmwbi(s3); }
Lmwbi.s3: is LsmwRb_ & LsmwRe_ { }
Lmwbi.s4: s4 is LsmwRb_<=10 & LsmwRe_>=10 & s4 { Lmwbi(s4); }
Lmwbi.s4: is LsmwRb_ & LsmwRe_ { }
Lmwbi.s5: s5 is LsmwRb_<=11 & LsmwRe_>=11 & s5 { Lmwbi(s5); }
Lmwbi.s5: is LsmwRb_ & LsmwRe_ { }
Lmwbi.s6: s6 is LsmwRb_<=12 & LsmwRe_>=12 & s6 { Lmwbi(s6); }
Lmwbi.s6: is LsmwRb_ & LsmwRe_ { }
Lmwbi.s7: s7 is LsmwRb_<=13 & LsmwRe_>=13 & s7 { Lmwbi(s7); }
Lmwbi.s7: is LsmwRb_ & LsmwRe_ { }
Lmwbi.s8: s8 is LsmwRb_<=14 & LsmwRe_>=14 & s8 { Lmwbi(s8); }
Lmwbi.s8: is LsmwRb_ & LsmwRe_ { }
Lmwbi.ta: ta is LsmwRb_<=15 & LsmwRe_>=15 & ta { Lmwbi(ta); }
Lmwbi.ta: is LsmwRb_ & LsmwRe_ { }
Lmwbi.t0: t0 is LsmwRb_<=16 & LsmwRe_>=16 & t0 { Lmwbi(t0); }
Lmwbi.t0: is LsmwRb_ & LsmwRe_ { }
Lmwbi.t1: t1 is LsmwRb_<=17 & LsmwRe_>=17 & t1 { Lmwbi(t1); }
Lmwbi.t1: is LsmwRb_ & LsmwRe_ { }
Lmwbi.t2: t2 is LsmwRb_<=18 & LsmwRe_>=18 & t2 { Lmwbi(t2); }
Lmwbi.t2: is LsmwRb_ & LsmwRe_ { }
Lmwbi.t3: t3 is LsmwRb_<=19 & LsmwRe_>=19 & t3 { Lmwbi(t3); }
Lmwbi.t3: is LsmwRb_ & LsmwRe_ { }
Lmwbi.t4: t4 is LsmwRb_<=20 & LsmwRe_>=20 & t4 { Lmwbi(t4); }
Lmwbi.t4: is LsmwRb_ & LsmwRe_ { }
Lmwbi.t5: t5 is LsmwRb_<=21 & LsmwRe_>=21 & t5 { Lmwbi(t5); }
Lmwbi.t5: is LsmwRb_ & LsmwRe_ { }
Lmwbi.t6: t6 is LsmwRb_<=22 & LsmwRe_>=22 & t6 { Lmwbi(t6); }
Lmwbi.t6: is LsmwRb_ & LsmwRe_ { }
Lmwbi.t7: t7 is LsmwRb_<=23 & LsmwRe_>=23 & t7 { Lmwbi(t7); }
Lmwbi.t7: is LsmwRb_ & LsmwRe_ { }
Lmwbi.t8: t8 is LsmwRb_<=24 & LsmwRe_>=24 & t8 { Lmwbi(t8); }
Lmwbi.t8: is LsmwRb_ & LsmwRe_ { }
Lmwbi.t9: t9 is LsmwRb_<=25 & LsmwRe_>=25 & t9 { Lmwbi(t9); }
Lmwbi.t9: is LsmwRb_ & LsmwRe_ { }
Lmwbi.p0: p0 is LsmwRb_<=26 & LsmwRe_>=26 & p0 { Lmwbi(p0); }
Lmwbi.p0: is LsmwRb_ & LsmwRe_ { }
Lmwbi.p1: p1 is LsmwRb_<=27 & LsmwRe_>=27 & p1 { Lmwbi(p1); }
Lmwbi.p1: is LsmwRb_ & LsmwRe_ { }
Lmwbi.fp: fp is Enable4_fp=1 & fp { Lmwbi(fp); }
Lmwbi.fp: is Enable4_fp=0 { }
Lmwbi.gp: gp is Enable4_gp=1 & gp { Lmwbi(gp); }
Lmwbi.gp: is Enable4_gp=0 { }
Lmwbi.lp: lp is Enable4_lp=1 & lp { Lmwbi(lp); }
Lmwbi.lp: is Enable4_lp=0 { }
Lmwbi.sp: sp is Enable4_sp=1 & sp { Lmwbi(sp); }
Lmwbi.sp: is Enable4_sp=0 { }
Lmwbd.a0: a0 is LsmwRb_<=0 & LsmwRe_>=0 & a0 { Lmwbd(a0); }
Lmwbd.a0: is LsmwRb_ & LsmwRe_ { }
Lmwbd.a1: a1 is LsmwRb_<=1 & LsmwRe_>=1 & a1 { Lmwbd(a1); }
Lmwbd.a1: is LsmwRb_ & LsmwRe_ { }
Lmwbd.a2: a2 is LsmwRb_<=2 & LsmwRe_>=2 & a2 { Lmwbd(a2); }
Lmwbd.a2: is LsmwRb_ & LsmwRe_ { }
Lmwbd.a3: a3 is LsmwRb_<=3 & LsmwRe_>=3 & a3 { Lmwbd(a3); }
Lmwbd.a3: is LsmwRb_ & LsmwRe_ { }
Lmwbd.a4: a4 is LsmwRb_<=4 & LsmwRe_>=4 & a4 { Lmwbd(a4); }
Lmwbd.a4: is LsmwRb_ & LsmwRe_ { }
Lmwbd.a5: a5 is LsmwRb_<=5 & LsmwRe_>=5 & a5 { Lmwbd(a5); }
Lmwbd.a5: is LsmwRb_ & LsmwRe_ { }
Lmwbd.s0: s0 is LsmwRb_<=6 & LsmwRe_>=6 & s0 { Lmwbd(s0); }
Lmwbd.s0: is LsmwRb_ & LsmwRe_ { }
Lmwbd.s1: s1 is LsmwRb_<=7 & LsmwRe_>=7 & s1 { Lmwbd(s1); }
Lmwbd.s1: is LsmwRb_ & LsmwRe_ { }
Lmwbd.s2: s2 is LsmwRb_<=8 & LsmwRe_>=8 & s2 { Lmwbd(s2); }
Lmwbd.s2: is LsmwRb_ & LsmwRe_ { }
Lmwbd.s3: s3 is LsmwRb_<=9 & LsmwRe_>=9 & s3 { Lmwbd(s3); }
Lmwbd.s3: is LsmwRb_ & LsmwRe_ { }
Lmwbd.s4: s4 is LsmwRb_<=10 & LsmwRe_>=10 & s4 { Lmwbd(s4); }
Lmwbd.s4: is LsmwRb_ & LsmwRe_ { }
Lmwbd.s5: s5 is LsmwRb_<=11 & LsmwRe_>=11 & s5 { Lmwbd(s5); }
Lmwbd.s5: is LsmwRb_ & LsmwRe_ { }
Lmwbd.s6: s6 is LsmwRb_<=12 & LsmwRe_>=12 & s6 { Lmwbd(s6); }
Lmwbd.s6: is LsmwRb_ & LsmwRe_ { }
Lmwbd.s7: s7 is LsmwRb_<=13 & LsmwRe_>=13 & s7 { Lmwbd(s7); }
Lmwbd.s7: is LsmwRb_ & LsmwRe_ { }
Lmwbd.s8: s8 is LsmwRb_<=14 & LsmwRe_>=14 & s8 { Lmwbd(s8); }
Lmwbd.s8: is LsmwRb_ & LsmwRe_ { }
Lmwbd.ta: ta is LsmwRb_<=15 & LsmwRe_>=15 & ta { Lmwbd(ta); }
Lmwbd.ta: is LsmwRb_ & LsmwRe_ { }
Lmwbd.t0: t0 is LsmwRb_<=16 & LsmwRe_>=16 & t0 { Lmwbd(t0); }
Lmwbd.t0: is LsmwRb_ & LsmwRe_ { }
Lmwbd.t1: t1 is LsmwRb_<=17 & LsmwRe_>=17 & t1 { Lmwbd(t1); }
Lmwbd.t1: is LsmwRb_ & LsmwRe_ { }
Lmwbd.t2: t2 is LsmwRb_<=18 & LsmwRe_>=18 & t2 { Lmwbd(t2); }
Lmwbd.t2: is LsmwRb_ & LsmwRe_ { }
Lmwbd.t3: t3 is LsmwRb_<=19 & LsmwRe_>=19 & t3 { Lmwbd(t3); }
Lmwbd.t3: is LsmwRb_ & LsmwRe_ { }
Lmwbd.t4: t4 is LsmwRb_<=20 & LsmwRe_>=20 & t4 { Lmwbd(t4); }
Lmwbd.t4: is LsmwRb_ & LsmwRe_ { }
Lmwbd.t5: t5 is LsmwRb_<=21 & LsmwRe_>=21 & t5 { Lmwbd(t5); }
Lmwbd.t5: is LsmwRb_ & LsmwRe_ { }
Lmwbd.t6: t6 is LsmwRb_<=22 & LsmwRe_>=22 & t6 { Lmwbd(t6); }
Lmwbd.t6: is LsmwRb_ & LsmwRe_ { }
Lmwbd.t7: t7 is LsmwRb_<=23 & LsmwRe_>=23 & t7 { Lmwbd(t7); }
Lmwbd.t7: is LsmwRb_ & LsmwRe_ { }
Lmwbd.t8: t8 is LsmwRb_<=24 & LsmwRe_>=24 & t8 { Lmwbd(t8); }
Lmwbd.t8: is LsmwRb_ & LsmwRe_ { }
Lmwbd.t9: t9 is LsmwRb_<=25 & LsmwRe_>=25 & t9 { Lmwbd(t9); }
Lmwbd.t9: is LsmwRb_ & LsmwRe_ { }
Lmwbd.p0: p0 is LsmwRb_<=26 & LsmwRe_>=26 & p0 { Lmwbd(p0); }
Lmwbd.p0: is LsmwRb_ & LsmwRe_ { }
Lmwbd.p1: p1 is LsmwRb_<=27 & LsmwRe_>=27 & p1 { Lmwbd(p1); }
Lmwbd.p1: is LsmwRb_ & LsmwRe_ { }
Lmwbd.fp: fp is Enable4_fp=1 & fp { Lmwbd(fp); }
Lmwbd.fp: is Enable4_fp=0 { }
Lmwbd.gp: gp is Enable4_gp=1 & gp { Lmwbd(gp); }
Lmwbd.gp: is Enable4_gp=0 { }
Lmwbd.lp: lp is Enable4_lp=1 & lp { Lmwbd(lp); }
Lmwbd.lp: is Enable4_lp=0 { }
Lmwbd.sp: sp is Enable4_sp=1 & sp { Lmwbd(sp); }
Lmwbd.sp: is Enable4_sp=0 { }
Lmwai.a0: a0 is LsmwRb_<=0 & LsmwRe_>=0 & a0 { Lmwai(a0); }
Lmwai.a0: is LsmwRb_ & LsmwRe_ { }
Lmwai.a1: a1 is LsmwRb_<=1 & LsmwRe_>=1 & a1 { Lmwai(a1); }
Lmwai.a1: is LsmwRb_ & LsmwRe_ { }
Lmwai.a2: a2 is LsmwRb_<=2 & LsmwRe_>=2 & a2 { Lmwai(a2); }
Lmwai.a2: is LsmwRb_ & LsmwRe_ { }
Lmwai.a3: a3 is LsmwRb_<=3 & LsmwRe_>=3 & a3 { Lmwai(a3); }
Lmwai.a3: is LsmwRb_ & LsmwRe_ { }
Lmwai.a4: a4 is LsmwRb_<=4 & LsmwRe_>=4 & a4 { Lmwai(a4); }
Lmwai.a4: is LsmwRb_ & LsmwRe_ { }
Lmwai.a5: a5 is LsmwRb_<=5 & LsmwRe_>=5 & a5 { Lmwai(a5); }
Lmwai.a5: is LsmwRb_ & LsmwRe_ { }
Lmwai.s0: s0 is LsmwRb_<=6 & LsmwRe_>=6 & s0 { Lmwai(s0); }
Lmwai.s0: is LsmwRb_ & LsmwRe_ { }
Lmwai.s1: s1 is LsmwRb_<=7 & LsmwRe_>=7 & s1 { Lmwai(s1); }
Lmwai.s1: is LsmwRb_ & LsmwRe_ { }
Lmwai.s2: s2 is LsmwRb_<=8 & LsmwRe_>=8 & s2 { Lmwai(s2); }
Lmwai.s2: is LsmwRb_ & LsmwRe_ { }
Lmwai.s3: s3 is LsmwRb_<=9 & LsmwRe_>=9 & s3 { Lmwai(s3); }
Lmwai.s3: is LsmwRb_ & LsmwRe_ { }
Lmwai.s4: s4 is LsmwRb_<=10 & LsmwRe_>=10 & s4 { Lmwai(s4); }
Lmwai.s4: is LsmwRb_ & LsmwRe_ { }
Lmwai.s5: s5 is LsmwRb_<=11 & LsmwRe_>=11 & s5 { Lmwai(s5); }
Lmwai.s5: is LsmwRb_ & LsmwRe_ { }
Lmwai.s6: s6 is LsmwRb_<=12 & LsmwRe_>=12 & s6 { Lmwai(s6); }
Lmwai.s6: is LsmwRb_ & LsmwRe_ { }
Lmwai.s7: s7 is LsmwRb_<=13 & LsmwRe_>=13 & s7 { Lmwai(s7); }
Lmwai.s7: is LsmwRb_ & LsmwRe_ { }
Lmwai.s8: s8 is LsmwRb_<=14 & LsmwRe_>=14 & s8 { Lmwai(s8); }
Lmwai.s8: is LsmwRb_ & LsmwRe_ { }
Lmwai.ta: ta is LsmwRb_<=15 & LsmwRe_>=15 & ta { Lmwai(ta); }
Lmwai.ta: is LsmwRb_ & LsmwRe_ { }
Lmwai.t0: t0 is LsmwRb_<=16 & LsmwRe_>=16 & t0 { Lmwai(t0); }
Lmwai.t0: is LsmwRb_ & LsmwRe_ { }
Lmwai.t1: t1 is LsmwRb_<=17 & LsmwRe_>=17 & t1 { Lmwai(t1); }
Lmwai.t1: is LsmwRb_ & LsmwRe_ { }
Lmwai.t2: t2 is LsmwRb_<=18 & LsmwRe_>=18 & t2 { Lmwai(t2); }
Lmwai.t2: is LsmwRb_ & LsmwRe_ { }
Lmwai.t3: t3 is LsmwRb_<=19 & LsmwRe_>=19 & t3 { Lmwai(t3); }
Lmwai.t3: is LsmwRb_ & LsmwRe_ { }
Lmwai.t4: t4 is LsmwRb_<=20 & LsmwRe_>=20 & t4 { Lmwai(t4); }
Lmwai.t4: is LsmwRb_ & LsmwRe_ { }
Lmwai.t5: t5 is LsmwRb_<=21 & LsmwRe_>=21 & t5 { Lmwai(t5); }
Lmwai.t5: is LsmwRb_ & LsmwRe_ { }
Lmwai.t6: t6 is LsmwRb_<=22 & LsmwRe_>=22 & t6 { Lmwai(t6); }
Lmwai.t6: is LsmwRb_ & LsmwRe_ { }
Lmwai.t7: t7 is LsmwRb_<=23 & LsmwRe_>=23 & t7 { Lmwai(t7); }
Lmwai.t7: is LsmwRb_ & LsmwRe_ { }
Lmwai.t8: t8 is LsmwRb_<=24 & LsmwRe_>=24 & t8 { Lmwai(t8); }
Lmwai.t8: is LsmwRb_ & LsmwRe_ { }
Lmwai.t9: t9 is LsmwRb_<=25 & LsmwRe_>=25 & t9 { Lmwai(t9); }
Lmwai.t9: is LsmwRb_ & LsmwRe_ { }
Lmwai.p0: p0 is LsmwRb_<=26 & LsmwRe_>=26 & p0 { Lmwai(p0); }
Lmwai.p0: is LsmwRb_ & LsmwRe_ { }
Lmwai.p1: p1 is LsmwRb_<=27 & LsmwRe_>=27 & p1 { Lmwai(p1); }
Lmwai.p1: is LsmwRb_ & LsmwRe_ { }
Lmwai.fp: fp is Enable4_fp=1 & fp { Lmwai(fp); }
Lmwai.fp: is Enable4_fp=0 { }
Lmwai.gp: gp is Enable4_gp=1 & gp { Lmwai(gp); }
Lmwai.gp: is Enable4_gp=0 { }
Lmwai.lp: lp is Enable4_lp=1 & lp { Lmwai(lp); }
Lmwai.lp: is Enable4_lp=0 { }
Lmwai.sp: sp is Enable4_sp=1 & sp { Lmwai(sp); }
Lmwai.sp: is Enable4_sp=0 { }
Lmwad.a0: a0 is LsmwRb_<=0 & LsmwRe_>=0 & a0 { Lmwad(a0); }
Lmwad.a0: is LsmwRb_ & LsmwRe_ { }
Lmwad.a1: a1 is LsmwRb_<=1 & LsmwRe_>=1 & a1 { Lmwad(a1); }
Lmwad.a1: is LsmwRb_ & LsmwRe_ { }
Lmwad.a2: a2 is LsmwRb_<=2 & LsmwRe_>=2 & a2 { Lmwad(a2); }
Lmwad.a2: is LsmwRb_ & LsmwRe_ { }
Lmwad.a3: a3 is LsmwRb_<=3 & LsmwRe_>=3 & a3 { Lmwad(a3); }
Lmwad.a3: is LsmwRb_ & LsmwRe_ { }
Lmwad.a4: a4 is LsmwRb_<=4 & LsmwRe_>=4 & a4 { Lmwad(a4); }
Lmwad.a4: is LsmwRb_ & LsmwRe_ { }
Lmwad.a5: a5 is LsmwRb_<=5 & LsmwRe_>=5 & a5 { Lmwad(a5); }
Lmwad.a5: is LsmwRb_ & LsmwRe_ { }
Lmwad.s0: s0 is LsmwRb_<=6 & LsmwRe_>=6 & s0 { Lmwad(s0); }
Lmwad.s0: is LsmwRb_ & LsmwRe_ { }
Lmwad.s1: s1 is LsmwRb_<=7 & LsmwRe_>=7 & s1 { Lmwad(s1); }
Lmwad.s1: is LsmwRb_ & LsmwRe_ { }
Lmwad.s2: s2 is LsmwRb_<=8 & LsmwRe_>=8 & s2 { Lmwad(s2); }
Lmwad.s2: is LsmwRb_ & LsmwRe_ { }
Lmwad.s3: s3 is LsmwRb_<=9 & LsmwRe_>=9 & s3 { Lmwad(s3); }
Lmwad.s3: is LsmwRb_ & LsmwRe_ { }
Lmwad.s4: s4 is LsmwRb_<=10 & LsmwRe_>=10 & s4 { Lmwad(s4); }
Lmwad.s4: is LsmwRb_ & LsmwRe_ { }
Lmwad.s5: s5 is LsmwRb_<=11 & LsmwRe_>=11 & s5 { Lmwad(s5); }
Lmwad.s5: is LsmwRb_ & LsmwRe_ { }
Lmwad.s6: s6 is LsmwRb_<=12 & LsmwRe_>=12 & s6 { Lmwad(s6); }
Lmwad.s6: is LsmwRb_ & LsmwRe_ { }
Lmwad.s7: s7 is LsmwRb_<=13 & LsmwRe_>=13 & s7 { Lmwad(s7); }
Lmwad.s7: is LsmwRb_ & LsmwRe_ { }
Lmwad.s8: s8 is LsmwRb_<=14 & LsmwRe_>=14 & s8 { Lmwad(s8); }
Lmwad.s8: is LsmwRb_ & LsmwRe_ { }
Lmwad.ta: ta is LsmwRb_<=15 & LsmwRe_>=15 & ta { Lmwad(ta); }
Lmwad.ta: is LsmwRb_ & LsmwRe_ { }
Lmwad.t0: t0 is LsmwRb_<=16 & LsmwRe_>=16 & t0 { Lmwad(t0); }
Lmwad.t0: is LsmwRb_ & LsmwRe_ { }
Lmwad.t1: t1 is LsmwRb_<=17 & LsmwRe_>=17 & t1 { Lmwad(t1); }
Lmwad.t1: is LsmwRb_ & LsmwRe_ { }
Lmwad.t2: t2 is LsmwRb_<=18 & LsmwRe_>=18 & t2 { Lmwad(t2); }
Lmwad.t2: is LsmwRb_ & LsmwRe_ { }
Lmwad.t3: t3 is LsmwRb_<=19 & LsmwRe_>=19 & t3 { Lmwad(t3); }
Lmwad.t3: is LsmwRb_ & LsmwRe_ { }
Lmwad.t4: t4 is LsmwRb_<=20 & LsmwRe_>=20 & t4 { Lmwad(t4); }
Lmwad.t4: is LsmwRb_ & LsmwRe_ { }
Lmwad.t5: t5 is LsmwRb_<=21 & LsmwRe_>=21 & t5 { Lmwad(t5); }
Lmwad.t5: is LsmwRb_ & LsmwRe_ { }
Lmwad.t6: t6 is LsmwRb_<=22 & LsmwRe_>=22 & t6 { Lmwad(t6); }
Lmwad.t6: is LsmwRb_ & LsmwRe_ { }
Lmwad.t7: t7 is LsmwRb_<=23 & LsmwRe_>=23 & t7 { Lmwad(t7); }
Lmwad.t7: is LsmwRb_ & LsmwRe_ { }
Lmwad.t8: t8 is LsmwRb_<=24 & LsmwRe_>=24 & t8 { Lmwad(t8); }
Lmwad.t8: is LsmwRb_ & LsmwRe_ { }
Lmwad.t9: t9 is LsmwRb_<=25 & LsmwRe_>=25 & t9 { Lmwad(t9); }
Lmwad.t9: is LsmwRb_ & LsmwRe_ { }
Lmwad.p0: p0 is LsmwRb_<=26 & LsmwRe_>=26 & p0 { Lmwad(p0); }
Lmwad.p0: is LsmwRb_ & LsmwRe_ { }
Lmwad.p1: p1 is LsmwRb_<=27 & LsmwRe_>=27 & p1 { Lmwad(p1); }
Lmwad.p1: is LsmwRb_ & LsmwRe_ { }
Lmwad.fp: fp is Enable4_fp=1 & fp { Lmwad(fp); }
Lmwad.fp: is Enable4_fp=0 { }
Lmwad.gp: gp is Enable4_gp=1 & gp { Lmwad(gp); }
Lmwad.gp: is Enable4_gp=0 { }
Lmwad.lp: lp is Enable4_lp=1 & lp { Lmwad(lp); }
Lmwad.lp: is Enable4_lp=0 { }
Lmwad.sp: sp is Enable4_sp=1 & sp { Lmwad(sp); }
Lmwad.sp: is Enable4_sp=0 { }
Smwbi.a0: a0 is LsmwRb_<=0 & LsmwRe_>=0 & a0 { Smwbi(a0); }
Smwbi.a0: is LsmwRb_ & LsmwRe_ { }
Smwbi.a1: a1 is LsmwRb_<=1 & LsmwRe_>=1 & a1 { Smwbi(a1); }
Smwbi.a1: is LsmwRb_ & LsmwRe_ { }
Smwbi.a2: a2 is LsmwRb_<=2 & LsmwRe_>=2 & a2 { Smwbi(a2); }
Smwbi.a2: is LsmwRb_ & LsmwRe_ { }
Smwbi.a3: a3 is LsmwRb_<=3 & LsmwRe_>=3 & a3 { Smwbi(a3); }
Smwbi.a3: is LsmwRb_ & LsmwRe_ { }
Smwbi.a4: a4 is LsmwRb_<=4 & LsmwRe_>=4 & a4 { Smwbi(a4); }
Smwbi.a4: is LsmwRb_ & LsmwRe_ { }
Smwbi.a5: a5 is LsmwRb_<=5 & LsmwRe_>=5 & a5 { Smwbi(a5); }
Smwbi.a5: is LsmwRb_ & LsmwRe_ { }
Smwbi.s0: s0 is LsmwRb_<=6 & LsmwRe_>=6 & s0 { Smwbi(s0); }
Smwbi.s0: is LsmwRb_ & LsmwRe_ { }
Smwbi.s1: s1 is LsmwRb_<=7 & LsmwRe_>=7 & s1 { Smwbi(s1); }
Smwbi.s1: is LsmwRb_ & LsmwRe_ { }
Smwbi.s2: s2 is LsmwRb_<=8 & LsmwRe_>=8 & s2 { Smwbi(s2); }
Smwbi.s2: is LsmwRb_ & LsmwRe_ { }
Smwbi.s3: s3 is LsmwRb_<=9 & LsmwRe_>=9 & s3 { Smwbi(s3); }
Smwbi.s3: is LsmwRb_ & LsmwRe_ { }
Smwbi.s4: s4 is LsmwRb_<=10 & LsmwRe_>=10 & s4 { Smwbi(s4); }
Smwbi.s4: is LsmwRb_ & LsmwRe_ { }
Smwbi.s5: s5 is LsmwRb_<=11 & LsmwRe_>=11 & s5 { Smwbi(s5); }
Smwbi.s5: is LsmwRb_ & LsmwRe_ { }
Smwbi.s6: s6 is LsmwRb_<=12 & LsmwRe_>=12 & s6 { Smwbi(s6); }
Smwbi.s6: is LsmwRb_ & LsmwRe_ { }
Smwbi.s7: s7 is LsmwRb_<=13 & LsmwRe_>=13 & s7 { Smwbi(s7); }
Smwbi.s7: is LsmwRb_ & LsmwRe_ { }
Smwbi.s8: s8 is LsmwRb_<=14 & LsmwRe_>=14 & s8 { Smwbi(s8); }
Smwbi.s8: is LsmwRb_ & LsmwRe_ { }
Smwbi.ta: ta is LsmwRb_<=15 & LsmwRe_>=15 & ta { Smwbi(ta); }
Smwbi.ta: is LsmwRb_ & LsmwRe_ { }
Smwbi.t0: t0 is LsmwRb_<=16 & LsmwRe_>=16 & t0 { Smwbi(t0); }
Smwbi.t0: is LsmwRb_ & LsmwRe_ { }
Smwbi.t1: t1 is LsmwRb_<=17 & LsmwRe_>=17 & t1 { Smwbi(t1); }
Smwbi.t1: is LsmwRb_ & LsmwRe_ { }
Smwbi.t2: t2 is LsmwRb_<=18 & LsmwRe_>=18 & t2 { Smwbi(t2); }
Smwbi.t2: is LsmwRb_ & LsmwRe_ { }
Smwbi.t3: t3 is LsmwRb_<=19 & LsmwRe_>=19 & t3 { Smwbi(t3); }
Smwbi.t3: is LsmwRb_ & LsmwRe_ { }
Smwbi.t4: t4 is LsmwRb_<=20 & LsmwRe_>=20 & t4 { Smwbi(t4); }
Smwbi.t4: is LsmwRb_ & LsmwRe_ { }
Smwbi.t5: t5 is LsmwRb_<=21 & LsmwRe_>=21 & t5 { Smwbi(t5); }
Smwbi.t5: is LsmwRb_ & LsmwRe_ { }
Smwbi.t6: t6 is LsmwRb_<=22 & LsmwRe_>=22 & t6 { Smwbi(t6); }
Smwbi.t6: is LsmwRb_ & LsmwRe_ { }
Smwbi.t7: t7 is LsmwRb_<=23 & LsmwRe_>=23 & t7 { Smwbi(t7); }
Smwbi.t7: is LsmwRb_ & LsmwRe_ { }
Smwbi.t8: t8 is LsmwRb_<=24 & LsmwRe_>=24 & t8 { Smwbi(t8); }
Smwbi.t8: is LsmwRb_ & LsmwRe_ { }
Smwbi.t9: t9 is LsmwRb_<=25 & LsmwRe_>=25 & t9 { Smwbi(t9); }
Smwbi.t9: is LsmwRb_ & LsmwRe_ { }
Smwbi.p0: p0 is LsmwRb_<=26 & LsmwRe_>=26 & p0 { Smwbi(p0); }
Smwbi.p0: is LsmwRb_ & LsmwRe_ { }
Smwbi.p1: p1 is LsmwRb_<=27 & LsmwRe_>=27 & p1 { Smwbi(p1); }
Smwbi.p1: is LsmwRb_ & LsmwRe_ { }
Smwbi.fp: fp is Enable4_fp=1 & fp { Smwbi(fp); }
Smwbi.fp: is Enable4_fp=0 { }
Smwbi.gp: gp is Enable4_gp=1 & gp { Smwbi(gp); }
Smwbi.gp: is Enable4_gp=0 { }
Smwbi.lp: lp is Enable4_lp=1 & lp { Smwbi(lp); }
Smwbi.lp: is Enable4_lp=0 { }
Smwbi.sp: sp is Enable4_sp=1 & sp { Smwbi(sp); }
Smwbi.sp: is Enable4_sp=0 { }
Smwbd.a0: a0 is LsmwRb_<=0 & LsmwRe_>=0 & a0 { Smwbd(a0); }
Smwbd.a0: is LsmwRb_ & LsmwRe_ { }
Smwbd.a1: a1 is LsmwRb_<=1 & LsmwRe_>=1 & a1 { Smwbd(a1); }
Smwbd.a1: is LsmwRb_ & LsmwRe_ { }
Smwbd.a2: a2 is LsmwRb_<=2 & LsmwRe_>=2 & a2 { Smwbd(a2); }
Smwbd.a2: is LsmwRb_ & LsmwRe_ { }
Smwbd.a3: a3 is LsmwRb_<=3 & LsmwRe_>=3 & a3 { Smwbd(a3); }
Smwbd.a3: is LsmwRb_ & LsmwRe_ { }
Smwbd.a4: a4 is LsmwRb_<=4 & LsmwRe_>=4 & a4 { Smwbd(a4); }
Smwbd.a4: is LsmwRb_ & LsmwRe_ { }
Smwbd.a5: a5 is LsmwRb_<=5 & LsmwRe_>=5 & a5 { Smwbd(a5); }
Smwbd.a5: is LsmwRb_ & LsmwRe_ { }
Smwbd.s0: s0 is LsmwRb_<=6 & LsmwRe_>=6 & s0 { Smwbd(s0); }
Smwbd.s0: is LsmwRb_ & LsmwRe_ { }
Smwbd.s1: s1 is LsmwRb_<=7 & LsmwRe_>=7 & s1 { Smwbd(s1); }
Smwbd.s1: is LsmwRb_ & LsmwRe_ { }
Smwbd.s2: s2 is LsmwRb_<=8 & LsmwRe_>=8 & s2 { Smwbd(s2); }
Smwbd.s2: is LsmwRb_ & LsmwRe_ { }
Smwbd.s3: s3 is LsmwRb_<=9 & LsmwRe_>=9 & s3 { Smwbd(s3); }
Smwbd.s3: is LsmwRb_ & LsmwRe_ { }
Smwbd.s4: s4 is LsmwRb_<=10 & LsmwRe_>=10 & s4 { Smwbd(s4); }
Smwbd.s4: is LsmwRb_ & LsmwRe_ { }
Smwbd.s5: s5 is LsmwRb_<=11 & LsmwRe_>=11 & s5 { Smwbd(s5); }
Smwbd.s5: is LsmwRb_ & LsmwRe_ { }
Smwbd.s6: s6 is LsmwRb_<=12 & LsmwRe_>=12 & s6 { Smwbd(s6); }
Smwbd.s6: is LsmwRb_ & LsmwRe_ { }
Smwbd.s7: s7 is LsmwRb_<=13 & LsmwRe_>=13 & s7 { Smwbd(s7); }
Smwbd.s7: is LsmwRb_ & LsmwRe_ { }
Smwbd.s8: s8 is LsmwRb_<=14 & LsmwRe_>=14 & s8 { Smwbd(s8); }
Smwbd.s8: is LsmwRb_ & LsmwRe_ { }
Smwbd.ta: ta is LsmwRb_<=15 & LsmwRe_>=15 & ta { Smwbd(ta); }
Smwbd.ta: is LsmwRb_ & LsmwRe_ { }
Smwbd.t0: t0 is LsmwRb_<=16 & LsmwRe_>=16 & t0 { Smwbd(t0); }
Smwbd.t0: is LsmwRb_ & LsmwRe_ { }
Smwbd.t1: t1 is LsmwRb_<=17 & LsmwRe_>=17 & t1 { Smwbd(t1); }
Smwbd.t1: is LsmwRb_ & LsmwRe_ { }
Smwbd.t2: t2 is LsmwRb_<=18 & LsmwRe_>=18 & t2 { Smwbd(t2); }
Smwbd.t2: is LsmwRb_ & LsmwRe_ { }
Smwbd.t3: t3 is LsmwRb_<=19 & LsmwRe_>=19 & t3 { Smwbd(t3); }
Smwbd.t3: is LsmwRb_ & LsmwRe_ { }
Smwbd.t4: t4 is LsmwRb_<=20 & LsmwRe_>=20 & t4 { Smwbd(t4); }
Smwbd.t4: is LsmwRb_ & LsmwRe_ { }
Smwbd.t5: t5 is LsmwRb_<=21 & LsmwRe_>=21 & t5 { Smwbd(t5); }
Smwbd.t5: is LsmwRb_ & LsmwRe_ { }
Smwbd.t6: t6 is LsmwRb_<=22 & LsmwRe_>=22 & t6 { Smwbd(t6); }
Smwbd.t6: is LsmwRb_ & LsmwRe_ { }
Smwbd.t7: t7 is LsmwRb_<=23 & LsmwRe_>=23 & t7 { Smwbd(t7); }
Smwbd.t7: is LsmwRb_ & LsmwRe_ { }
Smwbd.t8: t8 is LsmwRb_<=24 & LsmwRe_>=24 & t8 { Smwbd(t8); }
Smwbd.t8: is LsmwRb_ & LsmwRe_ { }
Smwbd.t9: t9 is LsmwRb_<=25 & LsmwRe_>=25 & t9 { Smwbd(t9); }
Smwbd.t9: is LsmwRb_ & LsmwRe_ { }
Smwbd.p0: p0 is LsmwRb_<=26 & LsmwRe_>=26 & p0 { Smwbd(p0); }
Smwbd.p0: is LsmwRb_ & LsmwRe_ { }
Smwbd.p1: p1 is LsmwRb_<=27 & LsmwRe_>=27 & p1 { Smwbd(p1); }
Smwbd.p1: is LsmwRb_ & LsmwRe_ { }
Smwbd.fp: fp is Enable4_fp=1 & fp { Smwbd(fp); }
Smwbd.fp: is Enable4_fp=0 { }
Smwbd.gp: gp is Enable4_gp=1 & gp { Smwbd(gp); }
Smwbd.gp: is Enable4_gp=0 { }
Smwbd.lp: lp is Enable4_lp=1 & lp { Smwbd(lp); }
Smwbd.lp: is Enable4_lp=0 { }
Smwbd.sp: sp is Enable4_sp=1 & sp { Smwbd(sp); }
Smwbd.sp: is Enable4_sp=0 { }
Smwai.a0: a0 is LsmwRb_<=0 & LsmwRe_>=0 & a0 { Smwai(a0); }
Smwai.a0: is LsmwRb_ & LsmwRe_ { }
Smwai.a1: a1 is LsmwRb_<=1 & LsmwRe_>=1 & a1 { Smwai(a1); }
Smwai.a1: is LsmwRb_ & LsmwRe_ { }
Smwai.a2: a2 is LsmwRb_<=2 & LsmwRe_>=2 & a2 { Smwai(a2); }
Smwai.a2: is LsmwRb_ & LsmwRe_ { }
Smwai.a3: a3 is LsmwRb_<=3 & LsmwRe_>=3 & a3 { Smwai(a3); }
Smwai.a3: is LsmwRb_ & LsmwRe_ { }
Smwai.a4: a4 is LsmwRb_<=4 & LsmwRe_>=4 & a4 { Smwai(a4); }
Smwai.a4: is LsmwRb_ & LsmwRe_ { }
Smwai.a5: a5 is LsmwRb_<=5 & LsmwRe_>=5 & a5 { Smwai(a5); }
Smwai.a5: is LsmwRb_ & LsmwRe_ { }
Smwai.s0: s0 is LsmwRb_<=6 & LsmwRe_>=6 & s0 { Smwai(s0); }
Smwai.s0: is LsmwRb_ & LsmwRe_ { }
Smwai.s1: s1 is LsmwRb_<=7 & LsmwRe_>=7 & s1 { Smwai(s1); }
Smwai.s1: is LsmwRb_ & LsmwRe_ { }
Smwai.s2: s2 is LsmwRb_<=8 & LsmwRe_>=8 & s2 { Smwai(s2); }
Smwai.s2: is LsmwRb_ & LsmwRe_ { }
Smwai.s3: s3 is LsmwRb_<=9 & LsmwRe_>=9 & s3 { Smwai(s3); }
Smwai.s3: is LsmwRb_ & LsmwRe_ { }
Smwai.s4: s4 is LsmwRb_<=10 & LsmwRe_>=10 & s4 { Smwai(s4); }
Smwai.s4: is LsmwRb_ & LsmwRe_ { }
Smwai.s5: s5 is LsmwRb_<=11 & LsmwRe_>=11 & s5 { Smwai(s5); }
Smwai.s5: is LsmwRb_ & LsmwRe_ { }
Smwai.s6: s6 is LsmwRb_<=12 & LsmwRe_>=12 & s6 { Smwai(s6); }
Smwai.s6: is LsmwRb_ & LsmwRe_ { }
Smwai.s7: s7 is LsmwRb_<=13 & LsmwRe_>=13 & s7 { Smwai(s7); }
Smwai.s7: is LsmwRb_ & LsmwRe_ { }
Smwai.s8: s8 is LsmwRb_<=14 & LsmwRe_>=14 & s8 { Smwai(s8); }
Smwai.s8: is LsmwRb_ & LsmwRe_ { }
Smwai.ta: ta is LsmwRb_<=15 & LsmwRe_>=15 & ta { Smwai(ta); }
Smwai.ta: is LsmwRb_ & LsmwRe_ { }
Smwai.t0: t0 is LsmwRb_<=16 & LsmwRe_>=16 & t0 { Smwai(t0); }
Smwai.t0: is LsmwRb_ & LsmwRe_ { }
Smwai.t1: t1 is LsmwRb_<=17 & LsmwRe_>=17 & t1 { Smwai(t1); }
Smwai.t1: is LsmwRb_ & LsmwRe_ { }
Smwai.t2: t2 is LsmwRb_<=18 & LsmwRe_>=18 & t2 { Smwai(t2); }
Smwai.t2: is LsmwRb_ & LsmwRe_ { }
Smwai.t3: t3 is LsmwRb_<=19 & LsmwRe_>=19 & t3 { Smwai(t3); }
Smwai.t3: is LsmwRb_ & LsmwRe_ { }
Smwai.t4: t4 is LsmwRb_<=20 & LsmwRe_>=20 & t4 { Smwai(t4); }
Smwai.t4: is LsmwRb_ & LsmwRe_ { }
Smwai.t5: t5 is LsmwRb_<=21 & LsmwRe_>=21 & t5 { Smwai(t5); }
Smwai.t5: is LsmwRb_ & LsmwRe_ { }
Smwai.t6: t6 is LsmwRb_<=22 & LsmwRe_>=22 & t6 { Smwai(t6); }
Smwai.t6: is LsmwRb_ & LsmwRe_ { }
Smwai.t7: t7 is LsmwRb_<=23 & LsmwRe_>=23 & t7 { Smwai(t7); }
Smwai.t7: is LsmwRb_ & LsmwRe_ { }
Smwai.t8: t8 is LsmwRb_<=24 & LsmwRe_>=24 & t8 { Smwai(t8); }
Smwai.t8: is LsmwRb_ & LsmwRe_ { }
Smwai.t9: t9 is LsmwRb_<=25 & LsmwRe_>=25 & t9 { Smwai(t9); }
Smwai.t9: is LsmwRb_ & LsmwRe_ { }
Smwai.p0: p0 is LsmwRb_<=26 & LsmwRe_>=26 & p0 { Smwai(p0); }
Smwai.p0: is LsmwRb_ & LsmwRe_ { }
Smwai.p1: p1 is LsmwRb_<=27 & LsmwRe_>=27 & p1 { Smwai(p1); }
Smwai.p1: is LsmwRb_ & LsmwRe_ { }
Smwai.fp: fp is Enable4_fp=1 & fp { Smwai(fp); }
Smwai.fp: is Enable4_fp=0 { }
Smwai.gp: gp is Enable4_gp=1 & gp { Smwai(gp); }
Smwai.gp: is Enable4_gp=0 { }
Smwai.lp: lp is Enable4_lp=1 & lp { Smwai(lp); }
Smwai.lp: is Enable4_lp=0 { }
Smwai.sp: sp is Enable4_sp=1 & sp { Smwai(sp); }
Smwai.sp: is Enable4_sp=0 { }
Smwad.a0: a0 is LsmwRb_<=0 & LsmwRe_>=0 & a0 { Smwad(a0); }
Smwad.a0: is LsmwRb_ & LsmwRe_ { }
Smwad.a1: a1 is LsmwRb_<=1 & LsmwRe_>=1 & a1 { Smwad(a1); }
Smwad.a1: is LsmwRb_ & LsmwRe_ { }
Smwad.a2: a2 is LsmwRb_<=2 & LsmwRe_>=2 & a2 { Smwad(a2); }
Smwad.a2: is LsmwRb_ & LsmwRe_ { }
Smwad.a3: a3 is LsmwRb_<=3 & LsmwRe_>=3 & a3 { Smwad(a3); }
Smwad.a3: is LsmwRb_ & LsmwRe_ { }
Smwad.a4: a4 is LsmwRb_<=4 & LsmwRe_>=4 & a4 { Smwad(a4); }
Smwad.a4: is LsmwRb_ & LsmwRe_ { }
Smwad.a5: a5 is LsmwRb_<=5 & LsmwRe_>=5 & a5 { Smwad(a5); }
Smwad.a5: is LsmwRb_ & LsmwRe_ { }
Smwad.s0: s0 is LsmwRb_<=6 & LsmwRe_>=6 & s0 { Smwad(s0); }
Smwad.s0: is LsmwRb_ & LsmwRe_ { }
Smwad.s1: s1 is LsmwRb_<=7 & LsmwRe_>=7 & s1 { Smwad(s1); }
Smwad.s1: is LsmwRb_ & LsmwRe_ { }
Smwad.s2: s2 is LsmwRb_<=8 & LsmwRe_>=8 & s2 { Smwad(s2); }
Smwad.s2: is LsmwRb_ & LsmwRe_ { }
Smwad.s3: s3 is LsmwRb_<=9 & LsmwRe_>=9 & s3 { Smwad(s3); }
Smwad.s3: is LsmwRb_ & LsmwRe_ { }
Smwad.s4: s4 is LsmwRb_<=10 & LsmwRe_>=10 & s4 { Smwad(s4); }
Smwad.s4: is LsmwRb_ & LsmwRe_ { }
Smwad.s5: s5 is LsmwRb_<=11 & LsmwRe_>=11 & s5 { Smwad(s5); }
Smwad.s5: is LsmwRb_ & LsmwRe_ { }
Smwad.s6: s6 is LsmwRb_<=12 & LsmwRe_>=12 & s6 { Smwad(s6); }
Smwad.s6: is LsmwRb_ & LsmwRe_ { }
Smwad.s7: s7 is LsmwRb_<=13 & LsmwRe_>=13 & s7 { Smwad(s7); }
Smwad.s7: is LsmwRb_ & LsmwRe_ { }
Smwad.s8: s8 is LsmwRb_<=14 & LsmwRe_>=14 & s8 { Smwad(s8); }
Smwad.s8: is LsmwRb_ & LsmwRe_ { }
Smwad.ta: ta is LsmwRb_<=15 & LsmwRe_>=15 & ta { Smwad(ta); }
Smwad.ta: is LsmwRb_ & LsmwRe_ { }
Smwad.t0: t0 is LsmwRb_<=16 & LsmwRe_>=16 & t0 { Smwad(t0); }
Smwad.t0: is LsmwRb_ & LsmwRe_ { }
Smwad.t1: t1 is LsmwRb_<=17 & LsmwRe_>=17 & t1 { Smwad(t1); }
Smwad.t1: is LsmwRb_ & LsmwRe_ { }
Smwad.t2: t2 is LsmwRb_<=18 & LsmwRe_>=18 & t2 { Smwad(t2); }
Smwad.t2: is LsmwRb_ & LsmwRe_ { }
Smwad.t3: t3 is LsmwRb_<=19 & LsmwRe_>=19 & t3 { Smwad(t3); }
Smwad.t3: is LsmwRb_ & LsmwRe_ { }
Smwad.t4: t4 is LsmwRb_<=20 & LsmwRe_>=20 & t4 { Smwad(t4); }
Smwad.t4: is LsmwRb_ & LsmwRe_ { }
Smwad.t5: t5 is LsmwRb_<=21 & LsmwRe_>=21 & t5 { Smwad(t5); }
Smwad.t5: is LsmwRb_ & LsmwRe_ { }
Smwad.t6: t6 is LsmwRb_<=22 & LsmwRe_>=22 & t6 { Smwad(t6); }
Smwad.t6: is LsmwRb_ & LsmwRe_ { }
Smwad.t7: t7 is LsmwRb_<=23 & LsmwRe_>=23 & t7 { Smwad(t7); }
Smwad.t7: is LsmwRb_ & LsmwRe_ { }
Smwad.t8: t8 is LsmwRb_<=24 & LsmwRe_>=24 & t8 { Smwad(t8); }
Smwad.t8: is LsmwRb_ & LsmwRe_ { }
Smwad.t9: t9 is LsmwRb_<=25 & LsmwRe_>=25 & t9 { Smwad(t9); }
Smwad.t9: is LsmwRb_ & LsmwRe_ { }
Smwad.p0: p0 is LsmwRb_<=26 & LsmwRe_>=26 & p0 { Smwad(p0); }
Smwad.p0: is LsmwRb_ & LsmwRe_ { }
Smwad.p1: p1 is LsmwRb_<=27 & LsmwRe_>=27 & p1 { Smwad(p1); }
Smwad.p1: is LsmwRb_ & LsmwRe_ { }
Smwad.fp: fp is Enable4_fp=1 & fp { Smwad(fp); }
Smwad.fp: is Enable4_fp=0 { }
Smwad.gp: gp is Enable4_gp=1 & gp { Smwad(gp); }
Smwad.gp: is Enable4_gp=0 { }
Smwad.lp: lp is Enable4_lp=1 & lp { Smwad(lp); }
Smwad.lp: is Enable4_lp=0 { }
Smwad.sp: sp is Enable4_sp=1 & sp { Smwad(sp); }
Smwad.sp: is Enable4_sp=0 { }
Lmw.regs: is LsmwBa=0 & LsmwId=0 & Lmwbi.sp & Lmwbi.lp & Lmwbi.gp & Lmwbi.fp & Lmwbi.p1 & Lmwbi.p0 & Lmwbi.t9 & Lmwbi.t8 & Lmwbi.t7 & Lmwbi.t6 & Lmwbi.t5 & Lmwbi.t4 & Lmwbi.t3 & Lmwbi.t2 & Lmwbi.t1 & Lmwbi.t0 & Lmwbi.ta & Lmwbi.s8 & Lmwbi.s7 & Lmwbi.s6 & Lmwbi.s5 & Lmwbi.s4 & Lmwbi.s3 & Lmwbi.s2 & Lmwbi.s1 & Lmwbi.s0 & Lmwbi.a5 & Lmwbi.a4 & Lmwbi.a3 & Lmwbi.a2 & Lmwbi.a1 & Lmwbi.a0 { }
Lmw.regs: is LsmwBa=0 & LsmwId=1 & Lmwbd.a0 & Lmwbd.a1 & Lmwbd.a2 & Lmwbd.a3 & Lmwbd.a4 & Lmwbd.a5 & Lmwbd.s0 & Lmwbd.s1 & Lmwbd.s2 & Lmwbd.s3 & Lmwbd.s4 & Lmwbd.s5 & Lmwbd.s6 & Lmwbd.s7 & Lmwbd.s8 & Lmwbd.ta & Lmwbd.t0 & Lmwbd.t1 & Lmwbd.t2 & Lmwbd.t3 & Lmwbd.t4 & Lmwbd.t5 & Lmwbd.t6 & Lmwbd.t7 & Lmwbd.t8 & Lmwbd.t9 & Lmwbd.p0 & Lmwbd.p1 & Lmwbd.fp & Lmwbd.gp & Lmwbd.lp & Lmwbd.sp { }
Lmw.regs: is LsmwBa=1 & LsmwId=0 & Lmwai.sp & Lmwai.lp & Lmwai.gp & Lmwai.fp & Lmwai.p1 & Lmwai.p0 & Lmwai.t9 & Lmwai.t8 & Lmwai.t7 & Lmwai.t6 & Lmwai.t5 & Lmwai.t4 & Lmwai.t3 & Lmwai.t2 & Lmwai.t1 & Lmwai.t0 & Lmwai.ta & Lmwai.s8 & Lmwai.s7 & Lmwai.s6 & Lmwai.s5 & Lmwai.s4 & Lmwai.s3 & Lmwai.s2 & Lmwai.s1 & Lmwai.s0 & Lmwai.a5 & Lmwai.a4 & Lmwai.a3 & Lmwai.a2 & Lmwai.a1 & Lmwai.a0 { }
Lmw.regs: is LsmwBa=1 & LsmwId=1 & Lmwad.a0 & Lmwad.a1 & Lmwad.a2 & Lmwad.a3 & Lmwad.a4 & Lmwad.a5 & Lmwad.s0 & Lmwad.s1 & Lmwad.s2 & Lmwad.s3 & Lmwad.s4 & Lmwad.s5 & Lmwad.s6 & Lmwad.s7 & Lmwad.s8 & Lmwad.ta & Lmwad.t0 & Lmwad.t1 & Lmwad.t2 & Lmwad.t3 & Lmwad.t4 & Lmwad.t5 & Lmwad.t6 & Lmwad.t7 & Lmwad.t8 & Lmwad.t9 & Lmwad.p0 & Lmwad.p1 & Lmwad.fp & Lmwad.gp & Lmwad.lp & Lmwad.sp { }
Smw.regs: is LsmwBa=0 & LsmwId=0 & Smwbi.sp & Smwbi.lp & Smwbi.gp & Smwbi.fp & Smwbi.p1 & Smwbi.p0 & Smwbi.t9 & Smwbi.t8 & Smwbi.t7 & Smwbi.t6 & Smwbi.t5 & Smwbi.t4 & Smwbi.t3 & Smwbi.t2 & Smwbi.t1 & Smwbi.t0 & Smwbi.ta & Smwbi.s8 & Smwbi.s7 & Smwbi.s6 & Smwbi.s5 & Smwbi.s4 & Smwbi.s3 & Smwbi.s2 & Smwbi.s1 & Smwbi.s0 & Smwbi.a5 & Smwbi.a4 & Smwbi.a3 & Smwbi.a2 & Smwbi.a1 & Smwbi.a0 { }
Smw.regs: is LsmwBa=0 & LsmwId=1 & Smwbd.a0 & Smwbd.a1 & Smwbd.a2 & Smwbd.a3 & Smwbd.a4 & Smwbd.a5 & Smwbd.s0 & Smwbd.s1 & Smwbd.s2 & Smwbd.s3 & Smwbd.s4 & Smwbd.s5 & Smwbd.s6 & Smwbd.s7 & Smwbd.s8 & Smwbd.ta & Smwbd.t0 & Smwbd.t1 & Smwbd.t2 & Smwbd.t3 & Smwbd.t4 & Smwbd.t5 & Smwbd.t6 & Smwbd.t7 & Smwbd.t8 & Smwbd.t9 & Smwbd.p0 & Smwbd.p1 & Smwbd.fp & Smwbd.gp & Smwbd.lp & Smwbd.sp { }
Smw.regs: is LsmwBa=1 & LsmwId=0 & Smwai.sp & Smwai.lp & Smwai.gp & Smwai.fp & Smwai.p1 & Smwai.p0 & Smwai.t9 & Smwai.t8 & Smwai.t7 & Smwai.t6 & Smwai.t5 & Smwai.t4 & Smwai.t3 & Smwai.t2 & Smwai.t1 & Smwai.t0 & Smwai.ta & Smwai.s8 & Smwai.s7 & Smwai.s6 & Smwai.s5 & Smwai.s4 & Smwai.s3 & Smwai.s2 & Smwai.s1 & Smwai.s0 & Smwai.a5 & Smwai.a4 & Smwai.a3 & Smwai.a2 & Smwai.a1 & Smwai.a0 { }
Smw.regs: is LsmwBa=1 & LsmwId=1 & Smwad.a0 & Smwad.a1 & Smwad.a2 & Smwad.a3 & Smwad.a4 & Smwad.a5 & Smwad.s0 & Smwad.s1 & Smwad.s2 & Smwad.s3 & Smwad.s4 & Smwad.s5 & Smwad.s6 & Smwad.s7 & Smwad.s8 & Smwad.ta & Smwad.t0 & Smwad.t1 & Smwad.t2 & Smwad.t3 & Smwad.t4 & Smwad.t5 & Smwad.t6 & Smwad.t7 & Smwad.t8 & Smwad.t9 & Smwad.p0 & Smwad.p1 & Smwad.fp & Smwad.gp & Smwad.lp & Smwad.sp { }
Lmwa.regs: is LsmwBa=0 & LsmwId=0 & Lmwbi.sp & Lmwbi.lp & Lmwbi.gp & Lmwbi.fp & Lmwbi.p1 & Lmwbi.p0 & Lmwbi.t9 & Lmwbi.t8 & Lmwbi.t7 & Lmwbi.t6 & Lmwbi.t5 & Lmwbi.t4 & Lmwbi.t3 & Lmwbi.t2 & Lmwbi.t1 & Lmwbi.t0 & Lmwbi.ta & Lmwbi.s8 & Lmwbi.s7 & Lmwbi.s6 & Lmwbi.s5 & Lmwbi.s4 & Lmwbi.s3 & Lmwbi.s2 & Lmwbi.s1 & Lmwbi.s0 & Lmwbi.a5 & Lmwbi.a4 & Lmwbi.a3 & Lmwbi.a2 & Lmwbi.a1 & Lmwbi.a0 { }
Lmwa.regs: is LsmwBa=0 & LsmwId=1 & Lmwbd.a0 & Lmwbd.a1 & Lmwbd.a2 & Lmwbd.a3 & Lmwbd.a4 & Lmwbd.a5 & Lmwbd.s0 & Lmwbd.s1 & Lmwbd.s2 & Lmwbd.s3 & Lmwbd.s4 & Lmwbd.s5 & Lmwbd.s6 & Lmwbd.s7 & Lmwbd.s8 & Lmwbd.ta & Lmwbd.t0 & Lmwbd.t1 & Lmwbd.t2 & Lmwbd.t3 & Lmwbd.t4 & Lmwbd.t5 & Lmwbd.t6 & Lmwbd.t7 & Lmwbd.t8 & Lmwbd.t9 & Lmwbd.p0 & Lmwbd.p1 & Lmwbd.fp & Lmwbd.gp & Lmwbd.lp & Lmwbd.sp { }
Lmwa.regs: is LsmwBa=1 & LsmwId=0 & Lmwai.sp & Lmwai.lp & Lmwai.gp & Lmwai.fp & Lmwai.p1 & Lmwai.p0 & Lmwai.t9 & Lmwai.t8 & Lmwai.t7 & Lmwai.t6 & Lmwai.t5 & Lmwai.t4 & Lmwai.t3 & Lmwai.t2 & Lmwai.t1 & Lmwai.t0 & Lmwai.ta & Lmwai.s8 & Lmwai.s7 & Lmwai.s6 & Lmwai.s5 & Lmwai.s4 & Lmwai.s3 & Lmwai.s2 & Lmwai.s1 & Lmwai.s0 & Lmwai.a5 & Lmwai.a4 & Lmwai.a3 & Lmwai.a2 & Lmwai.a1 & Lmwai.a0 { }
Lmwa.regs: is LsmwBa=1 & LsmwId=1 & Lmwad.a0 & Lmwad.a1 & Lmwad.a2 & Lmwad.a3 & Lmwad.a4 & Lmwad.a5 & Lmwad.s0 & Lmwad.s1 & Lmwad.s2 & Lmwad.s3 & Lmwad.s4 & Lmwad.s5 & Lmwad.s6 & Lmwad.s7 & Lmwad.s8 & Lmwad.ta & Lmwad.t0 & Lmwad.t1 & Lmwad.t2 & Lmwad.t3 & Lmwad.t4 & Lmwad.t5 & Lmwad.t6 & Lmwad.t7 & Lmwad.t8 & Lmwad.t9 & Lmwad.p0 & Lmwad.p1 & Lmwad.fp & Lmwad.gp & Lmwad.lp & Lmwad.sp { }
Smwa.regs: is LsmwBa=0 & LsmwId=0 & Smwbi.sp & Smwbi.lp & Smwbi.gp & Smwbi.fp & Smwbi.p1 & Smwbi.p0 & Smwbi.t9 & Smwbi.t8 & Smwbi.t7 & Smwbi.t6 & Smwbi.t5 & Smwbi.t4 & Smwbi.t3 & Smwbi.t2 & Smwbi.t1 & Smwbi.t0 & Smwbi.ta & Smwbi.s8 & Smwbi.s7 & Smwbi.s6 & Smwbi.s5 & Smwbi.s4 & Smwbi.s3 & Smwbi.s2 & Smwbi.s1 & Smwbi.s0 & Smwbi.a5 & Smwbi.a4 & Smwbi.a3 & Smwbi.a2 & Smwbi.a1 & Smwbi.a0 { }
Smwa.regs: is LsmwBa=0 & LsmwId=1 & Smwbd.a0 & Smwbd.a1 & Smwbd.a2 & Smwbd.a3 & Smwbd.a4 & Smwbd.a5 & Smwbd.s0 & Smwbd.s1 & Smwbd.s2 & Smwbd.s3 & Smwbd.s4 & Smwbd.s5 & Smwbd.s6 & Smwbd.s7 & Smwbd.s8 & Smwbd.ta & Smwbd.t0 & Smwbd.t1 & Smwbd.t2 & Smwbd.t3 & Smwbd.t4 & Smwbd.t5 & Smwbd.t6 & Smwbd.t7 & Smwbd.t8 & Smwbd.t9 & Smwbd.p0 & Smwbd.p1 & Smwbd.fp & Smwbd.gp & Smwbd.lp & Smwbd.sp { }
Smwa.regs: is LsmwBa=1 & LsmwId=0 & Smwai.sp & Smwai.lp & Smwai.gp & Smwai.fp & Smwai.p1 & Smwai.p0 & Smwai.t9 & Smwai.t8 & Smwai.t7 & Smwai.t6 & Smwai.t5 & Smwai.t4 & Smwai.t3 & Smwai.t2 & Smwai.t1 & Smwai.t0 & Smwai.ta & Smwai.s8 & Smwai.s7 & Smwai.s6 & Smwai.s5 & Smwai.s4 & Smwai.s3 & Smwai.s2 & Smwai.s1 & Smwai.s0 & Smwai.a5 & Smwai.a4 & Smwai.a3 & Smwai.a2 & Smwai.a1 & Smwai.a0 { }
Smwa.regs: is LsmwBa=1 & LsmwId=1 & Smwad.a0 & Smwad.a1 & Smwad.a2 & Smwad.a3 & Smwad.a4 & Smwad.a5 & Smwad.s0 & Smwad.s1 & Smwad.s2 & Smwad.s3 & Smwad.s4 & Smwad.s5 & Smwad.s6 & Smwad.s7 & Smwad.s8 & Smwad.ta & Smwad.t0 & Smwad.t1 & Smwad.t2 & Smwad.t3 & Smwad.t4 & Smwad.t5 & Smwad.t6 & Smwad.t7 & Smwad.t8 & Smwad.t9 & Smwad.p0 & Smwad.p1 & Smwad.fp & Smwad.gp & Smwad.lp & Smwad.sp { }

View File

@ -0,0 +1,105 @@
<?xml version="1.0" encoding="UTF-8"?>
<compiler_spec>
<data_organization>
<absolute_max_alignment value="0" />
<machine_alignment value="2" />
<default_alignment value="1" />
<default_pointer_alignment value="4" />
<pointer_size value="4" />
<wchar_size value="2" />
<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="4" />
</size_alignment_map>
</data_organization>
<global>
<range space="ram"/>
</global>
<stackpointer register="sp" space="ram"/>
<returnaddress>
<register name="lp"/>
</returnaddress>
<default_proto>
<prototype name="__stdcall" extrapop="0" stackshift="0">
<input>
<pentry minsize="1" maxsize="4" extension="inttype">
<register name="a0"/>
</pentry>
<pentry minsize="1" maxsize="4" extension="inttype">
<register name="a1"/>
</pentry>
<pentry minsize="1" maxsize="4" extension="inttype">
<register name="a2"/>
</pentry>
<pentry minsize="1" maxsize="4" extension="inttype">
<register name="a3"/>
</pentry>
<pentry minsize="1" maxsize="4" extension="inttype">
<register name="a4"/>
</pentry>
<pentry minsize="1" maxsize="4" extension="inttype">
<register name="a5"/>
</pentry>
<pentry minsize="1" maxsize="500" align="4">
<addr offset="24" space="stack"/>
</pentry>
</input>
<output killedbycall="true">
<pentry minsize="1" maxsize="4" extension="inttype">
<register name="a0"/>
</pentry>
<pentry minsize="5" maxsize="8">
<addr space="join" piece1="a1" piece2="a0"/>
</pentry>
</output>
<unaffected>
<register name="s0"/>
<register name="s1"/>
<register name="s2"/>
<register name="s3"/>
<register name="s4"/>
<register name="s5"/>
<register name="s6"/>
<register name="s7"/>
<register name="s8"/>
<register name="p0"/>
<register name="p1"/>
<register name="fp"/>
<register name="gp"/>
<register name="lp"/>
<register name="sp"/>
</unaffected>
<killedbycall>
<register name="a0"/>
<register name="a1"/>
<register name="a2"/>
<register name="a3"/>
<register name="a4"/>
<register name="a5"/>
<register name="ta"/>
<register name="t0"/>
<register name="t1"/>
<register name="t2"/>
<register name="t3"/>
<register name="t4"/>
<register name="t5"/>
<register name="t6"/>
<register name="t7"/>
<register name="t8"/>
<register name="t9"/>
</killedbycall>
</prototype>
</default_proto>
</compiler_spec>

View File

@ -0,0 +1,14 @@
<dwarf>
<register_mappings>
<register_mapping dwarf="0" ghidra="a0" auto_count="6"/> <!-- a0..a5 -->
<register_mapping dwarf="6" ghidra="s0" auto_count="9"/> <!-- s0..s8 -->
<register_mapping dwarf="15" ghidra="ta"/>
<register_mapping dwarf="16" ghidra="t0" auto_count="10"/> <!-- t0..t9 -->
<register_mapping dwarf="26" ghidra="p0" auto_count="2"/> <!-- p0..p1 -->
<register_mapping dwarf="28" ghidra="fp"/>
<register_mapping dwarf="29" ghidra="gp"/>
<register_mapping dwarf="30" ghidra="lp"/>
<register_mapping dwarf="31" ghidra="sp" stackpointer="true"/>
</register_mappings>
<call_frame_cfa value="0"/>
</dwarf>

View File

@ -0,0 +1,31 @@
<?xml version="1.0" encoding="UTF-8"?>
<language_definitions>
<language processor="NDS32"
endian="big"
instructionEndian="big"
size="32"
variant="default"
version="1.0"
slafile="nds32be.sla"
processorspec="nds32.pspec"
id="NDS32:BE:32:default">
<description>NDS32 default processor 32-bit big-endian</description>
<compiler name="default" spec="nds32.cspec" id="default"/>
<external_name tool="DWARF.register.mapping.file" name="nds32.dwarf"/>
</language>
<language processor="NDS32"
endian="little"
instructionEndian="big"
size="32"
variant="default"
version="1.0"
slafile="nds32le.sla"
processorspec="nds32.pspec"
id="NDS32:LE:32:default">
<description>NDS32 default processor 32-bit little-endian</description>
<compiler name="default" spec="nds32.cspec" id="default"/>
<external_name tool="DWARF.register.mapping.file" name="nds32.dwarf"/>
</language>
</language_definitions>

View File

@ -0,0 +1,5 @@
<opinions>
<constraint loader="Executable and Linking Format (ELF)" compilerSpecID="default">
<constraint primary="167" processor="NDS32" size="32" />
</constraint>
</opinions>

View File

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<processor_spec>
<programcounter register="pc"/>
</processor_spec>

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,7 @@
@define BASELINE_V2 "yes"
@define BASELINE_V3 "yes"
@define PERFORMANCE_V1 "yes"
@define PERFORMANCE_V2 "yes"
@define ENDIAN "big"
@include "nds32.sinc"

View File

@ -0,0 +1,7 @@
@define BASELINE_V2 "yes"
@define BASELINE_V3 "yes"
@define PERFORMANCE_V1 "yes"
@define PERFORMANCE_V2 "yes"
@define ENDIAN "little"
@include "nds32.sinc"

View File

@ -0,0 +1,13 @@
<patternlist>
<patternpairs totalbits="32" postbits="16">
<prepatterns>
<data>0xd5 ........</data>
<data>0x48 ........ ........ ........</data>
<data>0x92 0x00</data>
</prepatterns>
<postpatterns>
<data>0011101. ....1111 1......0 .0111100</data>
<funcstart/>
</postpatterns>
</patternpairs>
</patternlist>

View File

@ -0,0 +1,5 @@
<patternconstraints>
<language id="NDS32:*:*:*">
<patternfile>nds32_patterns.xml</patternfile>
</language>
</patternconstraints>

View File

@ -0,0 +1,6 @@
# Add sleigh compiler options to this file (one per line) which will
# be used when compiling each language within this module.
# All options should start with a '-' character.
#
# IMPORTANT: The -a option should NOT be specified
#

View File

@ -0,0 +1,187 @@
package ghidra.app.plugin.core.analysis;
import java.math.BigInteger;
import ghidra.app.util.importer.MessageLog;
import ghidra.framework.options.Options;
import ghidra.program.model.address.Address;
import ghidra.program.model.address.AddressSet;
import ghidra.program.model.address.AddressSetView;
import ghidra.program.model.lang.Processor;
import ghidra.program.model.lang.Register;
import ghidra.program.model.lang.RegisterValue;
import ghidra.program.model.listing.ContextChangeException;
import ghidra.program.model.listing.Function;
import ghidra.program.model.listing.Instruction;
import ghidra.program.model.listing.Program;
import ghidra.program.model.listing.ProgramContext;
import ghidra.program.model.symbol.FlowType;
import ghidra.program.model.symbol.Symbol;
import ghidra.program.model.symbol.SymbolUtilities;
import ghidra.program.util.ContextEvaluator;
import ghidra.program.util.SymbolicPropogator;
import ghidra.program.util.VarnodeContext;
import ghidra.util.Msg;
import ghidra.util.exception.AssertException;
import ghidra.util.exception.CancelledException;
import ghidra.util.task.TaskMonitor;
public class NDS32Analyzer extends ConstantPropagationAnalyzer {
private final static String PROCESSOR_NAME = "NDS32";
private static final String SWITCH_OPTION_NAME = "Switch Table Recovery";
private static final String SWITCH_OPTION_DESCRIPTION = "Turn on to recover switch tables (not implemented yet !)";
private static final boolean SWITCH_OPTION_DEFAULT_VALUE = false;
private static final String RECOVER_GP_OPTION_NAME = "Recover global GP register writes";
private static final String RECOVER_GP_OPTION_DESCRIPTION = "Reads the global GP value from the symbol _SDA_BASE_";
private static final boolean RECOVER_GP_OPTION_DEFAULT_VALUE = true;
private boolean recoverSwitchTables = SWITCH_OPTION_DEFAULT_VALUE;
private boolean recoverGp = RECOVER_GP_OPTION_DEFAULT_VALUE;
private Address gpAssumptionValue = null;
private Register gp;
public NDS32Analyzer() {
super(PROCESSOR_NAME);
}
@Override
public boolean canAnalyze(Program program) {
boolean canAnalyze = program.getLanguage().getProcessor().equals(
Processor.findOrPossiblyCreateProcessor(PROCESSOR_NAME));
if (!canAnalyze) {
return false;
}
gp = program.getRegister("gp");
return true;
}
@Override
public void optionsChanged(Options options, Program program) {
super.optionsChanged(options, program);
options.registerOption(SWITCH_OPTION_NAME, recoverSwitchTables, null,
SWITCH_OPTION_DESCRIPTION);
recoverSwitchTables = options.getBoolean(SWITCH_OPTION_NAME, recoverSwitchTables);
options.registerOption(RECOVER_GP_OPTION_NAME, recoverGp, null,
RECOVER_GP_OPTION_DESCRIPTION);
recoverGp = options.getBoolean(RECOVER_GP_OPTION_NAME, recoverGp);
}
@Override
public boolean added(Program program, AddressSetView set, TaskMonitor monitor, MessageLog log)
throws CancelledException {
gpAssumptionValue = null;
checkForGlobalGP(program, set, monitor);
return super.added(program, set, monitor, log);
}
/**
* Check for a global GP register symbol or discovered symbol
* @param set
*/
private void checkForGlobalGP(Program program, AddressSetView set, TaskMonitor monitor) {
if (!recoverGp) {
return;
}
Symbol symbol = SymbolUtilities.getLabelOrFunctionSymbol(program, "_SDA_BASE_",
err -> Msg.error(this, err));
if (symbol != null) {
gpAssumptionValue = symbol.getAddress();
return;
}
// TODO : if the symbol doesn't exist, check manually... somewhere else
return;
}
@Override
public AddressSetView flowConstants(final Program program, Address flowStart,
AddressSetView flowSet, final SymbolicPropogator symEval, final TaskMonitor monitor)
throws CancelledException {
// get the function body
final Function func = program.getFunctionManager().getFunctionContaining(flowStart);
final AddressSet coveredSet = new AddressSet();
Address currentGPAssumptionValue = gpAssumptionValue;
// TODO : copypaste more code from MipsAddressAnalyzer to see if gp is written and act accordingly
if (func != null) {
flowStart = func.getEntryPoint();
if (currentGPAssumptionValue != null) {
ProgramContext programContext = program.getProgramContext();
RegisterValue gpVal = programContext.getRegisterValue(gp, flowStart);
if (gpVal == null || !gpVal.hasValue()) {
gpVal = new RegisterValue(gp,
BigInteger.valueOf(currentGPAssumptionValue.getOffset()));
try {
program.getProgramContext().setRegisterValue(func.getEntryPoint(),
func.getEntryPoint(), gpVal);
}
catch (ContextChangeException e) {
throw new AssertException("unexpected", e); // only happens for context register
}
}
}
}
ContextEvaluator eval = new ConstantPropagationContextEvaluator(trustWriteMemOption) {
@Override
public boolean evaluateDestination(VarnodeContext context, Instruction instruction) {
FlowType flowtype = instruction.getFlowType();
if (!flowtype.isJump()) {
return false;
}
if (recoverSwitchTables) {
String mnemonic = instruction.getMnemonicString();
if (mnemonic.equals("jr")) {
fixJumpTable(program, instruction, monitor);
}
}
return false;
}
};
AddressSet resultSet = symEval.flowConstants(flowStart, null, eval, true, monitor);
// Add in any addresses we should assume got covered
// These addresses are put on because we had to stop analysis due to an unknown register value
resultSet.add(coveredSet);
return resultSet;
}
/**
* @param program
* @param startInstr
* @param monitor
*/
private void fixJumpTable(Program program, Instruction startInstr, TaskMonitor monitor) {
/* TODO: implement switch recovery ?
* We are looking for tables like this :
*
* slti45 a0,0x4 <- table size
* beqzs8 LAB_005159ea <- default jump
* sethi ta, 0x515
* ori ta, ta, 0x9a0
* lw a0, [ta + (a0 << 0x2)] <- ref to table
* jr a0 <- table jump
*/
}
}

View File

@ -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.relocation;
public class NDS32_ElfRelocationConstants {
public static final int R_NDS32_NONE = 0;
public static final int R_NDS32_16_RELA = 19;
public static final int R_NDS32_32_RELA = 20;
public static final int R_NDS32_9_PCREL_RELA = 22;
public static final int R_NDS32_15_PCREL_RELA = 23;
public static final int R_NDS32_17_PCREL_RELA = 24;
public static final int R_NDS32_25_PCREL_RELA = 25;
public static final int R_NDS32_HI20_RELA = 26;
public static final int R_NDS32_LO12S3_RELA = 27;
public static final int R_NDS32_LO12S2_RELA = 28;
public static final int R_NDS32_LO12S1_RELA = 29;
public static final int R_NDS32_LO12S0_RELA = 30;
public static final int R_NDS32_SDA15S3_RELA = 31;
public static final int R_NDS32_SDA15S2_RELA = 32;
public static final int R_NDS32_SDA15S1_RELA = 33;
public static final int R_NDS32_SDA15S0_RELA = 34;
public static final int R_NDS32_GOT20 = 37;
public static final int R_NDS32_25_PLTREL = 38;
public static final int R_NDS32_COPY = 39;
public static final int R_NDS32_GLOB_DAT = 40;
public static final int R_NDS32_JMP_SLOT = 41;
public static final int R_NDS32_RELATIVE = 42;
public static final int R_NDS32_GOTOFF = 43;
public static final int R_NDS32_GOTPC20 = 44;
public static final int R_NDS32_GOT_HI20 = 45;
public static final int R_NDS32_GOT_LO12 = 46;
public static final int R_NDS32_GOTPC_HI20 = 47;
public static final int R_NDS32_GOTPC_LO12 = 48;
public static final int R_NDS32_GOTOFF_HI20 = 49;
public static final int R_NDS32_GOTOFF_LO12 = 50;
public static final int R_NDS32_INSN16 = 51;
public static final int R_NDS32_LABEL = 52;
public static final int R_NDS32_LONGCALL1 = 53;
public static final int R_NDS32_LONGCALL2 = 54;
public static final int R_NDS32_LONGCALL3 = 55;
public static final int R_NDS32_LONGJUMP1 = 56;
public static final int R_NDS32_LONGJUMP2 = 57;
public static final int R_NDS32_LONGJUMP3 = 58;
public static final int R_NDS32_LOADSTORE = 59;
public static final int R_NDS32_9_FIXED_RELA = 60;
public static final int R_NDS32_15_FIXED_RELA = 61;
public static final int R_NDS32_17_FIXED_RELA = 62;
public static final int R_NDS32_25_FIXED_RELA = 63;
public static final int R_NDS32_PLTREL_HI20 = 64;
public static final int R_NDS32_PLTREL_LO12 = 65;
public static final int R_NDS32_PLT_GOTREL_HI20 = 66;
public static final int R_NDS32_PLT_GOTREL_LO12 = 67;
public static final int R_NDS32_LO12S0_ORI_RELA = 72;
public static final int R_NDS32_DWARF2_OP1_RELA = 77;
public static final int R_NDS32_DWARF2_OP2_RELA = 78;
public static final int R_NDS32_DWARF2_LEB_RELA = 79;
public static final int R_NDS32_WORD_9_PCREL_RELA = 94;
public static final int R_NDS32_LONGCALL4 = 107;
public static final int R_NDS32_RELA_NOP_MIX = 192;
public static final int R_NDS32_RELA_NOP_MAX = 255;
}

View File

@ -0,0 +1,111 @@
/* ###
* 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 java.util.Map;
import ghidra.app.util.bin.format.elf.ElfConstants;
import ghidra.app.util.bin.format.elf.ElfHeader;
import ghidra.app.util.bin.format.elf.ElfLoadHelper;
import ghidra.app.util.bin.format.elf.ElfRelocation;
import ghidra.app.util.bin.format.elf.ElfRelocationTable;
import ghidra.app.util.bin.format.elf.ElfSymbol;
import ghidra.app.util.importer.MessageLog;
import ghidra.program.model.address.Address;
import ghidra.program.model.address.AddressOutOfBoundsException;
import ghidra.program.model.listing.Program;
import ghidra.program.model.mem.Memory;
import ghidra.program.model.mem.MemoryAccessException;
import ghidra.util.exception.NotFoundException;
public class NDS32_ElfRelocationHandler extends ElfRelocationHandler {
@Override
public boolean canRelocate(ElfHeader elf) {
return elf.e_machine() == ElfConstants.EM_NDS32;
}
@Override
public NDS32_ElfRelocationContext createRelocationContext(ElfLoadHelper loadHelper,
ElfRelocationTable relocationTable, Map<ElfSymbol, Address> symbolMap) {
return new NDS32_ElfRelocationContext(this, loadHelper, relocationTable, symbolMap);
}
@Override
public void relocate(ElfRelocationContext elfRelocationContext, ElfRelocation relocation, Address relocationAddress)
throws MemoryAccessException, NotFoundException {
ElfHeader elf = elfRelocationContext.getElfHeader();
if (elf.e_machine() != ElfConstants.EM_NDS32) {
return;
}
if (!elf.is32Bit()) {
return;
}
NDS32_ElfRelocationContext nds32RelocationContext =
(NDS32_ElfRelocationContext) elfRelocationContext;
int type = relocation.getType();
int symbolIndex = relocation.getSymbolIndex();
doRelocate(nds32RelocationContext, type, symbolIndex, relocation, relocationAddress);
}
private void doRelocate(NDS32_ElfRelocationContext nds32RelocationContext, int relocType,
int symbolIndex, ElfRelocation relocation, Address relocationAddress)
throws MemoryAccessException, NotFoundException, AddressOutOfBoundsException {
Program program = nds32RelocationContext.getProgram();
Memory memory = program.getMemory();
MessageLog log = nds32RelocationContext.getLog();
ElfSymbol elfSymbol = nds32RelocationContext.getSymbol(symbolIndex);
long symbolValue = nds32RelocationContext.getSymbolValue(elfSymbol);
String symbolName = elfSymbol.getNameAsString();
// Read instruction as big endian
int oldValue = memory.getInt(relocationAddress, true);
long addend = 0;
if(relocation.hasAddend()) {
addend = relocation.getAddend();
}
int value = 0;
int newValue = 0;
switch(relocType) {
case NDS32_ElfRelocationConstants.R_NDS32_HI20_RELA:
value = (int)(symbolValue + addend);
newValue = (oldValue & 0xfff00000) | (value >> 12);
memory.setInt(relocationAddress, newValue, true);
break;
case NDS32_ElfRelocationConstants.R_NDS32_LO12S0_RELA:
value = (int)(symbolValue + addend);
newValue = (oldValue & 0xfffff000) | (value & 0xfff);
memory.setInt(relocationAddress, newValue, true);
break;
default:
markAsUnhandled(program, relocationAddress, relocType, symbolIndex, symbolName, log);
}
}
private static class NDS32_ElfRelocationContext extends ElfRelocationContext {
protected NDS32_ElfRelocationContext(ElfRelocationHandler handler, ElfLoadHelper loadHelper,
ElfRelocationTable relocationTable, Map<ElfSymbol, Address> symbolMap) {
super(handler, loadHelper, relocationTable, symbolMap);
}
}
}

View File

@ -0,0 +1,41 @@
/* ###
* 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.test.processors.support.ProcessorEmulatorTestAdapter;
import junit.framework.Test;
public class NDS32_LE_O0_EmulatorTest extends ProcessorEmulatorTestAdapter {
private static final String LANGUAGE_ID = "NDS32:LE:32:default";
private static final String COMPILER_SPEC_ID = "default";
private static final String[] REG_DUMP_SET = new String[] {};
public NDS32_LE_O0_EmulatorTest(String name) throws Exception {
super(name, LANGUAGE_ID, COMPILER_SPEC_ID, REG_DUMP_SET);
}
@Override
protected String getProcessorDesignator() {
return "NDS32LE_GCC_O0";
}
public static Test suite() {
return ProcessorEmulatorTestAdapter.buildEmulatorTestSuite(NDS32_LE_O0_EmulatorTest.class);
}
}

View File

@ -0,0 +1,41 @@
/* ###
* 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.test.processors.support.ProcessorEmulatorTestAdapter;
import junit.framework.Test;
public class NDS32_LE_O3_EmulatorTest extends ProcessorEmulatorTestAdapter {
private static final String LANGUAGE_ID = "NDS32:LE:32:default";
private static final String COMPILER_SPEC_ID = "default";
private static final String[] REG_DUMP_SET = new String[] {};
public NDS32_LE_O3_EmulatorTest(String name) throws Exception {
super(name, LANGUAGE_ID, COMPILER_SPEC_ID, REG_DUMP_SET);
}
@Override
protected String getProcessorDesignator() {
return "NDS32LE_GCC_O3";
}
public static Test suite() {
return ProcessorEmulatorTestAdapter.buildEmulatorTestSuite(NDS32_LE_O3_EmulatorTest.class);
}
}

View File

@ -2,23 +2,23 @@
<!--Information from "MSP430 Embedded Application Binary Interface Rev A -->
<compiler_spec>
<data_organization>
<machine_alignment value="2" />
<default_alignment value="1" />
<default_pointer_alignment value="2" />
<pointer_size value="2" />
<short_size value="2" />
<integer_size value="2" />
<wchar_size value="2" />
<long_size value="4" />
<long_long_size value="8" />
<float_size value="4" />
<double_size value="8" />
<long_double_size value="8" />
<machine_alignment value="2"/>
<default_alignment value="1"/>
<default_pointer_alignment value="2"/>
<pointer_size value="2"/>
<short_size value="2"/>
<integer_size value="2"/>
<wchar_size value="2"/>
<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="2" />
<entry size="8" alignment="2" />
<entry size="1" alignment="1"/>
<entry size="2" alignment="2"/>
<entry size="4" alignment="2"/>
<entry size="8" alignment="2"/>
</size_alignment_map>
</data_organization>
<global>
@ -40,23 +40,43 @@
<pentry maxsize="2" minsize="1">
<register name="R15"/>
</pentry>
<pentry maxsize="500" minsize="1" align="2">
<pentry maxsize="500" minsize="1" align="1">
<addr space="stack" offset="2"/>
</pentry>
<rule>
<datatype name="struct" minsize="1"/>
<convert_to_ptr/>
</rule>
<rule>
<datatype name="any" maxsize="4"/>
<join stackspill="true"/>
</rule>
<rule>
<datatype name="any" minsize="5" maxsize="8"/>
<join stackspill="false"/>
</rule>
</input>
<output>
<pentry minsize="1" maxsize="2">
<register name="R12"/>
</pentry>
<pentry minsize="3" maxsize="4">
<addr space="join" piece1="R13" piece2="R12"/>
<pentry minsize="1" maxsize="2">
<register name="R13"/>
</pentry>
<pentry minsize="5" maxsize="6">
<addr space="join" piece1="R14" piece2="R13" piece3="R12"/>
<pentry minsize="1" maxsize="2">
<register name="R14"/>
</pentry>
<pentry minsize="7" maxsize="8">
<addr space="join" piece1="R15" piece2="R14" piece3="R13" piece4="R12"/>
<pentry minsize="1" maxsize="2">
<register name="R15"/>
</pentry>
<rule>
<datatype name="struct"/>
<hidden_return/>
</rule>
<rule>
<datatype name="any" maxsize="8"/>
<join/>
</rule>
</output>
<unaffected>
<register name="SP"/>

View File

@ -4,9 +4,9 @@
* 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.
@ -52,14 +52,14 @@ public class BookmarkPluginScreenShots extends GhidraScreenShotGenerator {
public void testBookmarks() {
removeFlowArrows();
createBookmarks();
performAction("Show Bookmarks", "BookmarkPlugin", true);
performAction("Bookmarks", "BookmarkPlugin", true);
captureIsolatedProvider(BookmarkProvider.class, 900, 300);
}
@Test
public void testBookmarksFilter() {
performAction("Show Bookmarks", "BookmarkPlugin", true);
performAction("Bookmarks", "BookmarkPlugin", true);
performAction("Filter Bookmarks", "BookmarkPlugin", false);
waitForSwing();