mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2025-10-05 19:42:36 +02:00
Merge remote-tracking branch 'origin/patch'
This commit is contained in:
commit
f0cb8d4ac1
13 changed files with 304 additions and 22 deletions
Binary file not shown.
Before Width: | Height: | Size: 45 KiB After Width: | Height: | Size: 45 KiB |
|
@ -197,6 +197,7 @@ public class DebuggerLocationLabel extends JLabel {
|
|||
}
|
||||
|
||||
public void updateLabel() {
|
||||
setText(computeLocationString());
|
||||
String label = computeLocationString();
|
||||
setText(label);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -285,6 +285,13 @@ public class DebuggerMemoryBytesProvider extends ProgramByteViewerComponentProvi
|
|||
locationLabel.updateLabel();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean goTo(Program gotoProgram, ProgramLocation location) {
|
||||
boolean result = super.goTo(gotoProgram, location);
|
||||
locationLabel.goToAddress(location == null ? null : location.getAddress());
|
||||
return result;
|
||||
}
|
||||
|
||||
protected DebuggerCoordinates adjustCoordinates(DebuggerCoordinates coordinates) {
|
||||
if (followsCurrentThread) {
|
||||
return coordinates;
|
||||
|
|
|
@ -29,6 +29,7 @@ import docking.DialogComponentProvider;
|
|||
import docking.widgets.model.GAddressRangeField;
|
||||
import docking.widgets.model.GLifespanField;
|
||||
import ghidra.app.services.DebuggerStaticMappingService;
|
||||
import ghidra.framework.model.DomainFile;
|
||||
import ghidra.program.model.address.*;
|
||||
import ghidra.program.model.listing.Program;
|
||||
import ghidra.program.util.ProgramLocation;
|
||||
|
@ -357,7 +358,15 @@ public class DebuggerAddMappingDialog extends DialogComponentProvider {
|
|||
public void setProgram(Program program) {
|
||||
this.program = program;
|
||||
if (program != null) {
|
||||
labelProg.setText(program.getName());
|
||||
String name;
|
||||
DomainFile df = program.getDomainFile();
|
||||
if (df != null) {
|
||||
name = df.getName();
|
||||
}
|
||||
else {
|
||||
name = program.getName();
|
||||
}
|
||||
labelProg.setText(name);
|
||||
fieldProgRange.setAddressFactory(program.getAddressFactory());
|
||||
}
|
||||
else {
|
||||
|
|
|
@ -0,0 +1,243 @@
|
|||
/* ###
|
||||
* 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.debug.gui.modules;
|
||||
|
||||
import java.awt.BorderLayout;
|
||||
import java.util.*;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.function.Function;
|
||||
|
||||
import javax.swing.*;
|
||||
import javax.swing.table.TableColumn;
|
||||
import javax.swing.table.TableColumnModel;
|
||||
|
||||
import docking.DialogComponentProvider;
|
||||
import docking.widgets.table.*;
|
||||
import docking.widgets.table.ColumnSortState.SortDirection;
|
||||
import docking.widgets.table.DefaultEnumeratedColumnTableModel.EnumeratedTableColumn;
|
||||
import ghidra.app.services.DebuggerStaticMappingService;
|
||||
import ghidra.framework.model.DomainFile;
|
||||
import ghidra.framework.plugintool.PluginTool;
|
||||
import ghidra.program.model.address.Address;
|
||||
import ghidra.program.model.listing.Program;
|
||||
import ghidra.program.model.mem.MemoryBlock;
|
||||
import ghidra.program.util.ProgramLocation;
|
||||
import ghidra.trace.model.modules.TraceSection;
|
||||
import ghidra.util.table.GhidraTableFilterPanel;
|
||||
|
||||
public class DebuggerBlockChooserDialog extends DialogComponentProvider {
|
||||
static class MemoryBlockRow {
|
||||
private final Program program;
|
||||
private final MemoryBlock block;
|
||||
private double score;
|
||||
|
||||
public MemoryBlockRow(Program program, MemoryBlock block) {
|
||||
this.program = program;
|
||||
this.block = block;
|
||||
}
|
||||
|
||||
public Program getProgram() {
|
||||
return program;
|
||||
}
|
||||
|
||||
public MemoryBlock getBlock() {
|
||||
return block;
|
||||
}
|
||||
|
||||
public String getProgramName() {
|
||||
DomainFile df = program.getDomainFile();
|
||||
if (df != null) {
|
||||
return df.getName();
|
||||
}
|
||||
return program.getName();
|
||||
}
|
||||
|
||||
public String getBlockName() {
|
||||
return block.getName();
|
||||
}
|
||||
|
||||
public Address getMinAddress() {
|
||||
return block.getStart();
|
||||
}
|
||||
|
||||
public Address getMaxAddress() {
|
||||
return block.getEnd();
|
||||
}
|
||||
|
||||
public long getLength() {
|
||||
return block.getSize();
|
||||
}
|
||||
|
||||
public double getScore() {
|
||||
return score;
|
||||
}
|
||||
|
||||
public double score(TraceSection section, DebuggerStaticMappingService service) {
|
||||
if (section == null) {
|
||||
return score = 0;
|
||||
}
|
||||
return score = service.proposeSectionMap(section, program, block).computeScore();
|
||||
}
|
||||
|
||||
public ProgramLocation getProgramLocation() {
|
||||
return new ProgramLocation(program, block.getStart());
|
||||
}
|
||||
}
|
||||
|
||||
enum MemoryBlockTableColumns
|
||||
implements EnumeratedTableColumn<MemoryBlockTableColumns, MemoryBlockRow> {
|
||||
SCORE("Score", Double.class, MemoryBlockRow::getScore, SortDirection.DESCENDING),
|
||||
PROGRAM("Program", String.class, MemoryBlockRow::getProgramName, SortDirection.ASCENDING),
|
||||
BLOCK("Block", String.class, MemoryBlockRow::getBlockName, SortDirection.ASCENDING),
|
||||
START("Start Address", Address.class, MemoryBlockRow::getMinAddress, SortDirection.ASCENDING),
|
||||
END("End Address", Address.class, MemoryBlockRow::getMaxAddress, SortDirection.ASCENDING),
|
||||
LENGTH("Length", Long.class, MemoryBlockRow::getLength, SortDirection.ASCENDING);
|
||||
|
||||
<T> MemoryBlockTableColumns(String header, Class<T> cls, Function<MemoryBlockRow, T> getter,
|
||||
SortDirection dir) {
|
||||
this.header = header;
|
||||
this.cls = cls;
|
||||
this.getter = getter;
|
||||
this.dir = dir;
|
||||
}
|
||||
|
||||
private final String header;
|
||||
private final Function<MemoryBlockRow, ?> getter;
|
||||
private final Class<?> cls;
|
||||
private final SortDirection dir;
|
||||
|
||||
@Override
|
||||
public String getHeader() {
|
||||
return header;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<?> getValueClass() {
|
||||
return cls;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getValueOf(MemoryBlockRow row) {
|
||||
return getter.apply(row);
|
||||
}
|
||||
|
||||
@Override
|
||||
public SortDirection defaultSortDirection() {
|
||||
return dir;
|
||||
}
|
||||
}
|
||||
|
||||
final EnumeratedColumnTableModel<MemoryBlockRow> tableModel =
|
||||
new DefaultEnumeratedColumnTableModel<>("Blocks", MemoryBlockTableColumns.class);
|
||||
|
||||
GTable table;
|
||||
GhidraTableFilterPanel<MemoryBlockRow> filterPanel;
|
||||
|
||||
private Entry<Program, MemoryBlock> chosen;
|
||||
|
||||
protected DebuggerBlockChooserDialog() {
|
||||
super("Memory Blocks", true, true, true, false);
|
||||
populateComponents();
|
||||
}
|
||||
|
||||
protected void populateComponents() {
|
||||
JPanel panel = new JPanel(new BorderLayout());
|
||||
|
||||
table = new GTable(tableModel);
|
||||
table.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
|
||||
panel.add(new JScrollPane(table));
|
||||
|
||||
filterPanel = new GhidraTableFilterPanel<>(table, tableModel);
|
||||
panel.add(filterPanel, BorderLayout.SOUTH);
|
||||
|
||||
addWorkPanel(panel);
|
||||
|
||||
addOKButton();
|
||||
addCancelButton();
|
||||
|
||||
table.getSelectionModel().addListSelectionListener(evt -> {
|
||||
okButton.setEnabled(filterPanel.getSelectedItems().size() == 1);
|
||||
// Prevent empty selection
|
||||
});
|
||||
|
||||
// TODO: Adjust column widths?
|
||||
TableColumnModel columnModel = table.getColumnModel();
|
||||
|
||||
TableColumn startCol = columnModel.getColumn(MemoryBlockTableColumns.START.ordinal());
|
||||
startCol.setCellRenderer(CustomToStringCellRenderer.MONO_OBJECT);
|
||||
|
||||
TableColumn endCol = columnModel.getColumn(MemoryBlockTableColumns.END.ordinal());
|
||||
endCol.setCellRenderer(CustomToStringCellRenderer.MONO_OBJECT);
|
||||
|
||||
TableColumn lenCol = columnModel.getColumn(MemoryBlockTableColumns.LENGTH.ordinal());
|
||||
lenCol.setCellRenderer(CustomToStringCellRenderer.MONO_ULONG_HEX);
|
||||
}
|
||||
|
||||
public Map.Entry<Program, MemoryBlock> chooseBlock(PluginTool tool, TraceSection section,
|
||||
Collection<Program> programs) {
|
||||
setBlocksFromPrograms(programs);
|
||||
computeScores(section, tool.getService(DebuggerStaticMappingService.class));
|
||||
selectHighestScoringBlock();
|
||||
tool.showDialog(this);
|
||||
return getChosen();
|
||||
}
|
||||
|
||||
protected void computeScores(TraceSection section, DebuggerStaticMappingService service) {
|
||||
for (MemoryBlockRow rec : tableModel.getModelData()) {
|
||||
rec.score(section, service);
|
||||
}
|
||||
}
|
||||
|
||||
protected void setBlocksFromPrograms(Collection<Program> programs) {
|
||||
this.tableModel.clear();
|
||||
List<MemoryBlockRow> rows = new ArrayList<>();
|
||||
for (Program program : programs) {
|
||||
for (MemoryBlock block : program.getMemory().getBlocks()) {
|
||||
rows.add(new MemoryBlockRow(program, block));
|
||||
}
|
||||
}
|
||||
this.tableModel.addAll(rows);
|
||||
}
|
||||
|
||||
protected void selectHighestScoringBlock() {
|
||||
MemoryBlockRow best = null;
|
||||
for (MemoryBlockRow rec : tableModel.getModelData()) {
|
||||
if (best == null || rec.getScore() > best.getScore()) {
|
||||
best = rec;
|
||||
}
|
||||
}
|
||||
if (best != null) {
|
||||
filterPanel.setSelectedItem(best);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void okCallback() {
|
||||
MemoryBlockRow sel = filterPanel.getSelectedItem();
|
||||
this.chosen = sel == null ? null : Map.entry(sel.program, sel.block);
|
||||
close();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void cancelCallback() {
|
||||
this.chosen = null;
|
||||
close();
|
||||
}
|
||||
|
||||
public Entry<Program, MemoryBlock> getChosen() {
|
||||
return chosen;
|
||||
}
|
||||
}
|
|
@ -44,7 +44,9 @@ public class DebuggerModuleMapProposalDialog
|
|||
MODULE_NAME("Module", String.class, e -> e.getModule().getName()),
|
||||
DYNAMIC_BASE("Dynamic Base", Address.class, e -> e.getModule().getBase()),
|
||||
CHOOSE("Choose", String.class, e -> "Choose Program", (e, v) -> nop()),
|
||||
PROGRAM_NAME("Program", String.class, e -> e.getToProgram().getName()),
|
||||
PROGRAM_NAME("Program", String.class, e -> (e.getToProgram().getDomainFile() == null
|
||||
? e.getToProgram().getName()
|
||||
: e.getToProgram().getDomainFile().getName())),
|
||||
STATIC_BASE("Static Base", Address.class, e -> e.getToProgram().getImageBase()),
|
||||
SIZE("Size", Long.class, e -> e.getModuleRange().getLength());
|
||||
|
||||
|
|
|
@ -1148,7 +1148,19 @@ public class DebuggerModulesProvider extends ComponentProviderAdapter {
|
|||
|
||||
public void setProgram(Program program) {
|
||||
currentProgram = program;
|
||||
String name = (program == null ? "..." : program.getName());
|
||||
String name;
|
||||
if (program != null) {
|
||||
DomainFile df = program.getDomainFile();
|
||||
if (df != null) {
|
||||
name = df.getName();
|
||||
}
|
||||
else {
|
||||
name = program.getName();
|
||||
}
|
||||
}
|
||||
else {
|
||||
name = "...";
|
||||
}
|
||||
actionMapModuleTo.getPopupMenuData().setMenuItemName(MapModuleToAction.NAME_PREFIX + name);
|
||||
actionMapSectionsTo.getPopupMenuData()
|
||||
.setMenuItemName(MapSectionsToAction.NAME_PREFIX + name);
|
||||
|
@ -1174,7 +1186,13 @@ public class DebuggerModulesProvider extends ComponentProviderAdapter {
|
|||
if (block == null) {
|
||||
return "...";
|
||||
}
|
||||
return location.getProgram().getName() + ":" + block.getName();
|
||||
Program program = location.getProgram();
|
||||
String name = program.getName();
|
||||
DomainFile df = program.getDomainFile();
|
||||
if (df != null) {
|
||||
name = df.getName();
|
||||
}
|
||||
return name + ":" + block.getName();
|
||||
}
|
||||
|
||||
public void setLocation(ProgramLocation location) {
|
||||
|
|
|
@ -33,11 +33,6 @@ public class DbgDebuggerProgramLaunchOpinion implements DebuggerProgramLaunchOpi
|
|||
super(program, tool, factory);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getMenuParentTitle() {
|
||||
return "Debug " + program.getName();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected List<String> getLauncherPath() {
|
||||
return PathUtils.parse("");
|
||||
|
|
|
@ -34,11 +34,6 @@ public class GdbDebuggerProgramLaunchOpinion implements DebuggerProgramLaunchOpi
|
|||
super(program, tool, factory);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getMenuParentTitle() {
|
||||
return "Debug " + program.getName();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected List<String> getLauncherPath() {
|
||||
return PathUtils.parse("Inferiors[1]");
|
||||
|
|
|
@ -33,11 +33,6 @@ public class LldbDebuggerProgramLaunchOpinion implements DebuggerProgramLaunchOp
|
|||
super(program, tool, factory);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getMenuParentTitle() {
|
||||
return "Debug " + program.getName();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected List<String> getLauncherPath() {
|
||||
return PathUtils.parse("");
|
||||
|
|
|
@ -256,7 +256,13 @@ public class TraceObjectManager {
|
|||
recorder.createSnapshot(traceThread + " started", traceThread, null);
|
||||
try (UndoableTransaction tid =
|
||||
UndoableTransaction.start(recorder.getTrace(), "Adjust thread creation", true)) {
|
||||
traceThread.setCreationSnap(recorder.getSnap());
|
||||
long existing = traceThread.getCreationSnap();
|
||||
if (existing == Long.MIN_VALUE) {
|
||||
traceThread.setCreationSnap(recorder.getSnap());
|
||||
}
|
||||
else {
|
||||
traceThread.setDestructionSnap(Long.MAX_VALUE);
|
||||
}
|
||||
}
|
||||
catch (DuplicateNameException e) {
|
||||
throw new AssertionError(e); // Should be shrinking
|
||||
|
|
|
@ -34,6 +34,7 @@ import ghidra.dbg.target.TargetMethod.ParameterDescription;
|
|||
import ghidra.dbg.target.TargetObject;
|
||||
import ghidra.dbg.target.schema.TargetObjectSchema;
|
||||
import ghidra.dbg.util.PathUtils;
|
||||
import ghidra.framework.model.DomainFile;
|
||||
import ghidra.framework.options.SaveState;
|
||||
import ghidra.framework.plugintool.AutoConfigState.ConfigStateField;
|
||||
import ghidra.framework.plugintool.PluginTool;
|
||||
|
@ -56,6 +57,16 @@ public abstract class AbstractDebuggerProgramLaunchOffer implements DebuggerProg
|
|||
this.factory = factory;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getMenuParentTitle() {
|
||||
String name = program.getName();
|
||||
DomainFile df = program.getDomainFile();
|
||||
if (df != null) {
|
||||
name = df.getName();
|
||||
}
|
||||
return "Debug " + name;
|
||||
}
|
||||
|
||||
protected List<String> getLauncherPath() {
|
||||
return PathUtils.parse("");
|
||||
}
|
||||
|
|
|
@ -44,7 +44,7 @@ import ghidra.app.plugin.core.debug.DebuggerCoordinates;
|
|||
import ghidra.app.plugin.core.debug.gui.AbstractGhidraHeadedDebuggerGUITest;
|
||||
import ghidra.app.plugin.core.debug.gui.DebuggerResources;
|
||||
import ghidra.app.plugin.core.debug.gui.DebuggerResources.AbstractFollowsCurrentThreadAction;
|
||||
import ghidra.app.plugin.core.debug.gui.action.*;
|
||||
import ghidra.app.plugin.core.debug.gui.action.DebuggerGoToDialog;
|
||||
import ghidra.app.plugin.core.debug.gui.listing.DebuggerListingPlugin;
|
||||
import ghidra.app.services.TraceRecorder;
|
||||
import ghidra.async.SwingExecutorService;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue