diff --git a/Ghidra/Features/Base/src/main/help/help/topics/ClipboardPlugin/Clipboard.htm b/Ghidra/Features/Base/src/main/help/help/topics/ClipboardPlugin/Clipboard.htm index 0bc4b2e13e..df8fcc01a6 100644 --- a/Ghidra/Features/Base/src/main/help/help/topics/ClipboardPlugin/Clipboard.htm +++ b/Ghidra/Features/Base/src/main/help/help/topics/ClipboardPlugin/Clipboard.htm @@ -182,6 +182,10 @@ current selection. The text is formatted to show the offset from the entry point of the function, for example: main + 0x2 +
  • Byte Source Offset - Copies the byte source offset from the start of the file for + each address in the current selection. If the address is not backed by a file, + <NO_OFFSET> is copied.
  • +
  • GhidraURL - Creates a GhidraURL for the address under the cursor then copies that URL to the clipboard.
  • diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/clipboard/CodeBrowserClipboardProvider.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/clipboard/CodeBrowserClipboardProvider.java index afe37c17ad..e88f2d9095 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/clipboard/CodeBrowserClipboardProvider.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/clipboard/CodeBrowserClipboardProvider.java @@ -44,10 +44,12 @@ import ghidra.app.util.viewer.listingpanel.ListingModel; import ghidra.framework.cmd.Command; import ghidra.framework.model.DomainFile; import ghidra.framework.plugintool.PluginTool; +import ghidra.program.database.mem.AddressSourceInfo; import ghidra.program.database.symbol.CodeSymbol; import ghidra.program.database.symbol.FunctionSymbol; import ghidra.program.model.address.*; import ghidra.program.model.listing.*; +import ghidra.program.model.mem.Memory; import ghidra.program.model.symbol.*; import ghidra.program.util.*; import ghidra.util.Msg; @@ -65,6 +67,8 @@ public class CodeBrowserClipboardProvider extends ByteCopier new ClipboardType(DataFlavor.stringFlavor, "Address"); public static final ClipboardType ADDRESS_TEXT_WITH_OFFSET_TYPE = new ClipboardType(DataFlavor.stringFlavor, "Address w/ Offset"); + public static final ClipboardType BYTE_SOURCE_OFFSET_TYPE = + new ClipboardType(DataFlavor.stringFlavor, "Byte Source Offset"); public static final ClipboardType CODE_TEXT_TYPE = new ClipboardType(DataFlavor.stringFlavor, "Formatted Code"); public static final ClipboardType LABELS_COMMENTS_TYPE = @@ -94,6 +98,7 @@ public class CodeBrowserClipboardProvider extends ByteCopier list.add(CPP_BYTE_ARRAY_TYPE); list.add(ADDRESS_TEXT_TYPE); list.add(ADDRESS_TEXT_WITH_OFFSET_TYPE); + list.add(BYTE_SOURCE_OFFSET_TYPE); return list; } @@ -221,6 +226,9 @@ public class CodeBrowserClipboardProvider extends ByteCopier else if (copyType == ADDRESS_TEXT_WITH_OFFSET_TYPE) { return copySymbolString(monitor); } + else if (copyType == BYTE_SOURCE_OFFSET_TYPE) { + return copyByteSourceOffset(monitor); + } else if (copyType == CODE_TEXT_TYPE) { return copyCode(monitor); } @@ -382,6 +390,24 @@ public class CodeBrowserClipboardProvider extends ByteCopier return createStringTransferable(StringUtils.join(strings, "\n")); } + private Transferable copyByteSourceOffset(TaskMonitor monitor) { + AddressSetView addrs = getSelectedAddresses(); + Memory currentMemory = currentProgram.getMemory(); + List strings = new ArrayList<>(); + AddressIterator addresses = addrs.getAddresses(true); + while (addresses.hasNext() && !monitor.isCancelled()) { + AddressSourceInfo addressSourceInfo = + currentMemory.getAddressSourceInfo(addresses.next()); + if (addressSourceInfo != null) { + long fileOffset = addressSourceInfo.getFileOffset(); + String fileOffsetString = + fileOffset != -1 ? "%x".formatted(fileOffset) : ""; + strings.add(fileOffsetString); + } + } + return createStringTransferable(String.join("\n", strings)); + } + protected Transferable copyCode(TaskMonitor monitor) { AddressSetView addressSet = getSelectedAddresses();