mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2026-05-30 09:15:43 +08:00
Merge remote-tracking branch 'origin/patch'
This commit is contained in:
@@ -36,6 +36,7 @@ language_map: Dict[str, List[str]] = {
|
|||||||
'armv4t': ['ARM:BE:32:v4t', 'ARM:LE:32:v4t'],
|
'armv4t': ['ARM:BE:32:v4t', 'ARM:LE:32:v4t'],
|
||||||
'armv5': ['ARM:BE:32:v5', 'ARM:LE:32:v5'],
|
'armv5': ['ARM:BE:32:v5', 'ARM:LE:32:v5'],
|
||||||
'armv5t': ['ARM:BE:32:v5t', 'ARM:LE:32:v5t'],
|
'armv5t': ['ARM:BE:32:v5t', 'ARM:LE:32:v5t'],
|
||||||
|
'armv5te': ['ARM:BE:32:v5t', 'ARM:LE:32:v5t'],
|
||||||
'armv5tej': ['ARM:BE:32:v5t', 'ARM:LE:32:v5t'],
|
'armv5tej': ['ARM:BE:32:v5t', 'ARM:LE:32:v5t'],
|
||||||
'armv6': ['ARM:BE:32:v6', 'ARM:LE:32:v6'],
|
'armv6': ['ARM:BE:32:v6', 'ARM:LE:32:v6'],
|
||||||
'armv6-m': ['ARM:BE:32:Cortex', 'ARM:LE:32:Cortex'],
|
'armv6-m': ['ARM:BE:32:Cortex', 'ARM:LE:32:Cortex'],
|
||||||
|
|||||||
+26
-19
@@ -17,19 +17,23 @@ package ghidra.app.plugin.core.analysis;
|
|||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.*;
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
import ghidra.app.cmd.function.CreateFunctionCmd;
|
import ghidra.app.cmd.function.CreateFunctionCmd;
|
||||||
import ghidra.app.services.*;
|
import ghidra.app.services.*;
|
||||||
import ghidra.app.util.PseudoDisassembler;
|
import ghidra.app.util.PseudoDisassembler;
|
||||||
|
import ghidra.app.util.PseudoInstruction;
|
||||||
import ghidra.app.util.bin.*;
|
import ghidra.app.util.bin.*;
|
||||||
import ghidra.app.util.bin.format.macho.MachException;
|
import ghidra.app.util.bin.format.macho.MachException;
|
||||||
import ghidra.app.util.bin.format.macho.MachHeader;
|
import ghidra.app.util.bin.format.macho.MachHeader;
|
||||||
import ghidra.app.util.bin.format.macho.commands.*;
|
import ghidra.app.util.bin.format.macho.commands.*;
|
||||||
import ghidra.app.util.bin.format.macho.dyld.*;
|
import ghidra.app.util.bin.format.macho.dyld.DyldCacheHeader;
|
||||||
|
import ghidra.app.util.bin.format.macho.dyld.DyldCacheMappingInfo;
|
||||||
import ghidra.app.util.importer.MessageLog;
|
import ghidra.app.util.importer.MessageLog;
|
||||||
import ghidra.app.util.opinion.DyldCacheLoader;
|
import ghidra.app.util.opinion.*;
|
||||||
import ghidra.app.util.opinion.MachoLoader;
|
import ghidra.app.util.opinion.DyldCacheUtils.DyldCacheImageRecord;
|
||||||
|
import ghidra.app.util.opinion.DyldCacheUtils.SplitDyldCache;
|
||||||
import ghidra.framework.options.Options;
|
import ghidra.framework.options.Options;
|
||||||
import ghidra.program.database.mem.FileBytes;
|
import ghidra.program.database.mem.FileBytes;
|
||||||
import ghidra.program.disassemble.Disassembler;
|
import ghidra.program.disassemble.Disassembler;
|
||||||
@@ -191,29 +195,31 @@ public class MachoFunctionStartsAnalyzer extends AbstractAnalyzer {
|
|||||||
private void analyzeDyldCacheFunctionStarts(Program program, List<ByteProvider> providers,
|
private void analyzeDyldCacheFunctionStarts(Program program, List<ByteProvider> providers,
|
||||||
AddressSetView set, TaskMonitor monitor, MessageLog log)
|
AddressSetView set, TaskMonitor monitor, MessageLog log)
|
||||||
throws MachException, IOException, CancelledException {
|
throws MachException, IOException, CancelledException {
|
||||||
Map<DyldCacheHeader, ByteProvider> providerMap = new HashMap<>();
|
List<DyldCacheHeader> headers = new ArrayList<>();
|
||||||
|
List<String> names = new ArrayList<>();
|
||||||
|
|
||||||
// Parse all DYLD Cache headers. There could be more that one if the DYLD Cache is "split".
|
// Parse all DYLD Cache headers. There could be more that one if the DYLD Cache is "split".
|
||||||
for (ByteProvider provider : providers) {
|
for (ByteProvider provider : providers) {
|
||||||
DyldCacheHeader header = new DyldCacheHeader(new BinaryReader(provider, true));
|
DyldCacheHeader header = new DyldCacheHeader(new BinaryReader(provider, true));
|
||||||
header.parseFromFile(false, log, monitor);
|
header.parseFromFile(false, log, monitor);
|
||||||
providerMap.put(header, provider);
|
headers.add(header);
|
||||||
|
names.add(provider.getName());
|
||||||
}
|
}
|
||||||
|
|
||||||
// Process each Mach-O header found in each DYLD Cache header
|
// Process each Mach-O header
|
||||||
for (DyldCacheHeader dyldCacheHeader : providerMap.keySet()) {
|
try (SplitDyldCache splitDyldCache =
|
||||||
List<DyldCacheImage> mappedImages = dyldCacheHeader.getMappedImages();
|
new SplitDyldCache(providers, headers, names, log, monitor)) {
|
||||||
monitor.initialize(mappedImages.size());
|
List<DyldCacheImageRecord> imageRecords = DyldCacheUtils.getImageRecords(headers);
|
||||||
for (DyldCacheImage mappedImage : mappedImages) {
|
monitor.initialize(imageRecords.size());
|
||||||
String name = new File(mappedImage.getPath()).getName();
|
for (DyldCacheImageRecord imageRecord : imageRecords) {
|
||||||
|
String name = new File(imageRecord.image().getPath()).getName();
|
||||||
monitor.checkCancelled();
|
monitor.checkCancelled();
|
||||||
monitor.setMessage("Analyzing function starts for " + name + "...");
|
monitor.setMessage("Analyzing function starts for " + name + "...");
|
||||||
monitor.incrementProgress(1);
|
monitor.incrementProgress(1);
|
||||||
|
|
||||||
// Parse Mach-O header
|
// Parse Mach-O header
|
||||||
MachHeader machoHeader = new MachHeader(providerMap.get(dyldCacheHeader),
|
MachHeader machoHeader = splitDyldCache.getMacho(imageRecord);
|
||||||
mappedImage.getAddress() - dyldCacheHeader.getBaseAddress(), false);
|
machoHeader.parse(splitDyldCache);
|
||||||
machoHeader.parse();
|
|
||||||
|
|
||||||
// The list of function starts should always be in a __LINKEDIT segment.
|
// The list of function starts should always be in a __LINKEDIT segment.
|
||||||
// If the DYLD Cache is "split", a Mach-O's __LINKEDIT segment may live in a
|
// If the DYLD Cache is "split", a Mach-O's __LINKEDIT segment may live in a
|
||||||
@@ -221,8 +227,8 @@ public class MachoFunctionStartsAnalyzer extends AbstractAnalyzer {
|
|||||||
SegmentCommand linkEdit = machoHeader.getSegment(SegmentNames.SEG_LINKEDIT);
|
SegmentCommand linkEdit = machoHeader.getSegment(SegmentNames.SEG_LINKEDIT);
|
||||||
if (linkEdit != null) {
|
if (linkEdit != null) {
|
||||||
boolean foundLinkEdit = false;
|
boolean foundLinkEdit = false;
|
||||||
for (DyldCacheHeader header : providerMap.keySet()) {
|
for (DyldCacheHeader h : headers) {
|
||||||
for (DyldCacheMappingInfo mappingInfo : header.getMappingInfos()) {
|
for (DyldCacheMappingInfo mappingInfo : h.getMappingInfos()) {
|
||||||
if (mappingInfo.contains(linkEdit.getVMaddress(), true)) {
|
if (mappingInfo.contains(linkEdit.getVMaddress(), true)) {
|
||||||
analyzeFunctionStarts(program, machoHeader, set, monitor);
|
analyzeFunctionStarts(program, machoHeader, set, monitor);
|
||||||
foundLinkEdit = true;
|
foundLinkEdit = true;
|
||||||
@@ -287,7 +293,8 @@ public class MachoFunctionStartsAnalyzer extends AbstractAnalyzer {
|
|||||||
else if (usePseudoDisassembler) {
|
else if (usePseudoDisassembler) {
|
||||||
try {
|
try {
|
||||||
final String UDF = "UDF";
|
final String UDF = "UDF";
|
||||||
if (pdis.disassemble(addr).getMnemonicString().equalsIgnoreCase(UDF)) {
|
PseudoInstruction instr = pdis.disassemble(addr);
|
||||||
|
if (instr != null && instr.getMnemonicString().equalsIgnoreCase(UDF)) {
|
||||||
skipMessage = "Skipped \"" + UDF + "\" Instruction";
|
skipMessage = "Skipped \"" + UDF + "\" Instruction";
|
||||||
}
|
}
|
||||||
else if (!pdis.isValidSubroutine(addr, true, false)) {
|
else if (!pdis.isValidSubroutine(addr, true, false)) {
|
||||||
@@ -295,7 +302,7 @@ public class MachoFunctionStartsAnalyzer extends AbstractAnalyzer {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (Exception e) {
|
catch (Exception e) {
|
||||||
// ignore
|
skipMessage = e.getMessage();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (skipMessage != null) {
|
if (skipMessage != null) {
|
||||||
|
|||||||
+16
-1
@@ -19,6 +19,7 @@ import javax.swing.Icon;
|
|||||||
|
|
||||||
import org.apache.commons.lang3.StringUtils;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
|
||||||
|
import docking.ComponentProvider;
|
||||||
import docking.action.builder.ActionBuilder;
|
import docking.action.builder.ActionBuilder;
|
||||||
import docking.tool.ToolConstants;
|
import docking.tool.ToolConstants;
|
||||||
import generic.theme.GIcon;
|
import generic.theme.GIcon;
|
||||||
@@ -85,6 +86,7 @@ public class CodeBrowserSelectionPlugin extends Plugin {
|
|||||||
.keyBinding("ctrl A")
|
.keyBinding("ctrl A")
|
||||||
.helpLocation(new HelpLocation(HelpTopics.SELECTION, "Select All"))
|
.helpLocation(new HelpLocation(HelpTopics.SELECTION, "Select All"))
|
||||||
.withContext(ListingActionContext.class, true)
|
.withContext(ListingActionContext.class, true)
|
||||||
|
.enabledWhen(this::hasCodeViewer)
|
||||||
.inWindow(ActionBuilder.When.CONTEXT_MATCHES)
|
.inWindow(ActionBuilder.When.CONTEXT_MATCHES)
|
||||||
.onAction(c -> ((CodeViewerProvider) c.getComponentProvider()).selectAll())
|
.onAction(c -> ((CodeViewerProvider) c.getComponentProvider()).selectAll())
|
||||||
.buildAndInstall(tool);
|
.buildAndInstall(tool);
|
||||||
@@ -105,6 +107,7 @@ public class CodeBrowserSelectionPlugin extends Plugin {
|
|||||||
.menuGroup(SELECT_GROUP, "c")
|
.menuGroup(SELECT_GROUP, "c")
|
||||||
.helpLocation(new HelpLocation(HelpTopics.SELECTION, "Select Complement"))
|
.helpLocation(new HelpLocation(HelpTopics.SELECTION, "Select Complement"))
|
||||||
.withContext(ListingActionContext.class, true)
|
.withContext(ListingActionContext.class, true)
|
||||||
|
.enabledWhen(this::hasCodeViewer)
|
||||||
.inWindow(ActionBuilder.When.CONTEXT_MATCHES)
|
.inWindow(ActionBuilder.When.CONTEXT_MATCHES)
|
||||||
.onAction(c -> ((CodeViewerProvider) c.getComponentProvider()).selectComplement())
|
.onAction(c -> ((CodeViewerProvider) c.getComponentProvider()).selectComplement())
|
||||||
.buildAndInstall(tool);
|
.buildAndInstall(tool);
|
||||||
@@ -116,6 +119,7 @@ public class CodeBrowserSelectionPlugin extends Plugin {
|
|||||||
.menuGroup("SelectUtils")
|
.menuGroup("SelectUtils")
|
||||||
.helpLocation(new HelpLocation(HelpTopics.CODE_BROWSER, "Selection_Tables"))
|
.helpLocation(new HelpLocation(HelpTopics.CODE_BROWSER, "Selection_Tables"))
|
||||||
.withContext(ListingActionContext.class, true)
|
.withContext(ListingActionContext.class, true)
|
||||||
|
.enabledWhen(this::hasCodeViewer)
|
||||||
.inWindow(ActionBuilder.When.CONTEXT_MATCHES)
|
.inWindow(ActionBuilder.When.CONTEXT_MATCHES)
|
||||||
.onAction(c -> createTable((CodeViewerProvider) c.getComponentProvider()))
|
.onAction(c -> createTable((CodeViewerProvider) c.getComponentProvider()))
|
||||||
.buildAndInstall(tool);
|
.buildAndInstall(tool);
|
||||||
@@ -125,6 +129,7 @@ public class CodeBrowserSelectionPlugin extends Plugin {
|
|||||||
.menuGroup("SelectUtils")
|
.menuGroup("SelectUtils")
|
||||||
.helpLocation(new HelpLocation(HelpTopics.CODE_BROWSER, "Selection_Tables"))
|
.helpLocation(new HelpLocation(HelpTopics.CODE_BROWSER, "Selection_Tables"))
|
||||||
.withContext(ListingActionContext.class, true)
|
.withContext(ListingActionContext.class, true)
|
||||||
|
.enabledWhen(this::hasCodeViewer)
|
||||||
.inWindow(ActionBuilder.When.CONTEXT_MATCHES)
|
.inWindow(ActionBuilder.When.CONTEXT_MATCHES)
|
||||||
.onAction(
|
.onAction(
|
||||||
c -> createAddressRangeTable((CodeViewerProvider) c.getComponentProvider()))
|
c -> createAddressRangeTable((CodeViewerProvider) c.getComponentProvider()))
|
||||||
@@ -193,12 +198,22 @@ public class CodeBrowserSelectionPlugin extends Plugin {
|
|||||||
tableProvider.installRemoveItemsAction();
|
tableProvider.installRemoveItemsAction();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private boolean hasCodeViewer(ListingActionContext c) {
|
||||||
|
ComponentProvider provider = c.getComponentProvider();
|
||||||
|
return provider instanceof CodeViewerProvider;
|
||||||
|
}
|
||||||
|
|
||||||
private boolean hasSelection(ListingActionContext c) {
|
private boolean hasSelection(ListingActionContext c) {
|
||||||
|
if (!hasCodeViewer(c)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
if (c.hasSelection()) {
|
if (c.hasSelection()) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
String textSelection = ((CodeViewerProvider) c.getComponentProvider()).getTextSelection();
|
CodeViewerProvider provider = (CodeViewerProvider) c.getComponentProvider();
|
||||||
|
String textSelection = provider.getTextSelection();
|
||||||
return !StringUtils.isBlank(textSelection);
|
return !StringUtils.isBlank(textSelection);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+3
@@ -187,6 +187,9 @@ public class DtFilterState {
|
|||||||
public void restore(SaveState parentSaveState) {
|
public void restore(SaveState parentSaveState) {
|
||||||
|
|
||||||
SaveState ss = parentSaveState.getSaveState(XML_NAME);
|
SaveState ss = parentSaveState.getSaveState(XML_NAME);
|
||||||
|
if (ss == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
arraysFilter = DtTypeFilter.restore("Arrays", ss.getSaveState("Arrays"));
|
arraysFilter = DtTypeFilter.restore("Arrays", ss.getSaveState("Arrays"));
|
||||||
enumsFilter = DtTypeFilter.restore("Enums", ss.getSaveState("Enums"));
|
enumsFilter = DtTypeFilter.restore("Enums", ss.getSaveState("Enums"));
|
||||||
|
|||||||
+8
-4
@@ -363,11 +363,15 @@ public class DynamicSymbolTableCommand extends LoadCommand {
|
|||||||
|
|
||||||
markupPlateComment(program, indirectSymbolTableAddr, source, "indirect");
|
markupPlateComment(program, indirectSymbolTableAddr, source, "indirect");
|
||||||
|
|
||||||
|
Address symbolTableAddr = null;
|
||||||
|
Address stringTableAddr = null;
|
||||||
SymbolTableCommand symbolTable = header.getFirstLoadCommand(SymbolTableCommand.class);
|
SymbolTableCommand symbolTable = header.getFirstLoadCommand(SymbolTableCommand.class);
|
||||||
Address symbolTableAddr = fileOffsetToAddress(program, header,
|
if (symbolTable != null) {
|
||||||
symbolTable.getSymbolOffset(), symbolTable.getNumberOfSymbols());
|
symbolTableAddr = fileOffsetToAddress(program, header, symbolTable.getSymbolOffset(),
|
||||||
Address stringTableAddr = fileOffsetToAddress(program, header,
|
symbolTable.getNumberOfSymbols());
|
||||||
symbolTable.getStringTableOffset(), symbolTable.getStringTableSize());
|
stringTableAddr = fileOffsetToAddress(program, header,
|
||||||
|
symbolTable.getStringTableOffset(), symbolTable.getStringTableSize());
|
||||||
|
}
|
||||||
|
|
||||||
ReferenceManager referenceManager = program.getReferenceManager();
|
ReferenceManager referenceManager = program.getReferenceManager();
|
||||||
try {
|
try {
|
||||||
|
|||||||
+7
-1
@@ -175,7 +175,13 @@ public abstract class LoadCommand implements StructConverter {
|
|||||||
long size) {
|
long size) {
|
||||||
if (fileOffset != 0 && size != 0) {
|
if (fileOffset != 0 && size != 0) {
|
||||||
AddressSpace space = program.getAddressFactory().getDefaultAddressSpace();
|
AddressSpace space = program.getAddressFactory().getDefaultAddressSpace();
|
||||||
SegmentCommand segment = getContainingSegment(header, fileOffset);
|
SegmentCommand segment = null;
|
||||||
|
if (getLinkerDataOffset() != 0) {
|
||||||
|
segment = header.getSegment(SegmentNames.SEG_LINKEDIT);
|
||||||
|
}
|
||||||
|
if (segment == null) {
|
||||||
|
segment = getContainingSegment(header, fileOffset);
|
||||||
|
}
|
||||||
if (segment != null) {
|
if (segment != null) {
|
||||||
return space.getAddress(
|
return space.getAddress(
|
||||||
segment.getVMaddress() + (fileOffset - segment.getFileOffset()));
|
segment.getVMaddress() + (fileOffset - segment.getFileOffset()));
|
||||||
|
|||||||
+1
-1
@@ -36,7 +36,7 @@ import ghidra.util.task.TaskMonitor;
|
|||||||
/**
|
/**
|
||||||
* Represents a dyld_cache_accelerator_info structure.
|
* Represents a dyld_cache_accelerator_info structure.
|
||||||
*
|
*
|
||||||
* @see <a href="https://github.com/apple-oss-distributions/dyld/blob/main/cache-builder/dyld_cache_format.h">dyld_cache_format.h</a>
|
* @see <a href="https://github.com/apple-oss-distributions/dyld/blob/main/include/mach-o/dyld_cache_format.h">dyld_cache_format.h</a>
|
||||||
*/
|
*/
|
||||||
@SuppressWarnings("unused")
|
@SuppressWarnings("unused")
|
||||||
public class DyldCacheAccelerateInfo implements StructConverter {
|
public class DyldCacheAccelerateInfo implements StructConverter {
|
||||||
|
|||||||
+3
-3
@@ -4,9 +4,9 @@
|
|||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
* You may obtain a copy of the License at
|
* You may obtain a copy of the License at
|
||||||
*
|
*
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
*
|
*
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
@@ -26,7 +26,7 @@ import ghidra.util.exception.DuplicateNameException;
|
|||||||
/**
|
/**
|
||||||
* Represents a dyld_cache_accelerator_dof structure.
|
* Represents a dyld_cache_accelerator_dof structure.
|
||||||
*
|
*
|
||||||
* @see <a href="https://github.com/apple-oss-distributions/dyld/blob/main/cache-builder/dyld_cache_format.h">dyld_cache_format.h</a>
|
* @see <a href="https://github.com/apple-oss-distributions/dyld/blob/main/include/mach-o/dyld_cache_format.h">dyld_cache_format.h</a>
|
||||||
*/
|
*/
|
||||||
@SuppressWarnings("unused")
|
@SuppressWarnings("unused")
|
||||||
public class DyldCacheAcceleratorDof implements StructConverter {
|
public class DyldCacheAcceleratorDof implements StructConverter {
|
||||||
|
|||||||
+3
-3
@@ -4,9 +4,9 @@
|
|||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
* You may obtain a copy of the License at
|
* You may obtain a copy of the License at
|
||||||
*
|
*
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
*
|
*
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
@@ -26,7 +26,7 @@ import ghidra.util.exception.DuplicateNameException;
|
|||||||
/**
|
/**
|
||||||
* Represents a dyld_cache_accelerator_initializer structure.
|
* Represents a dyld_cache_accelerator_initializer structure.
|
||||||
*
|
*
|
||||||
* @see <a href="https://github.com/apple-oss-distributions/dyld/blob/main/cache-builder/dyld_cache_format.h">dyld_cache_format.h</a>
|
* @see <a href="https://github.com/apple-oss-distributions/dyld/blob/main/include/mach-o/dyld_cache_format.h">dyld_cache_format.h</a>
|
||||||
*/
|
*/
|
||||||
@SuppressWarnings("unused")
|
@SuppressWarnings("unused")
|
||||||
public class DyldCacheAcceleratorInitializer implements StructConverter {
|
public class DyldCacheAcceleratorInitializer implements StructConverter {
|
||||||
|
|||||||
+53
-20
@@ -34,7 +34,7 @@ import ghidra.util.task.TaskMonitor;
|
|||||||
/**
|
/**
|
||||||
* Represents a dyld_cache_header structure.
|
* Represents a dyld_cache_header structure.
|
||||||
*
|
*
|
||||||
* @see <a href="https://github.com/apple-oss-distributions/dyld/blob/main/cache-builder/dyld_cache_format.h">dyld_cache_format.h</a>
|
* @see <a href="https://github.com/apple-oss-distributions/dyld/blob/main/include/mach-o/dyld_cache_format.h">dyld_cache_format.h</a>
|
||||||
*/
|
*/
|
||||||
public class DyldCacheHeader implements StructConverter {
|
public class DyldCacheHeader implements StructConverter {
|
||||||
|
|
||||||
@@ -115,6 +115,10 @@ public class DyldCacheHeader implements StructConverter {
|
|||||||
private long dynamicDataMaxSize;
|
private long dynamicDataMaxSize;
|
||||||
private int tproMappingsOffset;
|
private int tproMappingsOffset;
|
||||||
private int tproMappingsCount;
|
private int tproMappingsCount;
|
||||||
|
private long functionVariantInfoAddr;
|
||||||
|
private long functionVariantInfoSize;
|
||||||
|
private long prewarmingDataOffset;
|
||||||
|
private long prewarmingDataSize;
|
||||||
|
|
||||||
private int headerSize;
|
private int headerSize;
|
||||||
private BinaryReader reader;
|
private BinaryReader reader;
|
||||||
@@ -358,6 +362,18 @@ public class DyldCacheHeader implements StructConverter {
|
|||||||
if (reader.getPointerIndex() < mappingOffset) {
|
if (reader.getPointerIndex() < mappingOffset) {
|
||||||
tproMappingsCount = reader.readNextInt();
|
tproMappingsCount = reader.readNextInt();
|
||||||
}
|
}
|
||||||
|
if (reader.getPointerIndex() < mappingOffset) {
|
||||||
|
functionVariantInfoAddr = reader.readNextLong();
|
||||||
|
}
|
||||||
|
if (reader.getPointerIndex() < mappingOffset) {
|
||||||
|
functionVariantInfoSize = reader.readNextLong();
|
||||||
|
}
|
||||||
|
if (reader.getPointerIndex() < mappingOffset) {
|
||||||
|
prewarmingDataOffset = reader.readNextLong();
|
||||||
|
}
|
||||||
|
if (reader.getPointerIndex() < mappingOffset) {
|
||||||
|
prewarmingDataSize = reader.readNextLong();
|
||||||
|
}
|
||||||
|
|
||||||
headerSize = (int) (reader.getPointerIndex() - startIndex);
|
headerSize = (int) (reader.getPointerIndex() - startIndex);
|
||||||
|
|
||||||
@@ -1025,6 +1041,34 @@ public class DyldCacheHeader implements StructConverter {
|
|||||||
return tproMappingsCount;
|
return tproMappingsCount;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@return the function variant info address}
|
||||||
|
*/
|
||||||
|
public long getFunctionVariantInfoAddr() {
|
||||||
|
return functionVariantInfoAddr;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@return the function variant info size}
|
||||||
|
*/
|
||||||
|
public long getFunctionVariantInfoSize() {
|
||||||
|
return functionVariantInfoSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@return the pre-warming data offset}
|
||||||
|
*/
|
||||||
|
public long getPreWarmingDataOffset() {
|
||||||
|
return prewarmingDataOffset;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@return the pre-warming data size}
|
||||||
|
*/
|
||||||
|
public long getPreWarmingDataSize() {
|
||||||
|
return prewarmingDataSize;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* {@return the reader associated with the header}
|
* {@return the reader associated with the header}
|
||||||
*
|
*
|
||||||
@@ -1052,27 +1096,12 @@ public class DyldCacheHeader implements StructConverter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Generates a {@link List} of {@link DyldCacheImage}s that are mapped in by this
|
* Gets the {@link List} of {@link DyldCacheImageInfo}s. Requires header to have been parsed.
|
||||||
* {@link DyldCacheHeader}. Requires header to have been parsed.
|
|
||||||
* <p>
|
|
||||||
* NOTE: A DYLD subcache header may declare an image, but that image may get loaded at an
|
|
||||||
* address defined by the memory map of a different subcache header. This method will only
|
|
||||||
* return the images that are mapped by "this" header's memory map.
|
|
||||||
*
|
*
|
||||||
* @return A {@link List} of {@link DyldCacheImage}s mapped by this {@link DyldCacheHeader}
|
* @return The {@link List} of {@link DyldCacheImageInfo}s
|
||||||
*/
|
*/
|
||||||
public List<DyldCacheImage> getMappedImages() {
|
public List<DyldCacheImageInfo> getImageInfos() {
|
||||||
// NOTE: A subcache will have an entry for every image, but not every image will be mapped
|
return imageInfoList;
|
||||||
List<DyldCacheImage> images = new ArrayList<>();
|
|
||||||
for (DyldCacheImage imageInfo : imageInfoList) {
|
|
||||||
for (DyldCacheMappingInfo mappingInfo : mappingInfoList) {
|
|
||||||
if (mappingInfo.contains(imageInfo.getAddress(), true)) {
|
|
||||||
images.add(imageInfo);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return images;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -1213,6 +1242,10 @@ public class DyldCacheHeader implements StructConverter {
|
|||||||
addHeaderField(struct, QWORD, "dynamicDataMaxSize", "maximum size of space reserved from dynamic data");
|
addHeaderField(struct, QWORD, "dynamicDataMaxSize", "maximum size of space reserved from dynamic data");
|
||||||
addHeaderField(struct, DWORD, "tproMappingsOffset", "file offset to first dyld_cache_tpro_mapping_info");
|
addHeaderField(struct, DWORD, "tproMappingsOffset", "file offset to first dyld_cache_tpro_mapping_info");
|
||||||
addHeaderField(struct, DWORD, "tproMappingsCount", "number of dyld_cache_tpro_mapping_info entries");
|
addHeaderField(struct, DWORD, "tproMappingsCount", "number of dyld_cache_tpro_mapping_info entries");
|
||||||
|
addHeaderField(struct, QWORD, "functionVariantInfoAddr", "(unslid) address of dyld_cache_function_variant_info");
|
||||||
|
addHeaderField(struct, QWORD, "functionVariantInfoSize", "Size of all of the variant information pointed to via the dyld_cache_function_variant_info");
|
||||||
|
addHeaderField(struct, QWORD, "prewarmingDataOffset", "file offset to dyld_prewarming_header");
|
||||||
|
addHeaderField(struct, QWORD, "prewarmingDataSize", "byte size of prewarming data");
|
||||||
// @formatter:on
|
// @formatter:on
|
||||||
|
|
||||||
struct.setCategoryPath(new CategoryPath(MachConstants.DATA_TYPE_CATEGORY));
|
struct.setCategoryPath(new CategoryPath(MachConstants.DATA_TYPE_CATEGORY));
|
||||||
|
|||||||
+3
-3
@@ -4,9 +4,9 @@
|
|||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
* You may obtain a copy of the License at
|
* You may obtain a copy of the License at
|
||||||
*
|
*
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
*
|
*
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
@@ -26,7 +26,7 @@ import ghidra.util.exception.DuplicateNameException;
|
|||||||
/**
|
/**
|
||||||
* Represents a dyld_cache_image_info structure.
|
* Represents a dyld_cache_image_info structure.
|
||||||
*
|
*
|
||||||
* @see <a href="https://github.com/apple-oss-distributions/dyld/blob/main/cache-builder/dyld_cache_format.h">dyld_cache_format.h</a>
|
* @see <a href="https://github.com/apple-oss-distributions/dyld/blob/main/include/mach-o/dyld_cache_format.h">dyld_cache_format.h</a>
|
||||||
*/
|
*/
|
||||||
@SuppressWarnings("unused")
|
@SuppressWarnings("unused")
|
||||||
public class DyldCacheImageInfo implements DyldCacheImage, StructConverter {
|
public class DyldCacheImageInfo implements DyldCacheImage, StructConverter {
|
||||||
|
|||||||
+3
-3
@@ -4,9 +4,9 @@
|
|||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
* You may obtain a copy of the License at
|
* You may obtain a copy of the License at
|
||||||
*
|
*
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
*
|
*
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
@@ -26,7 +26,7 @@ import ghidra.util.exception.DuplicateNameException;
|
|||||||
/**
|
/**
|
||||||
* Represents a dyld_cache_image_info_extra structure.
|
* Represents a dyld_cache_image_info_extra structure.
|
||||||
*
|
*
|
||||||
* @see <a href="https://github.com/apple-oss-distributions/dyld/blob/main/cache-builder/dyld_cache_format.h">dyld_cache_format.h</a>
|
* @see <a href="https://github.com/apple-oss-distributions/dyld/blob/main/include/mach-o/dyld_cache_format.h">dyld_cache_format.h</a>
|
||||||
*/
|
*/
|
||||||
@SuppressWarnings("unused")
|
@SuppressWarnings("unused")
|
||||||
public class DyldCacheImageInfoExtra implements StructConverter {
|
public class DyldCacheImageInfoExtra implements StructConverter {
|
||||||
|
|||||||
+3
-3
@@ -4,9 +4,9 @@
|
|||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
* You may obtain a copy of the License at
|
* You may obtain a copy of the License at
|
||||||
*
|
*
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
*
|
*
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
@@ -26,7 +26,7 @@ import ghidra.util.exception.DuplicateNameException;
|
|||||||
/**
|
/**
|
||||||
* Represents a dyld_cache_image_text_info structure.
|
* Represents a dyld_cache_image_text_info structure.
|
||||||
*
|
*
|
||||||
* @see <a href="https://github.com/apple-oss-distributions/dyld/blob/main/cache-builder/dyld_cache_format.h">dyld_cache_format.h</a>
|
* @see <a href="https://github.com/apple-oss-distributions/dyld/blob/main/include/mach-o/dyld_cache_format.h">dyld_cache_format.h</a>
|
||||||
*/
|
*/
|
||||||
@SuppressWarnings("unused")
|
@SuppressWarnings("unused")
|
||||||
public class DyldCacheImageTextInfo implements DyldCacheImage, StructConverter {
|
public class DyldCacheImageTextInfo implements DyldCacheImage, StructConverter {
|
||||||
|
|||||||
+3
-3
@@ -4,9 +4,9 @@
|
|||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
* You may obtain a copy of the License at
|
* You may obtain a copy of the License at
|
||||||
*
|
*
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
*
|
*
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
@@ -26,7 +26,7 @@ import ghidra.util.exception.DuplicateNameException;
|
|||||||
/**
|
/**
|
||||||
* Represents a dyld_cache_local_symbols_entry structure.
|
* Represents a dyld_cache_local_symbols_entry structure.
|
||||||
*
|
*
|
||||||
* @see <a href="https://github.com/apple-oss-distributions/dyld/blob/main/cache-builder/dyld_cache_format.h">dyld_cache_format.h</a>
|
* @see <a href="https://github.com/apple-oss-distributions/dyld/blob/main/include/mach-o/dyld_cache_format.h">dyld_cache_format.h</a>
|
||||||
*/
|
*/
|
||||||
public class DyldCacheLocalSymbolsEntry implements StructConverter {
|
public class DyldCacheLocalSymbolsEntry implements StructConverter {
|
||||||
|
|
||||||
|
|||||||
+3
-3
@@ -4,9 +4,9 @@
|
|||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
* You may obtain a copy of the License at
|
* You may obtain a copy of the License at
|
||||||
*
|
*
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
*
|
*
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
@@ -38,7 +38,7 @@ import ghidra.util.task.TaskMonitor;
|
|||||||
/**
|
/**
|
||||||
* Represents a dyld_cache_local_symbols_info structure.
|
* Represents a dyld_cache_local_symbols_info structure.
|
||||||
*
|
*
|
||||||
* @see <a href="https://github.com/apple-oss-distributions/dyld/blob/main/cache-builder/dyld_cache_format.h">dyld_cache_format.h</a>
|
* @see <a href="https://github.com/apple-oss-distributions/dyld/blob/main/include/mach-o/dyld_cache_format.h">dyld_cache_format.h</a>
|
||||||
*/
|
*/
|
||||||
@SuppressWarnings("unused")
|
@SuppressWarnings("unused")
|
||||||
public class DyldCacheLocalSymbolsInfo implements StructConverter {
|
public class DyldCacheLocalSymbolsInfo implements StructConverter {
|
||||||
|
|||||||
+1
-1
@@ -27,7 +27,7 @@ import ghidra.util.exception.DuplicateNameException;
|
|||||||
/**
|
/**
|
||||||
* Represents a dyld_cache_mapping_and_slide_info structure.
|
* Represents a dyld_cache_mapping_and_slide_info structure.
|
||||||
*
|
*
|
||||||
* @see <a href="https://github.com/apple-oss-distributions/dyld/blob/main/cache-builder/dyld_cache_format.h">dyld_cache_format.h</a>
|
* @see <a href="https://github.com/apple-oss-distributions/dyld/blob/main/include/mach-o/dyld_cache_format.h">dyld_cache_format.h</a>
|
||||||
*/
|
*/
|
||||||
@SuppressWarnings("unused")
|
@SuppressWarnings("unused")
|
||||||
public class DyldCacheMappingAndSlideInfo implements StructConverter {
|
public class DyldCacheMappingAndSlideInfo implements StructConverter {
|
||||||
|
|||||||
+1
-1
@@ -27,7 +27,7 @@ import ghidra.util.exception.DuplicateNameException;
|
|||||||
/**
|
/**
|
||||||
* Represents a dyld_cache_mapping_info structure.
|
* Represents a dyld_cache_mapping_info structure.
|
||||||
*
|
*
|
||||||
* @see <a href="https://github.com/apple-oss-distributions/dyld/blob/main/cache-builder/dyld_cache_format.h">dyld_cache_format.h</a>
|
* @see <a href="https://github.com/apple-oss-distributions/dyld/blob/main/include/mach-o/dyld_cache_format.h">dyld_cache_format.h</a>
|
||||||
*/
|
*/
|
||||||
@SuppressWarnings("unused")
|
@SuppressWarnings("unused")
|
||||||
public class DyldCacheMappingInfo implements StructConverter {
|
public class DyldCacheMappingInfo implements StructConverter {
|
||||||
|
|||||||
+3
-3
@@ -4,9 +4,9 @@
|
|||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
* You may obtain a copy of the License at
|
* You may obtain a copy of the License at
|
||||||
*
|
*
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
*
|
*
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
@@ -26,7 +26,7 @@ import ghidra.util.exception.DuplicateNameException;
|
|||||||
/**
|
/**
|
||||||
* Represents a dyld_cache_range_entry structure.
|
* Represents a dyld_cache_range_entry structure.
|
||||||
*
|
*
|
||||||
* @see <a href="https://github.com/apple-oss-distributions/dyld/blob/main/cache-builder/dyld_cache_format.h">dyld_cache_format.h</a>
|
* @see <a href="https://github.com/apple-oss-distributions/dyld/blob/main/include/mach-o/dyld_cache_format.h">dyld_cache_format.h</a>
|
||||||
*/
|
*/
|
||||||
@SuppressWarnings("unused")
|
@SuppressWarnings("unused")
|
||||||
public class DyldCacheRangeEntry implements StructConverter {
|
public class DyldCacheRangeEntry implements StructConverter {
|
||||||
|
|||||||
+1
-1
@@ -38,7 +38,7 @@ import ghidra.util.task.TaskMonitor;
|
|||||||
* The intent is for the full dyld_cache_slide_info structures to extend this and add their
|
* The intent is for the full dyld_cache_slide_info structures to extend this and add their
|
||||||
* specific parts.
|
* specific parts.
|
||||||
*
|
*
|
||||||
* @see <a href="https://github.com/apple-oss-distributions/dyld/blob/main/cache-builder/dyld_cache_format.h">dyld_cache_format.h</a>
|
* @see <a href="https://github.com/apple-oss-distributions/dyld/blob/main/include/mach-o/dyld_cache_format.h">dyld_cache_format.h</a>
|
||||||
*/
|
*/
|
||||||
public abstract class DyldCacheSlideInfoCommon implements StructConverter {
|
public abstract class DyldCacheSlideInfoCommon implements StructConverter {
|
||||||
|
|
||||||
|
|||||||
+3
-3
@@ -4,9 +4,9 @@
|
|||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
* You may obtain a copy of the License at
|
* You may obtain a copy of the License at
|
||||||
*
|
*
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
*
|
*
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
@@ -28,7 +28,7 @@ import ghidra.util.exception.DuplicateNameException;
|
|||||||
/**
|
/**
|
||||||
* Represents a dyld_subcache_entry structure.
|
* Represents a dyld_subcache_entry structure.
|
||||||
*
|
*
|
||||||
* @see <a href="https://github.com/apple-oss-distributions/dyld/blob/main/cache-builder/dyld_cache_format.h">dyld_cache_format.h</a>
|
* @see <a href="https://github.com/apple-oss-distributions/dyld/blob/main/include/mach-o/dyld_cache_format.h">dyld_cache_format.h</a>
|
||||||
*/
|
*/
|
||||||
public class DyldSubcacheEntry implements StructConverter {
|
public class DyldSubcacheEntry implements StructConverter {
|
||||||
|
|
||||||
|
|||||||
+17
-15
@@ -26,6 +26,7 @@ import ghidra.app.util.bin.format.macho.*;
|
|||||||
import ghidra.app.util.bin.format.macho.commands.*;
|
import ghidra.app.util.bin.format.macho.commands.*;
|
||||||
import ghidra.app.util.bin.format.macho.dyld.*;
|
import ghidra.app.util.bin.format.macho.dyld.*;
|
||||||
import ghidra.app.util.importer.MessageLog;
|
import ghidra.app.util.importer.MessageLog;
|
||||||
|
import ghidra.app.util.opinion.DyldCacheUtils.DyldCacheImageRecord;
|
||||||
import ghidra.app.util.opinion.DyldCacheUtils.SplitDyldCache;
|
import ghidra.app.util.opinion.DyldCacheUtils.SplitDyldCache;
|
||||||
import ghidra.program.database.mem.FileBytes;
|
import ghidra.program.database.mem.FileBytes;
|
||||||
import ghidra.program.model.address.Address;
|
import ghidra.program.model.address.Address;
|
||||||
@@ -109,6 +110,9 @@ public class DyldCacheProgramBuilder extends MachoProgramBuilder {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Process DYLIBs
|
||||||
|
processDylibs(splitDyldCache, localSymbolsPresent);
|
||||||
|
|
||||||
// Perform additional DYLD processing
|
// Perform additional DYLD processing
|
||||||
for (int i = 0; i < splitDyldCache.size(); i++) {
|
for (int i = 0; i < splitDyldCache.size(); i++) {
|
||||||
DyldCacheHeader header = splitDyldCache.getDyldCacheHeader(i);
|
DyldCacheHeader header = splitDyldCache.getDyldCacheHeader(i);
|
||||||
@@ -118,7 +122,6 @@ public class DyldCacheProgramBuilder extends MachoProgramBuilder {
|
|||||||
markupHeaders(header);
|
markupHeaders(header);
|
||||||
markupBranchIslands(header, bp);
|
markupBranchIslands(header, bp);
|
||||||
createLocalSymbols(header);
|
createLocalSymbols(header);
|
||||||
processDylibs(splitDyldCache, header, bp, localSymbolsPresent);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -310,27 +313,26 @@ public class DyldCacheProgramBuilder extends MachoProgramBuilder {
|
|||||||
* Processes the DYLD Cache's DYLIB files. This will mark up the DYLIB files, added them to the
|
* Processes the DYLD Cache's DYLIB files. This will mark up the DYLIB files, added them to the
|
||||||
* program tree, and make memory blocks for them.
|
* program tree, and make memory blocks for them.
|
||||||
*
|
*
|
||||||
* @param dyldCacheHeader The {@link DyldCacheHeader}
|
|
||||||
* @param bp The corresponding {@link ByteProvider}
|
|
||||||
* @param localSymbolsPresent True if DYLD local symbols are present; otherwise, false
|
* @param localSymbolsPresent True if DYLD local symbols are present; otherwise, false
|
||||||
* @throws Exception if there was a problem processing the DYLIB files
|
* @throws Exception if there was a problem processing the DYLIB files
|
||||||
*/
|
*/
|
||||||
private void processDylibs(SplitDyldCache splitDyldCache, DyldCacheHeader dyldCacheHeader,
|
private void processDylibs(SplitDyldCache splitDyldCache, boolean localSymbolsPresent)
|
||||||
ByteProvider bp, boolean localSymbolsPresent) throws Exception {
|
throws Exception {
|
||||||
// Create an "info" object for each DyldCache DYLIB, which will make processing them
|
// Create an "info" object for each DyldCache DYLIB, which will make processing them
|
||||||
// easier. Save off the "libobjc" DYLIB for additional processing later.
|
// easier. Save off the "libobjc" DYLIB for additional processing later.
|
||||||
monitor.setMessage("Parsing DYLIB's...");
|
monitor.setMessage("Parsing DYLIB's...");
|
||||||
DyldCacheMachoInfo libobjcInfo = null;
|
DyldCacheMachoInfo libobjcInfo = null;
|
||||||
TreeSet<DyldCacheMachoInfo> infoSet =
|
TreeSet<DyldCacheMachoInfo> infoSet =
|
||||||
new TreeSet<>((a, b) -> a.headerAddr.compareTo(b.headerAddr));
|
new TreeSet<>((a, b) -> a.headerAddr.compareTo(b.headerAddr));
|
||||||
List<DyldCacheImage> mappedImages = dyldCacheHeader.getMappedImages();
|
List<DyldCacheImageRecord> imageRecords = splitDyldCache.getImageRecords();
|
||||||
monitor.initialize(mappedImages.size());
|
monitor.initialize(imageRecords.size());
|
||||||
for (DyldCacheImage mappedImage : mappedImages) {
|
for (DyldCacheImageRecord imageRecord : imageRecords) {
|
||||||
monitor.checkCancelled();
|
monitor.checkCancelled();
|
||||||
monitor.incrementProgress(1);
|
monitor.incrementProgress(1);
|
||||||
DyldCacheMachoInfo info = new DyldCacheMachoInfo(splitDyldCache, bp,
|
DyldCacheImage image = imageRecord.image();
|
||||||
mappedImage.getAddress() - dyldCacheHeader.getBaseAddress(),
|
DyldCacheMachoInfo info =
|
||||||
space.getAddress(mappedImage.getAddress()), mappedImage.getPath());
|
new DyldCacheMachoInfo(splitDyldCache, splitDyldCache.getMacho(imageRecord),
|
||||||
|
space.getAddress(image.getAddress()), image.getPath());
|
||||||
infoSet.add(info);
|
infoSet.add(info);
|
||||||
if (libobjcInfo == null && info.name.contains("libobjc.")) {
|
if (libobjcInfo == null && info.name.contains("libobjc.")) {
|
||||||
libobjcInfo = info;
|
libobjcInfo = info;
|
||||||
@@ -427,15 +429,15 @@ public class DyldCacheProgramBuilder extends MachoProgramBuilder {
|
|||||||
* Creates a new {@link DyldCacheMachoInfo} object with the given parameters.
|
* Creates a new {@link DyldCacheMachoInfo} object with the given parameters.
|
||||||
*
|
*
|
||||||
* @param splitDyldCache The {@link SplitDyldCache}
|
* @param splitDyldCache The {@link SplitDyldCache}
|
||||||
* @param provider The {@link ByteProvider} that contains the Mach-O's bytes
|
* @param header The {@link MachHeader#parse(SplitDyldCache) unparsed} {@link MachHeader}
|
||||||
* @param offset The offset in the provider to the start of the Mach-O
|
|
||||||
* @param headerAddr The Mach-O's header address
|
* @param headerAddr The Mach-O's header address
|
||||||
* @param path The path of the Mach-O
|
* @param path The path of the Mach-O
|
||||||
* @throws Exception If there was a problem handling the Mach-O info
|
* @throws Exception If there was a problem handling the Mach-O info
|
||||||
*/
|
*/
|
||||||
public DyldCacheMachoInfo(SplitDyldCache splitDyldCache, ByteProvider provider, long offset, Address headerAddr, String path) throws Exception {
|
public DyldCacheMachoInfo(SplitDyldCache splitDyldCache, MachHeader header,
|
||||||
|
Address headerAddr, String path) throws Exception {
|
||||||
this.headerAddr = headerAddr;
|
this.headerAddr = headerAddr;
|
||||||
this.header = new MachHeader(provider, offset, false);
|
this.header = header;
|
||||||
this.header.parse(splitDyldCache);
|
this.header.parse(splitDyldCache);
|
||||||
this.path = path;
|
this.path = path;
|
||||||
this.name = new File(path).getName();
|
this.name = new File(path).getName();
|
||||||
|
|||||||
@@ -21,6 +21,8 @@ import java.util.*;
|
|||||||
|
|
||||||
import ghidra.app.util.bin.BinaryReader;
|
import ghidra.app.util.bin.BinaryReader;
|
||||||
import ghidra.app.util.bin.ByteProvider;
|
import ghidra.app.util.bin.ByteProvider;
|
||||||
|
import ghidra.app.util.bin.format.macho.MachException;
|
||||||
|
import ghidra.app.util.bin.format.macho.MachHeader;
|
||||||
import ghidra.app.util.bin.format.macho.dyld.*;
|
import ghidra.app.util.bin.format.macho.dyld.*;
|
||||||
import ghidra.app.util.importer.MessageLog;
|
import ghidra.app.util.importer.MessageLog;
|
||||||
import ghidra.formats.gfilesystem.*;
|
import ghidra.formats.gfilesystem.*;
|
||||||
@@ -80,6 +82,43 @@ public class DyldCacheUtils {
|
|||||||
return isDyldCache(new String(bytes).trim());
|
return isDyldCache(new String(bytes).trim());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A {@link DyldCacheImage} and its corresponding metadata
|
||||||
|
*
|
||||||
|
* @param image The {@link DyldCacheImage}
|
||||||
|
* @param splitCacheIndex The image's index in the {@link SplitDyldCache}
|
||||||
|
*/
|
||||||
|
public record DyldCacheImageRecord(DyldCacheImage image, int splitCacheIndex) {}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets all the {@link DyldCacheImageRecord}s for the given {@link List} of
|
||||||
|
* {@link DyldCacheHeader}s
|
||||||
|
*
|
||||||
|
* @param headers The {@link List} of {@link DyldCacheHeader}s
|
||||||
|
* @return A {@link List} of {@link DyldCacheImageRecord}s
|
||||||
|
*/
|
||||||
|
public final static List<DyldCacheImageRecord> getImageRecords(List<DyldCacheHeader> headers) {
|
||||||
|
Set<Long> addrs = new HashSet<>();
|
||||||
|
List<DyldCacheImageRecord> imageRecords = new ArrayList<>();
|
||||||
|
for (DyldCacheHeader header : headers) {
|
||||||
|
for (DyldCacheImage image : header.getImageInfos()) {
|
||||||
|
if (addrs.contains(image.getAddress())) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
for (int i = 0; i < headers.size(); i++) {
|
||||||
|
for (DyldCacheMappingInfo mappingInfo : headers.get(i).getMappingInfos()) {
|
||||||
|
if (mappingInfo.contains(image.getAddress(), true)) {
|
||||||
|
imageRecords.add(new DyldCacheImageRecord(image, i));
|
||||||
|
addrs.add(image.getAddress());
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return imageRecords;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Determines if the given signature represents a DYLD cache signature with an architecture we
|
* Determines if the given signature represents a DYLD cache signature with an architecture we
|
||||||
* support.
|
* support.
|
||||||
@@ -106,7 +145,7 @@ public class DyldCacheUtils {
|
|||||||
private List<ByteProvider> providers = new ArrayList<>();
|
private List<ByteProvider> providers = new ArrayList<>();
|
||||||
private List<DyldCacheHeader> headers = new ArrayList<>();
|
private List<DyldCacheHeader> headers = new ArrayList<>();
|
||||||
private List<String> names = new ArrayList<>();
|
private List<String> names = new ArrayList<>();
|
||||||
private FileSystemService fsService;
|
private FileSystemService fsService = FileSystemService.getInstance();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a new {@link SplitDyldCache}
|
* Creates a new {@link SplitDyldCache}
|
||||||
@@ -135,7 +174,6 @@ public class DyldCacheUtils {
|
|||||||
baseHeader.getSymbolFileUUID() == null) {
|
baseHeader.getSymbolFileUUID() == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
fsService = FileSystemService.getInstance();
|
|
||||||
Map<String, FSRL> uuidToFileMap = new HashMap<>();
|
Map<String, FSRL> uuidToFileMap = new HashMap<>();
|
||||||
for (FSRL splitFSRL : findSplitDyldCacheFiles(baseProvider.getFSRL(), monitor)) {
|
for (FSRL splitFSRL : findSplitDyldCacheFiles(baseProvider.getFSRL(), monitor)) {
|
||||||
monitor.setMessage("Parsing " + splitFSRL.getName() + " headers...");
|
monitor.setMessage("Parsing " + splitFSRL.getName() + " headers...");
|
||||||
@@ -179,6 +217,22 @@ public class DyldCacheUtils {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new {@link SplitDyldCache}
|
||||||
|
*
|
||||||
|
* @param providers The cache's ordered {@link ByteProvider}s
|
||||||
|
* @param headers The cache's ordered {@link DyldCacheHeader}s
|
||||||
|
* @param names The cache's ordered names
|
||||||
|
* @param log The log
|
||||||
|
* @param monitor A cancelable task monitor
|
||||||
|
*/
|
||||||
|
public SplitDyldCache(List<ByteProvider> providers, List<DyldCacheHeader> headers,
|
||||||
|
List<String> names, MessageLog log, TaskMonitor monitor) {
|
||||||
|
this.providers = new ArrayList<>(providers);
|
||||||
|
this.headers = new ArrayList<>(headers);
|
||||||
|
this.names = new ArrayList<>(names);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the i'th {@link ByteProvider} in the split DYLD Cache
|
* Gets the i'th {@link ByteProvider} in the split DYLD Cache
|
||||||
*
|
*
|
||||||
@@ -242,6 +296,33 @@ public class DyldCacheUtils {
|
|||||||
.orElse(null);
|
.orElse(null);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets all the {@link DyldCacheImageRecord}s from the entire cache
|
||||||
|
*
|
||||||
|
* @return A {@link List} of {@link DyldCacheImageRecord}s from the entire cache
|
||||||
|
*/
|
||||||
|
public List<DyldCacheImageRecord> getImageRecords() {
|
||||||
|
return DyldCacheUtils.getImageRecords(headers);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the Mach-O of the given {@link DyldCacheImageRecord}.
|
||||||
|
* <p>
|
||||||
|
* NOTE: The returned Mach-O is not yet {@link MachHeader#parse(SplitDyldCache) parsed}.
|
||||||
|
*
|
||||||
|
* @param imageRecord The desired Mach-O's {@link DyldCacheImageRecord}
|
||||||
|
* @return The {@link DyldCacheImageRecord}'s Mach-O
|
||||||
|
* @throws MachException If there was a problem creating the {@link MachHeader}
|
||||||
|
* @throws IOException If there was an IO-related error
|
||||||
|
*/
|
||||||
|
public MachHeader getMacho(DyldCacheImageRecord imageRecord)
|
||||||
|
throws MachException, IOException {
|
||||||
|
int i = imageRecord.splitCacheIndex();
|
||||||
|
DyldCacheImage image = imageRecord.image();
|
||||||
|
return new MachHeader(providers.get(i),
|
||||||
|
image.getAddress() - headers.get(i).getBaseAddress(), false);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void close() throws IOException {
|
public void close() throws IOException {
|
||||||
// Assume someone else is responsible for closing the base providers that was passed
|
// Assume someone else is responsible for closing the base providers that was passed
|
||||||
|
|||||||
+16
-18
@@ -28,6 +28,7 @@ import ghidra.app.util.bin.format.macho.MachHeader;
|
|||||||
import ghidra.app.util.bin.format.macho.commands.SegmentCommand;
|
import ghidra.app.util.bin.format.macho.commands.SegmentCommand;
|
||||||
import ghidra.app.util.bin.format.macho.dyld.*;
|
import ghidra.app.util.bin.format.macho.dyld.*;
|
||||||
import ghidra.app.util.importer.MessageLog;
|
import ghidra.app.util.importer.MessageLog;
|
||||||
|
import ghidra.app.util.opinion.DyldCacheUtils.DyldCacheImageRecord;
|
||||||
import ghidra.app.util.opinion.DyldCacheUtils.SplitDyldCache;
|
import ghidra.app.util.opinion.DyldCacheUtils.SplitDyldCache;
|
||||||
import ghidra.formats.gfilesystem.*;
|
import ghidra.formats.gfilesystem.*;
|
||||||
import ghidra.formats.gfilesystem.annotations.FileSystemInfo;
|
import ghidra.formats.gfilesystem.annotations.FileSystemInfo;
|
||||||
@@ -78,26 +79,23 @@ public class DyldCacheFileSystem extends AbstractFileSystem<DyldCacheEntry> {
|
|||||||
RangeSet<Long> allDylibRanges = TreeRangeSet.create();
|
RangeSet<Long> allDylibRanges = TreeRangeSet.create();
|
||||||
|
|
||||||
// Find the DYLIB's and add them as files
|
// Find the DYLIB's and add them as files
|
||||||
monitor.initialize(splitDyldCache.size(), "Find DYLD DYLIBs...");
|
List<DyldCacheImageRecord> imageRecords = splitDyldCache.getImageRecords();
|
||||||
for (int i = 0; i < splitDyldCache.size(); i++) {
|
monitor.initialize(imageRecords.size(), "Find DYLD DYLIBs...");
|
||||||
|
for (DyldCacheImageRecord imageRecord : imageRecords) {
|
||||||
monitor.increment();
|
monitor.increment();
|
||||||
DyldCacheHeader header = splitDyldCache.getDyldCacheHeader(i);
|
DyldCacheImage image = imageRecord.image();
|
||||||
ByteProvider p = splitDyldCache.getProvider(i);
|
MachHeader machHeader = splitDyldCache.getMacho(imageRecord);
|
||||||
for (DyldCacheImage mappedImage : header.getMappedImages()) {
|
RangeSet<Long> rangeSet = TreeRangeSet.create();
|
||||||
MachHeader machHeader =
|
for (SegmentCommand segment : machHeader.parseSegments()) {
|
||||||
new MachHeader(p, mappedImage.getAddress() - header.getBaseAddress());
|
Range<Long> range = Range.openClosed(segment.getVMaddress(),
|
||||||
RangeSet<Long> rangeSet = TreeRangeSet.create();
|
segment.getVMaddress() + segment.getVMsize());
|
||||||
for (SegmentCommand segment : machHeader.parseSegments()) {
|
rangeSet.add(range);
|
||||||
Range<Long> range = Range.openClosed(segment.getVMaddress(),
|
|
||||||
segment.getVMaddress() + segment.getVMsize());
|
|
||||||
rangeSet.add(range);
|
|
||||||
}
|
|
||||||
DyldCacheEntry entry =
|
|
||||||
new DyldCacheEntry(mappedImage.getPath(), i, rangeSet, null, null, -1);
|
|
||||||
rangeSet.asRanges().forEach(r -> rangeMap.put(r, entry));
|
|
||||||
allDylibRanges.addAll(rangeSet);
|
|
||||||
fsIndex.storeFile(mappedImage.getPath(), fsIndex.getFileCount(), false, -1, entry);
|
|
||||||
}
|
}
|
||||||
|
DyldCacheEntry entry = new DyldCacheEntry(image.getPath(),
|
||||||
|
imageRecord.splitCacheIndex(), rangeSet, null, null, -1);
|
||||||
|
rangeSet.asRanges().forEach(r -> rangeMap.put(r, entry));
|
||||||
|
allDylibRanges.addAll(rangeSet);
|
||||||
|
fsIndex.storeFile(image.getPath(), fsIndex.getFileCount(), false, -1, entry);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Find and store all the mappings for all of the subcaches. We need to remove the DYLIB's
|
// Find and store all the mappings for all of the subcaches. We need to remove the DYLIB's
|
||||||
|
|||||||
@@ -2580,7 +2580,12 @@ public class DockingWindowManager implements PropertyChangeListener, Placeholder
|
|||||||
*
|
*
|
||||||
* @param context the context
|
* @param context the context
|
||||||
*/
|
*/
|
||||||
void doContextChanged(ActionContext context) {
|
void notifyContextListeners(ActionContext context) {
|
||||||
|
|
||||||
|
if (context == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
for (DockingContextListener listener : contextListeners) {
|
for (DockingContextListener listener : contextListeners) {
|
||||||
listener.contextChanged(context);
|
listener.contextChanged(context);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,9 +4,9 @@
|
|||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
* You may obtain a copy of the License at
|
* You may obtain a copy of the License at
|
||||||
*
|
*
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
*
|
*
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
@@ -15,6 +15,8 @@
|
|||||||
*/
|
*/
|
||||||
package docking;
|
package docking;
|
||||||
|
|
||||||
|
import java.awt.KeyboardFocusManager;
|
||||||
|
import java.awt.Window;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
|
||||||
import docking.action.DockingActionIf;
|
import docking.action.DockingActionIf;
|
||||||
@@ -184,24 +186,40 @@ public class GlobalMenuAndToolBarManager implements DockingWindowListener {
|
|||||||
}
|
}
|
||||||
|
|
||||||
WindowActionManager actionManager = windowToActionManagerMap.get(windowNode);
|
WindowActionManager actionManager = windowToActionManagerMap.get(windowNode);
|
||||||
ActionContext localContext = getContext(windowNode);
|
ActionContext localContext = getComponentProviderContext(windowNode);
|
||||||
actionManager.contextChanged(defaultContextMap, localContext, focusedWindowActions);
|
actionManager.contextChanged(defaultContextMap, localContext, focusedWindowActions);
|
||||||
}
|
}
|
||||||
|
|
||||||
// now update the focused window's actions
|
// now update the focused window's actions
|
||||||
|
updateFocusedWindowActions(focusedWindowNode, defaultContextMap);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void updateFocusedWindowActions(WindowNode focusedWindowNode,
|
||||||
|
Map<Class<? extends ActionContext>, ActionContext> defaultContextMap) {
|
||||||
|
|
||||||
|
ActionContext focusedContext = getFocusedWindowContext(focusedWindowNode);
|
||||||
WindowActionManager actionManager = windowToActionManagerMap.get(focusedWindowNode);
|
WindowActionManager actionManager = windowToActionManagerMap.get(focusedWindowNode);
|
||||||
ActionContext focusedContext = getContext(focusedWindowNode);
|
|
||||||
if (actionManager != null) {
|
if (actionManager != null) {
|
||||||
actionManager.contextChanged(defaultContextMap, focusedContext, Collections.emptySet());
|
actionManager.contextChanged(defaultContextMap, focusedContext, Collections.emptySet());
|
||||||
}
|
}
|
||||||
|
|
||||||
// update the docking window manager ; no focused context when no window is focused
|
// this is for non-action listeners that wish to do work when the context changes
|
||||||
if (focusedContext != null) {
|
windowManager.notifyContextListeners(focusedContext);
|
||||||
windowManager.doContextChanged(focusedContext);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private ActionContext getContext(WindowNode windowNode) {
|
private ActionContext getFocusedWindowContext(WindowNode focusedWindowNode) {
|
||||||
|
|
||||||
|
KeyboardFocusManager kfm = KeyboardFocusManager.getCurrentKeyboardFocusManager();
|
||||||
|
Window w = kfm.getFocusedWindow();
|
||||||
|
if (w instanceof DockingDialog dialog) {
|
||||||
|
DialogComponentProvider provider = dialog.getDialogComponent();
|
||||||
|
return provider.getActionContext(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
return getComponentProviderContext(focusedWindowNode);
|
||||||
|
}
|
||||||
|
|
||||||
|
private ActionContext getComponentProviderContext(WindowNode windowNode) {
|
||||||
if (windowNode == null) {
|
if (windowNode == null) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user