mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2024-11-30 08:00:39 +00:00
GP-2049 Add DumpFileLoader support for Apport format
This commit is contained in:
parent
e66e5b70e9
commit
114895b79d
@ -13,6 +13,9 @@ data/ExtensionPoint.manifest||GHIDRA||||END|
|
|||||||
data/android/eclipse-classpath||GHIDRA||reviewed||END|
|
data/android/eclipse-classpath||GHIDRA||reviewed||END|
|
||||||
data/android/eclipse-project||GHIDRA||reviewed||END|
|
data/android/eclipse-project||GHIDRA||reviewed||END|
|
||||||
data/crypto/README.txt||GHIDRA||||END|
|
data/crypto/README.txt||GHIDRA||||END|
|
||||||
|
data/languages/apport.opinion||GHIDRA||||END|
|
||||||
data/languages/dumpfile.opinion||GHIDRA||||END|
|
data/languages/dumpfile.opinion||GHIDRA||||END|
|
||||||
|
data/languages/minidump.opinion||GHIDRA||||END|
|
||||||
|
data/languages/pagedump.opinion||GHIDRA||||END|
|
||||||
src/main/help/help/TOC_Source.xml||GHIDRA||||END|
|
src/main/help/help/TOC_Source.xml||GHIDRA||||END|
|
||||||
src/main/help/help/topics/FileFormatsPlugin/FileFormats.html||GHIDRA||||END|
|
src/main/help/help/topics/FileFormatsPlugin/FileFormats.html||GHIDRA||||END|
|
||||||
|
@ -0,0 +1,7 @@
|
|||||||
|
<opinions>
|
||||||
|
<constraint loader="Dump File Loader">
|
||||||
|
<constraint compilerSpecID="linux">
|
||||||
|
<constraint primary="amd64" processor="x86" endian="little" size="64" />
|
||||||
|
</constraint>
|
||||||
|
</constraint>
|
||||||
|
</opinions>
|
23
Ghidra/Features/FileFormats/data/languages/minidump.opinion
Normal file
23
Ghidra/Features/FileFormats/data/languages/minidump.opinion
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
<opinions>
|
||||||
|
<constraint loader="Dump File Loader">
|
||||||
|
<constraint compilerSpecID="windows">
|
||||||
|
<constraint primary="0" processor="x86" endian="little" size="32" />
|
||||||
|
<constraint primary="1" processor="MIPS" endian="little" size="32" />
|
||||||
|
<!-- constraint primary="2" processor="ALPHA" endian="little" size="32" -->
|
||||||
|
<constraint primary="4" processor="SuperH4" endian="little" size="32" />
|
||||||
|
<constraint primary="5" processor="ARM" endian="little" size="32" />
|
||||||
|
<!-- constraint primary="6" processor="IA64" endian="little" size="32" -->
|
||||||
|
<!-- constraint primary="7" processor="ALPHA64" endian="little" size="32" -->
|
||||||
|
<!-- constraint primary="8" processor="MSIL" endian="little" size="32" -->
|
||||||
|
<constraint primary="9" processor="x86" endian="little" size="64" />
|
||||||
|
<!-- constraint primary="10" processor="IA32/64" endian="little" size="32" -->
|
||||||
|
<!-- constraint primary="11" processor="NEUTRAL" endian="little" size="32" -->
|
||||||
|
<constraint primary="12" processor="ARM" endian="little" size="64" />
|
||||||
|
<constraint primary="13" processor="ARM" endian="little" size="32" />
|
||||||
|
<!-- constraint primary="14" processor="IA32" endian="little" size="32" -->
|
||||||
|
</constraint>
|
||||||
|
<constraint compilerSpecID="default">
|
||||||
|
<constraint primary="3" processor="PowerPC" endian="little" size="32" />
|
||||||
|
</constraint>
|
||||||
|
</constraint>
|
||||||
|
</opinions>
|
@ -1,7 +1,6 @@
|
|||||||
<opinions>
|
<opinions>
|
||||||
<constraint loader="Dump File Loader">
|
<constraint loader="Dump File Loader">
|
||||||
<constraint compilerSpecID="windows">
|
<constraint compilerSpecID="windows">
|
||||||
<!-- Page/Userdump MachineImageType values -->
|
|
||||||
<!-- constraint primary="21064" processor="ALPHA" endian="little" size="64" -->
|
<!-- constraint primary="21064" processor="ALPHA" endian="little" size="64" -->
|
||||||
<constraint primary="1824" processor="ARM" endian="little" size="32" variant="v8" />
|
<constraint primary="1824" processor="ARM" endian="little" size="32" variant="v8" />
|
||||||
<constraint primary="2080" processor="ARM" endian="little" size="32" variant="v8T" /> <!-- THUMB -->
|
<constraint primary="2080" processor="ARM" endian="little" size="32" variant="v8T" /> <!-- THUMB -->
|
||||||
@ -21,28 +20,12 @@
|
|||||||
<constraint primary="486" processor="x86" endian="little" size="32" />
|
<constraint primary="486" processor="x86" endian="little" size="32" />
|
||||||
<constraint primary="586" processor="x86" endian="little" size="32" />
|
<constraint primary="586" processor="x86" endian="little" size="32" />
|
||||||
<constraint primary="8664" processor="x86" endian="little" size="64" />
|
<constraint primary="8664" processor="x86" endian="little" size="64" />
|
||||||
<!-- MDMP Architecture values -->
|
|
||||||
<constraint primary="0" processor="x86" endian="little" size="32" />
|
|
||||||
<constraint primary="1" processor="MIPS" endian="little" size="32" />
|
|
||||||
<!-- constraint primary="2" processor="ALPHA" endian="little" size="32" -->
|
|
||||||
<constraint primary="4" processor="SuperH4" endian="little" size="32" />
|
|
||||||
<constraint primary="5" processor="ARM" endian="little" size="32" />
|
|
||||||
<!-- constraint primary="6" processor="IA64" endian="little" size="32" -->
|
|
||||||
<!-- constraint primary="7" processor="ALPHA64" endian="little" size="32" -->
|
|
||||||
<!-- constraint primary="8" processor="MSIL" endian="little" size="32" -->
|
|
||||||
<constraint primary="9" processor="x86" endian="little" size="64" />
|
|
||||||
<!-- constraint primary="10" processor="IA32/64" endian="little" size="32" -->
|
|
||||||
<!-- constraint primary="11" processor="NEUTRAL" endian="little" size="32" -->
|
|
||||||
<constraint primary="12" processor="ARM" endian="little" size="64" />
|
|
||||||
<constraint primary="13" processor="ARM" endian="little" size="32" />
|
|
||||||
<!-- constraint primary="14" processor="IA32" endian="little" size="32" -->
|
|
||||||
</constraint>
|
</constraint>
|
||||||
<constraint compilerSpecID="default">
|
<constraint compilerSpecID="default">
|
||||||
<constraint primary="601" processor="PowerPC" endian="little" size="32" />
|
<constraint primary="601" processor="PowerPC" endian="little" size="32" />
|
||||||
<constraint primary="603" processor="PowerPC" endian="little" size="32" />
|
<constraint primary="603" processor="PowerPC" endian="little" size="32" />
|
||||||
<constraint primary="604" processor="PowerPC" endian="little" size="32" />
|
<constraint primary="604" processor="PowerPC" endian="little" size="32" />
|
||||||
<constraint primary="620" processor="PowerPC" endian="little" size="32" />
|
<constraint primary="620" processor="PowerPC" endian="little" size="32" />
|
||||||
<constraint primary="3" processor="PowerPC" endian="little" size="32" />
|
|
||||||
</constraint>
|
</constraint>
|
||||||
</constraint>
|
</constraint>
|
||||||
</opinions>
|
</opinions>
|
@ -15,6 +15,7 @@
|
|||||||
*/
|
*/
|
||||||
package ghidra.file.formats.dump;
|
package ghidra.file.formats.dump;
|
||||||
|
|
||||||
|
import ghidra.program.model.address.AddressSpace;
|
||||||
import ghidra.program.model.data.DataType;
|
import ghidra.program.model.data.DataType;
|
||||||
|
|
||||||
public class DumpData {
|
public class DumpData {
|
||||||
@ -25,6 +26,7 @@ public class DumpData {
|
|||||||
private boolean generateSymbol;
|
private boolean generateSymbol;
|
||||||
private boolean generateFragment;
|
private boolean generateFragment;
|
||||||
private long size;
|
private long size;
|
||||||
|
private AddressSpace space;
|
||||||
|
|
||||||
public DumpData(long offset, DataType dt) {
|
public DumpData(long offset, DataType dt) {
|
||||||
this(offset, dt, dt.getDisplayName(), false, true);
|
this(offset, dt, dt.getDisplayName(), false, true);
|
||||||
@ -99,4 +101,12 @@ public class DumpData {
|
|||||||
public long getSize() {
|
public long getSize() {
|
||||||
return size;
|
return size;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public AddressSpace getAddressSpace() {
|
||||||
|
return space;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setAddressSpace(AddressSpace space) {
|
||||||
|
this.space = space;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -23,7 +23,9 @@ import java.util.Map.Entry;
|
|||||||
import ghidra.app.plugin.core.analysis.AutoAnalysisManager;
|
import ghidra.app.plugin.core.analysis.AutoAnalysisManager;
|
||||||
import ghidra.app.plugin.core.datamgr.util.DataTypeArchiveUtility;
|
import ghidra.app.plugin.core.datamgr.util.DataTypeArchiveUtility;
|
||||||
import ghidra.app.services.DataTypeManagerService;
|
import ghidra.app.services.DataTypeManagerService;
|
||||||
|
import ghidra.app.util.MemoryBlockUtils;
|
||||||
import ghidra.app.util.Option;
|
import ghidra.app.util.Option;
|
||||||
|
import ghidra.program.database.mem.FileBytes;
|
||||||
import ghidra.program.model.address.Address;
|
import ghidra.program.model.address.Address;
|
||||||
import ghidra.program.model.address.AddressFactory;
|
import ghidra.program.model.address.AddressFactory;
|
||||||
import ghidra.program.model.data.*;
|
import ghidra.program.model.data.*;
|
||||||
@ -31,10 +33,12 @@ import ghidra.program.model.lang.Language;
|
|||||||
import ghidra.program.model.lang.Register;
|
import ghidra.program.model.lang.Register;
|
||||||
import ghidra.program.model.listing.*;
|
import ghidra.program.model.listing.*;
|
||||||
import ghidra.util.Msg;
|
import ghidra.util.Msg;
|
||||||
|
import ghidra.util.exception.CancelledException;
|
||||||
import ghidra.util.task.TaskMonitor;
|
import ghidra.util.task.TaskMonitor;
|
||||||
|
|
||||||
public class DumpFile {
|
public class DumpFile {
|
||||||
|
|
||||||
|
// If data defined so must intAddressRanges which are used to create memory blocks
|
||||||
protected List<DumpData> data = new ArrayList<DumpData>();
|
protected List<DumpData> data = new ArrayList<DumpData>();
|
||||||
// Interior ranges are actual defined memory ranges.
|
// Interior ranges are actual defined memory ranges.
|
||||||
// Exterior ranges are aggregates of interior ranges, typically corresponding to a module
|
// Exterior ranges are aggregates of interior ranges, typically corresponding to a module
|
||||||
@ -62,6 +66,8 @@ public class DumpFile {
|
|||||||
|
|
||||||
protected Map<String, DataTypeManager> managerList = new HashMap<>();
|
protected Map<String, DataTypeManager> managerList = new HashMap<>();
|
||||||
|
|
||||||
|
private FileBytes fileBytes;
|
||||||
|
|
||||||
public DumpFile(DumpFileReader reader, ProgramBasedDataTypeManager dtm, List<Option> options,
|
public DumpFile(DumpFileReader reader, ProgramBasedDataTypeManager dtm, List<Option> options,
|
||||||
TaskMonitor monitor) {
|
TaskMonitor monitor) {
|
||||||
|
|
||||||
@ -257,6 +263,22 @@ public class DumpFile {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get or create FileBytes within program
|
||||||
|
* @param monitor task monitor
|
||||||
|
* @return file bytes object to be used for block creation or null
|
||||||
|
* @throws IOException if error occurs reading source file or writing to program database
|
||||||
|
* @throws CancelledException if operation cancelled by user
|
||||||
|
*/
|
||||||
|
public FileBytes getFileBytes(TaskMonitor monitor) throws IOException, CancelledException {
|
||||||
|
if (fileBytes == null) {
|
||||||
|
monitor.setMessage("Creating file bytes");
|
||||||
|
fileBytes =
|
||||||
|
MemoryBlockUtils.createFileBytes(program, reader.getByteProvider(), monitor);
|
||||||
|
}
|
||||||
|
return fileBytes;
|
||||||
|
}
|
||||||
|
|
||||||
public void analyze(TaskMonitor monitor) {
|
public void analyze(TaskMonitor monitor) {
|
||||||
// Override if needed
|
// Override if needed
|
||||||
}
|
}
|
||||||
|
@ -23,6 +23,7 @@ import ghidra.app.util.*;
|
|||||||
import ghidra.app.util.bin.ByteProvider;
|
import ghidra.app.util.bin.ByteProvider;
|
||||||
import ghidra.app.util.importer.MessageLog;
|
import ghidra.app.util.importer.MessageLog;
|
||||||
import ghidra.app.util.opinion.*;
|
import ghidra.app.util.opinion.*;
|
||||||
|
import ghidra.file.formats.dump.apport.Apport;
|
||||||
import ghidra.file.formats.dump.mdmp.Minidump;
|
import ghidra.file.formats.dump.mdmp.Minidump;
|
||||||
import ghidra.file.formats.dump.pagedump.Pagedump;
|
import ghidra.file.formats.dump.pagedump.Pagedump;
|
||||||
import ghidra.file.formats.dump.userdump.Userdump;
|
import ghidra.file.formats.dump.userdump.Userdump;
|
||||||
@ -30,6 +31,7 @@ import ghidra.framework.model.DomainObject;
|
|||||||
import ghidra.framework.store.LockException;
|
import ghidra.framework.store.LockException;
|
||||||
import ghidra.program.database.mem.FileBytes;
|
import ghidra.program.database.mem.FileBytes;
|
||||||
import ghidra.program.database.mem.MemoryMapDB;
|
import ghidra.program.database.mem.MemoryMapDB;
|
||||||
|
import ghidra.program.database.register.AddressRangeObjectMap;
|
||||||
import ghidra.program.model.address.*;
|
import ghidra.program.model.address.*;
|
||||||
import ghidra.program.model.data.DataUtilities;
|
import ghidra.program.model.data.DataUtilities;
|
||||||
import ghidra.program.model.data.ProgramBasedDataTypeManager;
|
import ghidra.program.model.data.ProgramBasedDataTypeManager;
|
||||||
@ -64,7 +66,7 @@ public class DumpFileLoader extends AbstractLibrarySupportLoader {
|
|||||||
public static final boolean ANALYZE_EMBEDDED_OBJECTS_OPTION_DEFAULT = false; // must be off by default
|
public static final boolean ANALYZE_EMBEDDED_OBJECTS_OPTION_DEFAULT = false; // must be off by default
|
||||||
public static final String MEMORY = "Memory";
|
public static final String MEMORY = "Memory";
|
||||||
|
|
||||||
private Map<AddressRange, String> ranges = new HashMap<>();
|
private AddressRangeObjectMap<String> rangeMap = new AddressRangeObjectMap<>();
|
||||||
|
|
||||||
private MessageLog log;
|
private MessageLog log;
|
||||||
private boolean joinBlocks;
|
private boolean joinBlocks;
|
||||||
@ -104,6 +106,8 @@ public class DumpFileLoader extends AbstractLibrarySupportLoader {
|
|||||||
return Userdump.getMachineType(reader);
|
return Userdump.getMachineType(reader);
|
||||||
case Minidump.SIGNATURE:
|
case Minidump.SIGNATURE:
|
||||||
return Minidump.getMachineType(reader);
|
return Minidump.getMachineType(reader);
|
||||||
|
case Apport.SIGNATURE:
|
||||||
|
return Apport.getMachineType(reader);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (IOException e) {
|
catch (IOException e) {
|
||||||
@ -117,13 +121,12 @@ public class DumpFileLoader extends AbstractLibrarySupportLoader {
|
|||||||
protected void load(ByteProvider provider, LoadSpec loadSpec, List<Option> options,
|
protected void load(ByteProvider provider, LoadSpec loadSpec, List<Option> options,
|
||||||
Program program, TaskMonitor monitor, MessageLog log)
|
Program program, TaskMonitor monitor, MessageLog log)
|
||||||
throws CancelledException, IOException {
|
throws CancelledException, IOException {
|
||||||
|
|
||||||
this.log = log;
|
this.log = log;
|
||||||
parseDumpFile(provider, program, options, monitor);
|
parseDumpFile(provider, program, options, loadSpec, monitor);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void parseDumpFile(ByteProvider provider, Program program, List<Option> options,
|
private void parseDumpFile(ByteProvider provider, Program program, List<Option> options,
|
||||||
TaskMonitor monitor) throws IOException, CancelledException {
|
LoadSpec loadSpec, TaskMonitor monitor) throws IOException, CancelledException {
|
||||||
Language language = program.getLanguage();
|
Language language = program.getLanguage();
|
||||||
int size = language.getDefaultSpace().getSize();
|
int size = language.getDefaultSpace().getSize();
|
||||||
DumpFileReader reader = new DumpFileReader(provider, true, size);
|
DumpFileReader reader = new DumpFileReader(provider, true, size);
|
||||||
@ -144,31 +147,38 @@ public class DumpFileLoader extends AbstractLibrarySupportLoader {
|
|||||||
case Minidump.SIGNATURE:
|
case Minidump.SIGNATURE:
|
||||||
df = new Minidump(reader, dtm, options, monitor);
|
df = new Minidump(reader, dtm, options, monitor);
|
||||||
break;
|
break;
|
||||||
|
case Apport.SIGNATURE:
|
||||||
|
df = new Apport(reader, dtm, options, monitor, loadSpec, log);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
if (df != null) {
|
if (df != null) {
|
||||||
groupRanges(program, provider, df.getExteriorAddressRanges(), monitor);
|
groupRanges(program, df, monitor);
|
||||||
loadRanges(program, provider, df.getInteriorAddressRanges(), monitor);
|
loadRanges(program, df, monitor);
|
||||||
applyStructures(program, df, monitor);
|
applyStructures(program, df, monitor);
|
||||||
df.analyze(monitor);
|
df.analyze(monitor);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void loadRanges(Program program, ByteProvider provider,
|
public void loadRanges(Program program, DumpFile df, TaskMonitor monitor) {
|
||||||
Map<Address, DumpAddressObject> daos, TaskMonitor monitor) {
|
Map<Address, DumpAddressObject> daos = df.getInteriorAddressRanges();
|
||||||
|
if (daos.isEmpty()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
try {
|
try {
|
||||||
monitor.setMessage("Creating file bytes");
|
FileBytes fileBytes = df.getFileBytes(monitor);
|
||||||
FileBytes fileBytes = MemoryBlockUtils.createFileBytes(program, provider, monitor);
|
if (fileBytes == null) {
|
||||||
|
Msg.error(this,
|
||||||
|
"File bytes not provided by DumpFile: " + df.getClass().getSimpleName());
|
||||||
|
return;
|
||||||
|
}
|
||||||
int count = 0;
|
int count = 0;
|
||||||
monitor.setMessage("Tagging blocks");
|
monitor.setMessage("Tagging blocks");
|
||||||
monitor.initialize(daos.size());
|
monitor.initialize(daos.size());
|
||||||
for (Address address : daos.keySet()) {
|
for (Address address : daos.keySet()) {
|
||||||
DumpAddressObject d = daos.get(address);
|
DumpAddressObject d = daos.get(address);
|
||||||
String name = d.getProviderId();
|
String name = rangeMap.getObject(address);
|
||||||
for (AddressRange range : ranges.keySet()) {
|
if (name == null) {
|
||||||
if (range.contains(address)) {
|
name = d.getProviderId();
|
||||||
name = ranges.get(range);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
d.setRangeName(name);
|
d.setRangeName(name);
|
||||||
monitor.setProgress(count++);
|
monitor.setProgress(count++);
|
||||||
@ -237,27 +247,31 @@ public class DumpFileLoader extends AbstractLibrarySupportLoader {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void groupRanges(Program program, ByteProvider provider,
|
public void groupRanges(Program program, DumpFile df, TaskMonitor monitor)
|
||||||
Map<Address, DumpAddressObject> daos, TaskMonitor monitor) throws CancelledException {
|
throws CancelledException {
|
||||||
|
Map<Address, DumpAddressObject> daos = df.getExteriorAddressRanges();
|
||||||
|
if (daos.isEmpty()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
monitor.setMessage("Assigning ranges");
|
monitor.setMessage("Assigning ranges");
|
||||||
monitor.initialize(daos.size());
|
monitor.initialize(daos.size());
|
||||||
int count = 0;
|
int count = 0;
|
||||||
for (Entry<Address, DumpAddressObject> entry : daos.entrySet()) {
|
for (Entry<Address, DumpAddressObject> entry : daos.entrySet()) {
|
||||||
|
monitor.checkCanceled();
|
||||||
|
monitor.setProgress(count++);
|
||||||
DumpAddressObject d = entry.getValue();
|
DumpAddressObject d = entry.getValue();
|
||||||
Address address = entry.getKey();
|
Address address = entry.getKey();
|
||||||
if (d.getBase() == 0) {
|
if (d.getBase() == 0) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
AddressRangeImpl range = new AddressRangeImpl(address, d.getLength());
|
rangeMap.setObject(address, address.addNoWrap(d.getLength() - 1),
|
||||||
ranges.put(range, d.getProviderId());
|
d.getProviderId());
|
||||||
}
|
}
|
||||||
catch (AddressOverflowException | AddressOutOfBoundsException
|
catch (AddressOverflowException | AddressOutOfBoundsException
|
||||||
| IllegalArgumentException e) {
|
| IllegalArgumentException e) {
|
||||||
Msg.warn(this, e.getMessage());
|
Msg.warn(this, e.getMessage());
|
||||||
}
|
}
|
||||||
monitor.setProgress(count++);
|
|
||||||
monitor.checkCanceled();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -266,9 +280,14 @@ public class DumpFileLoader extends AbstractLibrarySupportLoader {
|
|||||||
SymbolTable symbolTable = program.getSymbolTable();
|
SymbolTable symbolTable = program.getSymbolTable();
|
||||||
monitor.setMessage("Applying data structures");
|
monitor.setMessage("Applying data structures");
|
||||||
List<DumpData> data = df.getData();
|
List<DumpData> data = df.getData();
|
||||||
|
if (data.isEmpty()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
monitor.initialize(data.size());
|
monitor.initialize(data.size());
|
||||||
int count = 0;
|
int count = 0;
|
||||||
for (DumpData dd : data) {
|
for (DumpData dd : data) {
|
||||||
|
monitor.checkCanceled();
|
||||||
|
monitor.setProgress(count++);
|
||||||
Address address = program.getImageBase().addWrap(dd.getOffset());
|
Address address = program.getImageBase().addWrap(dd.getOffset());
|
||||||
try {
|
try {
|
||||||
if (dd.getDataType() == null) {
|
if (dd.getDataType() == null) {
|
||||||
@ -289,8 +308,6 @@ public class DumpFileLoader extends AbstractLibrarySupportLoader {
|
|||||||
Msg.error(this,
|
Msg.error(this,
|
||||||
"Could not create " + dd.getDataType().getName() + " at " + address);
|
"Could not create " + dd.getDataType().getName() + " at " + address);
|
||||||
}
|
}
|
||||||
monitor.setProgress(count++);
|
|
||||||
monitor.checkCanceled();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -0,0 +1,174 @@
|
|||||||
|
/* ###
|
||||||
|
* 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.file.formats.dump.apport;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import ghidra.app.util.*;
|
||||||
|
import ghidra.app.util.bin.ByteProvider;
|
||||||
|
import ghidra.app.util.importer.MessageLog;
|
||||||
|
import ghidra.app.util.opinion.*;
|
||||||
|
import ghidra.file.formats.dump.*;
|
||||||
|
import ghidra.framework.options.Options;
|
||||||
|
import ghidra.framework.store.LockException;
|
||||||
|
import ghidra.program.database.mem.FileBytes;
|
||||||
|
import ghidra.program.model.address.*;
|
||||||
|
import ghidra.program.model.data.DataType;
|
||||||
|
import ghidra.program.model.data.ProgramBasedDataTypeManager;
|
||||||
|
import ghidra.program.model.listing.*;
|
||||||
|
import ghidra.program.model.mem.Memory;
|
||||||
|
import ghidra.program.model.mem.MemoryBlock;
|
||||||
|
import ghidra.program.model.util.CodeUnitInsertionException;
|
||||||
|
import ghidra.util.Msg;
|
||||||
|
import ghidra.util.exception.*;
|
||||||
|
import ghidra.util.task.TaskMonitor;
|
||||||
|
|
||||||
|
public class Apport extends DumpFile {
|
||||||
|
|
||||||
|
public static final int SIGNATURE = 0x626F7250; // "ProblemType"
|
||||||
|
|
||||||
|
ApportHeader header;
|
||||||
|
|
||||||
|
private MessageLog log;
|
||||||
|
|
||||||
|
public Apport(DumpFileReader reader, ProgramBasedDataTypeManager dtm, List<Option> options,
|
||||||
|
TaskMonitor monitor, LoadSpec loadSpec, MessageLog log)
|
||||||
|
throws CancelledException, IOException {
|
||||||
|
|
||||||
|
super(reader, dtm, options, monitor);
|
||||||
|
this.log = log;
|
||||||
|
|
||||||
|
Options props = program.getOptions(Program.PROGRAM_INFO);
|
||||||
|
props.setString("Executable Format", PeLoader.PE_NAME);
|
||||||
|
initManagerList(null);
|
||||||
|
|
||||||
|
header = new ApportHeader(reader, 0L, monitor);
|
||||||
|
|
||||||
|
boolean createBlocks =
|
||||||
|
OptionUtils.getBooleanOptionValue(DumpFileLoader.CREATE_MEMORY_BLOCKS_OPTION_NAME,
|
||||||
|
options, DumpFileLoader.CREATE_MEMORY_BLOCKS_OPTION_DEFAULT);
|
||||||
|
if (createBlocks) {
|
||||||
|
createBlocksFromElf(loadSpec, monitor);
|
||||||
|
}
|
||||||
|
|
||||||
|
buildStructures(loadSpec, monitor);
|
||||||
|
}
|
||||||
|
|
||||||
|
public ApportHeader getFileHeader() {
|
||||||
|
return header;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void createBlocksFromElf(LoadSpec loadSpec, TaskMonitor monitor)
|
||||||
|
throws IOException, CancelledException {
|
||||||
|
|
||||||
|
try (
|
||||||
|
DecodedProvider provider =
|
||||||
|
new DecodedProvider(this, reader.getByteProvider(), monitor)) {
|
||||||
|
ElfLoader elfLoader = new ElfLoader();
|
||||||
|
Option base = new Option(ElfLoaderOptionsFactory.IMAGE_BASE_OPTION_NAME,
|
||||||
|
Long.toHexString(header.getMemoryInfo(0).getBaseAddress()));
|
||||||
|
options.add(base);
|
||||||
|
elfLoader.load(provider, loadSpec, options, program, monitor, log);
|
||||||
|
}
|
||||||
|
|
||||||
|
Memory memory = program.getMemory();
|
||||||
|
Address minAddress = memory.getMinAddress();
|
||||||
|
Listing listing = program.getListing();
|
||||||
|
ProgramModule root = listing.getDefaultRootModule();
|
||||||
|
Group[] children = root.getChildren();
|
||||||
|
|
||||||
|
try {
|
||||||
|
for (int i = 0; i < header.getMemoryRegionCount(); i++) {
|
||||||
|
MemoryInfo minfo = header.getMemoryInfo(i);
|
||||||
|
String id = minfo.getDescription();
|
||||||
|
if (id == null) {
|
||||||
|
id = "Memory";
|
||||||
|
}
|
||||||
|
Address addr = minAddress.getNewAddress(minfo.getBaseAddress());
|
||||||
|
MemoryBlock block = memory.getBlock(addr);
|
||||||
|
if (block != null) {
|
||||||
|
String name = block.getName();
|
||||||
|
block.setName(id);
|
||||||
|
|
||||||
|
boolean renamed = false;
|
||||||
|
try {
|
||||||
|
Group fragment = children[root.getIndex(name)];
|
||||||
|
if (fragment != null) {
|
||||||
|
fragment.setName(i + ":" + id);
|
||||||
|
renamed = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (DuplicateNameException e) {
|
||||||
|
// ignore
|
||||||
|
}
|
||||||
|
if (!renamed) {
|
||||||
|
Msg.error(this, "Failed to rename module: " + name);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (LockException e) {
|
||||||
|
throw new IOException(e); // unexpected during import
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void buildStructures(LoadSpec loadSpec, TaskMonitor monitor)
|
||||||
|
throws IOException {
|
||||||
|
|
||||||
|
DataType dt = header.toDataType();
|
||||||
|
|
||||||
|
try {
|
||||||
|
ByteProvider byteProvider = reader.getByteProvider();
|
||||||
|
MemoryBlock headerBlock = MemoryBlockUtils.createInitializedBlock(program, true,
|
||||||
|
"DumpHeader",
|
||||||
|
AddressSpace.OTHER_SPACE.getMinAddress(),
|
||||||
|
//fileBytes,
|
||||||
|
//d.getRVA(), // offset into filebytes
|
||||||
|
byteProvider.getInputStream(0),
|
||||||
|
dt.getLength(), // size
|
||||||
|
byteProvider.getName(), // comment
|
||||||
|
"Apport", // source
|
||||||
|
true, // section.isReadonly(),
|
||||||
|
true, // section.isWriteable(),
|
||||||
|
false, //section.isExecutable());
|
||||||
|
log,
|
||||||
|
monitor);
|
||||||
|
|
||||||
|
program.getListing().createData(headerBlock.getStart(), dt, dt.getLength());
|
||||||
|
}
|
||||||
|
catch (AddressOverflowException e) {
|
||||||
|
throw new AssertException(e);
|
||||||
|
}
|
||||||
|
catch (CodeUnitInsertionException e) {
|
||||||
|
Msg.warn(this, e.getMessage());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String getMachineType(DumpFileReader reader) throws IOException {
|
||||||
|
ApportHeader header = new ApportHeader(reader, 0L, TaskMonitor.DUMMY);
|
||||||
|
return header.getMachineImageType();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public FileBytes getFileBytes(TaskMonitor monitor) throws IOException, CancelledException {
|
||||||
|
// FileBytes not used for original file content
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,199 @@
|
|||||||
|
/* ###
|
||||||
|
* 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.file.formats.dump.apport;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.*;
|
||||||
|
|
||||||
|
import ghidra.app.util.bin.ByteProvider;
|
||||||
|
import ghidra.app.util.bin.StructConverter;
|
||||||
|
import ghidra.file.formats.dump.DumpFileReader;
|
||||||
|
import ghidra.program.model.data.*;
|
||||||
|
import ghidra.util.task.TaskMonitor;
|
||||||
|
|
||||||
|
public class ApportHeader implements StructConverter {
|
||||||
|
|
||||||
|
public final static String NAME = "APPORT_HEADER";
|
||||||
|
|
||||||
|
private Map<String,String> map = new HashMap<>();
|
||||||
|
private Map<String,Map<String,String>> smaps = new HashMap<>();
|
||||||
|
private Map<Integer, Integer> lineLens = new HashMap<>();
|
||||||
|
private Map<Integer, String> keys = new HashMap<>();
|
||||||
|
private String signature;
|
||||||
|
|
||||||
|
protected DumpFileReader reader;
|
||||||
|
protected long index;
|
||||||
|
|
||||||
|
private TaskMonitor monitor;
|
||||||
|
private int lineCount = 0;
|
||||||
|
private int memoryRegionOffset;
|
||||||
|
|
||||||
|
|
||||||
|
ApportHeader(DumpFileReader reader, long index, TaskMonitor monitor) throws IOException {
|
||||||
|
this.reader = reader;
|
||||||
|
this.index = index;
|
||||||
|
this.monitor = monitor;
|
||||||
|
parse();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void parse() throws IOException {
|
||||||
|
if (lineCount > 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
reader.setPointerIndex(index);
|
||||||
|
|
||||||
|
List<Integer> lineEnds = new ArrayList<>();
|
||||||
|
List<String> lines = new ArrayList<>();
|
||||||
|
ByteProvider provider = reader.getByteProvider();
|
||||||
|
byte [] bytes = new byte[(int) reader.length()];
|
||||||
|
int idx = 0;
|
||||||
|
monitor.setMessage("Parsing file");
|
||||||
|
monitor.initialize(reader.length());
|
||||||
|
for (int i = 0; i < reader.length(); i++) {
|
||||||
|
byte b = provider.readByte(i);
|
||||||
|
if (b == '\n') {
|
||||||
|
String l = new String(bytes, 0, idx);
|
||||||
|
lines.add(l);
|
||||||
|
lineEnds.add(i);
|
||||||
|
idx = 0;
|
||||||
|
lineLens.put(lineCount, l.length());
|
||||||
|
lineCount++;
|
||||||
|
monitor.setProgress(i);
|
||||||
|
} else {
|
||||||
|
bytes[idx++] = b;
|
||||||
|
}
|
||||||
|
if (monitor.isCancelled()) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
String key = "";
|
||||||
|
boolean useSubMap = false;
|
||||||
|
Map<String,String> submap = null;
|
||||||
|
int sub = 0;
|
||||||
|
monitor.setMessage("Parsing entries");
|
||||||
|
monitor.initialize(lineEnds.size());
|
||||||
|
for (int i = 0; i < lineEnds.size(); i++) {
|
||||||
|
monitor.setProgress(i);
|
||||||
|
if (monitor.isCancelled()) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
String line = lines.get(i);
|
||||||
|
if (line.startsWith("CoreDump")) {
|
||||||
|
memoryRegionOffset = lineEnds.get(i);
|
||||||
|
}
|
||||||
|
int sep = line.indexOf(":");
|
||||||
|
if (sep < 0 || line.substring(0,sep).contains(" ")) {
|
||||||
|
String subkey = key+"["+sub+"]";
|
||||||
|
keys.put(i, subkey);
|
||||||
|
if (useSubMap) {
|
||||||
|
submap.put(subkey, line);
|
||||||
|
if (line.length() < 100 && line.contains(": ")) {
|
||||||
|
String [] split = line.split(": ");
|
||||||
|
submap.put(split[0], split[1]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
sub++;
|
||||||
|
} else {
|
||||||
|
key = line.substring(0, sep);
|
||||||
|
String value = line.substring(sep+1).trim();
|
||||||
|
keys.put(i, key);
|
||||||
|
useSubMap = value.equals("") || value.equals("base64");
|
||||||
|
if (useSubMap) {
|
||||||
|
submap = new HashMap<>();
|
||||||
|
smaps.put(key, submap);
|
||||||
|
} else {
|
||||||
|
map.put(key, value);
|
||||||
|
submap = null;
|
||||||
|
}
|
||||||
|
sub = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @see ghidra.app.util.bin.StructConverter#toDataType()
|
||||||
|
*/
|
||||||
|
public DataType toDataType() {
|
||||||
|
StructureDataType struct = new StructureDataType(NAME, 0);
|
||||||
|
for (int i = 0; i < lineCount; i++) {
|
||||||
|
Integer length = lineLens.get(i);
|
||||||
|
if (length < 0) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
String key = keys.get(i);
|
||||||
|
StringDataType str = new StringDataType();
|
||||||
|
Map<String, String> smap = smaps.get(key);
|
||||||
|
struct.add(str, length+1, key, null);
|
||||||
|
if (key.equals("CoreDump")) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (smap != null) {
|
||||||
|
Structure substruct = new StructureDataType(key, 0);
|
||||||
|
for (String skey : smap.keySet()) {
|
||||||
|
length = lineLens.get(++i);
|
||||||
|
str = new StringDataType();
|
||||||
|
substruct.add(str, length+1, skey, null);
|
||||||
|
}
|
||||||
|
struct.add(substruct, substruct.getDisplayName(), null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct.setCategoryPath(new CategoryPath("/APDMP"));
|
||||||
|
|
||||||
|
return struct;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getSignature() {
|
||||||
|
return signature;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSignature(String signature) {
|
||||||
|
this.signature = signature;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getLineCount() {
|
||||||
|
return lineCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getMachineImageType() {
|
||||||
|
return map.get("Architecture");
|
||||||
|
}
|
||||||
|
|
||||||
|
public MemoryInfo getMemoryInfo(int i) {
|
||||||
|
Map<String, String> procMap = smaps.get("ProcMaps");
|
||||||
|
return new MemoryInfo(procMap.get("ProcMaps["+i+"]"));
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getMemoryRegionCount() {
|
||||||
|
return smaps.get("ProcMaps").size();
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getMemoryRegionOffset() {
|
||||||
|
return memoryRegionOffset;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getBlob(int i) {
|
||||||
|
Map<String, String> cd = smaps.get("CoreDump");
|
||||||
|
return cd.get("CoreDump["+i+"]");
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getBlobCount() {
|
||||||
|
Map<String, String> cd = smaps.get("CoreDump");
|
||||||
|
return cd.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,172 @@
|
|||||||
|
/* ###
|
||||||
|
* 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.file.formats.dump.apport;
|
||||||
|
|
||||||
|
import java.io.*;
|
||||||
|
import java.nio.file.AccessMode;
|
||||||
|
import java.nio.file.Files;
|
||||||
|
import java.nio.file.attribute.*;
|
||||||
|
import java.util.Base64;
|
||||||
|
import java.util.Base64.Decoder;
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.zip.DataFormatException;
|
||||||
|
import java.util.zip.Inflater;
|
||||||
|
|
||||||
|
import aQute.lib.io.IO;
|
||||||
|
import ghidra.app.util.bin.ByteProvider;
|
||||||
|
import ghidra.app.util.bin.FileByteProvider;
|
||||||
|
import ghidra.file.formats.dump.DumpFile;
|
||||||
|
import ghidra.util.Msg;
|
||||||
|
import ghidra.util.exception.CancelledException;
|
||||||
|
import ghidra.util.task.TaskMonitor;
|
||||||
|
|
||||||
|
public class DecodedProvider implements ByteProvider {
|
||||||
|
|
||||||
|
private String name;
|
||||||
|
private ApportHeader fileHeader;
|
||||||
|
private long decompressedLength;
|
||||||
|
private FileByteProvider tempProvider;
|
||||||
|
private byte compressionMethod;
|
||||||
|
private byte compressionHeaderFlags;
|
||||||
|
private Object compressionTimeStamp;
|
||||||
|
private byte compressionFlags;
|
||||||
|
private byte compressionOS;
|
||||||
|
|
||||||
|
public DecodedProvider(DumpFile df, ByteProvider provider, TaskMonitor monitor)
|
||||||
|
throws CancelledException, IOException {
|
||||||
|
Apport pt = (Apport) df;
|
||||||
|
fileHeader = pt.getFileHeader();
|
||||||
|
name = provider.getName() + "(decoded)";
|
||||||
|
init(monitor);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void init(TaskMonitor monitor) throws CancelledException, IOException {
|
||||||
|
FileAttribute<Set<PosixFilePermission>> permissions = PosixFilePermissions
|
||||||
|
.asFileAttribute(PosixFilePermissions.fromString("rw-------"));
|
||||||
|
File tempFile = Files.createTempFile("decode", ".dat", permissions).toFile();
|
||||||
|
boolean success = false;
|
||||||
|
try {
|
||||||
|
try (OutputStream out = IO.outputStream(tempFile)) {
|
||||||
|
Decoder decoder = Base64.getDecoder();
|
||||||
|
Inflater inflater = new Inflater(true);
|
||||||
|
byte[] decompressed = new byte[0x10000000];
|
||||||
|
monitor.setMessage("Decompressing data");
|
||||||
|
monitor.initialize(decompressedLength);
|
||||||
|
int written = 0;
|
||||||
|
byte[] header = decoder.decode(fileHeader.getBlob(0).trim());
|
||||||
|
parseHeader(header);
|
||||||
|
for (int i = 1; i < fileHeader.getBlobCount(); i++) {
|
||||||
|
monitor.checkCanceled();
|
||||||
|
byte[] decode = decoder.decode(fileHeader.getBlob(i).trim());
|
||||||
|
inflater.setInput(decode, 0, decode.length);
|
||||||
|
int nDecompressed = inflater.inflate(decompressed);
|
||||||
|
out.write(decompressed, 0, nDecompressed);
|
||||||
|
written += nDecompressed;
|
||||||
|
monitor.setProgress(written);
|
||||||
|
}
|
||||||
|
decompressedLength = written;
|
||||||
|
}
|
||||||
|
tempProvider = new FileByteProvider(tempFile, null, AccessMode.READ);
|
||||||
|
success = true;
|
||||||
|
}
|
||||||
|
catch (DataFormatException e) {
|
||||||
|
throw new IOException("apport decompress failure", e);
|
||||||
|
}
|
||||||
|
finally {
|
||||||
|
if (!success) {
|
||||||
|
tempFile.delete();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void parseHeader(byte[] header) {
|
||||||
|
compressionMethod = header[2];
|
||||||
|
compressionHeaderFlags = header[3];
|
||||||
|
compressionTimeStamp = (((header[4] << 8) | header[5]) << 8 | header[6]) << 8 | header[7];
|
||||||
|
compressionFlags = header[8];
|
||||||
|
compressionOS = header[9];
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public File getFile() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getName() {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getAbsolutePath() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public long length() {
|
||||||
|
if (decompressedLength <= 0) {
|
||||||
|
throw new RuntimeException("Decompressed length = "+decompressedLength);
|
||||||
|
}
|
||||||
|
return decompressedLength;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isValidIndex(long index) {
|
||||||
|
return index < length();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void close() throws IOException {
|
||||||
|
File tempFile = tempProvider.getFile();
|
||||||
|
tempProvider.close();
|
||||||
|
tempFile.delete();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public byte readByte(long index) throws IOException {
|
||||||
|
return readBytes(index,1)[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public byte[] readBytes(long index, long length) throws IOException {
|
||||||
|
try {
|
||||||
|
return tempProvider.readBytes(index, length);
|
||||||
|
} catch (IOException e) {
|
||||||
|
return new byte[(int) length];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public byte getCompressionMethod() {
|
||||||
|
return compressionMethod;
|
||||||
|
}
|
||||||
|
|
||||||
|
public byte getCompressionHeaderFlags() {
|
||||||
|
return compressionHeaderFlags;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Object getCompressionTimeStamp() {
|
||||||
|
return compressionTimeStamp;
|
||||||
|
}
|
||||||
|
|
||||||
|
public byte getCompressionFlags() {
|
||||||
|
return compressionFlags;
|
||||||
|
}
|
||||||
|
|
||||||
|
public byte getCompressionOS() {
|
||||||
|
return compressionOS;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,92 @@
|
|||||||
|
/* ###
|
||||||
|
* 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.file.formats.dump.apport;
|
||||||
|
|
||||||
|
public class MemoryInfo {
|
||||||
|
|
||||||
|
public final static String NAME = "MINIDUMP_MEMORY_INFO";
|
||||||
|
|
||||||
|
private long baseAddress;
|
||||||
|
private long regionSize;
|
||||||
|
private String permissions;
|
||||||
|
private long rva;
|
||||||
|
private String description;
|
||||||
|
|
||||||
|
private String text;
|
||||||
|
|
||||||
|
|
||||||
|
MemoryInfo(String text) {
|
||||||
|
this.text = text;
|
||||||
|
parse();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void parse() {
|
||||||
|
String[] split = text.trim().split("\\s+");
|
||||||
|
String range = split[0];
|
||||||
|
String[] rangeSplit = range.split("-");
|
||||||
|
long start = Long.parseUnsignedLong(rangeSplit[0], 16);
|
||||||
|
long stop = Long.parseUnsignedLong(rangeSplit[1], 16);
|
||||||
|
baseAddress = start;
|
||||||
|
regionSize = stop - start;
|
||||||
|
setPermissions(split[1]);
|
||||||
|
long offset = Long.parseUnsignedLong(split[2], 16);
|
||||||
|
setRva(offset);
|
||||||
|
if (split.length > 5) {
|
||||||
|
setDescription(split[5]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public long getBaseAddress() {
|
||||||
|
return baseAddress;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setBaseAddress(long baseAddress) {
|
||||||
|
this.baseAddress = baseAddress;
|
||||||
|
}
|
||||||
|
|
||||||
|
public long getRegionSize() {
|
||||||
|
return regionSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setRegionSize(long regionSize) {
|
||||||
|
this.regionSize = regionSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getPermissions() {
|
||||||
|
return permissions;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setPermissions(String permissions) {
|
||||||
|
this.permissions = permissions;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getDescription() {
|
||||||
|
return description;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setDescription(String description) {
|
||||||
|
this.description = description;
|
||||||
|
}
|
||||||
|
|
||||||
|
public long getRva() {
|
||||||
|
return rva;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setRva(long rva) {
|
||||||
|
this.rva = rva;
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user