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();