mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2026-01-10 06:27:59 -05:00
Merge remote-tracking branch 'origin/GP-1978_Dan_torchFrameworkDebugging-pt1--SQUASHED'
This commit is contained in:
@@ -24,17 +24,6 @@ apply from: "$rootProject.projectDir/gradle/debugger/hasNodepJar.gradle"
|
||||
apply plugin: 'eclipse'
|
||||
eclipse.project.name = 'Debug Debugger-agent-dbgeng'
|
||||
|
||||
dependencies {
|
||||
api project(":Framework-AsyncComm")
|
||||
api project(":Framework-Debugging")
|
||||
api project(":Debugger-gadp")
|
||||
|
||||
//testImplementation project(":Base")
|
||||
testImplementation project(path: ':Framework-AsyncComm', configuration: 'testArtifacts')
|
||||
testImplementation project(path: ':Framework-Debugging', configuration: 'testArtifacts')
|
||||
testImplementation project(path: ":Debugger-gadp", configuration: 'testArtifacts')
|
||||
}
|
||||
|
||||
ext.tlb = file("build/os/win_x86_64/dbgmodel.tlb")
|
||||
|
||||
if ("win_x86_64".equals(getCurrentPlatformName())) {
|
||||
@@ -98,15 +87,3 @@ distributePyDep("capstone-5.0.1-py3-none-win_amd64.whl")
|
||||
distributePyDep("comtypes-1.4.1-py3-none-any.whl")
|
||||
distributePyDep("pywin32-306-cp312-cp312-win_amd64.whl")
|
||||
|
||||
tasks.nodepJar {
|
||||
manifest {
|
||||
attributes['Main-Class'] = 'agent.dbgeng.gadp.DbgEngGadpServer'
|
||||
}
|
||||
}
|
||||
|
||||
test {
|
||||
jvmArgs('-Xrs') // TODO: Is this needed, or left over from trial-and-error
|
||||
if ("win_x86_64".equals(getCurrentPlatformName())) {
|
||||
dependsOn(":Framework-Debugging:testSpecimenWin_x86_64")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,95 +0,0 @@
|
||||
/* ###
|
||||
* 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 agent.dbgeng;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
|
||||
import agent.dbgeng.model.impl.DbgModelImpl;
|
||||
import ghidra.dbg.DebuggerModelFactory;
|
||||
import ghidra.dbg.DebuggerObjectModel;
|
||||
import ghidra.dbg.util.ConfigurableFactory.FactoryDescription;
|
||||
import ghidra.program.model.listing.Program;
|
||||
|
||||
@FactoryDescription(
|
||||
brief = "MS dbgeng.dll (WinDbg)",
|
||||
htmlDetails = """
|
||||
Connect to the Microsoft Debug Engine.
|
||||
This is the same engine that powers WinDbg.
|
||||
This is best for most Windows userspace and kernel targets.
|
||||
Kernel debugging is still experimental.
|
||||
This will access the native API, which may put Ghidra's JVM at risk.""")
|
||||
public class DbgEngInJvmDebuggerModelFactory implements DebuggerModelFactory {
|
||||
|
||||
protected String remote = "none"; // Require user to start server
|
||||
@FactoryOption("DebugConnect options (.server)")
|
||||
public final Property<String> agentRemoteOption =
|
||||
Property.fromAccessors(String.class, this::getAgentRemote, this::setAgentRemote);
|
||||
|
||||
protected String transport = "none"; // Require user to start server
|
||||
@FactoryOption("Remote process server options (untested)")
|
||||
public final Property<String> agentTransportOption =
|
||||
Property.fromAccessors(String.class, this::getAgentTransport, this::setAgentTransport);
|
||||
|
||||
@Override
|
||||
public CompletableFuture<? extends DebuggerObjectModel> build() {
|
||||
DbgModelImpl model = new DbgModelImpl();
|
||||
List<String> cmds = new ArrayList<>();
|
||||
completeCommandLine(cmds);
|
||||
return model.startDbgEng(cmds.toArray(new String[cmds.size()])).thenApply(__ -> model);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getPriority(Program program) {
|
||||
// TODO: Might instead look for the DLL
|
||||
if (!System.getProperty("os.name").toLowerCase().contains("windows")) {
|
||||
return -1;
|
||||
}
|
||||
if (program != null) {
|
||||
String exe = program.getExecutablePath();
|
||||
if (exe == null || exe.isBlank()) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
return 80;
|
||||
}
|
||||
|
||||
public String getAgentTransport() {
|
||||
return transport;
|
||||
}
|
||||
|
||||
public void setAgentTransport(String transport) {
|
||||
this.transport = transport;
|
||||
}
|
||||
|
||||
public String getAgentRemote() {
|
||||
return remote;
|
||||
}
|
||||
|
||||
public void setAgentRemote(String remote) {
|
||||
this.remote = remote;
|
||||
}
|
||||
|
||||
protected void completeCommandLine(List<String> cmd) {
|
||||
if (!remote.equals("none") && !remote.equals("")) {
|
||||
cmd.addAll(List.of(remote));
|
||||
}
|
||||
if (!transport.equals("none") && !transport.equals("")) {
|
||||
cmd.addAll(List.of(transport));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,72 +0,0 @@
|
||||
/* ###
|
||||
* 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 agent.dbgeng.dbgeng;
|
||||
|
||||
import com.sun.jna.platform.win32.WinNT.HRESULT;
|
||||
import com.sun.jna.platform.win32.COM.COMException;
|
||||
import com.sun.jna.platform.win32.COM.COMUtils;
|
||||
|
||||
/**
|
||||
* Utilities for interacting with Microsoft COM objects beyond those provided by {@link COMUtils}.
|
||||
*
|
||||
* See the MSDN for details on the meanings of the return codes for the function or method of
|
||||
* interest.
|
||||
*/
|
||||
public interface COMUtilsExtra {
|
||||
|
||||
public static HRESULT E_UNEXPECTED = new HRESULT(0x8000FFFF);
|
||||
public static HRESULT E_BOUNDS = new HRESULT(0x8000000B);
|
||||
public static HRESULT E_NOTIMPLEMENTED = new HRESULT(0x80004001);
|
||||
public static HRESULT E_NOINTERFACE = new HRESULT(0x80004002);
|
||||
public static HRESULT E_COM_EXC = new HRESULT(0x80004003);
|
||||
public static HRESULT E_FAIL = new HRESULT(0x80004005);
|
||||
public static HRESULT E_CANTCALLOUT_INASYNCCALL = new HRESULT(0x80010004);
|
||||
public static HRESULT E_INTERNALEXCEPTION = new HRESULT(0x80040205);
|
||||
public static HRESULT E_ACCESS_DENIED = new HRESULT(0x80070005);
|
||||
public static HRESULT E_CANNOT_READ = new HRESULT(0x8007001E);
|
||||
public static HRESULT E_INVALID_PARAM = new HRESULT(0x80070057);
|
||||
public static HRESULT E_SCOPE_NOT_FOUND = new HRESULT(0x8007013E);
|
||||
|
||||
/**
|
||||
* Check if the given exception represents an {@code E_NOINTERFACE} result
|
||||
*
|
||||
* @param e the exception
|
||||
* @return true if {@code E_NOINTERFACE}
|
||||
*/
|
||||
static boolean isE_NOINTERFACE(COMException e) {
|
||||
return E_NOINTERFACE.equals(e.getHresult());
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the given exception represents an {@code E_UNEXPECTED} result
|
||||
*
|
||||
* @param e the exception
|
||||
* @return true if {@code E_UNEXPECTED}
|
||||
*/
|
||||
static boolean isE_UNEXPECTED(COMException e) {
|
||||
return E_UNEXPECTED.equals(e.getHresult());
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the given exception represents an {@code E_INTERNALEXCEPTION} result
|
||||
*
|
||||
* @param e the exception
|
||||
* @return true if {@code E_INTERNALEXCEPTION}
|
||||
*/
|
||||
static boolean isE_INTERNALEXCEPTION(COMException e) {
|
||||
return E_INTERNALEXCEPTION.equals(e.getHresult());
|
||||
}
|
||||
}
|
||||
@@ -1,163 +0,0 @@
|
||||
/* ###
|
||||
* 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 agent.dbgeng.dbgeng;
|
||||
|
||||
import java.lang.ref.Cleaner;
|
||||
|
||||
import com.sun.jna.WString;
|
||||
import com.sun.jna.platform.win32.Kernel32Util;
|
||||
import com.sun.jna.platform.win32.WinDef.DWORD;
|
||||
import com.sun.jna.platform.win32.WinNT.HANDLE;
|
||||
import com.sun.jna.platform.win32.COM.IUnknown;
|
||||
|
||||
import agent.dbgeng.impl.dbgeng.client.DebugClientInternal;
|
||||
import agent.dbgeng.jna.dbgeng.DbgEngNative;
|
||||
import ghidra.comm.util.BitmaskSet;
|
||||
import ghidra.util.Msg;
|
||||
|
||||
/**
|
||||
* A wrapper for Microsoft's {@code dbgeng.dll} that presents a Java-friendly interface.
|
||||
*
|
||||
* This is the "root interface" from which all other interfaces to {@code dbgeng.dll} are generated.
|
||||
* Not every method listed in the documentation, nor every method present in the header, is
|
||||
* implemented. Only those that were necessary to implement the SCTL adapter. However, the class and
|
||||
* interface hierarchy was designed so that adding the remaining methods should be fairly
|
||||
* straightforward. This wrapper attempts to obtain the most capable COM interfaces for the debug
|
||||
* client that it knows. Again, newer interfaces should be fairly straightforward to add.
|
||||
*
|
||||
* Methods that are "obviously" wrappers for a COM method are left undocumented, unless there is
|
||||
* some nuance to how it has been wrapped. In many cases, a parameter which is an integer in the COM
|
||||
* method may be presented as an {@code enum} or {@link BitmaskSet} by the wrapper. Consult the MSDN
|
||||
* for the meaning of the various values and bit flags.
|
||||
*
|
||||
* Each wrapper interface is implemented by several COM interface wrappers: one for each known COM
|
||||
* interface version. The wrapper is optimistic, in that it declares wrapper methods even for COM
|
||||
* methods that are only available in later versions. The implementations limited to earlier COM
|
||||
* interfaces should either emulate the operation, or throw an
|
||||
* {@link UnsupportedOperationException}. Where a newer method is provided by a newer interface, a
|
||||
* wrapper implementation should prefer the latest. For example, one series of interfaces introduces
|
||||
* {@code *Wide} variants of existing methods. Since Java also uses a UTF-16-like string encoding
|
||||
* internally, JNA permits wide strings to be passed by reference. Thus, the wide variant is always
|
||||
* preferred.
|
||||
*
|
||||
* Pay careful attention to the threading requirements imposed by {@code dbgeng.dll} these can be
|
||||
* found in the MSDN. As a general rule of thumb, if the method is reentrant (i.e., it can be called
|
||||
* from any thread), it is declared in the {@code *Reentrant} variant of the wrapper interface.
|
||||
* There are few of these. Unless the documentation explicitly lists the method as reentrant, do not
|
||||
* declare it there. Many methods appear to execute successfully from the wrong thread, but cause
|
||||
* latent issues. A practice to prevent accidental use of non-reentrant methods outside of the
|
||||
* client's owning thread is to ensure that only the owning thread can see the full interface. All
|
||||
* other threads should only have access to the reentrant interface.
|
||||
*
|
||||
* If you implement methods that introduce a new callback class, use the existing callback type
|
||||
* hierarchies as a model. There are many classes to implement. Furthermore, be sure to keep a
|
||||
* reference to any active callback instances within the wrapper that uses them. The JNA has no way
|
||||
* of knowing whether or not the instance is still being used by the external C/C++ library. If you
|
||||
* do not store a reference, the JVM will think it's garbage and free it, even though COM is still
|
||||
* using it. Drop the reference only when you are certain nothing external has a reference to it.
|
||||
*/
|
||||
public class DbgEng {
|
||||
private static final Cleaner CLEANER = Cleaner.create();
|
||||
|
||||
private static class ReleaseCOMObject implements Runnable {
|
||||
private final IUnknown obj;
|
||||
|
||||
ReleaseCOMObject(IUnknown obj) {
|
||||
this.obj = obj;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
Msg.debug(this, "Releasing COM object: " + obj);
|
||||
obj.Release();
|
||||
}
|
||||
}
|
||||
|
||||
private static class ReleaseHANDLE implements Runnable {
|
||||
private final HANDLE handle;
|
||||
|
||||
public ReleaseHANDLE(HANDLE handle) {
|
||||
this.handle = handle;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
Kernel32Util.closeHandle(handle);
|
||||
}
|
||||
}
|
||||
|
||||
public static class OpaqueCleanable {
|
||||
@SuppressWarnings("unused") // A reference to control GC
|
||||
private final Object state;
|
||||
@SuppressWarnings("unused") // A reference to control GC
|
||||
private final Cleaner.Cleanable cleanable;
|
||||
|
||||
public OpaqueCleanable(Object state, Cleaner.Cleanable cleanable) {
|
||||
this.state = state;
|
||||
this.cleanable = cleanable;
|
||||
}
|
||||
}
|
||||
|
||||
public static OpaqueCleanable releaseWhenPhantom(Object owner, IUnknown obj) {
|
||||
ReleaseCOMObject state = new ReleaseCOMObject(obj);
|
||||
return new OpaqueCleanable(state, CLEANER.register(owner, state));
|
||||
}
|
||||
|
||||
public static OpaqueCleanable releaseWhenPhantom(Object owner, HANDLE handle) {
|
||||
ReleaseHANDLE state = new ReleaseHANDLE(handle);
|
||||
return new OpaqueCleanable(state, CLEANER.register(owner, state));
|
||||
}
|
||||
|
||||
/**
|
||||
* Connect to a debug session.
|
||||
*
|
||||
* See {@code DebugConnect} or {@code DebugConnectWide} on the MSDN.
|
||||
*
|
||||
* @param remoteOptions the options, like those given to {@code -remote}
|
||||
* @return a new client connected as specified
|
||||
*/
|
||||
public static DebugClient debugConnect(String remoteOptions) {
|
||||
WString options = new WString(remoteOptions);
|
||||
return DebugClientInternal.tryPreferredInterfaces((refiid,
|
||||
ppClient) -> DbgEngNative.INSTANCE.DebugConnectWide(options, refiid, ppClient));
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a debug client.
|
||||
*
|
||||
* Typically, this client is connected to the "local server". See {@code DebugCreate} on the
|
||||
* MSDN.
|
||||
*
|
||||
* @return a new client
|
||||
*/
|
||||
public static DebugClient debugCreate() {
|
||||
return DebugClientInternal.tryPreferredInterfaces(DbgEngNative.INSTANCE::DebugCreate);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a debug client with the given options.
|
||||
*
|
||||
* See {@code DebugCreateEx} on the MSDN.
|
||||
*
|
||||
* @param options the options
|
||||
* @return a new client
|
||||
*/
|
||||
public static DebugClient debugCreate(int options) {
|
||||
DWORD dwOpts = new DWORD(options);
|
||||
return DebugClientInternal.tryPreferredInterfaces(
|
||||
(refiid, ppClient) -> DbgEngNative.INSTANCE.DebugCreateEx(refiid, dwOpts, ppClient));
|
||||
}
|
||||
}
|
||||
@@ -1,83 +0,0 @@
|
||||
/* ###
|
||||
* 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 agent.dbgeng.dbgeng;
|
||||
|
||||
/**
|
||||
* A wrapper for {@code IDebugAdvanced} and its newer variants.
|
||||
*/
|
||||
public interface DebugAdvanced {
|
||||
public static class DebugThreadBasicInformation {
|
||||
public final Integer exitStatus;
|
||||
public final Integer priorityClass;
|
||||
public final Integer priority;
|
||||
public final Long createTime;
|
||||
public final Long exitTime;
|
||||
public final Long kernelTime;
|
||||
public final Long userTime;
|
||||
public final Long startOffset;
|
||||
public final Long affinity;
|
||||
|
||||
public DebugThreadBasicInformation(Integer exitStatus, Integer priorityClass,
|
||||
Integer priority, Long createTime, Long exitTime, Long kernelTime, Long userTime,
|
||||
Long startOffset, Long affinity) {
|
||||
this.exitStatus = exitStatus;
|
||||
this.priorityClass = priorityClass;
|
||||
this.priority = priority;
|
||||
this.createTime = createTime;
|
||||
this.exitTime = exitTime;
|
||||
this.kernelTime = kernelTime;
|
||||
this.userTime = userTime;
|
||||
this.startOffset = startOffset;
|
||||
this.affinity = affinity;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuilder sb = new StringBuilder("<DebugThreadBasicInformation:\n");
|
||||
if (exitStatus != null) {
|
||||
sb.append(" exitStatus: " + exitStatus + "\n");
|
||||
}
|
||||
if (priorityClass != null) {
|
||||
sb.append(" priorityClass: " + priorityClass + "\n");
|
||||
}
|
||||
if (priority != null) {
|
||||
sb.append(" priority: " + priority + "\n");
|
||||
}
|
||||
if (createTime != null) {
|
||||
sb.append(" createTime: " + createTime + "\n");
|
||||
}
|
||||
if (exitTime != null) {
|
||||
sb.append(" exitTime: " + exitTime + "\n");
|
||||
}
|
||||
if (kernelTime != null) {
|
||||
sb.append(" kernelTime: " + kernelTime + "\n");
|
||||
}
|
||||
if (userTime != null) {
|
||||
sb.append(" userTime: " + userTime + "\n");
|
||||
}
|
||||
if (startOffset != null) {
|
||||
sb.append(" startOffset: " + startOffset + "\n");
|
||||
}
|
||||
if (affinity != null) {
|
||||
sb.append(" affinity: " + affinity + "\n");
|
||||
}
|
||||
sb.append(">");
|
||||
return sb.toString();
|
||||
}
|
||||
}
|
||||
|
||||
DebugThreadBasicInformation getThreadBasicInformation(DebugThreadId tid);
|
||||
}
|
||||
@@ -1,137 +0,0 @@
|
||||
/* ###
|
||||
* 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 agent.dbgeng.dbgeng;
|
||||
|
||||
import agent.dbgeng.jna.dbgeng.WinNTExtra.Machine;
|
||||
import ghidra.comm.util.BitmaskSet;
|
||||
import ghidra.comm.util.BitmaskUniverse;
|
||||
|
||||
/**
|
||||
* A wrapper for {@code IDebugBreakpoint} and its newer variants.
|
||||
*/
|
||||
public interface DebugBreakpoint {
|
||||
public static enum BreakType {
|
||||
CODE, DATA, TIME, INLINE;
|
||||
}
|
||||
|
||||
public static class BreakFullType {
|
||||
public final BreakType breakType;
|
||||
public final Machine procType; // TODO: Guessing the values are from WinNT
|
||||
|
||||
public BreakFullType(BreakType breakType, Machine procType) {
|
||||
this.breakType = breakType;
|
||||
this.procType = procType;
|
||||
}
|
||||
}
|
||||
|
||||
public static enum BreakFlags implements BitmaskUniverse {
|
||||
GO_ONLY(1 << 0), //
|
||||
DEFERRED(1 << 1), //
|
||||
ENABLED(1 << 2), //
|
||||
ADDER_ONLY(1 << 3), //
|
||||
ONE_SHOT(1 << 4), //
|
||||
;
|
||||
|
||||
private BreakFlags(int mask) {
|
||||
this.mask = mask;
|
||||
}
|
||||
|
||||
private final int mask;
|
||||
|
||||
@Override
|
||||
public long getMask() {
|
||||
return mask;
|
||||
}
|
||||
}
|
||||
|
||||
public static enum BreakAccess implements BitmaskUniverse {
|
||||
READ(1 << 0), //
|
||||
WRITE(1 << 1), //
|
||||
EXECUTE(1 << 2), //
|
||||
IO(1 << 3), //
|
||||
;
|
||||
|
||||
private BreakAccess(int mask) {
|
||||
this.mask = mask;
|
||||
}
|
||||
|
||||
private final int mask;
|
||||
|
||||
@Override
|
||||
public long getMask() {
|
||||
return mask;
|
||||
}
|
||||
}
|
||||
|
||||
public static class BreakDataParameters {
|
||||
public int size;
|
||||
public BitmaskSet<BreakAccess> access;
|
||||
|
||||
public BreakDataParameters(int size, BitmaskSet<BreakAccess> access) {
|
||||
this.size = size;
|
||||
this.access = access;
|
||||
}
|
||||
}
|
||||
|
||||
void remove();
|
||||
|
||||
int getId();
|
||||
|
||||
BreakFullType getType();
|
||||
|
||||
DebugClient getAdder();
|
||||
|
||||
BitmaskSet<BreakFlags> getFlags();
|
||||
|
||||
void addFlags(BitmaskSet<BreakFlags> flags);
|
||||
|
||||
void addFlags(BreakFlags... flags);
|
||||
|
||||
void removeFlags(BitmaskSet<BreakFlags> flags);
|
||||
|
||||
void removeFlags(BreakFlags... flags);
|
||||
|
||||
void setFlags(BitmaskSet<BreakFlags> flags);
|
||||
|
||||
void setFlags(BreakFlags... flags);
|
||||
|
||||
/**
|
||||
* Get the location on target that triggers the breakpoint
|
||||
*
|
||||
* <p>
|
||||
* If the breakpoint is deferred, this will return {@code null}. In that case, use
|
||||
* {@link #getOffsetExpression()}.
|
||||
*
|
||||
* @return the offset, or {@code null}
|
||||
*/
|
||||
Long getOffset();
|
||||
|
||||
void setOffset(long offset);
|
||||
|
||||
String getOffsetExpression();
|
||||
|
||||
void setOffsetExpression(String expression);
|
||||
|
||||
BreakDataParameters getDataParameters();
|
||||
|
||||
void setDataParameters(BreakDataParameters params);
|
||||
|
||||
void setDataParameters(int size, BitmaskSet<BreakAccess> access);
|
||||
|
||||
void setDataParameters(int size, BreakAccess... access);
|
||||
|
||||
void dispose();
|
||||
}
|
||||
@@ -1,434 +0,0 @@
|
||||
/* ###
|
||||
* 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 agent.dbgeng.dbgeng;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import com.sun.jna.platform.win32.WinBase;
|
||||
|
||||
import agent.dbgeng.dbgeng.DebugRunningProcess.Description;
|
||||
import agent.dbgeng.dbgeng.DebugRunningProcess.Description.ProcessDescriptionFlags;
|
||||
import ghidra.comm.util.BitmaskSet;
|
||||
import ghidra.comm.util.BitmaskUniverse;
|
||||
|
||||
/**
|
||||
* A wrapper for {@code IDebugClient} and its newer variants.
|
||||
*/
|
||||
public interface DebugClient extends DebugClientReentrant {
|
||||
public static enum ExecutionState {
|
||||
RUNNING, STOPPED;
|
||||
}
|
||||
|
||||
public static enum DebugStatus {
|
||||
NO_CHANGE(false, null, 13), //
|
||||
GO(true, ExecutionState.RUNNING, 10), //
|
||||
GO_HANDLED(true, ExecutionState.RUNNING, 9), //
|
||||
GO_NOT_HANDLED(true, ExecutionState.RUNNING, 8), //
|
||||
STEP_OVER(true, ExecutionState.RUNNING, 7), //
|
||||
STEP_INTO(true, ExecutionState.RUNNING, 5), //
|
||||
BREAK(false, ExecutionState.STOPPED, 0), //
|
||||
NO_DEBUGGEE(true, null, 1), // shouldWait is true to handle process creation
|
||||
STEP_BRANCH(true, ExecutionState.RUNNING, 6), //
|
||||
IGNORE_EVENT(false, null, 11), //
|
||||
RESTART_REQUESTED(true, null, 12), //
|
||||
REVERSE_GO(true, null, 0xff), //
|
||||
REVERSE_STEP_BRANCH(true, null, 0xff), //
|
||||
REVERSE_STEP_OVER(true, null, 0xff), //
|
||||
REVERSE_STEP_INTO(true, null, 0xff), //
|
||||
OUT_OF_SYNC(false, null, 2), //
|
||||
WAIT_INPUT(false, null, 3), //
|
||||
TIMEOUT(false, null, 4), //
|
||||
;
|
||||
|
||||
public static final long MASK = 0xaf;
|
||||
public static final long INSIDE_WAIT = 0x100000000L;
|
||||
public static final long WAIT_TIMEOUT = 0x200000000L;
|
||||
|
||||
DebugStatus(boolean shouldWait, ExecutionState threadState, int precedence) {
|
||||
this.shouldWait = shouldWait;
|
||||
this.threadState = threadState;
|
||||
this.precedence = precedence;
|
||||
}
|
||||
|
||||
public final boolean shouldWait;
|
||||
public final ExecutionState threadState;
|
||||
public final int precedence; // 0 is highest
|
||||
|
||||
public static DebugStatus fromArgument(long argument) {
|
||||
return values()[(int) (argument & MASK)];
|
||||
}
|
||||
|
||||
public static boolean isInsideWait(long argument) {
|
||||
return (argument & INSIDE_WAIT) != 0;
|
||||
}
|
||||
|
||||
public static boolean isWaitTimeout(long argument) {
|
||||
return (argument & WAIT_TIMEOUT) != 0;
|
||||
}
|
||||
}
|
||||
|
||||
public static enum SessionStatus {
|
||||
ACTIVE, //
|
||||
END_SESSION_ACTIVE_TERMINATE,//
|
||||
END_SESSION_ACTIVE_DETACH, //
|
||||
END_SESSION_PASSIVE, //
|
||||
END, //
|
||||
REBOOT, //
|
||||
HIBERNATE, //
|
||||
FAILURE, //
|
||||
;
|
||||
}
|
||||
|
||||
public static enum ChangeDebuggeeState implements BitmaskUniverse {
|
||||
ALL(0xffffffff), //
|
||||
REGISTERS(1 << 0), //
|
||||
DATA(1 << 1), //
|
||||
REFRESH(1 << 2), //
|
||||
;
|
||||
|
||||
private ChangeDebuggeeState(int mask) {
|
||||
this.mask = mask;
|
||||
}
|
||||
|
||||
private final int mask;
|
||||
|
||||
@Override
|
||||
public long getMask() {
|
||||
return mask;
|
||||
}
|
||||
}
|
||||
|
||||
public static enum ChangeEngineState implements BitmaskUniverse {
|
||||
ALL(0xffffffff), //
|
||||
CURRENT_THREAD(1 << 0), //
|
||||
EFFECTIVE_PROCESSOR(1 << 1), //
|
||||
BREAKPOINTS(1 << 2), //
|
||||
CODE_LEVEL(1 << 3), //
|
||||
EXECUTION_STATUS(1 << 4), //
|
||||
ENGINE_OPTIONS(1 << 5), //
|
||||
LOG_FILE(1 << 6), //
|
||||
RADIX(1 << 7), //
|
||||
EVENT_FILTERS(1 << 8), //
|
||||
PROCESS_OPTIONS(1 << 9), //
|
||||
EXTENSIONS(1 << 10), //
|
||||
SYSTEMS(1 << 11), //
|
||||
ASSEMBLY_OPTIONS(1 << 12), //
|
||||
EXPRESSION_SYNTAX(1 << 13), //
|
||||
TEXT_REPLACEMENTS(1 << 14), //
|
||||
;
|
||||
|
||||
private ChangeEngineState(int mask) {
|
||||
this.mask = mask;
|
||||
}
|
||||
|
||||
private final int mask;
|
||||
|
||||
@Override
|
||||
public long getMask() {
|
||||
return mask;
|
||||
}
|
||||
}
|
||||
|
||||
public static enum ChangeSymbolState implements BitmaskUniverse {
|
||||
ALL(0xffffffff), //
|
||||
LOADS(1 << 0), //
|
||||
UNLOADS(1 << 1), //
|
||||
SCOPE(1 << 2), //
|
||||
PATHS(1 << 3), //
|
||||
SYMBOL_OPTIONS(1 << 4), //
|
||||
TYPE_OPTIONS(1 << 5), //
|
||||
;
|
||||
|
||||
private ChangeSymbolState(int mask) {
|
||||
this.mask = mask;
|
||||
}
|
||||
|
||||
private final int mask;
|
||||
|
||||
@Override
|
||||
public long getMask() {
|
||||
return mask;
|
||||
}
|
||||
}
|
||||
|
||||
public static enum DebugAttachFlags implements BitmaskUniverse {
|
||||
DEFAULT(0), //
|
||||
NONINVASIVE(1 << 0), //
|
||||
EXISTING(1 << 1), //
|
||||
NONINVASIVE_NO_SUSPEND(1 << 2), //
|
||||
INVASIVE_NO_INITIAL_BREAK(1 << 3), //
|
||||
INVASIVE_RESUME_PROCESS(1 << 4), //
|
||||
NONINVASIVE_ALLOW_PARTIAL(1 << 5), //
|
||||
;
|
||||
|
||||
DebugAttachFlags(int mask) {
|
||||
this.mask = mask;
|
||||
}
|
||||
|
||||
private final int mask;
|
||||
|
||||
@Override
|
||||
public long getMask() {
|
||||
return mask;
|
||||
}
|
||||
}
|
||||
|
||||
public static enum DebugCreateFlags implements BitmaskUniverse {
|
||||
DEBUG_PROCESS(WinBase.DEBUG_PROCESS), //
|
||||
DEBUG_ONLY_THIS_PROCESS(WinBase.DEBUG_ONLY_THIS_PROCESS), //
|
||||
CREATE_SUSPENDED(WinBase.CREATE_SUSPENDED), //
|
||||
DETACHED_PROCESS(WinBase.DETACHED_PROCESS), //
|
||||
|
||||
CREATE_NEW_CONSOLE(WinBase.CREATE_NEW_CONSOLE), //
|
||||
//NORMAL_PRIORITY_CLASS(WinBase.NORMAL_PRIORITY_CLASS), //
|
||||
//IDLE_PRIORITY_CLASS(WinBase.IDLE_PRIORITY_CLASS), //
|
||||
//HIGH_PRIORITY_CLASS(WinBase.HIGH_PRIORITY_CLASS), //
|
||||
|
||||
//REALTIME_PRIORITY_CLASS(WinBase.REALTIME_PRIORITY_CLASS), //
|
||||
CREATE_NEW_PROCESS_GROUP(WinBase.CREATE_NEW_PROCESS_GROUP), //
|
||||
CREATE_UNICODE_ENVIRONMENT(WinBase.CREATE_UNICODE_ENVIRONMENT), //
|
||||
CREATE_SEPARATE_WOW_VDM(WinBase.CREATE_SEPARATE_WOW_VDM), //
|
||||
|
||||
CREATE_SHARED_WOW_VDM(WinBase.CREATE_SHARED_WOW_VDM), //
|
||||
CREATE_FORCEDOS(WinBase.CREATE_FORCEDOS), //
|
||||
//BELOW_NORMAL_PRIORITY_CLASS(WinBase.BELOW_NORMAL_PRIORITY_CLASS), //
|
||||
//ABOVE_NORMAL_PRIORITY_CLASS(WinBase.ABOVE_NORMAL_PRIORITY_CLASS), //
|
||||
|
||||
INHERIT_PARENT_AFFINITY(WinBase.INHERIT_PARENT_AFFINITY), //
|
||||
//INHERIT_CALLER_PRIORITY(WinBase.INHERIT_CALLER_PRIORITY), //
|
||||
CREATE_PROTECTED_PROCESS(WinBase.CREATE_PROTECTED_PROCESS), //
|
||||
EXTENDED_STARTUPINFO_PRESENT(WinBase.EXTENDED_STARTUPINFO_PRESENT), //
|
||||
|
||||
//PROCESS_MODE_BACKGROUND_BEGIN(WinBase.PROCESS_MODE_BACKGROUND_BEGIN), //
|
||||
//PROCESS_MODE_BACKGROUND_END(WinBase.PROCESS_MODE_BACKGROUND_END), //
|
||||
|
||||
CREATE_BREAKAWAY_FROM_JOB(WinBase.CREATE_BREAKAWAY_FROM_JOB), //
|
||||
CREATE_PRESERVE_CODE_AUTHZ_LEVEL(WinBase.CREATE_PRESERVE_CODE_AUTHZ_LEVEL), //
|
||||
CREATE_DEFAULT_ERROR_MODE(WinBase.CREATE_DEFAULT_ERROR_MODE), //
|
||||
CREATE_NO_WINDOW(WinBase.CREATE_NO_WINDOW), //
|
||||
|
||||
//PROFILE_USER(WinBase.PROFILE_USER), //
|
||||
//PROFILE_KERNEL(WinBase.PROFILE_KERNEL), //
|
||||
//PROFILE_SERVER(WinBase.PROFILE_SERVER), //
|
||||
//CREATE_IGNORE_SYSTEM_DEFAULT(WinBase.CREATE_IGNORE_SYSTEM_DEFAULT), //
|
||||
DEBUG_CREATE_NO_DEBUG_HEAP(0x00000400), //
|
||||
DEBUG_CREATE_THROUGH_RTL(0x00010000), //
|
||||
;
|
||||
|
||||
DebugCreateFlags(int mask) {
|
||||
this.mask = mask;
|
||||
}
|
||||
|
||||
private final int mask;
|
||||
|
||||
@Override
|
||||
public long getMask() {
|
||||
return mask;
|
||||
}
|
||||
}
|
||||
|
||||
public enum DebugEngCreateFlags implements BitmaskUniverse {
|
||||
DEBUG_ECREATE_PROCESS_DEFAULT(0x00000000),
|
||||
DEBUG_ECREATE_INHERIT_HANDLES(0x00000001),
|
||||
DEBUG_ECREATE_USE_VERIFIER_FLAGS(0x00000002),
|
||||
DEBUG_ECREATE_USE_IMPLICIT_COMMAND_LINE(0x00000004);
|
||||
|
||||
DebugEngCreateFlags(int mask) {
|
||||
this.mask = mask;
|
||||
}
|
||||
|
||||
private final int mask;
|
||||
|
||||
@Override
|
||||
public long getMask() {
|
||||
return mask;
|
||||
}
|
||||
}
|
||||
|
||||
public enum DebugVerifierFlags implements BitmaskUniverse {
|
||||
DEBUG_VERIFIER_DEFAULT(0x00000000);
|
||||
|
||||
DebugVerifierFlags(int mask) {
|
||||
this.mask = mask;
|
||||
}
|
||||
|
||||
private final int mask;
|
||||
|
||||
@Override
|
||||
public long getMask() {
|
||||
return mask;
|
||||
}
|
||||
}
|
||||
|
||||
public enum DebugEndSessionFlags {
|
||||
DEBUG_END_PASSIVE(0x00000000),
|
||||
DEBUG_END_ACTIVE_TERMINATE(0x00000001),
|
||||
DEBUG_END_ACTIVE_DETACH(0x00000002),
|
||||
DEBUG_END_REENTRANT(0x00000003),
|
||||
DEBUG_END_DISCONNECT(0x00000004);
|
||||
|
||||
DebugEndSessionFlags(int value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
private final int value;
|
||||
|
||||
public long getValue() {
|
||||
return value;
|
||||
}
|
||||
}
|
||||
|
||||
public enum DebugOutputFlags {
|
||||
DEBUG_OUTPUT_NORMAL(0x1), //
|
||||
DEBUG_OUTPUT_ERROR(0x2), //
|
||||
DEBUG_OUTPUT_WARNING(0x4), //
|
||||
DEBUG_OUTPUT_VERBOSE(0x8), //
|
||||
DEBUG_OUTPUT_PROMPT(0x10), //
|
||||
DEBUG_OUTPUT_PROMPT_REGISTERS(0x20), //
|
||||
DEBUG_OUTPUT_EXTENSION_WARNING(0x40), //
|
||||
DEBUG_OUTPUT_DEBUGGEE(0x80), //
|
||||
DEBUG_OUTPUT_DEBUGGEE_PROMPT(0x100), //
|
||||
DEBUG_OUTPUT_SYMBOLS(0x200);
|
||||
|
||||
DebugOutputFlags(int value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
private final int value;
|
||||
|
||||
public long getValue() {
|
||||
return value;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Obtain the advanced interface to this client.
|
||||
*
|
||||
* @return the advanced interface
|
||||
*/
|
||||
DebugAdvanced getAdvanced();
|
||||
|
||||
/**
|
||||
* Obtain the control interface to this client
|
||||
*
|
||||
* @return the control interface
|
||||
*/
|
||||
@Override
|
||||
DebugControl getControl();
|
||||
|
||||
/**
|
||||
* Obtain the data spaces interface to this client
|
||||
*
|
||||
* @return the data spaces interface
|
||||
*/
|
||||
DebugDataSpaces getDataSpaces();
|
||||
|
||||
/**
|
||||
* Obtain the registers interface to this client
|
||||
*
|
||||
* @return the registers interface
|
||||
*/
|
||||
DebugRegisters getRegisters();
|
||||
|
||||
/**
|
||||
* Obtain the symbols interface to this client
|
||||
*
|
||||
* @return the symbols interface
|
||||
*/
|
||||
DebugSymbols getSymbols();
|
||||
|
||||
/**
|
||||
* Obtain the system objects interface to this client
|
||||
*
|
||||
* @return the system objects interface
|
||||
*/
|
||||
DebugSystemObjects getSystemObjects();
|
||||
|
||||
/**
|
||||
* The ID for the local server
|
||||
*
|
||||
* @return the ID
|
||||
*/
|
||||
DebugServerId getLocalServer();
|
||||
|
||||
void attachKernel(long flags, String options);
|
||||
|
||||
void startProcessServer(String options);
|
||||
|
||||
DebugServerId connectProcessServer(String options);
|
||||
|
||||
boolean dispatchCallbacks(int timeout);
|
||||
|
||||
void flushCallbacks();
|
||||
|
||||
default void dispatchCallbacks() {
|
||||
this.dispatchCallbacks(-1);
|
||||
}
|
||||
|
||||
void exitDispatch(DebugClient client);
|
||||
|
||||
default void exitDispatch() {
|
||||
exitDispatch(this);
|
||||
}
|
||||
|
||||
void setInputCallbacks(DebugInputCallbacks cb);
|
||||
|
||||
void setOutputCallbacks(DebugOutputCallbacks cb);
|
||||
|
||||
void setEventCallbacks(DebugEventCallbacks cb);
|
||||
|
||||
List<DebugRunningProcess> getRunningProcesses(DebugServerId server);
|
||||
|
||||
Description getProcessDescription(DebugServerId si, int systemId,
|
||||
BitmaskSet<ProcessDescriptionFlags> flags);
|
||||
|
||||
void attachProcess(DebugServerId si, long processId, BitmaskSet<DebugAttachFlags> attachFlags);
|
||||
|
||||
void createProcess(DebugServerId si, String commandLine,
|
||||
String initialDirectory, String environment,
|
||||
BitmaskSet<DebugCreateFlags> createFlags,
|
||||
BitmaskSet<DebugEngCreateFlags> engCreateFlags,
|
||||
BitmaskSet<DebugVerifierFlags> verifierFlags);
|
||||
|
||||
void createProcessAndAttach(DebugServerId si, String commandLine,
|
||||
BitmaskSet<DebugCreateFlags> createFlags, int processId,
|
||||
BitmaskSet<DebugAttachFlags> attachFlags);
|
||||
|
||||
void startServer(String options);
|
||||
|
||||
// Only in IDebugClient2
|
||||
|
||||
void waitForProcessServerEnd(int timeout);
|
||||
|
||||
default void waitForProcessServerEnd() {
|
||||
waitForProcessServerEnd(-1);
|
||||
}
|
||||
|
||||
void terminateCurrentProcess();
|
||||
|
||||
void detachCurrentProcess();
|
||||
|
||||
void abandonCurrentProcess();
|
||||
|
||||
void connectSession(int flags);
|
||||
|
||||
void endSession(DebugEndSessionFlags flags);
|
||||
|
||||
// Only in IDebugClient4+
|
||||
|
||||
void openDumpFileWide(String fileName);
|
||||
|
||||
}
|
||||
@@ -1,46 +0,0 @@
|
||||
/* ###
|
||||
* 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 agent.dbgeng.dbgeng;
|
||||
|
||||
/**
|
||||
* An interface containing the subset of {@link DebugClient} methods which are reentrant.
|
||||
*
|
||||
* All other methods should be called only by the thread which created the client.
|
||||
*/
|
||||
public interface DebugClientReentrant {
|
||||
/**
|
||||
* Create a new client for the calling thread, connected to the same session as this client.
|
||||
*
|
||||
* @return the new client
|
||||
*/
|
||||
DebugClient createClient();
|
||||
|
||||
/**
|
||||
* Get the reentrant control interface to the client
|
||||
*
|
||||
* @return the control interface
|
||||
*/
|
||||
DebugControlReentrant getControl();
|
||||
|
||||
/**
|
||||
* End a session without acquiring locks
|
||||
*
|
||||
* Note. This method calls {@code IDebugClient::EndSession(DEBUG_END_REENTRANT)}. Per the MSDN,
|
||||
* this may leave the engine in an indeterminate state. The engine should no longer be used by
|
||||
* this process. It's really only appropriate to use this method when terminating the debugger.
|
||||
*/
|
||||
void endSessionReentrant();
|
||||
}
|
||||
@@ -1,447 +0,0 @@
|
||||
/* ###
|
||||
* 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 agent.dbgeng.dbgeng;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import com.sun.jna.platform.win32.WinBase;
|
||||
import com.sun.jna.platform.win32.COM.COMException;
|
||||
|
||||
import agent.dbgeng.dbgeng.DebugBreakpoint.BreakType;
|
||||
import agent.dbgeng.dbgeng.DebugClient.DebugStatus;
|
||||
import ghidra.comm.util.BitmaskSet;
|
||||
import ghidra.comm.util.BitmaskUniverse;
|
||||
import ghidra.util.Msg;
|
||||
|
||||
/**
|
||||
* A wrapper for {@code IDebugControl} and its newer variants.
|
||||
*/
|
||||
public interface DebugControl extends DebugControlReentrant {
|
||||
public static final BitmaskSet<DebugOutputControl> SET_ALL_CLIENTS =
|
||||
BitmaskSet.of(DebugOutputControl.ALL_CLIENTS);
|
||||
public static final BitmaskSet<DebugExecute> SET_DEFAULT = BitmaskSet.of(DebugExecute.DEFAULT);
|
||||
|
||||
public static enum DebugOutputLevel implements BitmaskUniverse {
|
||||
NORMAL(1 << 0), //
|
||||
ERROR(1 << 1), //
|
||||
WARNING(1 << 2), //
|
||||
VERBOSE(1 << 3), //
|
||||
PROMPT(1 << 4), //
|
||||
PROMPT_REGISTERS(1 << 5), //
|
||||
EXTENSION_WARNING(1 << 6), //
|
||||
OUTPUT_DEBUGEE(1 << 7), //
|
||||
OUTPUT_DEBUGEE_PROMPT(1 << 8), //
|
||||
OUTPUT_SYMBOLS(1 << 9), //
|
||||
OUTPUT_STATUS(1 << 10), //
|
||||
;
|
||||
|
||||
private final int mask;
|
||||
|
||||
DebugOutputLevel(int mask) {
|
||||
this.mask = mask;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getMask() {
|
||||
return mask;
|
||||
}
|
||||
}
|
||||
|
||||
public static enum DebugOutputControl implements BitmaskUniverse {
|
||||
THIS_CLIENT(0), //
|
||||
ALL_CLIENTS(1), //
|
||||
ALL_OTHER_CLIENTS(2), //
|
||||
IGNORE(3), //
|
||||
LOG_ONLY(4), //
|
||||
SEND_MASK(7), //
|
||||
NOT_LOGGED(1 << 3), //
|
||||
OVERRIDE_MASK(1 << 4), //
|
||||
DML(1 << 5), //
|
||||
AMBIENT_DML(0xfffffffe), //
|
||||
AMBIENT_TEXT(0xffffffff), //
|
||||
AMBIENT(0xffffffff), //
|
||||
;
|
||||
|
||||
private final int mask;
|
||||
|
||||
DebugOutputControl(int mask) {
|
||||
this.mask = mask;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getMask() {
|
||||
return mask;
|
||||
}
|
||||
}
|
||||
|
||||
public static enum DebugExecute implements BitmaskUniverse {
|
||||
DEFAULT(0), //
|
||||
ECHO(1 << 0), //
|
||||
NOT_LOGGED(1 << 1), //
|
||||
NO_REPEAT(1 << 2), //
|
||||
;
|
||||
|
||||
private final int mask;
|
||||
|
||||
DebugExecute(int mask) {
|
||||
this.mask = mask;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getMask() {
|
||||
return mask;
|
||||
}
|
||||
}
|
||||
|
||||
public static enum DebugInterrupt {
|
||||
ACTIVE, //
|
||||
PASSIVE, //
|
||||
EXIT, //
|
||||
;
|
||||
}
|
||||
|
||||
public static enum DebugFilterOrdinals {
|
||||
DEBUG_FILTER_CREATE_THREAD, //
|
||||
DEBUG_FILTER_EXIT_THREAD, //
|
||||
DEBUG_FILTER_CREATE_PROCESS, //
|
||||
DEBUG_FILTER_EXIT_PROCESS, //
|
||||
DEBUG_FILTER_LOAD_MODULE, //
|
||||
DEBUG_FILTER_UNLOAD_MODULE, //
|
||||
DEBUG_FILTER_SYSTEM_ERROR, //
|
||||
DEBUG_FILTER_INITIAL_BREAKPOINT, //
|
||||
DEBUG_FILTER_INITIAL_MODULE_LOAD, //
|
||||
DEBUG_FILTER_DEBUGGEE_OUTPUT, //
|
||||
;
|
||||
}
|
||||
|
||||
public static enum DebugFilterExecutionOption {
|
||||
DEBUG_FILTER_BREAK(0, "Break"), //
|
||||
DEBUG_FILTER_SECOND_CHANCE_BREAK(1, "Second-chance Break"), //
|
||||
DEBUG_FILTER_OUTPUT(2, "Output-only"), //
|
||||
DEBUG_FILTER_IGNORE(3, "Ignore"), //
|
||||
DEBUG_FILTER_REMOVE(4, "Remove"), //
|
||||
;
|
||||
|
||||
public static DebugFilterExecutionOption getByNumber(int val) {
|
||||
for (DebugFilterExecutionOption m : DebugFilterExecutionOption.values()) {
|
||||
if (m.val == val) {
|
||||
return m;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
DebugFilterExecutionOption(int val, String description) {
|
||||
this.val = val;
|
||||
this.description = description;
|
||||
}
|
||||
|
||||
public final int val;
|
||||
public final String description;
|
||||
}
|
||||
|
||||
public static enum DebugFilterContinuationOption {
|
||||
DEBUG_FILTER_GO_HANDLED(0, "Handled"), //
|
||||
DEBUG_FILTER_GO_NOT_HANDLED(1, "Not Handled"), //
|
||||
;
|
||||
|
||||
public static DebugFilterContinuationOption getByNumber(int val) {
|
||||
for (DebugFilterContinuationOption m : DebugFilterContinuationOption.values()) {
|
||||
if (m.val == val) {
|
||||
return m;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
DebugFilterContinuationOption(int val, String description) {
|
||||
this.val = val;
|
||||
this.description = description;
|
||||
}
|
||||
|
||||
public final int val;
|
||||
public final String description;
|
||||
}
|
||||
|
||||
boolean getInterrupt();
|
||||
|
||||
int getInterruptTimeout();
|
||||
|
||||
void setInterruptTimeout(int seconds);
|
||||
|
||||
void print(BitmaskSet<DebugOutputLevel> levels, String message);
|
||||
|
||||
/**
|
||||
* A shortcut for {@link #print(BitmaskSet, String)} that includes a newline.
|
||||
*
|
||||
* @param levels the log levels for the message
|
||||
* @param message the message
|
||||
*/
|
||||
void println(BitmaskSet<DebugOutputLevel> levels, String message);
|
||||
|
||||
/**
|
||||
* A shortcut for {@link #print(BitmaskSet, String)} that applies to a single level.
|
||||
*
|
||||
* @param level the log level for the message
|
||||
* @param message the message
|
||||
*/
|
||||
default void print(DebugOutputLevel level, String message) {
|
||||
print(BitmaskSet.of(level), message);
|
||||
}
|
||||
|
||||
/**
|
||||
* A shortcut for {@link #print(BitmaskSet, String)} that includes a newline and applies to a
|
||||
* single level.
|
||||
*
|
||||
* @param level the log level for the message
|
||||
* @param message the message
|
||||
*/
|
||||
default void println(DebugOutputLevel level, String message) {
|
||||
println(BitmaskSet.of(level), message);
|
||||
}
|
||||
|
||||
/**
|
||||
* A shortcut for {@link #print(BitmaskSet, String)} at normal level.
|
||||
*
|
||||
* @param message the message
|
||||
*/
|
||||
default void out(String message) {
|
||||
print(DebugOutputLevel.NORMAL, message);
|
||||
}
|
||||
|
||||
/**
|
||||
* A shortcut for {@link #println(BitmaskSet, String)} at normal level.
|
||||
*
|
||||
* @param message the message
|
||||
*/
|
||||
default void outln(String message) {
|
||||
println(DebugOutputLevel.NORMAL, message);
|
||||
}
|
||||
|
||||
/**
|
||||
* A shortcut for {@link #print(BitmaskSet, String)} at warning level.
|
||||
*
|
||||
* @param message the message
|
||||
*/
|
||||
default void warn(String message) {
|
||||
print(DebugOutputLevel.WARNING, message);
|
||||
}
|
||||
|
||||
/**
|
||||
* A shortcut for {@link #println(BitmaskSet, String)} at warning level.
|
||||
*
|
||||
* @param message the message
|
||||
*/
|
||||
default void warnln(String message) {
|
||||
println(DebugOutputLevel.WARNING, message);
|
||||
}
|
||||
|
||||
/**
|
||||
* A shortcut for {@link #print(BitmaskSet, String)} at error level.
|
||||
*
|
||||
* @param message the message
|
||||
*/
|
||||
default void err(String message) {
|
||||
print(DebugOutputLevel.ERROR, message);
|
||||
}
|
||||
|
||||
/**
|
||||
* A shortcut for {@link #println(BitmaskSet, String)} at error level.
|
||||
*
|
||||
* @param message the message
|
||||
*/
|
||||
default void errln(String message) {
|
||||
println(DebugOutputLevel.ERROR, message);
|
||||
}
|
||||
|
||||
/**
|
||||
* A shortcut for {@link #print(BitmaskSet, String)} at verbose level.
|
||||
*
|
||||
* @param message the message
|
||||
*/
|
||||
default void verb(String message) {
|
||||
print(DebugOutputLevel.VERBOSE, message);
|
||||
}
|
||||
|
||||
/**
|
||||
* A shortcut for {@link #println(BitmaskSet, String)} at verbose level.
|
||||
*
|
||||
* @param message the message
|
||||
*/
|
||||
default void verbln(String message) {
|
||||
println(DebugOutputLevel.VERBOSE, message);
|
||||
}
|
||||
|
||||
<T extends DebugValue> T evaluate(Class<T> desiredType, String expression);
|
||||
|
||||
void execute(BitmaskSet<DebugOutputControl> ctl, String str, BitmaskSet<DebugExecute> flags);
|
||||
|
||||
/**
|
||||
* A shortcut for {@link #execute(BitmaskSet, String, BitmaskSet)} outputting to all clients
|
||||
* with the default execution flag.
|
||||
*
|
||||
* @param str the command string
|
||||
*/
|
||||
default void execute(String str) {
|
||||
execute(SET_ALL_CLIENTS, str, SET_DEFAULT);
|
||||
}
|
||||
|
||||
void prompt(BitmaskSet<DebugOutputControl> ctl, String message);
|
||||
|
||||
String getPromptText();
|
||||
|
||||
void returnInput(String input);
|
||||
|
||||
DebugStatus getExecutionStatus();
|
||||
|
||||
void setExecutionStatus(DebugStatus status);
|
||||
|
||||
int getNumberBreakpoints();
|
||||
|
||||
DebugBreakpoint getBreakpointByIndex(int index);
|
||||
|
||||
/**
|
||||
* Shortcut to retrieve all breakpoints for the current process.
|
||||
*
|
||||
* <p>
|
||||
* Uses {@link #getNumberBreakpoints()} and {@link #getBreakpointByIndex(int)} to enumerate all
|
||||
* breakpoints for the current process.
|
||||
*
|
||||
* @return the list of retrieved breakpoints.
|
||||
*/
|
||||
default List<DebugBreakpoint> getBreakpoints() {
|
||||
int count = getNumberBreakpoints();
|
||||
List<DebugBreakpoint> result = new ArrayList<>(count);
|
||||
for (int i = 0; i < count; i++) {
|
||||
try {
|
||||
result.add(getBreakpointByIndex(i));
|
||||
}
|
||||
catch (COMException e) {
|
||||
if (!COMUtilsExtra.isE_NOINTERFACE(e)) {
|
||||
throw e;
|
||||
}
|
||||
Msg.trace(this, "Discarding private breakpoint at index " + i);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a breakpoint by ID
|
||||
*
|
||||
* According to the MSDN, though the IDs may be global, this method should only succeed for
|
||||
* breakpoints belonging to the current process.
|
||||
*
|
||||
* @param id
|
||||
* @return
|
||||
*/
|
||||
DebugBreakpoint getBreakpointById(int id);
|
||||
|
||||
/**
|
||||
* Add a (resolved) breakpoint with the given type and desired id
|
||||
*
|
||||
* <p>
|
||||
* This is equivalent, in part, to the {@code bp} command.
|
||||
*
|
||||
* @param type the type
|
||||
* @param desiredId the desired id
|
||||
* @return the breakpoint, disabled at offset 0
|
||||
*/
|
||||
DebugBreakpoint addBreakpoint(BreakType type, int desiredId);
|
||||
|
||||
/**
|
||||
* Add a (resolved) breakpoint with the given type and any id
|
||||
*
|
||||
* <p>
|
||||
* This is equivalent, in part, to the {@code bp} command.
|
||||
*
|
||||
* @param type the type
|
||||
* @return the breakpoint, disable at offset 0
|
||||
*/
|
||||
DebugBreakpoint addBreakpoint(BreakType type);
|
||||
|
||||
/**
|
||||
* Add an unresolved breakpoint with the given type and desired id
|
||||
*
|
||||
* <p>
|
||||
* This is equivalent, in part, to the {@code bu} command. See the MSDN for a comparison of
|
||||
* {@code bu} and {@code bp}.
|
||||
*
|
||||
* @param type the type
|
||||
* @param desiredId the desired id
|
||||
* @return the breakpoint, disabled at offset 0
|
||||
*/
|
||||
DebugBreakpoint addBreakpoint2(BreakType type, int desiredId);
|
||||
|
||||
/**
|
||||
* Add an unresolved breakpoint with the given type and any id
|
||||
*
|
||||
* <p>
|
||||
* This is equivalent, in part, to the {@code bu} command. See the MSDN for a comparison of
|
||||
* {@code bu} and {@code bp}.
|
||||
*
|
||||
* @param desiredId the desired id
|
||||
* @return the breakpoint, disabled at offset 0
|
||||
*/
|
||||
DebugBreakpoint addBreakpoint2(BreakType type);
|
||||
|
||||
void waitForEvent(int timeout);
|
||||
|
||||
DebugEventInformation getLastEventInformation();
|
||||
|
||||
DebugStackInformation getStackTrace(long frameOffset, long stackOffset, long instructionOffset);
|
||||
|
||||
/**
|
||||
* Shortcut for {@link #waitForEvent(int)} with infinite timeout.
|
||||
*/
|
||||
default void waitForEvent() {
|
||||
waitForEvent(WinBase.INFINITE);
|
||||
}
|
||||
|
||||
int getActualProcessorType();
|
||||
|
||||
int getEffectiveProcessorType();
|
||||
|
||||
int getExecutingProcessorType();
|
||||
|
||||
int getDebuggeeType();
|
||||
|
||||
DebugFilterInformation getNumberEventFilters();
|
||||
|
||||
String getEventFilterText(int index, int size);
|
||||
|
||||
String getEventFilterCommand(int index, int size);
|
||||
|
||||
void setEventFilterCommand(int index, String text);
|
||||
|
||||
DebugSpecificFilterInformation getSpecificFilterParameters(int start, int count);
|
||||
|
||||
void setSpecificFilterParameters(int start, int count, DebugSpecificFilterInformation info);
|
||||
|
||||
String getSpecificFilterArgument(int index, int size);
|
||||
|
||||
void setSpecificFilterArgument(int index, String arg);
|
||||
|
||||
DebugExceptionFilterInformation getExceptionFilterParameters(int start, int[] codes, int count);
|
||||
|
||||
void setExceptionFilterParameters(int count, DebugExceptionFilterInformation info);
|
||||
|
||||
String getExceptionFilterSecondCommand(int index, int size);
|
||||
|
||||
void setExceptionFilterSecondCommand(int index, String cmd);
|
||||
|
||||
}
|
||||
@@ -1,27 +0,0 @@
|
||||
/* ###
|
||||
* 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 agent.dbgeng.dbgeng;
|
||||
|
||||
import agent.dbgeng.dbgeng.DebugControl.DebugInterrupt;
|
||||
|
||||
/**
|
||||
* An interface containing the subset of {@link DebugControl} methods which are reentrant.
|
||||
*
|
||||
* All other methods should be called only by the thread which created the client.
|
||||
*/
|
||||
public interface DebugControlReentrant {
|
||||
void setInterrupt(DebugInterrupt interrupt);
|
||||
}
|
||||
@@ -1,290 +0,0 @@
|
||||
/* ###
|
||||
* 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 agent.dbgeng.dbgeng;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.*;
|
||||
|
||||
import com.sun.jna.platform.win32.COM.COMException;
|
||||
|
||||
import ghidra.comm.util.BitmaskSet;
|
||||
import ghidra.comm.util.BitmaskUniverse;
|
||||
import ghidra.util.Msg;
|
||||
|
||||
/**
|
||||
* A wrapper for {@code IDebugDataSpaces} and its newer variants.
|
||||
*/
|
||||
public interface DebugDataSpaces {
|
||||
public enum PageState {
|
||||
COMMIT(0x1000), FREE(0x10000), RESERVE(0x2000);
|
||||
|
||||
private final int val;
|
||||
|
||||
private PageState(int val) {
|
||||
this.val = val;
|
||||
}
|
||||
|
||||
public static PageState byValue(int val) {
|
||||
for (PageState state : values()) {
|
||||
if (state.val == val) {
|
||||
return state;
|
||||
}
|
||||
}
|
||||
Msg.warn(PageState.class, "No such value: 0x" + Integer.toHexString(val));
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public enum PageProtection implements BitmaskUniverse {
|
||||
NOACCESS(1 << 0, false, false, false), //
|
||||
READONLY(1 << 1, true, false, false), //
|
||||
READWRITE(1 << 2, true, true, false), //
|
||||
WRITE_COPY(1 << 3, true, true, false), // Becomes READWRITE after copy
|
||||
EXECUTE(1 << 4, false, false, true), //
|
||||
EXECUTE_READ(1 << 5, true, false, true), //
|
||||
EXECUTE_READWRITE(1 << 6, true, true, true), //
|
||||
EXECUTE_WRITECOPY(1 << 7, true, true, true), //
|
||||
//
|
||||
GUARD(1 << 8, false, false, false), //
|
||||
NOCACHE(1 << 9, false, false, false), //
|
||||
WRITECOMBINE(1 << 10, false, false, false), //
|
||||
;
|
||||
|
||||
private PageProtection(int mask, boolean isRead, boolean isWrite, boolean isExecute) {
|
||||
this.mask = mask;
|
||||
this.isRead = isRead;
|
||||
this.isWrite = isWrite;
|
||||
this.isExecute = isExecute;
|
||||
}
|
||||
|
||||
final int mask;
|
||||
final boolean isRead;
|
||||
final boolean isWrite;
|
||||
final boolean isExecute;
|
||||
|
||||
@Override
|
||||
public long getMask() {
|
||||
return mask;
|
||||
}
|
||||
|
||||
public boolean isRead() {
|
||||
return isRead;
|
||||
}
|
||||
|
||||
public boolean isWrite() {
|
||||
return isWrite;
|
||||
}
|
||||
|
||||
public boolean isExecute() {
|
||||
return isExecute;
|
||||
}
|
||||
}
|
||||
|
||||
public enum PageType {
|
||||
NONE(0), //
|
||||
IMAGE(0x1000000), //
|
||||
MAPPED(0x40000), //
|
||||
PRIVATE(0x20000), //
|
||||
;
|
||||
|
||||
private final int val;
|
||||
|
||||
private PageType(int val) {
|
||||
this.val = val;
|
||||
}
|
||||
|
||||
public static PageType byValue(int val) {
|
||||
for (PageType type : values()) {
|
||||
if (type.val == val) {
|
||||
return type;
|
||||
}
|
||||
}
|
||||
Msg.warn(PageType.class, "No such value: 0x" + Integer.toHexString(val));
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public static class DebugMemoryBasicInformation {
|
||||
public final long baseAddress;
|
||||
public final long allocationBase;
|
||||
public final Set<PageProtection> allocationProtect;
|
||||
public final long regionSize;
|
||||
public final PageState state;
|
||||
public final Set<PageProtection> protect;
|
||||
public final PageType type;
|
||||
|
||||
public DebugMemoryBasicInformation(long baseAddress, long allocationBase,
|
||||
BitmaskSet<PageProtection> allocationProtect, long regionSize, PageState state,
|
||||
BitmaskSet<PageProtection> protect, PageType type) {
|
||||
this.baseAddress = baseAddress;
|
||||
this.allocationBase = allocationBase;
|
||||
this.allocationProtect = Collections.unmodifiableSet(allocationProtect);
|
||||
this.regionSize = regionSize;
|
||||
this.state = state;
|
||||
this.protect = Collections.unmodifiableSet(protect);
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "<DebugMemoryBasicInformation:\n" + //
|
||||
" baseAddress=" + Long.toHexString(baseAddress) + "h,\n" + //
|
||||
" allocationBase=" + Long.toHexString(allocationBase) + "h,\n" + //
|
||||
" allocationProtect=" + allocationProtect + ",\n" + //
|
||||
" regionSize=" + Long.toHexString(regionSize) + "h,\n" + //
|
||||
" state=" + state + ",\n" + //
|
||||
" protect=" + protect + ",\n" + //
|
||||
" type=" + type + "\n" + //
|
||||
">";
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(baseAddress, allocationBase, allocationProtect, regionSize, state,
|
||||
protect, type);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (!(obj instanceof DebugMemoryBasicInformation)) {
|
||||
return false;
|
||||
}
|
||||
DebugMemoryBasicInformation that = (DebugMemoryBasicInformation) obj;
|
||||
if (this.baseAddress != that.baseAddress) {
|
||||
return false;
|
||||
}
|
||||
if (this.allocationBase != that.allocationBase) {
|
||||
return false;
|
||||
}
|
||||
if (!this.allocationProtect.equals(that.allocationProtect)) {
|
||||
return false;
|
||||
}
|
||||
if (this.regionSize != that.regionSize) {
|
||||
return false;
|
||||
}
|
||||
if (this.state != that.state) {
|
||||
return false;
|
||||
}
|
||||
if (!this.protect.equals(that.protect)) {
|
||||
return false;
|
||||
}
|
||||
if (this.type != that.type) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
int readVirtual(long offset, ByteBuffer into, int len);
|
||||
|
||||
int writeVirtual(long offset, ByteBuffer from, int len);
|
||||
|
||||
int readVirtualUncached(long offset, ByteBuffer into, int len);
|
||||
|
||||
int writeVirtualUncached(long offset, ByteBuffer from, int len);
|
||||
|
||||
int readPhysical(long offset, ByteBuffer into, int len);
|
||||
|
||||
int writePhysical(long offset, ByteBuffer from, int len);
|
||||
|
||||
int readControl(int processor, long offset, ByteBuffer into, int len);
|
||||
|
||||
int writeControl(int processor, long offset, ByteBuffer from, int len);
|
||||
|
||||
int readBusData(int busDataType, int busNumber, int slotNumber, long offset, ByteBuffer into,
|
||||
int len);
|
||||
|
||||
int writeBusData(int busDataType, int busNumber, int slotNumber, long offset, ByteBuffer from,
|
||||
int len);
|
||||
|
||||
int readIo(int interfaceType, int busNumber, int addressSpace, long offset, ByteBuffer into,
|
||||
int len);
|
||||
|
||||
int writeIo(int interfaceType, int busNumber, int addressSpace, long offset, ByteBuffer from,
|
||||
int len);
|
||||
|
||||
long readMsr(int msr);
|
||||
|
||||
void writeMsr(int msr, long value);
|
||||
|
||||
int readDebuggerData(int offset, ByteBuffer into, int len);
|
||||
|
||||
DebugMemoryBasicInformation queryVirtual(long offset);
|
||||
|
||||
long virtualToPhysical(long offset);
|
||||
|
||||
/**
|
||||
* A shortcut for iterating over virtual memory regions.
|
||||
*
|
||||
* This operates by calling {@link #queryVirtual(long)} to get each next entry, starting at an
|
||||
* offset of -start-, adding the size of the returned region to determine the offset for the
|
||||
* next call.
|
||||
*
|
||||
* @param start the starting offset
|
||||
* @return an iterator over virtual memory regions after the given start
|
||||
*/
|
||||
default Iterable<DebugMemoryBasicInformation> iterateVirtual(long start) {
|
||||
return new Iterable<DebugMemoryBasicInformation>() {
|
||||
@Override
|
||||
public Iterator<DebugMemoryBasicInformation> iterator() {
|
||||
return new Iterator<DebugMemoryBasicInformation>() {
|
||||
private long last = start;
|
||||
private long offset = start;
|
||||
private DebugMemoryBasicInformation next = doGetNext();
|
||||
|
||||
private DebugMemoryBasicInformation getNext() {
|
||||
if (Long.compareUnsigned(last, offset) < 0) {
|
||||
return doGetNext();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private DebugMemoryBasicInformation doGetNext() {
|
||||
try {
|
||||
DebugMemoryBasicInformation info = queryVirtual(offset);
|
||||
last = offset;
|
||||
if (info != null) {
|
||||
offset += info.regionSize;
|
||||
}
|
||||
return info;
|
||||
}
|
||||
catch (COMException e) {
|
||||
if (!COMUtilsExtra.isE_NOINTERFACE(e)) {
|
||||
throw e;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasNext() {
|
||||
return next != null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DebugMemoryBasicInformation next() {
|
||||
DebugMemoryBasicInformation ret = next;
|
||||
next = getNext();
|
||||
if (ret.equals(next)) {
|
||||
next = null;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
};
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -1,116 +0,0 @@
|
||||
/* ###
|
||||
* 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 agent.dbgeng.dbgeng;
|
||||
|
||||
import java.lang.annotation.*;
|
||||
|
||||
import agent.dbgeng.dbgeng.DebugClient.*;
|
||||
import ghidra.comm.util.BitmaskSet;
|
||||
import ghidra.comm.util.BitmaskUniverse;
|
||||
|
||||
/**
|
||||
* The interface for receiving event callbacks via {@code IDebugEventCallbacks} or a newer variant.
|
||||
*
|
||||
* Note: The wrapper implementation will select the appropriate native interface version.
|
||||
*
|
||||
* Note: Even though {@link #changeDebuggeeState(BitmaskSet, long)},
|
||||
* {@link #changeEngineState(BitmaskSet, long)} and {@link #changeSymbolState(BitmaskSet, long)}
|
||||
* purport to return a {@link DebugStatus}, the returned value is ignored by {@code dbgeng.dll}.
|
||||
*/
|
||||
public interface DebugEventCallbacks {
|
||||
public static enum DebugEvent implements BitmaskUniverse {
|
||||
BREAKPOINT(1 << 0), //
|
||||
EXCEPTION(1 << 1), //
|
||||
CREATE_THREAD(1 << 2), //
|
||||
EXIT_THREAD(1 << 3), //
|
||||
CREATE_PROCESS(1 << 4), //
|
||||
EXIT_PROCESS(1 << 5), //
|
||||
LOAD_MODULE(1 << 6), //
|
||||
UNLOAD_MODULE(1 << 7), //
|
||||
SYSTEM_ERROR(1 << 8), //
|
||||
SESSION_STATUS(1 << 9), //
|
||||
CHANGE_DEBUGEE_STATE(1 << 10), //
|
||||
CHANGE_ENGINE_STATE(1 << 11), //
|
||||
CHANGE_SYMBOL_STATE(1 << 12), //
|
||||
;
|
||||
|
||||
private DebugEvent(int mask) {
|
||||
this.mask = mask;
|
||||
}
|
||||
|
||||
private final int mask;
|
||||
|
||||
@Override
|
||||
public long getMask() {
|
||||
return mask;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* An annotation for marking each callback with its interest flag.
|
||||
*/
|
||||
@Target(ElementType.METHOD)
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
static @interface ForInterest {
|
||||
/**
|
||||
* The flag corresponding to the annotated callback method
|
||||
*
|
||||
* @return the flag
|
||||
*/
|
||||
DebugEvent value();
|
||||
}
|
||||
|
||||
BitmaskSet<DebugEvent> getInterestMask();
|
||||
|
||||
@ForInterest(DebugEvent.BREAKPOINT)
|
||||
DebugStatus breakpoint(DebugBreakpoint bp);
|
||||
|
||||
@ForInterest(DebugEvent.EXCEPTION)
|
||||
DebugStatus exception(DebugExceptionRecord64 exception, boolean firstChance);
|
||||
|
||||
@ForInterest(DebugEvent.CREATE_THREAD)
|
||||
DebugStatus createThread(DebugThreadInfo debugThreadInfo);
|
||||
|
||||
@ForInterest(DebugEvent.EXIT_THREAD)
|
||||
DebugStatus exitThread(int exitCode);
|
||||
|
||||
@ForInterest(DebugEvent.CREATE_PROCESS)
|
||||
DebugStatus createProcess(DebugProcessInfo debugProcessInfo);
|
||||
|
||||
@ForInterest(DebugEvent.EXIT_PROCESS)
|
||||
DebugStatus exitProcess(int exitCode);
|
||||
|
||||
@ForInterest(DebugEvent.LOAD_MODULE)
|
||||
DebugStatus loadModule(DebugModuleInfo debugModuleInfo);
|
||||
|
||||
@ForInterest(DebugEvent.UNLOAD_MODULE)
|
||||
DebugStatus unloadModule(String imageBaseName, long baseOffset);
|
||||
|
||||
@ForInterest(DebugEvent.SYSTEM_ERROR)
|
||||
DebugStatus systemError(int error, int level);
|
||||
|
||||
@ForInterest(DebugEvent.SESSION_STATUS)
|
||||
DebugStatus sessionStatus(SessionStatus status);
|
||||
|
||||
@ForInterest(DebugEvent.CHANGE_DEBUGEE_STATE)
|
||||
DebugStatus changeDebuggeeState(BitmaskSet<ChangeDebuggeeState> flags, long argument);
|
||||
|
||||
@ForInterest(DebugEvent.CHANGE_ENGINE_STATE)
|
||||
DebugStatus changeEngineState(BitmaskSet<ChangeEngineState> flags, long argument);
|
||||
|
||||
@ForInterest(DebugEvent.CHANGE_SYMBOL_STATE)
|
||||
DebugStatus changeSymbolState(BitmaskSet<ChangeSymbolState> flags, long argument);
|
||||
}
|
||||
@@ -1,70 +0,0 @@
|
||||
/* ###
|
||||
* 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 agent.dbgeng.dbgeng;
|
||||
|
||||
import agent.dbgeng.jna.dbgeng.WinNTExtra;
|
||||
|
||||
public class DebugEventInformation {
|
||||
|
||||
private int type;
|
||||
private DebugProcessId pid;
|
||||
private DebugThreadId tid;
|
||||
private DebugSessionId sid;
|
||||
private int executingProcessorType = WinNTExtra.Machine.IMAGE_FILE_MACHINE_AMD64.val;
|
||||
|
||||
public DebugEventInformation(int type, int pid, int tid) {
|
||||
this.type = type;
|
||||
this.pid = new DebugProcessRecord(pid);
|
||||
this.tid = new DebugThreadRecord(tid);
|
||||
}
|
||||
|
||||
public int getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
public DebugSessionId getSessionId() {
|
||||
return sid;
|
||||
}
|
||||
|
||||
public DebugProcessId getProcessId() {
|
||||
return pid;
|
||||
}
|
||||
|
||||
public DebugThreadId getThreadId() {
|
||||
return tid;
|
||||
}
|
||||
|
||||
public void setThread(DebugThreadId tid) {
|
||||
this.tid = tid;
|
||||
}
|
||||
|
||||
public void setProcess(DebugProcessId pid) {
|
||||
this.pid = pid;
|
||||
}
|
||||
|
||||
public void setSession(DebugSessionId sid) {
|
||||
this.sid = sid;
|
||||
}
|
||||
|
||||
public int getExecutingProcessorType() {
|
||||
return executingProcessorType;
|
||||
}
|
||||
|
||||
public void setExecutingProcessorType(int execType) {
|
||||
this.executingProcessorType = execType;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,42 +0,0 @@
|
||||
/* ###
|
||||
* 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 agent.dbgeng.dbgeng;
|
||||
|
||||
import agent.dbgeng.jna.dbgeng.DbgEngNative.DEBUG_EXCEPTION_FILTER_PARAMETERS;
|
||||
|
||||
public class DebugExceptionFilterInformation {
|
||||
|
||||
private int nParams;
|
||||
private DEBUG_EXCEPTION_FILTER_PARAMETERS[] parameters;
|
||||
|
||||
public DebugExceptionFilterInformation(int nParams,
|
||||
DEBUG_EXCEPTION_FILTER_PARAMETERS[] parameters) {
|
||||
this.nParams = nParams;
|
||||
this.parameters = parameters;
|
||||
}
|
||||
|
||||
public int getNumberOfParameters() {
|
||||
return nParams;
|
||||
}
|
||||
|
||||
public DEBUG_EXCEPTION_FILTER_PARAMETERS getParameter(int paramNumber) {
|
||||
return parameters[paramNumber];
|
||||
}
|
||||
|
||||
public DEBUG_EXCEPTION_FILTER_PARAMETERS[] getParameters() {
|
||||
return parameters;
|
||||
}
|
||||
}
|
||||
@@ -1,41 +0,0 @@
|
||||
/* ###
|
||||
* 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 agent.dbgeng.dbgeng;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Data copied from a {@code EXCEPTION_RECORD64} as defined in {@code winnt.h}.
|
||||
*
|
||||
* TODO: Some enums, flags, etc., to help interpret some of the fields.
|
||||
*/
|
||||
public class DebugExceptionRecord64 {
|
||||
public final int code; // TODO: How to interpret
|
||||
public final int flags; // TODO: How to interpret
|
||||
public final long record; // TODO: How to interpret
|
||||
public final long address;
|
||||
public final List<Long> information;
|
||||
|
||||
public DebugExceptionRecord64(int code, int flags, long record, long address,
|
||||
List<Long> information) {
|
||||
this.code = code;
|
||||
this.flags = flags;
|
||||
this.record = record;
|
||||
this.address = address;
|
||||
this.information = Collections.unmodifiableList(information);
|
||||
}
|
||||
}
|
||||
@@ -1,42 +0,0 @@
|
||||
/* ###
|
||||
* 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 agent.dbgeng.dbgeng;
|
||||
|
||||
public class DebugFilterInformation {
|
||||
|
||||
private int nEvents;
|
||||
private int nSpecificExceptions;
|
||||
private int nArbitraryExceptions;
|
||||
|
||||
public DebugFilterInformation(int nEvents, int nSpecificExceptions, int nArbitraryExceptions) {
|
||||
this.nEvents = nEvents;
|
||||
this.nSpecificExceptions = nSpecificExceptions;
|
||||
this.nArbitraryExceptions = nArbitraryExceptions;
|
||||
}
|
||||
|
||||
public int getNumberEvents() {
|
||||
return nEvents;
|
||||
}
|
||||
|
||||
public int getNumberSpecificExceptions() {
|
||||
return nSpecificExceptions;
|
||||
}
|
||||
|
||||
public int getNumberArbitraryExceptions() {
|
||||
return nArbitraryExceptions;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,31 +0,0 @@
|
||||
/* ###
|
||||
* 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 agent.dbgeng.dbgeng;
|
||||
|
||||
/**
|
||||
* The interface for receiving input callbacks via {@code IDebugInputCallbacks} or a newer variant.
|
||||
*
|
||||
* Note: The wrapper implementation will select the appropriate native interface version.
|
||||
*/
|
||||
@FunctionalInterface
|
||||
public interface DebugInputCallbacks {
|
||||
|
||||
public void startInput(long bufferSize);
|
||||
|
||||
default void endInput() {
|
||||
// Optional implementation
|
||||
}
|
||||
}
|
||||
@@ -1,47 +0,0 @@
|
||||
/* ###
|
||||
* 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 agent.dbgeng.dbgeng;
|
||||
|
||||
/**
|
||||
* Handle to a module (program or library image).
|
||||
*/
|
||||
public interface DebugModule {
|
||||
public enum DebugModuleName {
|
||||
IMAGE, MODULE, LOADED_IMAGE, SYMBOL_FILE, MAPPED_IMAGE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a name for the module.
|
||||
*
|
||||
* @param which identifies which name
|
||||
* @return the requested name, if available
|
||||
*/
|
||||
String getName(DebugModuleName which);
|
||||
|
||||
/**
|
||||
* Get the index assigned to this module.
|
||||
*
|
||||
* @return the index
|
||||
*/
|
||||
int getIndex();
|
||||
|
||||
/**
|
||||
* Get the base address where this module is loaded, if applicable.
|
||||
*
|
||||
* @return the base address
|
||||
*/
|
||||
long getBase();
|
||||
}
|
||||
@@ -1,64 +0,0 @@
|
||||
/* ###
|
||||
* 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 agent.dbgeng.dbgeng;
|
||||
|
||||
/**
|
||||
* Information about a module (program or library image).
|
||||
*
|
||||
* The fields correspond to the parameters taken by {@code LoadModule} of
|
||||
* {@code IDebugEventCallbacks}. They also appear as a subset of parameters taken by
|
||||
* {@code CreateProcess} of {@code IDebugEventCallbacks}.
|
||||
*/
|
||||
public class DebugModuleInfo {
|
||||
public final long imageFileHandle;
|
||||
public final long baseOffset;
|
||||
public final int moduleSize;
|
||||
public final int checkSum;
|
||||
public final int timeDateStamp;
|
||||
private String moduleName;
|
||||
private String imageName;
|
||||
|
||||
public DebugModuleInfo(long imageFileHandle, long baseOffset, int moduleSize, String moduleName,
|
||||
String imageName, int checkSum, int timeDateStamp) {
|
||||
this.imageFileHandle = imageFileHandle;
|
||||
this.baseOffset = baseOffset;
|
||||
this.moduleSize = moduleSize;
|
||||
this.setModuleName(moduleName);
|
||||
this.setImageName(imageName);
|
||||
this.checkSum = checkSum;
|
||||
this.timeDateStamp = timeDateStamp; // TODO: Convert to DateTime?
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return Long.toHexString(baseOffset);
|
||||
}
|
||||
|
||||
public String getModuleName() {
|
||||
return moduleName;
|
||||
}
|
||||
|
||||
public void setModuleName(String moduleName) {
|
||||
this.moduleName = moduleName;
|
||||
}
|
||||
|
||||
public String getImageName() {
|
||||
return imageName;
|
||||
}
|
||||
|
||||
public void setImageName(String imageName) {
|
||||
this.imageName = imageName;
|
||||
}
|
||||
}
|
||||
@@ -1,32 +0,0 @@
|
||||
/* ###
|
||||
* 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 agent.dbgeng.dbgeng;
|
||||
|
||||
import agent.dbgeng.dbgeng.DebugControl.DebugOutputLevel;
|
||||
|
||||
/**
|
||||
* The interface for receiving output callbacks via {@code IDebugOutputCallbacks} or a newer
|
||||
* variant.
|
||||
*
|
||||
* Note: The wrapper implementation will select the apprirate native interface version.
|
||||
*
|
||||
* TODO: Change {@link #output(int, String)} {@code mask} parameter to use {@link DebugOutputLevel}
|
||||
* flags.
|
||||
*/
|
||||
@FunctionalInterface
|
||||
public interface DebugOutputCallbacks {
|
||||
void output(int mask, String text);
|
||||
}
|
||||
@@ -1,38 +0,0 @@
|
||||
/* ###
|
||||
* 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 agent.dbgeng.dbgeng;
|
||||
|
||||
/**
|
||||
* The <em>engine</em> ID assigned to a debugged process.
|
||||
*
|
||||
* Note: This is not the same as the "PID." {@code dbgeng.dll} calls that the <em>system</em> ID of
|
||||
* the process.
|
||||
*
|
||||
* This is essentially just a boxed integer, but having an explicit data type prevents confusion
|
||||
* with other integral values. In particular, this prevents confusion of engine PIDs with system
|
||||
* PIDs.
|
||||
*/
|
||||
public interface DebugProcessId extends Comparable<DebugProcessId> {
|
||||
|
||||
public String id();
|
||||
public long value();
|
||||
public boolean isSystem();
|
||||
|
||||
@Override
|
||||
public default int compareTo(DebugProcessId that) {
|
||||
return this.id().compareTo(that.id());
|
||||
}
|
||||
}
|
||||
@@ -1,36 +0,0 @@
|
||||
/* ###
|
||||
* 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 agent.dbgeng.dbgeng;
|
||||
|
||||
/**
|
||||
* Information about a process.
|
||||
*
|
||||
* The fields correspond to parameters taken by {@code CreateProcess} of
|
||||
* {@code IDebugEventCallbacks}. Note that parameters common to other callbacks have been factored
|
||||
* into types aggregated here.
|
||||
*/
|
||||
public class DebugProcessInfo {
|
||||
public final long handle;
|
||||
public final DebugModuleInfo moduleInfo;
|
||||
public final DebugThreadInfo initialThreadInfo;
|
||||
|
||||
public DebugProcessInfo(long handle, DebugModuleInfo moduleInfo,
|
||||
DebugThreadInfo initialThreadInfo) {
|
||||
this.handle = handle;
|
||||
this.moduleInfo = moduleInfo;
|
||||
this.initialThreadInfo = initialThreadInfo;
|
||||
}
|
||||
}
|
||||
@@ -1,34 +0,0 @@
|
||||
/* ###
|
||||
* 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 agent.dbgeng.dbgeng;
|
||||
|
||||
public record DebugProcessRecord(long value) implements DebugProcessId {
|
||||
|
||||
@Override
|
||||
public boolean isSystem() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String id() {
|
||||
return Long.toHexString(value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "<dbgeng.dll Engine PID " + Long.toHexString(value) + ">";
|
||||
}
|
||||
}
|
||||
@@ -1,158 +0,0 @@
|
||||
/* ###
|
||||
* 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 agent.dbgeng.dbgeng;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
import agent.dbgeng.dbgeng.DebugValue.DebugValueType;
|
||||
import ghidra.comm.util.BitmaskSet;
|
||||
import ghidra.comm.util.BitmaskUniverse;
|
||||
|
||||
/**
|
||||
* A wrapper for {@code IDebugRegisters} and its newer variants.
|
||||
*/
|
||||
public interface DebugRegisters {
|
||||
public static enum DebugRegisterSource {
|
||||
DEBUG_REGSRC_DEBUGGEE, //
|
||||
DEBUG_REGSRC_EXPLICIT, //
|
||||
DEBUG_REGSRC_FRAME, //
|
||||
;
|
||||
}
|
||||
|
||||
public static enum DebugRegisterFlags implements BitmaskUniverse {
|
||||
SUB_REGISTER(1 << 0), //
|
||||
;
|
||||
|
||||
private DebugRegisterFlags(int mask) {
|
||||
this.mask = mask;
|
||||
}
|
||||
|
||||
private final int mask;
|
||||
|
||||
@Override
|
||||
public long getMask() {
|
||||
return mask;
|
||||
}
|
||||
}
|
||||
|
||||
public static class DebugRegisterDescription {
|
||||
public final String name;
|
||||
public final int index;
|
||||
public final DebugValueType type;
|
||||
public final Set<DebugRegisterFlags> flags;
|
||||
public final int subregMaster;
|
||||
public final int subregLengthBits;
|
||||
public final long subregMask;
|
||||
public final int subregShift;
|
||||
|
||||
public DebugRegisterDescription(String name, int index, DebugValueType type,
|
||||
BitmaskSet<DebugRegisterFlags> flags, int subregMaster, int subregLengthBits,
|
||||
long subregMask, int subregShift) {
|
||||
this.name = name;
|
||||
this.index = index;
|
||||
this.type = type;
|
||||
this.flags = Collections.unmodifiableSet(flags);
|
||||
this.subregMaster = subregMaster;
|
||||
this.subregLengthBits = subregLengthBits;
|
||||
this.subregMask = subregMask;
|
||||
this.subregShift = subregShift;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return String.format(
|
||||
"<%s: name='%s' index=%d type=%s flags=%s subregMaster=%d subregLengthBits=%d" +
|
||||
" subregMask=%x subregShift=%d>",
|
||||
getClass().getSimpleName(), name, index, type, flags, subregMaster,
|
||||
subregLengthBits, subregMask, subregShift);
|
||||
}
|
||||
}
|
||||
|
||||
int getNumberRegisters();
|
||||
|
||||
DebugRegisterDescription getDescription(int registerNumber);
|
||||
|
||||
/**
|
||||
* A shortcut to get all register descriptions for the current process.
|
||||
*
|
||||
* Uses {@link #getNumberRegisters()} and {@link #getDescription(int)} to retrieve all
|
||||
* descriptions for the current process.
|
||||
*
|
||||
* @return the list of register descriptions
|
||||
*/
|
||||
default Set<DebugRegisterDescription> getAllDescriptions() {
|
||||
Set<DebugRegisterDescription> result = new LinkedHashSet<>();
|
||||
int count = getNumberRegisters();
|
||||
for (int i = 0; i < count; i++) {
|
||||
result.add(getDescription(i));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
int getIndexByName(String name);
|
||||
|
||||
/**
|
||||
* A shortcut to get many register indices in one call.
|
||||
*
|
||||
* Uses {@link #getIndexByName(String)}.
|
||||
*
|
||||
* @param names the names whose indices to get
|
||||
* @return the indices in respective order to the given names
|
||||
*/
|
||||
default int[] getIndicesByNames(String... names) {
|
||||
int[] indices = new int[names.length];
|
||||
for (int i = 0; i < names.length; i++) {
|
||||
indices[i] = getIndexByName(names[i]);
|
||||
}
|
||||
return indices;
|
||||
}
|
||||
|
||||
DebugValue getValue(int index);
|
||||
|
||||
Map<Integer, DebugValue> getValues(DebugRegisterSource source, Collection<Integer> indices);
|
||||
|
||||
/**
|
||||
* A shortcut to get a register value by name.
|
||||
*
|
||||
* Uses {@link #getIndexByName(String)} followed by {@link #getValue(int)}.
|
||||
*
|
||||
* @param name the name of the register
|
||||
* @return the value
|
||||
*/
|
||||
default DebugValue getValueByName(String name) {
|
||||
int indexByName = getIndexByName(name);
|
||||
if (indexByName >= 0) {
|
||||
return getValue(indexByName);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
void setValue(int index, DebugValue value);
|
||||
|
||||
void setValues(DebugRegisterSource source, Map<Integer, DebugValue> values);
|
||||
|
||||
/**
|
||||
* A shortcut to set a register value by name.
|
||||
*
|
||||
* Uses {@link #getIndexByName(String)} followed by {@link #setValue(int, DebugValue)}.
|
||||
*
|
||||
* @param name the name of the register
|
||||
* @param value the desired value
|
||||
*/
|
||||
default void setValueByName(String name, DebugValue value) {
|
||||
setValue(getIndexByName(name), value);
|
||||
}
|
||||
}
|
||||
@@ -1,123 +0,0 @@
|
||||
/* ###
|
||||
* 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 agent.dbgeng.dbgeng;
|
||||
|
||||
import agent.dbgeng.dbgeng.DebugRunningProcess.Description.ProcessDescriptionFlags;
|
||||
import ghidra.comm.util.BitmaskUniverse;
|
||||
|
||||
/**
|
||||
* Information about a running process, not necessarily a debugged process.
|
||||
*/
|
||||
public interface DebugRunningProcess {
|
||||
/**
|
||||
* Description of a running process
|
||||
*/
|
||||
public static class Description {
|
||||
public static enum ProcessDescriptionFlags implements BitmaskUniverse {
|
||||
NO_PATHS(1 << 0), //
|
||||
NO_SERVICES(1 << 1), //
|
||||
NO_MTS_PACKAGES(1 << 2), //
|
||||
NO_COMMAND_LINE(1 << 3), //
|
||||
NO_SESSION_ID(1 << 4), //
|
||||
NO_USER_NAME(1 << 5), //
|
||||
;
|
||||
|
||||
ProcessDescriptionFlags(int mask) {
|
||||
this.mask = mask;
|
||||
}
|
||||
|
||||
private final int mask;
|
||||
|
||||
@Override
|
||||
public long getMask() {
|
||||
return mask;
|
||||
}
|
||||
}
|
||||
|
||||
public Description(int systemId, String exeName, String description) {
|
||||
this.systemId = systemId;
|
||||
this.exeName = exeName;
|
||||
this.description = description;
|
||||
}
|
||||
|
||||
private final int systemId;
|
||||
private final String exeName;
|
||||
private final String description;
|
||||
|
||||
/**
|
||||
* The system ID (PID) for the process.
|
||||
*
|
||||
* @return the PID
|
||||
*/
|
||||
public int getSystemId() {
|
||||
return systemId;
|
||||
}
|
||||
|
||||
/**
|
||||
* The name of the executable defining the process
|
||||
*
|
||||
* @return the name
|
||||
*/
|
||||
public String getExecutableName() {
|
||||
return exeName;
|
||||
}
|
||||
|
||||
/**
|
||||
* A textual description of the process.
|
||||
*
|
||||
* @return the description
|
||||
*/
|
||||
public String getDescription() {
|
||||
return description;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return String.format("PID:%d, EXE:%s, Description:%s", systemId, exeName, description);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The system ID (PID) for the process.
|
||||
*
|
||||
* @return the PID
|
||||
*/
|
||||
int getSystemId();
|
||||
|
||||
/**
|
||||
* Get the "full" description of the process.
|
||||
*
|
||||
* @param flags indicate which information to include in the description
|
||||
* @return the description
|
||||
*/
|
||||
Description getFullDescription(ProcessDescriptionFlags... flags);
|
||||
|
||||
/**
|
||||
* The name of the executable defining the process.
|
||||
*
|
||||
* @param flags indicate which information to include in the description
|
||||
* @return the name
|
||||
*/
|
||||
String getExecutableName(ProcessDescriptionFlags... flags);
|
||||
|
||||
/**
|
||||
* A textual description of the process.
|
||||
*
|
||||
* @param flags indicate which information to include in the description
|
||||
* @return the description
|
||||
*/
|
||||
String getDescription(ProcessDescriptionFlags... flags);
|
||||
}
|
||||
@@ -1,58 +0,0 @@
|
||||
/* ###
|
||||
* 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 agent.dbgeng.dbgeng;
|
||||
|
||||
/**
|
||||
* The ID of a debug server.
|
||||
*
|
||||
* Each server to which a client is connected is assigned a server ID. The local server, to which
|
||||
* every client is connected by default, has the ID 0. This is essentially just a boxed integer, but
|
||||
* having an explicit data type prevents confusion with other integral values.
|
||||
*/
|
||||
public class DebugServerId implements Comparable<DebugServerId> {
|
||||
public final long id;
|
||||
|
||||
public DebugServerId(long id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Long.hashCode(id);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (!(obj instanceof DebugServerId)) {
|
||||
return false;
|
||||
}
|
||||
DebugServerId that = (DebugServerId) obj;
|
||||
if (this.id != that.id) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int compareTo(DebugServerId that) {
|
||||
return Long.compare(this.id, that.id);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "<dbgeng.dll Server ID " + id + ">";
|
||||
}
|
||||
}
|
||||
@@ -1,38 +0,0 @@
|
||||
/* ###
|
||||
* 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 agent.dbgeng.dbgeng;
|
||||
|
||||
/**
|
||||
* The <em>engine</em> ID assigned to a debugged process.
|
||||
*
|
||||
* Note: This is not the same as the "PID." {@code dbgeng.dll} calls that the <em>system</em> ID of
|
||||
* the process.
|
||||
*
|
||||
* This is essentially just a boxed integer, but having an explicit data type prevents confusion
|
||||
* with other integral values. In particular, this prevents confusion of engine PIDs with system
|
||||
* PIDs.
|
||||
*/
|
||||
public interface DebugSessionId extends Comparable<DebugSessionId> {
|
||||
|
||||
public String id();
|
||||
public long value();
|
||||
public boolean isSystem();
|
||||
|
||||
@Override
|
||||
public default int compareTo(DebugSessionId that) {
|
||||
return this.id().compareTo(that.id());
|
||||
}
|
||||
}
|
||||
@@ -1,34 +0,0 @@
|
||||
/* ###
|
||||
* 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 agent.dbgeng.dbgeng;
|
||||
|
||||
public record DebugSessionRecord(long value) implements DebugSessionId {
|
||||
|
||||
@Override
|
||||
public boolean isSystem() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String id() {
|
||||
return Long.toHexString(value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "<dbgeng.dll Engine SYSID " + Long.toHexString(value) + ">";
|
||||
}
|
||||
}
|
||||
@@ -1,42 +0,0 @@
|
||||
/* ###
|
||||
* 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 agent.dbgeng.dbgeng;
|
||||
|
||||
import agent.dbgeng.jna.dbgeng.DbgEngNative.DEBUG_SPECIFIC_FILTER_PARAMETERS;
|
||||
|
||||
public class DebugSpecificFilterInformation {
|
||||
|
||||
private int nParams;
|
||||
private DEBUG_SPECIFIC_FILTER_PARAMETERS[] parameters;
|
||||
|
||||
public DebugSpecificFilterInformation(int nParams,
|
||||
DEBUG_SPECIFIC_FILTER_PARAMETERS[] parameters) {
|
||||
this.nParams = nParams;
|
||||
this.parameters = parameters;
|
||||
}
|
||||
|
||||
public int getNumberOfParameters() {
|
||||
return nParams;
|
||||
}
|
||||
|
||||
public DEBUG_SPECIFIC_FILTER_PARAMETERS getParameter(int paramNumber) {
|
||||
return parameters[paramNumber];
|
||||
}
|
||||
|
||||
public DEBUG_SPECIFIC_FILTER_PARAMETERS[] getParameters() {
|
||||
return parameters;
|
||||
}
|
||||
}
|
||||
@@ -1,37 +0,0 @@
|
||||
/* ###
|
||||
* 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 agent.dbgeng.dbgeng;
|
||||
|
||||
import agent.dbgeng.jna.dbgeng.DbgEngNative.DEBUG_STACK_FRAME;
|
||||
|
||||
public class DebugStackInformation {
|
||||
|
||||
private int nFrames;
|
||||
private DEBUG_STACK_FRAME[] stackFrames;
|
||||
|
||||
public DebugStackInformation(int nFrames, DEBUG_STACK_FRAME[] stackFrames) {
|
||||
this.nFrames = nFrames;
|
||||
this.stackFrames = stackFrames;
|
||||
}
|
||||
|
||||
public int getNumberOfFrames() {
|
||||
return nFrames;
|
||||
}
|
||||
|
||||
public DEBUG_STACK_FRAME getFrame(int frameNumber) {
|
||||
return stackFrames[frameNumber];
|
||||
}
|
||||
}
|
||||
@@ -1,56 +0,0 @@
|
||||
/* ###
|
||||
* 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 agent.dbgeng.dbgeng;
|
||||
|
||||
/**
|
||||
* Data copied from a {@code DEBUG_SYMBOL_ENTRY} as defined in {@code dbgeng.h}.
|
||||
*
|
||||
* TODO: Some enums, flags, etc., to help interpret some of the fields.
|
||||
*/
|
||||
public class DebugSymbolEntry {
|
||||
public final long moduleBase;
|
||||
public final long offset;
|
||||
public final long symbolId;
|
||||
public final long size;
|
||||
public final int flags;
|
||||
public final int typeId;
|
||||
public final String name;
|
||||
public final int tag;
|
||||
|
||||
public DebugSymbolEntry(long moduleBase, long offset, long symbolId, long size, int flags,
|
||||
int typeId, String name, int tag) {
|
||||
this.moduleBase = moduleBase;
|
||||
this.offset = offset;
|
||||
this.symbolId = symbolId;
|
||||
this.size = size;
|
||||
this.flags = flags;
|
||||
this.typeId = typeId;
|
||||
this.name = name;
|
||||
this.tag = tag;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return String.format("<DebugSymbolEntry %016x:%016x\n" + //
|
||||
" offset=%016xh,\n" + //
|
||||
" size=%xh,\n" + //
|
||||
" flags=%xh,\n" + //
|
||||
" typeId=%xh,\n" + //
|
||||
" name='%s',\n" + //
|
||||
" tag=%xh>", //
|
||||
moduleBase, symbolId, offset, size, flags, typeId, name, tag);
|
||||
}
|
||||
}
|
||||
@@ -1,34 +0,0 @@
|
||||
/* ###
|
||||
* 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 agent.dbgeng.dbgeng;
|
||||
|
||||
/**
|
||||
* Symbol identifier, consisting of module ID and symbol index.
|
||||
*/
|
||||
public class DebugSymbolId {
|
||||
public final long moduleBase;
|
||||
public final long symbolIndex;
|
||||
|
||||
public DebugSymbolId(long moduleBase, long symbolIndex) {
|
||||
this.moduleBase = moduleBase;
|
||||
this.symbolIndex = symbolIndex;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return String.format("<DebugSymbolId %016x:%016x>", moduleBase, symbolIndex);
|
||||
}
|
||||
}
|
||||
@@ -1,34 +0,0 @@
|
||||
/* ###
|
||||
* 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 agent.dbgeng.dbgeng;
|
||||
|
||||
/**
|
||||
* Symbol name, consisting of textual name and offset.
|
||||
*/
|
||||
public class DebugSymbolName {
|
||||
public final String name;
|
||||
public final long offset;
|
||||
|
||||
public DebugSymbolName(String name, long offset) {
|
||||
this.name = name;
|
||||
this.offset = offset;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return String.format("<%016x: %s>", offset, name);
|
||||
}
|
||||
}
|
||||
@@ -1,85 +0,0 @@
|
||||
/* ###
|
||||
* 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 agent.dbgeng.dbgeng;
|
||||
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* A wrapper for {@code IDebugSymbols} and its newer variants.
|
||||
*/
|
||||
public interface DebugSymbols {
|
||||
int getNumberLoadedModules();
|
||||
|
||||
int getNumberUnloadedModules();
|
||||
|
||||
DebugModule getModuleByIndex(int index);
|
||||
|
||||
DebugModule getModuleByModuleName(String name, int startIndex);
|
||||
|
||||
DebugModule getModuleByOffset(long offset, int startIndex);
|
||||
|
||||
DebugModuleInfo getModuleParameters(int count, int startIndex);
|
||||
|
||||
/**
|
||||
* A shortcut for iterating over all loaded modules, lazily.
|
||||
*
|
||||
* @param startIndex the module index to start at
|
||||
* @return an iterator over modules starting at the given index
|
||||
*/
|
||||
default Iterable<DebugModule> iterateModules(int startIndex) {
|
||||
int count = getNumberLoadedModules(); // TODO: What about unloaded?
|
||||
return new Iterable<DebugModule>() {
|
||||
@Override
|
||||
public Iterator<DebugModule> iterator() {
|
||||
return new Iterator<DebugModule>() {
|
||||
int cur = startIndex;
|
||||
|
||||
@Override
|
||||
public boolean hasNext() {
|
||||
return cur < count;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DebugModule next() {
|
||||
DebugModule ret = getModuleByIndex(cur);
|
||||
cur++;
|
||||
return ret;
|
||||
}
|
||||
};
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
Iterable<DebugSymbolName> iterateSymbolMatches(String pattern);
|
||||
|
||||
List<DebugSymbolId> getSymbolIdsByName(String pattern);
|
||||
|
||||
DebugSymbolEntry getSymbolEntry(DebugSymbolId id);
|
||||
|
||||
String getSymbolPath();
|
||||
|
||||
void setSymbolPath(String path);
|
||||
|
||||
int getSymbolOptions();
|
||||
|
||||
void setSymbolOptions(int options);
|
||||
|
||||
public int getCurrentScopeFrameIndex();
|
||||
|
||||
public void setCurrentScopeFrameIndex(int index);
|
||||
|
||||
}
|
||||
@@ -1,116 +0,0 @@
|
||||
/* ###
|
||||
* 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 agent.dbgeng.dbgeng;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* A wrapper for {@code IDebugSystemObjects} and its newer variants.
|
||||
*/
|
||||
public interface DebugSystemObjects {
|
||||
|
||||
DebugThreadId getEventThread();
|
||||
|
||||
DebugProcessId getEventProcess();
|
||||
|
||||
DebugSessionId getEventSystem();
|
||||
|
||||
DebugThreadId getCurrentThreadId();
|
||||
|
||||
void setCurrentThreadId(DebugThreadId id);
|
||||
|
||||
DebugProcessId getCurrentProcessId();
|
||||
|
||||
void setCurrentProcessId(DebugProcessId id);
|
||||
|
||||
DebugSessionId getCurrentSystemId();
|
||||
|
||||
void setCurrentSystemId(DebugSessionId id);
|
||||
|
||||
int getNumberThreads();
|
||||
|
||||
int getTotalNumberThreads(); // TODO: LargestProcess?
|
||||
|
||||
/**
|
||||
* Get the threads IDs by index from the current process
|
||||
*
|
||||
* @param start the starting index
|
||||
* @param count the number of threads
|
||||
* @return the list of thread IDs
|
||||
*/
|
||||
List<DebugThreadId> getThreads(int start, int count);
|
||||
|
||||
/**
|
||||
* Get all thread IDs in the current process
|
||||
*
|
||||
* @return the list of thread IDs
|
||||
*/
|
||||
default List<DebugThreadId> getThreads() {
|
||||
return getThreads(0, getNumberThreads());
|
||||
}
|
||||
|
||||
DebugThreadId getThreadIdByHandle(long handle);
|
||||
|
||||
DebugProcessId getProcessIdByHandle(long handle);
|
||||
|
||||
int getNumberSystems();
|
||||
|
||||
List<DebugSessionId> getSystems(int start, int count);
|
||||
|
||||
default List<DebugSessionId> getSessions() {
|
||||
int numberSystems = getNumberSystems();
|
||||
if (numberSystems < 0) {
|
||||
return new ArrayList<DebugSessionId>();
|
||||
}
|
||||
return getSystems(0, numberSystems);
|
||||
}
|
||||
|
||||
int getNumberProcesses();
|
||||
|
||||
List<DebugProcessId> getProcesses(int start, int count);
|
||||
|
||||
default List<DebugProcessId> getProcesses() {
|
||||
int numberProcesses = getNumberProcesses();
|
||||
if (numberProcesses < 0) {
|
||||
return new ArrayList<DebugProcessId>();
|
||||
}
|
||||
return getProcesses(0, numberProcesses);
|
||||
}
|
||||
|
||||
int getCurrentThreadSystemId();
|
||||
|
||||
int getCurrentProcessSystemId();
|
||||
|
||||
DebugThreadId getThreadIdBySystemId(int systemId);
|
||||
|
||||
DebugProcessId getProcessIdBySystemId(int systemId);
|
||||
|
||||
long getCurrentThreadDataOffset();
|
||||
|
||||
long getCurrentProcessDataOffset();
|
||||
|
||||
long getImplicitThreadDataOffset();
|
||||
|
||||
long getImplicitProcessDataOffset();
|
||||
|
||||
void setImplicitThreadDataOffset(long systemOffset);
|
||||
|
||||
void setImplicitProcessDataOffset(long systemOffset);
|
||||
|
||||
String getCurrentProcessExecutableName();
|
||||
|
||||
}
|
||||
@@ -1,34 +0,0 @@
|
||||
/* ###
|
||||
* 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 agent.dbgeng.dbgeng;
|
||||
|
||||
public record DebugSystemProcessRecord(long value) implements DebugProcessId {
|
||||
|
||||
@Override
|
||||
public boolean isSystem() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String id() {
|
||||
return "SYS"+Long.toHexString(value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "<dbgeng.dll System PID " + Long.toHexString(value) + ">";
|
||||
}
|
||||
}
|
||||
@@ -1,34 +0,0 @@
|
||||
/* ###
|
||||
* 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 agent.dbgeng.dbgeng;
|
||||
|
||||
public record DebugSystemSessionRecord(long value) implements DebugSessionId {
|
||||
|
||||
@Override
|
||||
public boolean isSystem() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String id() {
|
||||
return "SYS"+Long.toHexString(value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "<dbgeng.dll System SYSID " + Long.toHexString(value) + ">";
|
||||
}
|
||||
}
|
||||
@@ -1,34 +0,0 @@
|
||||
/* ###
|
||||
* 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 agent.dbgeng.dbgeng;
|
||||
|
||||
public record DebugSystemThreadRecord(long value) implements DebugThreadId {
|
||||
|
||||
@Override
|
||||
public boolean isSystem() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String id() {
|
||||
return "PCR"+Long.toHexString(value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "<dbgeng.dll System TID " + Long.toHexString(value) + ">";
|
||||
}
|
||||
}
|
||||
@@ -1,39 +0,0 @@
|
||||
/* ###
|
||||
* 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 agent.dbgeng.dbgeng;
|
||||
|
||||
/**
|
||||
* The <em>engine</em> ID assigned to a debugged thread.
|
||||
*
|
||||
* Note: This is not the same as the "TID." {@code dbgeng.dll} calls that the <em>system</em> ID of
|
||||
* the thread.
|
||||
*
|
||||
* This is essentially just a boxed integer, but having an explicit data type prevents confusion
|
||||
* with other integral values. In particular, this prevents confusion of engine TIDs with system
|
||||
* TIDs.
|
||||
*/
|
||||
public interface DebugThreadId extends Comparable<DebugThreadId> {
|
||||
|
||||
public String id();
|
||||
public long value();
|
||||
public boolean isSystem();
|
||||
|
||||
@Override
|
||||
public default int compareTo(DebugThreadId that) {
|
||||
return this.id().compareTo(that.id());
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,43 +0,0 @@
|
||||
/* ###
|
||||
* 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 agent.dbgeng.dbgeng;
|
||||
|
||||
/**
|
||||
* Information about a thread.
|
||||
*
|
||||
* <p>
|
||||
* The fields correspond to parameters taken by {@code CreateThread} of
|
||||
* {@code IDebugEventCallbacks}. They also appear as a subset of parameters taken by
|
||||
* {@code CreateProcess} of {@code IDebugEventCallbacks}.
|
||||
*/
|
||||
public class DebugThreadInfo {
|
||||
public final long handle;
|
||||
public final long dataOffset;
|
||||
public final long startOffset;
|
||||
|
||||
public DebugThreadInfo(long handle, long dataOffset, long startOffset) {
|
||||
this.handle = handle;
|
||||
this.dataOffset = dataOffset;
|
||||
this.startOffset = startOffset;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return String.format("<%s@%08x handle=0x%04x,dataOffset=0x%08x,startOffset=0x%08x>",
|
||||
getClass().getSimpleName(), System.identityHashCode(this),
|
||||
handle, dataOffset, startOffset);
|
||||
}
|
||||
}
|
||||
@@ -1,34 +0,0 @@
|
||||
/* ###
|
||||
* 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 agent.dbgeng.dbgeng;
|
||||
|
||||
public record DebugThreadRecord(long value) implements DebugThreadId {
|
||||
|
||||
@Override
|
||||
public boolean isSystem() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String id() {
|
||||
return Long.toHexString(value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "<dbgeng.dll Engine TID " + Long.toHexString(value) + ">";
|
||||
}
|
||||
}
|
||||
@@ -1,457 +0,0 @@
|
||||
/* ###
|
||||
* 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 agent.dbgeng.dbgeng;
|
||||
|
||||
import java.lang.annotation.*;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.ByteOrder;
|
||||
import java.util.Arrays;
|
||||
|
||||
import agent.dbgeng.dbgeng.DebugValue.DebugValueType;
|
||||
import agent.dbgeng.dbgeng.DebugValue.ForDebugValueType;
|
||||
import ghidra.util.NumericUtilities;
|
||||
|
||||
/**
|
||||
* Data copied from a {@code DEBUG_VALUE} as defined in {dbgeng.h}.
|
||||
*/
|
||||
@ForDebugValueType(DebugValueType.INVALID)
|
||||
public interface DebugValue {
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.TYPE)
|
||||
public static @interface ForDebugValueType {
|
||||
DebugValueType value();
|
||||
}
|
||||
|
||||
public static enum DebugValueType {
|
||||
INVALID(0), //
|
||||
INT8(Byte.SIZE), //
|
||||
INT16(Short.SIZE), //
|
||||
INT32(Integer.SIZE), //
|
||||
INT64(Long.SIZE), //
|
||||
FLOAT32(Float.SIZE), //
|
||||
FLOAT64(Double.SIZE), //
|
||||
FLOAT80(80), //
|
||||
FLOAT82(82), //
|
||||
FLOAT128(128), //
|
||||
VECTOR64(64), //
|
||||
VECTOR128(128), //
|
||||
;
|
||||
|
||||
private static final Class<? extends DebugValue>[] CLASSES;
|
||||
|
||||
static {
|
||||
@SuppressWarnings("unchecked")
|
||||
Class<? extends DebugValue>[] supressed = new Class[DebugValueType.values().length];
|
||||
CLASSES = supressed;
|
||||
for (Class<?> cls : DebugValue.class.getDeclaredClasses()) {
|
||||
if (!DebugValue.class.isAssignableFrom(cls)) {
|
||||
continue;
|
||||
}
|
||||
Class<? extends DebugValue> dvCls = cls.asSubclass(DebugValue.class);
|
||||
DebugValueType type = getDebugValueTypeForClass(dvCls);
|
||||
CLASSES[type.ordinal()] = dvCls;
|
||||
}
|
||||
}
|
||||
|
||||
public static DebugValueType getDebugValueTypeForClass(Class<? extends DebugValue> cls) {
|
||||
ForDebugValueType annot = cls.getAnnotation(ForDebugValueType.class);
|
||||
if (annot == null) {
|
||||
throw new AssertionError(
|
||||
"INTERNAL: Missing ForDebugValueType annotation on " + cls);
|
||||
}
|
||||
return annot.value();
|
||||
}
|
||||
|
||||
public final int bitLength;
|
||||
public final int byteLength;
|
||||
|
||||
private DebugValueType(int bitLength) {
|
||||
this.bitLength = bitLength;
|
||||
this.byteLength = (bitLength + 7) / 8;
|
||||
}
|
||||
|
||||
public Class<? extends DebugValue> getDebugValueClass() {
|
||||
return CLASSES[ordinal()];
|
||||
}
|
||||
|
||||
public DebugValue decodeBytes(byte[] bytes) throws IllegalArgumentException {
|
||||
try {
|
||||
return CLASSES[ordinal()].getConstructor(byte[].class).newInstance(bytes);
|
||||
}
|
||||
catch (InstantiationException | IllegalAccessException | IllegalArgumentException
|
||||
| NoSuchMethodException | SecurityException e) {
|
||||
throw new AssertionError(e);
|
||||
}
|
||||
catch (InvocationTargetException e) {
|
||||
if (e.getCause() instanceof IllegalArgumentException) {
|
||||
throw (IllegalArgumentException) e.getCause();
|
||||
}
|
||||
throw new AssertionError(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ForDebugValueType(DebugValueType.INT8)
|
||||
public static class DebugInt8Value implements DebugValue {
|
||||
private final byte value;
|
||||
|
||||
public DebugInt8Value(byte value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public DebugInt8Value(byte[] bytes) {
|
||||
if (bytes.length != 1) {
|
||||
throw new IllegalArgumentException("Must have exactly 1 byte");
|
||||
}
|
||||
this.value = bytes[0];
|
||||
}
|
||||
|
||||
public byte byteValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] encodeAsBytes() {
|
||||
return new byte[] { value };
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "byte " + Integer.toHexString(value) + "h";
|
||||
}
|
||||
}
|
||||
|
||||
@ForDebugValueType(DebugValueType.INT16)
|
||||
public static class DebugInt16Value implements DebugValue {
|
||||
private final short value;
|
||||
|
||||
public DebugInt16Value(short value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public DebugInt16Value(byte[] bytes) {
|
||||
if (bytes.length != Short.BYTES) {
|
||||
throw new IllegalArgumentException("Must have exactly " + Short.BYTES + " bytes");
|
||||
}
|
||||
ByteBuffer buf = ByteBuffer.wrap(bytes).order(ByteOrder.BIG_ENDIAN);
|
||||
this.value = buf.getShort();
|
||||
}
|
||||
|
||||
public short shortValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] encodeAsBytes() {
|
||||
ByteBuffer buf = ByteBuffer.allocate(Short.BYTES).order(ByteOrder.BIG_ENDIAN);
|
||||
buf.putShort(value);
|
||||
return buf.array();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "word " + Integer.toHexString(value) + "h";
|
||||
}
|
||||
}
|
||||
|
||||
@ForDebugValueType(DebugValueType.INT32)
|
||||
public static class DebugInt32Value implements DebugValue {
|
||||
private final int value;
|
||||
|
||||
public DebugInt32Value(int value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public DebugInt32Value(byte[] bytes) {
|
||||
if (bytes.length != Integer.BYTES) {
|
||||
throw new IllegalArgumentException("Must have exactly " + Integer.BYTES + " bytes");
|
||||
}
|
||||
ByteBuffer buf = ByteBuffer.wrap(bytes).order(ByteOrder.BIG_ENDIAN);
|
||||
this.value = buf.getInt();
|
||||
}
|
||||
|
||||
public int intValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] encodeAsBytes() {
|
||||
ByteBuffer buf = ByteBuffer.allocate(Integer.BYTES).order(ByteOrder.BIG_ENDIAN);
|
||||
buf.putInt(value);
|
||||
return buf.array();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "dword " + Integer.toHexString(value) + "h";
|
||||
}
|
||||
}
|
||||
|
||||
@ForDebugValueType(DebugValueType.INT64)
|
||||
public static class DebugInt64Value implements DebugValue {
|
||||
private final long value;
|
||||
|
||||
public DebugInt64Value(long value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public DebugInt64Value(byte[] bytes) {
|
||||
if (bytes.length != Long.BYTES) {
|
||||
throw new IllegalArgumentException("Must have exactly " + Long.BYTES + " bytes");
|
||||
}
|
||||
ByteBuffer buf = ByteBuffer.wrap(bytes).order(ByteOrder.BIG_ENDIAN);
|
||||
this.value = buf.getLong();
|
||||
}
|
||||
|
||||
public long longValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] encodeAsBytes() {
|
||||
ByteBuffer buf = ByteBuffer.allocate(Long.BYTES).order(ByteOrder.BIG_ENDIAN);
|
||||
buf.putLong(value);
|
||||
return buf.array();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "qword " + Long.toHexString(value) + "h";
|
||||
}
|
||||
}
|
||||
|
||||
@ForDebugValueType(DebugValueType.FLOAT32)
|
||||
public static class DebugFloat32Value implements DebugValue {
|
||||
private final float value;
|
||||
|
||||
public DebugFloat32Value(float value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public DebugFloat32Value(byte[] bytes) {
|
||||
if (bytes.length != Float.BYTES) {
|
||||
throw new IllegalArgumentException("Must have exactly " + Float.BYTES + " bytes");
|
||||
}
|
||||
ByteBuffer buf = ByteBuffer.wrap(bytes).order(ByteOrder.BIG_ENDIAN);
|
||||
this.value = buf.getFloat();
|
||||
}
|
||||
|
||||
public float floatValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] encodeAsBytes() {
|
||||
ByteBuffer buf = ByteBuffer.allocate(Float.BYTES).order(ByteOrder.BIG_ENDIAN);
|
||||
buf.putFloat(value);
|
||||
return buf.array();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "f32 " + value;
|
||||
}
|
||||
}
|
||||
|
||||
@ForDebugValueType(DebugValueType.FLOAT64)
|
||||
public static class DebugFloat64Value implements DebugValue {
|
||||
private final double value;
|
||||
|
||||
public DebugFloat64Value(double value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public DebugFloat64Value(byte[] bytes) {
|
||||
if (bytes.length != Double.BYTES) {
|
||||
throw new IllegalArgumentException("Must have exactly " + Double.BYTES + " bytes");
|
||||
}
|
||||
ByteBuffer buf = ByteBuffer.wrap(bytes).order(ByteOrder.BIG_ENDIAN);
|
||||
this.value = buf.getDouble();
|
||||
}
|
||||
|
||||
public double doubleValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] encodeAsBytes() {
|
||||
ByteBuffer buf = ByteBuffer.allocate(Double.BYTES).order(ByteOrder.BIG_ENDIAN);
|
||||
buf.putDouble(value);
|
||||
return buf.array();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "f64 " + value;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Extended-precision float
|
||||
*/
|
||||
@ForDebugValueType(DebugValueType.FLOAT80)
|
||||
public static class DebugFloat80Value implements DebugValue {
|
||||
private final byte[] bytes;
|
||||
|
||||
public DebugFloat80Value(byte[] bytes) {
|
||||
if (bytes.length != 10) {
|
||||
throw new IllegalArgumentException("Must have exactly 10 bytes");
|
||||
}
|
||||
this.bytes = Arrays.copyOf(bytes, 10);
|
||||
}
|
||||
|
||||
public byte[] bytes() {
|
||||
return bytes;
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] encodeAsBytes() {
|
||||
return bytes;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "f80 " + NumericUtilities.convertBytesToString(bytes);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Specific to IA-64 (Itanium) floating-point registers
|
||||
*
|
||||
* 17-bit exponent, 64-bit fraction. Not sure how it's aligned in memory, though.
|
||||
*/
|
||||
@ForDebugValueType(DebugValueType.FLOAT82)
|
||||
public static class DebugFloat82Value implements DebugValue {
|
||||
private final byte[] bytes;
|
||||
|
||||
public DebugFloat82Value(byte[] bytes) {
|
||||
if (bytes.length != 11) {
|
||||
throw new IllegalArgumentException("Must have exactly 11 bytes");
|
||||
}
|
||||
this.bytes = Arrays.copyOf(bytes, 11);
|
||||
}
|
||||
|
||||
public byte[] bytes() {
|
||||
return bytes;
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] encodeAsBytes() {
|
||||
return bytes;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "f82 " + NumericUtilities.convertBytesToString(bytes);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Quadruple-precision float
|
||||
*/
|
||||
@ForDebugValueType(DebugValueType.FLOAT128)
|
||||
public static class DebugFloat128Value implements DebugValue {
|
||||
private final byte[] bytes;
|
||||
|
||||
public DebugFloat128Value(byte[] bytes) {
|
||||
if (bytes.length != 16) {
|
||||
throw new IllegalArgumentException("Must have exactly 16 bytes");
|
||||
}
|
||||
this.bytes = Arrays.copyOf(bytes, 16);
|
||||
}
|
||||
|
||||
public byte[] bytes() {
|
||||
return bytes;
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] encodeAsBytes() {
|
||||
return bytes;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "f128 " + NumericUtilities.convertBytesToString(bytes);
|
||||
}
|
||||
}
|
||||
|
||||
@ForDebugValueType(DebugValueType.VECTOR64)
|
||||
public static class DebugVector64Value implements DebugValue {
|
||||
private final byte[] bytes;
|
||||
|
||||
public DebugVector64Value(byte[] bytes) {
|
||||
if (bytes.length != 8) {
|
||||
throw new IllegalArgumentException("Must have exactly 8 bytes");
|
||||
}
|
||||
this.bytes = Arrays.copyOf(bytes, 8);
|
||||
}
|
||||
|
||||
public byte[] vi4() {
|
||||
return bytes;
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] encodeAsBytes() {
|
||||
return bytes;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "vec64 " + NumericUtilities.convertBytesToString(bytes);
|
||||
}
|
||||
}
|
||||
|
||||
@ForDebugValueType(DebugValueType.VECTOR128)
|
||||
public static class DebugVector128Value implements DebugValue {
|
||||
private final byte[] bytes;
|
||||
|
||||
public DebugVector128Value(byte[] bytes) {
|
||||
if (bytes.length != 16) {
|
||||
throw new IllegalArgumentException(
|
||||
"Must have exactly 16 bytes. got " + bytes.length);
|
||||
}
|
||||
this.bytes = Arrays.copyOf(bytes, 16);
|
||||
}
|
||||
|
||||
public byte[] vi8() {
|
||||
return bytes;
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] encodeAsBytes() {
|
||||
return bytes;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "vec128 " + NumericUtilities.convertBytesToString(bytes);
|
||||
}
|
||||
}
|
||||
|
||||
default DebugValueType getValueType() {
|
||||
return DebugValueType.getDebugValueTypeForClass(getClass());
|
||||
}
|
||||
|
||||
/**
|
||||
* TODO: Document me
|
||||
*
|
||||
* Encodes the value as an array of bytes in big-endian order
|
||||
*
|
||||
* @return the encoded value
|
||||
*/
|
||||
public byte[] encodeAsBytes();
|
||||
}
|
||||
@@ -1,29 +0,0 @@
|
||||
/* ###
|
||||
* 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 agent.dbgeng.dbgeng.err;
|
||||
|
||||
/**
|
||||
* The base exception for checked {@code dbgeng.dll} wrapper-related errors.
|
||||
*/
|
||||
public class DbgEngException extends Exception {
|
||||
public DbgEngException() {
|
||||
super();
|
||||
}
|
||||
|
||||
public DbgEngException(String message) {
|
||||
super(message);
|
||||
}
|
||||
}
|
||||
@@ -1,29 +0,0 @@
|
||||
/* ###
|
||||
* 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 agent.dbgeng.dbgeng.err;
|
||||
|
||||
/**
|
||||
* The base exception for unchecked {@code dbgeng.dll} wrapper-related errors.
|
||||
*/
|
||||
public class DbgEngRuntimeException extends RuntimeException {
|
||||
public DbgEngRuntimeException() {
|
||||
super();
|
||||
}
|
||||
|
||||
public DbgEngRuntimeException(String message) {
|
||||
super(message);
|
||||
}
|
||||
}
|
||||
@@ -1,49 +0,0 @@
|
||||
/* ###
|
||||
* 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 agent.dbgeng.dbgeng.ext;
|
||||
|
||||
import com.sun.jna.platform.win32.COM.COMUtils;
|
||||
import com.sun.jna.ptr.PointerByReference;
|
||||
|
||||
import agent.dbgeng.dbgeng.DebugClient;
|
||||
import agent.dbgeng.impl.dbgeng.client.DebugClientInternal;
|
||||
import agent.dbgeng.jna.dbgeng.client.WrapIDebugClient;
|
||||
import agent.dbgeng.jna.javaprovider.JavaProviderNative;
|
||||
|
||||
/**
|
||||
* Wrapper for "javaprovider" plugin library
|
||||
*
|
||||
* @deprecated In one (abandoned) use case, the SCTL server can be loaded as a
|
||||
* "{@code engext.cpp}-style" plugin, presumably into any {@code dbgeng.dll}-powered
|
||||
* debugger. This is accomplished by embedding the JVM into the plugin, and then calling
|
||||
* an alternative entry point. This plugin also provides a utility function for invoking
|
||||
* {@code CreateClient} on the client provided to the plugin by the host debugger.
|
||||
*/
|
||||
@Deprecated
|
||||
public class JavaProvider {
|
||||
public static DebugClient createClient() {
|
||||
PointerByReference pClient = new PointerByReference();
|
||||
COMUtils.checkRC(JavaProviderNative.INSTANCE.createClient(pClient.getPointer()));
|
||||
WrapIDebugClient wrap = new WrapIDebugClient(pClient.getValue());
|
||||
|
||||
try {
|
||||
return DebugClientInternal.tryPreferredInterfaces(wrap::QueryInterface);
|
||||
}
|
||||
finally {
|
||||
wrap.Release();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,125 +0,0 @@
|
||||
/* ###
|
||||
* 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 agent.dbgeng.dbgeng.util;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
import agent.dbgeng.dbgeng.*;
|
||||
import agent.dbgeng.dbgeng.DebugClient.*;
|
||||
import ghidra.comm.util.BitmaskSet;
|
||||
|
||||
/**
|
||||
* A convenient abstract implementation of {@link DebugEventCallbacks}
|
||||
*
|
||||
* This implementation automatically computes the value for {@link #getInterestMask()} based on the
|
||||
* overridden methods. The default implementations all return {@link DebugStatus#NO_CHANGE}, should
|
||||
* they happen to be called.
|
||||
*/
|
||||
public class DebugEventCallbacksAdapter implements DebugEventCallbacks {
|
||||
|
||||
private BitmaskSet<DebugEvent> interests = new BitmaskSet<>(DebugEvent.class);
|
||||
|
||||
public DebugEventCallbacksAdapter() {
|
||||
try {
|
||||
// Compute the interest mask based on methods that are overridden
|
||||
for (Method im : DebugEventCallbacks.class.getDeclaredMethods()) {
|
||||
Method m = this.getClass().getMethod(im.getName(), im.getParameterTypes());
|
||||
if (m.getDeclaringClass() == DebugEventCallbacksAdapter.class) {
|
||||
continue;
|
||||
}
|
||||
// The interface method is overridden, grab the annotation from the interface
|
||||
ForInterest fi = im.getAnnotation(ForInterest.class);
|
||||
if (fi == null) {
|
||||
throw new AssertionError("No ForInterest annotation present on " + m);
|
||||
}
|
||||
interests.add(fi.value());
|
||||
}
|
||||
}
|
||||
catch (NoSuchMethodException e) {
|
||||
throw new AssertionError(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public BitmaskSet<DebugEvent> getInterestMask() {
|
||||
return interests;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DebugStatus breakpoint(DebugBreakpoint bp) {
|
||||
return DebugStatus.NO_CHANGE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DebugStatus exception(DebugExceptionRecord64 exception, boolean firstChance) {
|
||||
return DebugStatus.NO_CHANGE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DebugStatus createThread(DebugThreadInfo debugThreadInfo) {
|
||||
return DebugStatus.NO_CHANGE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DebugStatus exitThread(int exitCode) {
|
||||
return DebugStatus.NO_CHANGE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DebugStatus createProcess(DebugProcessInfo debugProcessInfo) {
|
||||
return DebugStatus.NO_CHANGE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DebugStatus exitProcess(int exitCode) {
|
||||
return DebugStatus.NO_CHANGE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DebugStatus loadModule(DebugModuleInfo debugModuleInfo) {
|
||||
return DebugStatus.NO_CHANGE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DebugStatus unloadModule(String imageBaseName, long baseOffset) {
|
||||
return DebugStatus.NO_CHANGE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DebugStatus systemError(int error, int level) {
|
||||
return DebugStatus.NO_CHANGE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DebugStatus sessionStatus(SessionStatus status) {
|
||||
return DebugStatus.NO_CHANGE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DebugStatus changeDebuggeeState(BitmaskSet<ChangeDebuggeeState> flags, long argument) {
|
||||
return DebugStatus.NO_CHANGE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DebugStatus changeEngineState(BitmaskSet<ChangeEngineState> flags, long argument) {
|
||||
return DebugStatus.NO_CHANGE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DebugStatus changeSymbolState(BitmaskSet<ChangeSymbolState> flags, long argument) {
|
||||
return DebugStatus.NO_CHANGE;
|
||||
}
|
||||
}
|
||||
@@ -1,97 +0,0 @@
|
||||
/* ###
|
||||
* 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 agent.dbgeng.gadp;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import ghidra.dbg.gadp.server.AbstractGadpLocalDebuggerModelFactory;
|
||||
import ghidra.dbg.util.ConfigurableFactory.FactoryDescription;
|
||||
import ghidra.program.model.listing.Program;
|
||||
|
||||
@FactoryDescription(
|
||||
brief = "MS dbgeng.dll (WinDbg) via GADP",
|
||||
htmlDetails = """
|
||||
Connect to the Microsoft Debug Engine.
|
||||
This is the same engine that powers WinDbg.
|
||||
This is best for most Windows userspace and kernel targets.
|
||||
Kernel debugging is still experimental.
|
||||
This will protect Ghidra's JVM by using a subprocess to access the native API.""")
|
||||
public class DbgEngGadpDebuggerModelFactory extends AbstractGadpLocalDebuggerModelFactory {
|
||||
|
||||
protected String remote = "none"; // Require user to start server
|
||||
@FactoryOption("DebugConnect options (.server)")
|
||||
public final Property<String> agentRemoteOption =
|
||||
Property.fromAccessors(String.class, this::getAgentRemote, this::setAgentRemote);
|
||||
|
||||
protected String transport = "none"; // Require user to start server
|
||||
@FactoryOption("Remote process server options (untested)")
|
||||
public final Property<String> agentTransportOption =
|
||||
Property.fromAccessors(String.class, this::getAgentTransport, this::setAgentTransport);
|
||||
|
||||
@Override
|
||||
public int getPriority(Program program) {
|
||||
// TODO: Might instead look for the DLL
|
||||
if (!System.getProperty("os.name").toLowerCase().contains("windows")) {
|
||||
return -1;
|
||||
}
|
||||
if (program != null) {
|
||||
String exe = program.getExecutablePath();
|
||||
if (exe == null || exe.isBlank()) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
return 60;
|
||||
}
|
||||
|
||||
public String getAgentTransport() {
|
||||
return transport;
|
||||
}
|
||||
|
||||
public void setAgentTransport(String transport) {
|
||||
this.transport = transport;
|
||||
}
|
||||
|
||||
public String getAgentRemote() {
|
||||
return remote;
|
||||
}
|
||||
|
||||
public void setAgentRemote(String remote) {
|
||||
this.remote = remote;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getThreadName() {
|
||||
return "Local dbgeng.dll Agent stdout";
|
||||
}
|
||||
|
||||
protected Class<?> getServerClass() {
|
||||
return DbgEngGadpServer.class;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void completeCommandLine(List<String> cmd) {
|
||||
cmd.add(getServerClass().getCanonicalName());
|
||||
cmd.addAll(List.of("-H", host));
|
||||
cmd.addAll(List.of("-p", Integer.toString(port)));
|
||||
//cmd.addAll(List.of("-t", transport));
|
||||
if (!remote.equals("none") && !remote.equals("")) {
|
||||
cmd.addAll(List.of("-r", remote));
|
||||
}
|
||||
if (!transport.equals("none") && !transport.equals("")) {
|
||||
cmd.addAll(List.of("-t", transport));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,236 +0,0 @@
|
||||
/* ###
|
||||
* 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 agent.dbgeng.gadp;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.net.SocketAddress;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
|
||||
import org.apache.commons.lang3.exception.ExceptionUtils;
|
||||
|
||||
import agent.dbgeng.gadp.impl.DbgEngGadpServerImpl;
|
||||
import ghidra.async.AsyncUtils;
|
||||
import ghidra.dbg.agent.AgentWindow;
|
||||
import ghidra.util.Msg;
|
||||
|
||||
public interface DbgEngGadpServer extends AutoCloseable {
|
||||
public static final String USAGE =
|
||||
"""
|
||||
This is the GADP server for Windows dbgeng.dll. Usage:
|
||||
|
||||
gadp-agent-gdbeng [-H HOST/ADDR] [-p PORT] [-i ID] [-t TRANSPORT]
|
||||
[-r REMOTE]
|
||||
|
||||
Options:
|
||||
|
||||
--host/-H The address of the interface on which to listen.
|
||||
--port/-p The TCP port on which to listen for GADP. Default is 12345
|
||||
--transport/-t The transport specification for the Process Server. Default
|
||||
is tcp:port=11200
|
||||
--remote/-r The transport specification for a remote server.
|
||||
|
||||
Starts a dbgeng.dll-based GADP server "agent". Once the server has started, it
|
||||
will print the interface IP and port.
|
||||
""";
|
||||
public static final String DEFAULT_DBGSRV_TRANSPORT = "tcp:port=11200";
|
||||
|
||||
/**
|
||||
* The entry point for the GADP-DBGENG server in stand-alone mode
|
||||
*
|
||||
* Run it to see help.
|
||||
*
|
||||
* @param args the command-line arguments
|
||||
* @throws IOException if an I/O error occurs
|
||||
* @throws ExecutionException
|
||||
* @throws InterruptedException
|
||||
*/
|
||||
public static void main(String[] args) throws Exception {
|
||||
try {
|
||||
new DbgEngRunner().run(args);
|
||||
}
|
||||
catch (Throwable t) {
|
||||
System.err.println(ExceptionUtils.getMessage(t));
|
||||
System.exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new instance of the server
|
||||
*
|
||||
* @param addr the address to bind the GADP server to
|
||||
* @param busId the client ID the server should use on the bus for synthesized commands
|
||||
* @param dbgSrvTransport the transport specification for the {@code dbgeng.dll} server
|
||||
* @return the server instance
|
||||
* @throws IOException
|
||||
*/
|
||||
public static DbgEngGadpServer newInstance(SocketAddress addr) throws IOException {
|
||||
return new DbgEngGadpServerImpl(addr);
|
||||
}
|
||||
|
||||
/**
|
||||
* Runs the server from the command line
|
||||
*/
|
||||
public class DbgEngRunner {
|
||||
protected InetSocketAddress bindTo;
|
||||
protected List<String> dbgengArgs = new ArrayList<>();
|
||||
protected String dbgSrvTransport = DEFAULT_DBGSRV_TRANSPORT;
|
||||
protected String remote = null;
|
||||
|
||||
public DbgEngRunner() {
|
||||
}
|
||||
|
||||
public void run(String args[])
|
||||
throws IOException, InterruptedException, ExecutionException {
|
||||
parseArguments(args);
|
||||
|
||||
try (DbgEngGadpServer server = newInstance(bindTo)) {
|
||||
//TODO: fix/test the debugConnect case when args are passed
|
||||
server.startDbgEng(dbgengArgs.toArray(new String[] {})).exceptionally(e -> {
|
||||
e = AsyncUtils.unwrapThrowable(e);
|
||||
Msg.error(this, "Error starting dbgeng/GADP: " + e);
|
||||
System.exit(-1);
|
||||
return null;
|
||||
});
|
||||
new AgentWindow("dbgeng.dll Agent for Ghidra", server.getLocalAddress());
|
||||
while (server.isRunning()) {
|
||||
// TODO: Put consoleLoop back?
|
||||
Thread.sleep(1000);
|
||||
}
|
||||
System.exit(0);
|
||||
}
|
||||
}
|
||||
|
||||
protected void parseArguments(String[] args) {
|
||||
String iface = "localhost";
|
||||
int port = 12345;
|
||||
// NOTE: Maybe commons-cli or Argparse4j?
|
||||
Iterator<String> ait = Arrays.asList(args).iterator();
|
||||
while (ait.hasNext()) {
|
||||
String a = ait.next();
|
||||
if ("-h".equals(a) || "--help".equals(a)) {
|
||||
printUsage();
|
||||
System.exit(0);
|
||||
}
|
||||
else if ("-p".equals(a) || "--port".equals(a)) {
|
||||
if (!ait.hasNext()) {
|
||||
System.err.println("Expected PORT");
|
||||
printUsage();
|
||||
System.exit(-1);
|
||||
}
|
||||
String portStr = ait.next();
|
||||
try {
|
||||
port = Integer.parseInt(portStr);
|
||||
}
|
||||
catch (NumberFormatException e) {
|
||||
System.err.println("Integer required. Got " + portStr);
|
||||
printUsage();
|
||||
System.exit(-1);
|
||||
}
|
||||
}
|
||||
else if ("-H".equals(a) || "--host".equals(a)) {
|
||||
if (!ait.hasNext()) {
|
||||
System.err.println("Expected HOST/ADDR");
|
||||
printUsage();
|
||||
System.exit(-1);
|
||||
}
|
||||
iface = ait.next();
|
||||
}
|
||||
else if ("-t".equals(a) || "--transport".equals(a)) {
|
||||
if (!ait.hasNext()) {
|
||||
System.err.println("Expected TRANSPORT");
|
||||
System.err.println("See the MSDN 'Activating a Process Server'");
|
||||
printUsage();
|
||||
System.exit(-1);
|
||||
}
|
||||
dbgSrvTransport = ait.next();
|
||||
dbgengArgs.add(dbgSrvTransport);
|
||||
}
|
||||
else if ("-r".equals(a) || "--remote".equals(a)) {
|
||||
if (!ait.hasNext()) {
|
||||
System.err.println("Expected TRANSPORT:HOST,PORT");
|
||||
printUsage();
|
||||
System.exit(-1);
|
||||
}
|
||||
remote = ait.next();
|
||||
dbgengArgs.add(remote);
|
||||
}
|
||||
else {
|
||||
System.err.println("Unknown option: " + a);
|
||||
printUsage();
|
||||
System.exit(-1);
|
||||
}
|
||||
}
|
||||
|
||||
bindTo = new InetSocketAddress(iface, port);
|
||||
}
|
||||
|
||||
protected void printUsage() {
|
||||
System.out.println(USAGE);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Start the debugging server
|
||||
*
|
||||
* @return a future that completes when the server is ready
|
||||
*/
|
||||
CompletableFuture<Void> startDbgEng(String[] args);
|
||||
|
||||
/**
|
||||
* Get the local address to which the GADP server is bound.
|
||||
*
|
||||
* @return the local socket address
|
||||
*/
|
||||
SocketAddress getLocalAddress();
|
||||
|
||||
/**
|
||||
* Starts the dbgeng manager's console loop
|
||||
*
|
||||
* @throws IOException if an I/O error occurs
|
||||
*/
|
||||
//public void consoleLoop() throws IOException;
|
||||
|
||||
/**
|
||||
* Close all connections and ports, GADP and Process Server, and terminate the server
|
||||
*
|
||||
* @throws IOException if an I/O error occurs
|
||||
*/
|
||||
public void terminate() throws IOException;
|
||||
|
||||
/**
|
||||
* Check if the server is running
|
||||
*
|
||||
* This will return false: 1) Before the server has been started, 2) After a call to
|
||||
* {@link #terminate()}, or 3) When an error occurs causing the server to terminate
|
||||
* unexpectedly. Otherwise, it returns true.
|
||||
*
|
||||
* @return true if the server is currently running.
|
||||
*/
|
||||
public boolean isRunning();
|
||||
|
||||
/**
|
||||
* Calls {@link #terminate()}
|
||||
*
|
||||
* @throws IOException if an I/O error occurs
|
||||
*/
|
||||
@Override
|
||||
default void close() throws IOException {
|
||||
terminate();
|
||||
}
|
||||
}
|
||||
@@ -1,37 +0,0 @@
|
||||
/* ###
|
||||
* 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 agent.dbgeng.gadp;
|
||||
|
||||
import org.apache.commons.lang3.exception.ExceptionUtils;
|
||||
|
||||
import agent.dbgeng.gadp.DbgEngGadpServer.DbgEngRunner;
|
||||
import ghidra.GhidraApplicationLayout;
|
||||
import ghidra.GhidraLaunchable;
|
||||
|
||||
public class DbgEngGadpServerLaunchShim implements GhidraLaunchable {
|
||||
|
||||
@Override
|
||||
public void launch(GhidraApplicationLayout layout, String[] args) throws Exception {
|
||||
try {
|
||||
new DbgEngRunner().run(args);
|
||||
}
|
||||
catch (Throwable t) {
|
||||
System.err.println(ExceptionUtils.getMessage(t));
|
||||
System.exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,244 +0,0 @@
|
||||
/* ###
|
||||
* 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 agent.dbgeng.gadp.impl;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.concurrent.*;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import com.sun.jna.platform.win32.COM.COMException;
|
||||
|
||||
import agent.dbgeng.dbgeng.DebugClient;
|
||||
import agent.dbgeng.dbgeng.DebugClient.DebugStatus;
|
||||
import agent.dbgeng.dbgeng.DebugControl;
|
||||
import agent.dbgeng.manager.DbgManager;
|
||||
import ghidra.util.Msg;
|
||||
|
||||
/**
|
||||
* A single-threaded executor which creates and exclusively accesses the {@code dbgeng.dll} client.
|
||||
*
|
||||
* <p>
|
||||
* The executor also has a priority mechanism, so that callbacks may register follow-on handlers
|
||||
* which take precedence over other tasks in the queue (which could trigger additional callbacks).
|
||||
* This is required since certain operation are not allowed during normal callback processing. For
|
||||
* example, changing the current process is typically not allowed, but it is necessary to retrieve a
|
||||
* thread's context.
|
||||
*/
|
||||
public abstract class AbstractClientThreadExecutor extends AbstractExecutorService {
|
||||
private static final int DEFAULT_PRIORITY = 10;
|
||||
|
||||
protected DebugClient client;
|
||||
protected boolean shuttingDown = false;
|
||||
protected final Queue<Entry> queue = new PriorityQueue<>();
|
||||
protected Thread thread = new Thread(this::run, "DebugClient");
|
||||
protected final AtomicBoolean waitRegistered = new AtomicBoolean();
|
||||
|
||||
protected abstract void init();
|
||||
|
||||
public static class Entry implements Comparable<Entry> {
|
||||
final int priority;
|
||||
public final Runnable command;
|
||||
|
||||
public Entry(int priority, Runnable command) {
|
||||
this.priority = priority;
|
||||
this.command = command;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int compareTo(Entry that) {
|
||||
return Integer.compare(this.priority, that.priority);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Obtain a reference to the client, only if the calling thread is this executor's thread.
|
||||
*
|
||||
* @return the client
|
||||
*/
|
||||
public DebugClient getClient() {
|
||||
if (thread != Thread.currentThread()) {
|
||||
//TODO: throw new AssertionError("Cannot get client outside owning thread");
|
||||
}
|
||||
return client;
|
||||
}
|
||||
|
||||
/**
|
||||
* Instruct the executor to call {@link DebugClient#dispatchCallbacks()} when it next idles.
|
||||
*/
|
||||
public void cancelWait() {
|
||||
waitRegistered.set(false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Instruct the executor to call {@link DebugControl#waitForEvent()} when it next idles.
|
||||
*/
|
||||
public void registerWait() {
|
||||
waitRegistered.set(true);
|
||||
}
|
||||
|
||||
private Entry pollQueue() {
|
||||
synchronized (queue) {
|
||||
return queue.poll();
|
||||
}
|
||||
}
|
||||
|
||||
private void run() {
|
||||
/**
|
||||
* The general idea is to run indefinitely, taking every precaution to protect this thread's
|
||||
* life, since only it can access the client. Granted, if it turns out to be too difficult,
|
||||
* we can always create a new thread and client, using the existing client's reentrant
|
||||
* methods.
|
||||
*
|
||||
* <p>
|
||||
* As stated in the MSDN, this thread repeatedly calls {@code DispatchEvents} in order to
|
||||
* receive callbacks regarding events caused by other clients. If, however, an wait is
|
||||
* registered, or the current engine state indicates that a wait is proper, the thread calls
|
||||
* {@code WaitForEvent} instead. The thread is occupied until the wait completes, which is
|
||||
* fine since the engine is inaccessible (except to certain callbacks) until it completes,
|
||||
* anyway.
|
||||
*/
|
||||
try {
|
||||
init();
|
||||
while (!shuttingDown) {
|
||||
Entry next;
|
||||
while (null != (next = pollQueue())) {
|
||||
if (shuttingDown) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
//System.out.println("Executing: " + next);
|
||||
next.command.run();
|
||||
//System.out.println("Done");
|
||||
}
|
||||
catch (Throwable t) {
|
||||
Msg.error(this, "Task in executor threw: " + t);
|
||||
}
|
||||
}
|
||||
DebugStatus status = client.getControl().getExecutionStatus();
|
||||
if (status.shouldWait && status != DebugStatus.NO_DEBUGGEE ||
|
||||
waitRegistered.get()) {
|
||||
waitRegistered.set(false);
|
||||
try {
|
||||
getManager().waitForEventEx();
|
||||
//client.getControl().waitForEvent();
|
||||
}
|
||||
catch (COMException e) {
|
||||
Msg.error(this, "Error during WaitForEvents: " + e);
|
||||
}
|
||||
}
|
||||
else {
|
||||
try {
|
||||
client.dispatchCallbacks(100); // TODO: Better synchronization
|
||||
}
|
||||
catch (COMException e) {
|
||||
Msg.error(this, "Error during DispatchCallbacks: " + e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Throwable t) {
|
||||
Msg.error(this, "Non-respawnable executor terminated unexpectedly", t);
|
||||
shuttingDown = true;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void shutdown() {
|
||||
shuttingDown = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Runnable> shutdownNow() {
|
||||
shuttingDown = true;
|
||||
client.exitDispatch();
|
||||
thread.interrupt();
|
||||
List<Runnable> left = new ArrayList<>(queue.size());
|
||||
for (Entry ent : queue) {
|
||||
left.add(ent.command);
|
||||
}
|
||||
return left;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isShutdown() {
|
||||
return shuttingDown;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isTerminated() {
|
||||
return !thread.isAlive();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean awaitTermination(long timeout, TimeUnit unit) throws InterruptedException {
|
||||
long millis = TimeUnit.MILLISECONDS.convert(timeout, unit);
|
||||
thread.join(millis);
|
||||
return !thread.isAlive();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute(Runnable command) {
|
||||
execute(DEFAULT_PRIORITY, command);
|
||||
}
|
||||
|
||||
/**
|
||||
* Schedule a task with a given priority.
|
||||
*
|
||||
* <p>
|
||||
* Smaller priority values indicate earlier execution. The default priority is
|
||||
* {@link #DEFAULT_PRIORITY}.
|
||||
*
|
||||
* @param priority the priority
|
||||
* @param command the task
|
||||
*/
|
||||
public void execute(int priority, Runnable command) {
|
||||
if (shuttingDown) {
|
||||
// TODO: Is this the correct exception?
|
||||
throw new RejectedExecutionException("Executor is shutting down");
|
||||
}
|
||||
if (!thread.isAlive()) {
|
||||
throw new RejectedExecutionException("Executor has terminated");
|
||||
}
|
||||
synchronized (queue) {
|
||||
queue.add(new Entry(priority, command));
|
||||
// TODO: Putting this in causes sync/output flushing problems
|
||||
//client.exitDispatch();
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isCurrentThread() {
|
||||
return thread.equals(Thread.currentThread());
|
||||
}
|
||||
|
||||
/**
|
||||
* Schedule a task with the given priority, taking a reference to the client.
|
||||
*
|
||||
* <p>
|
||||
* This is a convenience which spares a call to {@link #getClient()}. See
|
||||
* {@link #execute(int, Runnable)} about priority.
|
||||
*
|
||||
* @param priority the priority
|
||||
* @param command the task
|
||||
*/
|
||||
public void execute(int priority, Consumer<DebugClient> command) {
|
||||
execute(priority, () -> command.accept(client));
|
||||
}
|
||||
|
||||
public abstract DbgManager getManager();
|
||||
|
||||
public abstract void setManager(DbgManager manager);
|
||||
}
|
||||
@@ -1,63 +0,0 @@
|
||||
/* ###
|
||||
* 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 agent.dbgeng.gadp.impl;
|
||||
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import agent.dbgeng.dbgeng.DebugClient;
|
||||
import agent.dbgeng.manager.DbgManager;
|
||||
|
||||
/**
|
||||
* A single-threaded executor which creates and exclusively accesses the {@code dbgeng.dll} client.
|
||||
*
|
||||
* The executor also has a priority mechanism, so that callbacks may register follow-on handlers
|
||||
* which take precedence over other tasks in the queue (which could trigger additional callbacks).
|
||||
* This is required since certain operation are not allowed during normal callback processing. For
|
||||
* example, changing the current process is typically not allowed, but it is necessary to retrieve a
|
||||
* thread's context.
|
||||
*/
|
||||
public class DbgEngClientThreadExecutor extends AbstractClientThreadExecutor {
|
||||
|
||||
private final Supplier<DebugClient> makeClient;
|
||||
private DbgManager manager;
|
||||
|
||||
/**
|
||||
* Instantiate a new executor, providing a means of creating the client
|
||||
*
|
||||
* @param makeClient the callback to create the client
|
||||
*/
|
||||
public DbgEngClientThreadExecutor(Supplier<DebugClient> makeClient) {
|
||||
this.makeClient = makeClient;
|
||||
thread.setDaemon(true);
|
||||
thread.start();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void init() {
|
||||
this.client = makeClient.get();
|
||||
}
|
||||
|
||||
@Override
|
||||
public DbgManager getManager() {
|
||||
return manager;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setManager(DbgManager manager) {
|
||||
this.manager = manager;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,64 +0,0 @@
|
||||
/* ###
|
||||
* 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 agent.dbgeng.gadp.impl;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.SocketAddress;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
|
||||
import agent.dbgeng.gadp.DbgEngGadpServer;
|
||||
import agent.dbgeng.model.AbstractDbgModel;
|
||||
import agent.dbgeng.model.impl.DbgModelImpl;
|
||||
import ghidra.dbg.gadp.server.AbstractGadpServer;
|
||||
|
||||
public class DbgEngGadpServerImpl implements DbgEngGadpServer {
|
||||
public class GadpSide extends AbstractGadpServer {
|
||||
public GadpSide(AbstractDbgModel model, SocketAddress addr)
|
||||
throws IOException {
|
||||
super(model, addr);
|
||||
}
|
||||
}
|
||||
|
||||
protected final AbstractDbgModel model;
|
||||
protected final GadpSide server;
|
||||
|
||||
public DbgEngGadpServerImpl(SocketAddress addr) throws IOException {
|
||||
super();
|
||||
this.model = new DbgModelImpl();
|
||||
this.server = new GadpSide(model, addr);
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompletableFuture<Void> startDbgEng(String[] args) {
|
||||
return model.startDbgEng(args).thenCompose(__ -> server.launchAsyncService());
|
||||
}
|
||||
|
||||
@Override
|
||||
public SocketAddress getLocalAddress() {
|
||||
return server.getLocalAddress();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isRunning() {
|
||||
return model.isRunning();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void terminate() throws IOException {
|
||||
model.terminate();
|
||||
server.terminate();
|
||||
}
|
||||
}
|
||||
@@ -1,93 +0,0 @@
|
||||
/* ###
|
||||
* 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 agent.dbgeng.impl.dbgeng;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.function.Function;
|
||||
|
||||
import com.sun.jna.Pointer;
|
||||
import com.sun.jna.platform.win32.Guid.IID;
|
||||
import com.sun.jna.platform.win32.Guid.REFIID;
|
||||
import com.sun.jna.platform.win32.WinDef.ULONG;
|
||||
import com.sun.jna.platform.win32.WinNT.HRESULT;
|
||||
import com.sun.jna.platform.win32.COM.*;
|
||||
import com.sun.jna.ptr.PointerByReference;
|
||||
|
||||
import agent.dbgeng.dbgeng.err.DbgEngRuntimeException;
|
||||
import ghidra.util.Msg;
|
||||
|
||||
public abstract class DbgEngUtil {
|
||||
public static final ULONG DEBUG_ANY_ID = new ULONG(-1);
|
||||
|
||||
private DbgEngUtil() {
|
||||
}
|
||||
|
||||
public record Preferred<T> (REFIID refiid, Class<? extends T> cls) {
|
||||
public Preferred(IID iid, Class<? extends T> cls) {
|
||||
this(new REFIID(iid), cls);
|
||||
}
|
||||
}
|
||||
|
||||
public static interface InterfaceSupplier {
|
||||
HRESULT get(REFIID refiid, PointerByReference pClient);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public static <I, T> I tryPreferredInterfaces(Class<I> cls, List<Preferred<T>> preferred,
|
||||
InterfaceSupplier supplier) {
|
||||
PointerByReference ppClient = new PointerByReference();
|
||||
for (Preferred<T> pref : preferred) {
|
||||
try {
|
||||
COMUtils.checkRC(supplier.get(pref.refiid, ppClient));
|
||||
if (ppClient.getValue() == null) {
|
||||
continue;
|
||||
}
|
||||
T impl = pref.cls.getConstructor(Pointer.class).newInstance(ppClient.getValue());
|
||||
Method instanceFor = cls.getMethod("instanceFor", pref.cls);
|
||||
Object instance = instanceFor.invoke(null, impl);
|
||||
return (I) instance;
|
||||
}
|
||||
catch (COMException e) {
|
||||
Msg.debug(DbgEngUtil.class, e + " (" + pref.cls + ")");
|
||||
// TODO: Only try next on E_NOINTERFACE?
|
||||
// Try next
|
||||
}
|
||||
catch (Exception e) {
|
||||
throw new AssertionError("INTERNAL: Unexpected exception", e);
|
||||
}
|
||||
}
|
||||
throw new DbgEngRuntimeException("None of the preferred interfaces are supported");
|
||||
}
|
||||
|
||||
public static <T extends Unknown, U> U lazyWeakCache(Map<Pointer, U> cache, T unk,
|
||||
Function<T, U> forNew) {
|
||||
U present = cache.get(unk.getPointer());
|
||||
if (present != null) {
|
||||
unk.Release();
|
||||
return present;
|
||||
}
|
||||
U absent = forNew.apply(unk);
|
||||
cache.put(unk.getPointer(), absent);
|
||||
return absent;
|
||||
}
|
||||
|
||||
public static void dbgline() {
|
||||
System.out.println(new Exception().getStackTrace()[1]);
|
||||
System.out.flush();
|
||||
}
|
||||
}
|
||||
@@ -1,66 +0,0 @@
|
||||
/* ###
|
||||
* 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 agent.dbgeng.impl.dbgeng;
|
||||
|
||||
import agent.dbgeng.dbgeng.DebugRunningProcess;
|
||||
import agent.dbgeng.dbgeng.DebugServerId;
|
||||
import agent.dbgeng.impl.dbgeng.client.DebugClientInternal;
|
||||
import ghidra.comm.util.BitmaskSet;
|
||||
|
||||
public class DebugRunningProcessImpl
|
||||
implements DebugRunningProcess, Comparable<DebugRunningProcessImpl> {
|
||||
public DebugRunningProcessImpl(DebugClientInternal client, DebugServerId server, int systemId) {
|
||||
this.client = client;
|
||||
this.server = server;
|
||||
this.systemId = systemId;
|
||||
}
|
||||
|
||||
protected final DebugClientInternal client;
|
||||
protected final DebugServerId server;
|
||||
protected final int systemId;
|
||||
|
||||
@Override
|
||||
public int getSystemId() {
|
||||
return systemId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Description getFullDescription(Description.ProcessDescriptionFlags... flags) {
|
||||
return client.getProcessDescription(server, systemId, BitmaskSet.of(flags));
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getExecutableName(Description.ProcessDescriptionFlags... flags) {
|
||||
return getFullDescription(flags).getExecutableName();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDescription(Description.ProcessDescriptionFlags... flags) {
|
||||
return getFullDescription(flags).getDescription();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int compareTo(DebugRunningProcessImpl that) {
|
||||
int result;
|
||||
|
||||
result = Integer.compare(this.systemId, that.systemId);
|
||||
if (result != 0) {
|
||||
return result;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
@@ -1,38 +0,0 @@
|
||||
/* ###
|
||||
* 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 agent.dbgeng.impl.dbgeng.advanced;
|
||||
|
||||
import agent.dbgeng.dbgeng.DbgEng;
|
||||
import agent.dbgeng.dbgeng.DebugThreadId;
|
||||
import agent.dbgeng.dbgeng.DbgEng.OpaqueCleanable;
|
||||
import agent.dbgeng.jna.dbgeng.advanced.IDebugAdvanced;
|
||||
|
||||
public class DebugAdvancedImpl1 implements DebugAdvancedInternal {
|
||||
@SuppressWarnings("unused")
|
||||
private final OpaqueCleanable cleanable;
|
||||
@SuppressWarnings("unused")
|
||||
private final IDebugAdvanced jnaAdvanced;
|
||||
|
||||
public DebugAdvancedImpl1(IDebugAdvanced jnaAdvanced) {
|
||||
this.cleanable = DbgEng.releaseWhenPhantom(this, jnaAdvanced);
|
||||
this.jnaAdvanced = jnaAdvanced;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DebugThreadBasicInformation getThreadBasicInformation(DebugThreadId tid) {
|
||||
throw new UnsupportedOperationException("Not supported by this interface");
|
||||
}
|
||||
}
|
||||
@@ -1,85 +0,0 @@
|
||||
/* ###
|
||||
* 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 agent.dbgeng.impl.dbgeng.advanced;
|
||||
|
||||
import com.sun.jna.platform.win32.WinDef.ULONG;
|
||||
import com.sun.jna.platform.win32.WinDef.ULONGLONG;
|
||||
|
||||
import agent.dbgeng.dbgeng.DebugThreadId;
|
||||
import agent.dbgeng.jna.dbgeng.DbgEngNative.DEBUG_THREAD_BASIC_INFORMATION;
|
||||
import agent.dbgeng.jna.dbgeng.advanced.IDebugAdvanced2;
|
||||
|
||||
import com.sun.jna.platform.win32.COM.COMUtils;
|
||||
|
||||
import ghidra.comm.util.BitmaskSet;
|
||||
|
||||
public class DebugAdvancedImpl2 extends DebugAdvancedImpl1 {
|
||||
private final IDebugAdvanced2 jnaAdvanced;
|
||||
|
||||
public DebugAdvancedImpl2(IDebugAdvanced2 jnaAdvanced) {
|
||||
super(jnaAdvanced);
|
||||
this.jnaAdvanced = jnaAdvanced;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DebugThreadBasicInformation getThreadBasicInformation(DebugThreadId tid) {
|
||||
ULONG ulWhich = new ULONG(WhichSystemObjectInformation.THREAD_BASIC_INFORMATION.ordinal());
|
||||
ULONGLONG ullUnused = new ULONGLONG(0);
|
||||
ULONG ulThreadId = new ULONG(tid.value());
|
||||
DEBUG_THREAD_BASIC_INFORMATION sInfo = new DEBUG_THREAD_BASIC_INFORMATION();
|
||||
ULONG ulBufferSize = new ULONG(sInfo.size());
|
||||
COMUtils.checkRC(jnaAdvanced.GetSystemObjectInformation(ulWhich, ullUnused, ulThreadId,
|
||||
sInfo.getPointer(), ulBufferSize, null));
|
||||
sInfo.read();
|
||||
|
||||
Integer exitStatus = null;
|
||||
Integer priorityClass = null;
|
||||
Integer priority = null;
|
||||
Long createTime = null;
|
||||
Long exitTime = null;
|
||||
Long kernelTime = null;
|
||||
Long userTime = null;
|
||||
Long startOffset = null;
|
||||
Long affinity = null;
|
||||
|
||||
BitmaskSet<ThreadBasicInformationValidBits> valid =
|
||||
new BitmaskSet<>(ThreadBasicInformationValidBits.class, sInfo.Valid.intValue());
|
||||
if (valid.contains(ThreadBasicInformationValidBits.EXIT_STATUS)) {
|
||||
exitStatus = sInfo.ExitStatus.intValue();
|
||||
}
|
||||
if (valid.contains(ThreadBasicInformationValidBits.PRIORITY_CLASS)) {
|
||||
priorityClass = sInfo.PriorityClass.intValue();
|
||||
}
|
||||
if (valid.contains(ThreadBasicInformationValidBits.PRIORITY)) {
|
||||
priority = sInfo.Priority.intValue();
|
||||
}
|
||||
if (valid.contains(ThreadBasicInformationValidBits.TIMES)) {
|
||||
createTime = sInfo.CreateTime.longValue();
|
||||
exitTime = sInfo.ExitTime.longValue();
|
||||
kernelTime = sInfo.KernelTime.longValue();
|
||||
userTime = sInfo.UserTime.longValue();
|
||||
}
|
||||
if (valid.contains(ThreadBasicInformationValidBits.START_OFFSET)) {
|
||||
startOffset = sInfo.StartOffset.longValue();
|
||||
}
|
||||
if (valid.contains(ThreadBasicInformationValidBits.AFFINITY)) {
|
||||
affinity = sInfo.Affinity.longValue();
|
||||
}
|
||||
|
||||
return new DebugThreadBasicInformation(exitStatus, priorityClass, priority, createTime,
|
||||
exitTime, kernelTime, userTime, startOffset, affinity);
|
||||
}
|
||||
}
|
||||
@@ -1,28 +0,0 @@
|
||||
/* ###
|
||||
* 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 agent.dbgeng.impl.dbgeng.advanced;
|
||||
|
||||
import agent.dbgeng.jna.dbgeng.advanced.IDebugAdvanced3;
|
||||
|
||||
public class DebugAdvancedImpl3 extends DebugAdvancedImpl2 {
|
||||
@SuppressWarnings("unused")
|
||||
private final IDebugAdvanced3 jnaAdvanced;
|
||||
|
||||
public DebugAdvancedImpl3(IDebugAdvanced3 jnaAdvanced) {
|
||||
super(jnaAdvanced);
|
||||
this.jnaAdvanced = jnaAdvanced;
|
||||
}
|
||||
}
|
||||
@@ -1,84 +0,0 @@
|
||||
/* ###
|
||||
* 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 agent.dbgeng.impl.dbgeng.advanced;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import com.sun.jna.Pointer;
|
||||
|
||||
import agent.dbgeng.dbgeng.DebugAdvanced;
|
||||
import agent.dbgeng.impl.dbgeng.DbgEngUtil;
|
||||
import agent.dbgeng.impl.dbgeng.DbgEngUtil.InterfaceSupplier;
|
||||
import agent.dbgeng.impl.dbgeng.DbgEngUtil.Preferred;
|
||||
import agent.dbgeng.jna.dbgeng.advanced.*;
|
||||
import ghidra.comm.util.BitmaskUniverse;
|
||||
import ghidra.util.datastruct.WeakValueHashMap;
|
||||
|
||||
public interface DebugAdvancedInternal extends DebugAdvanced {
|
||||
Map<Pointer, DebugAdvancedInternal> CACHE = new WeakValueHashMap<>();
|
||||
|
||||
static DebugAdvancedInternal instanceFor(WrapIDebugAdvanced advanced) {
|
||||
return DbgEngUtil.lazyWeakCache(CACHE, advanced, DebugAdvancedImpl1::new);
|
||||
}
|
||||
|
||||
static DebugAdvancedInternal instanceFor(WrapIDebugAdvanced2 advanced) {
|
||||
return DbgEngUtil.lazyWeakCache(CACHE, advanced, DebugAdvancedImpl2::new);
|
||||
}
|
||||
|
||||
static DebugAdvancedInternal instanceFor(WrapIDebugAdvanced3 advanced) {
|
||||
return DbgEngUtil.lazyWeakCache(CACHE, advanced, DebugAdvancedImpl3::new);
|
||||
}
|
||||
|
||||
List<Preferred<WrapIDebugAdvanced>> PREFERRED_ADVANCED_IIDS = List.of(
|
||||
new Preferred<>(IDebugAdvanced3.IID_IDEBUG_ADVANCED3, WrapIDebugAdvanced3.class),
|
||||
new Preferred<>(IDebugAdvanced2.IID_IDEBUG_ADVANCED2, WrapIDebugAdvanced2.class),
|
||||
new Preferred<>(IDebugAdvanced.IID_IDEBUG_ADVANCED, WrapIDebugAdvanced.class));
|
||||
|
||||
static DebugAdvancedInternal tryPreferredInterfaces(InterfaceSupplier supplier) {
|
||||
return DbgEngUtil.tryPreferredInterfaces(DebugAdvancedInternal.class,
|
||||
PREFERRED_ADVANCED_IIDS, supplier);
|
||||
}
|
||||
|
||||
public enum WhichSystemObjectInformation {
|
||||
THREAD_BASIC_INFORMATION, //
|
||||
THREAD_NAME_WIDE, //
|
||||
CURRENT_PROCESS_COOKIE, //
|
||||
;
|
||||
}
|
||||
|
||||
public enum ThreadBasicInformationValidBits implements BitmaskUniverse {
|
||||
EXIT_STATUS(1 << 0), //
|
||||
PRIORITY_CLASS(1 << 1), //
|
||||
PRIORITY(1 << 2), //
|
||||
TIMES(1 << 3), //
|
||||
START_OFFSET(1 << 4), //
|
||||
AFFINITY(1 << 5), //
|
||||
ALL(0x3f);
|
||||
;
|
||||
|
||||
ThreadBasicInformationValidBits(int mask) {
|
||||
this.mask = mask;
|
||||
}
|
||||
|
||||
int mask;
|
||||
|
||||
@Override
|
||||
public long getMask() {
|
||||
return mask;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,195 +0,0 @@
|
||||
/* ###
|
||||
* 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 agent.dbgeng.impl.dbgeng.breakpoint;
|
||||
|
||||
import com.sun.jna.Native;
|
||||
import com.sun.jna.platform.win32.Kernel32;
|
||||
import com.sun.jna.platform.win32.WinDef.*;
|
||||
import com.sun.jna.platform.win32.WinNT.HRESULT;
|
||||
import com.sun.jna.platform.win32.COM.COMUtils;
|
||||
import com.sun.jna.ptr.PointerByReference;
|
||||
|
||||
import agent.dbgeng.dbgeng.DbgEng;
|
||||
import agent.dbgeng.dbgeng.DbgEng.OpaqueCleanable;
|
||||
import agent.dbgeng.dbgeng.DebugClient;
|
||||
import agent.dbgeng.impl.dbgeng.client.DebugClientInternal;
|
||||
import agent.dbgeng.impl.dbgeng.control.DebugControlInternal;
|
||||
import agent.dbgeng.jna.dbgeng.WinNTExtra.Machine;
|
||||
import agent.dbgeng.jna.dbgeng.breakpoint.IDebugBreakpoint;
|
||||
import agent.dbgeng.jna.dbgeng.client.WrapIDebugClient;
|
||||
import ghidra.comm.util.BitmaskSet;
|
||||
|
||||
public class DebugBreakpointImpl1 implements DebugBreakpointInternal {
|
||||
@SuppressWarnings("unused")
|
||||
private final OpaqueCleanable cleanable;
|
||||
private IDebugBreakpoint jnaBreakpoint;
|
||||
private DebugControlInternal control;
|
||||
|
||||
public DebugBreakpointImpl1(IDebugBreakpoint jnaBreakpoint) {
|
||||
this.cleanable = DbgEng.releaseWhenPhantom(this, jnaBreakpoint);
|
||||
this.jnaBreakpoint = jnaBreakpoint;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setControl(DebugControlInternal control) {
|
||||
this.control = control;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void remove() {
|
||||
control.removeBreakpoint(jnaBreakpoint);
|
||||
// If we do this here, dispose will fail
|
||||
//jnaBreakpoint = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dispose() {
|
||||
// Prevent accidental access. Will be released during GC. NPE is better than segfault.
|
||||
CACHE.remove(jnaBreakpoint.getPointer());
|
||||
jnaBreakpoint = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getId() {
|
||||
ULONGByReference pulId = new ULONGByReference();
|
||||
COMUtils.checkRC(jnaBreakpoint.GetId(pulId));
|
||||
return pulId.getValue().intValue();
|
||||
}
|
||||
|
||||
@Override
|
||||
public BreakFullType getType() {
|
||||
ULONGByReference pulBreakType = new ULONGByReference();
|
||||
ULONGByReference pulProcType = new ULONGByReference();
|
||||
COMUtils.checkRC(jnaBreakpoint.GetType(pulBreakType, pulProcType));
|
||||
BreakType breakType = BreakType.values()[pulBreakType.getValue().intValue()];
|
||||
Machine procType = Machine.getByNumber(pulProcType.getValue().intValue());
|
||||
return new BreakFullType(breakType, procType);
|
||||
}
|
||||
|
||||
@Override
|
||||
public DebugClient getAdder() {
|
||||
PointerByReference pClient = new PointerByReference();
|
||||
COMUtils.checkRC(jnaBreakpoint.GetAdder(pClient.getPointer()));
|
||||
WrapIDebugClient wrap = new WrapIDebugClient(pClient.getValue());
|
||||
|
||||
try {
|
||||
return DebugClientInternal.tryPreferredInterfaces(wrap::QueryInterface);
|
||||
}
|
||||
finally {
|
||||
wrap.Release();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public BitmaskSet<BreakFlags> getFlags() {
|
||||
ULONGByReference pulFlags = new ULONGByReference();
|
||||
COMUtils.checkRC(jnaBreakpoint.GetFlags(pulFlags));
|
||||
return new BitmaskSet<>(BreakFlags.class, pulFlags.getValue().longValue());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addFlags(BitmaskSet<BreakFlags> flags) {
|
||||
ULONG ulFlags = new ULONG(flags.getBitmask());
|
||||
COMUtils.checkRC(jnaBreakpoint.AddFlags(ulFlags));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addFlags(BreakFlags... flags) {
|
||||
addFlags(BitmaskSet.of(flags));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeFlags(BitmaskSet<BreakFlags> flags) {
|
||||
ULONG ulFlags = new ULONG(flags.getBitmask());
|
||||
COMUtils.checkRC(jnaBreakpoint.RemoveFlags(ulFlags));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeFlags(BreakFlags... flags) {
|
||||
removeFlags(BitmaskSet.of(flags));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setFlags(BitmaskSet<BreakFlags> flags) {
|
||||
ULONG ulFlags = new ULONG(flags.getBitmask());
|
||||
COMUtils.checkRC(jnaBreakpoint.SetFlags(ulFlags));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setFlags(BreakFlags... flags) {
|
||||
setFlags(BitmaskSet.of(flags));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Long getOffset() {
|
||||
ULONGLONGByReference pullOffset = new ULONGLONGByReference();
|
||||
HRESULT getOffset = jnaBreakpoint.GetOffset(pullOffset);
|
||||
if (getOffset.longValue() == Kernel32.E_NOINTERFACE) {
|
||||
// Per MSDN, this means the placement is deferred
|
||||
return null;
|
||||
}
|
||||
COMUtils.checkRC(getOffset);
|
||||
return pullOffset.getValue().longValue();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setOffset(long offset) {
|
||||
ULONGLONG ullOffset = new ULONGLONG(offset);
|
||||
COMUtils.checkRC(jnaBreakpoint.SetOffset(ullOffset));
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getOffsetExpression() {
|
||||
ULONGByReference pulExpressionSize = new ULONGByReference();
|
||||
COMUtils.checkRC(jnaBreakpoint.GetOffsetExpression(null, new ULONG(0), pulExpressionSize));
|
||||
byte[] buffer = new byte[pulExpressionSize.getValue().intValue()];
|
||||
COMUtils.checkRC(
|
||||
jnaBreakpoint.GetOffsetExpression(buffer, pulExpressionSize.getValue(), null));
|
||||
return Native.toString(buffer);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setOffsetExpression(String expression) {
|
||||
COMUtils.checkRC(jnaBreakpoint.SetOffsetExpression(expression));
|
||||
}
|
||||
|
||||
@Override
|
||||
public BreakDataParameters getDataParameters() {
|
||||
ULONGByReference pulSize = new ULONGByReference();
|
||||
ULONGByReference pulAccessType = new ULONGByReference();
|
||||
COMUtils.checkRC(jnaBreakpoint.GetDataParameters(pulSize, pulAccessType));
|
||||
return new BreakDataParameters(pulSize.getValue().intValue(),
|
||||
new BitmaskSet<>(BreakAccess.class, pulAccessType.getValue().intValue()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setDataParameters(BreakDataParameters params) {
|
||||
setDataParameters(params.size, params.access);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setDataParameters(int size, BitmaskSet<BreakAccess> access) {
|
||||
ULONG ulSize = new ULONG(size);
|
||||
ULONG ulAccessType = new ULONG(access.getBitmask());
|
||||
COMUtils.checkRC(jnaBreakpoint.SetDataParameters(ulSize, ulAccessType));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setDataParameters(int size, BreakAccess... access) {
|
||||
setDataParameters(size, BitmaskSet.of(access));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,56 +0,0 @@
|
||||
/* ###
|
||||
* 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 agent.dbgeng.impl.dbgeng.breakpoint;
|
||||
|
||||
import com.sun.jna.Native;
|
||||
import com.sun.jna.WString;
|
||||
import com.sun.jna.platform.win32.WinDef.ULONG;
|
||||
import com.sun.jna.platform.win32.WinDef.ULONGByReference;
|
||||
import com.sun.jna.platform.win32.COM.COMUtils;
|
||||
|
||||
import agent.dbgeng.jna.dbgeng.breakpoint.IDebugBreakpoint2;
|
||||
|
||||
public class DebugBreakpointImpl2 extends DebugBreakpointImpl1 {
|
||||
|
||||
private IDebugBreakpoint2 jnaBreakpoint;
|
||||
|
||||
public DebugBreakpointImpl2(IDebugBreakpoint2 jnaBreakpoint) {
|
||||
super(jnaBreakpoint);
|
||||
this.jnaBreakpoint = jnaBreakpoint;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dispose() {
|
||||
super.dispose();
|
||||
jnaBreakpoint = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getOffsetExpression() {
|
||||
ULONGByReference pulExpressionSize = new ULONGByReference();
|
||||
COMUtils.checkRC(
|
||||
jnaBreakpoint.GetOffsetExpressionWide(null, new ULONG(0), pulExpressionSize));
|
||||
char[] buffer = new char[pulExpressionSize.getValue().intValue()];
|
||||
COMUtils.checkRC(
|
||||
jnaBreakpoint.GetOffsetExpressionWide(buffer, pulExpressionSize.getValue(), null));
|
||||
return Native.toString(buffer);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setOffsetExpression(String expression) {
|
||||
COMUtils.checkRC(jnaBreakpoint.SetOffsetExpressionWide(new WString(expression)));
|
||||
}
|
||||
}
|
||||
@@ -1,34 +0,0 @@
|
||||
/* ###
|
||||
* 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 agent.dbgeng.impl.dbgeng.breakpoint;
|
||||
|
||||
import agent.dbgeng.jna.dbgeng.breakpoint.IDebugBreakpoint3;
|
||||
|
||||
public class DebugBreakpointImpl3 extends DebugBreakpointImpl2 {
|
||||
@SuppressWarnings("unused")
|
||||
private IDebugBreakpoint3 jnaBreakpoint;
|
||||
|
||||
public DebugBreakpointImpl3(IDebugBreakpoint3 jnaBreakpoint) {
|
||||
super(jnaBreakpoint);
|
||||
this.jnaBreakpoint = jnaBreakpoint;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dispose() {
|
||||
super.dispose();
|
||||
jnaBreakpoint = null;
|
||||
}
|
||||
}
|
||||
@@ -1,60 +0,0 @@
|
||||
/* ###
|
||||
* 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 agent.dbgeng.impl.dbgeng.breakpoint;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import com.sun.jna.Pointer;
|
||||
|
||||
import agent.dbgeng.dbgeng.DebugBreakpoint;
|
||||
import agent.dbgeng.impl.dbgeng.DbgEngUtil;
|
||||
import agent.dbgeng.impl.dbgeng.DbgEngUtil.InterfaceSupplier;
|
||||
import agent.dbgeng.impl.dbgeng.DbgEngUtil.Preferred;
|
||||
import agent.dbgeng.impl.dbgeng.control.DebugControlInternal;
|
||||
import agent.dbgeng.jna.dbgeng.breakpoint.*;
|
||||
import ghidra.util.datastruct.WeakValueHashMap;
|
||||
|
||||
public interface DebugBreakpointInternal extends DebugBreakpoint {
|
||||
Map<Pointer, DebugBreakpointInternal> CACHE = new WeakValueHashMap<>();
|
||||
|
||||
static DebugBreakpointInternal instanceFor(WrapIDebugBreakpoint bp) {
|
||||
return DbgEngUtil.lazyWeakCache(CACHE, bp, DebugBreakpointImpl1::new);
|
||||
}
|
||||
|
||||
static DebugBreakpointInternal instanceFor(WrapIDebugBreakpoint2 bp) {
|
||||
return DbgEngUtil.lazyWeakCache(CACHE, bp, DebugBreakpointImpl2::new);
|
||||
}
|
||||
|
||||
static DebugBreakpointInternal instanceFor(WrapIDebugBreakpoint3 bp) {
|
||||
return DbgEngUtil.lazyWeakCache(CACHE, bp, DebugBreakpointImpl3::new);
|
||||
}
|
||||
|
||||
List<Preferred<WrapIDebugBreakpoint>> PREFERRED_BREAKPOINT_IIDS = List.of(
|
||||
new Preferred<>(IDebugBreakpoint3.IID_IDEBUG_BREAKPOINT3, WrapIDebugBreakpoint3.class),
|
||||
new Preferred<>(IDebugBreakpoint2.IID_IDEBUG_BREAKPOINT2, WrapIDebugBreakpoint2.class),
|
||||
new Preferred<>(IDebugBreakpoint.IID_IDEBUG_BREAKPOINT, WrapIDebugBreakpoint.class));
|
||||
|
||||
static DebugBreakpointInternal tryPreferredInterfaces(DebugControlInternal control,
|
||||
InterfaceSupplier supplier) {
|
||||
DebugBreakpointInternal bpt = DbgEngUtil.tryPreferredInterfaces(
|
||||
DebugBreakpointInternal.class, PREFERRED_BREAKPOINT_IIDS, supplier);
|
||||
bpt.setControl(control);
|
||||
return bpt;
|
||||
}
|
||||
|
||||
void setControl(DebugControlInternal control);
|
||||
}
|
||||
@@ -1,333 +0,0 @@
|
||||
/* ###
|
||||
* 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 agent.dbgeng.impl.dbgeng.client;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import com.sun.jna.Native;
|
||||
import com.sun.jna.platform.win32.WinDef.*;
|
||||
import com.sun.jna.platform.win32.WinNT;
|
||||
import com.sun.jna.platform.win32.WinNT.HRESULT;
|
||||
import com.sun.jna.platform.win32.COM.COMUtils;
|
||||
import com.sun.jna.ptr.PointerByReference;
|
||||
|
||||
import agent.dbgeng.dbgeng.*;
|
||||
import agent.dbgeng.dbgeng.DbgEng.OpaqueCleanable;
|
||||
import agent.dbgeng.impl.dbgeng.DebugRunningProcessImpl;
|
||||
import agent.dbgeng.impl.dbgeng.advanced.DebugAdvancedInternal;
|
||||
import agent.dbgeng.impl.dbgeng.control.DebugControlInternal;
|
||||
import agent.dbgeng.impl.dbgeng.dataspaces.DebugDataSpacesInternal;
|
||||
import agent.dbgeng.impl.dbgeng.event.WrapCallbackIDebugEventCallbacks;
|
||||
import agent.dbgeng.impl.dbgeng.io.WrapCallbackIDebugInputCallbacks;
|
||||
import agent.dbgeng.impl.dbgeng.io.WrapCallbackIDebugOutputCallbacks;
|
||||
import agent.dbgeng.impl.dbgeng.registers.DebugRegistersInternal;
|
||||
import agent.dbgeng.impl.dbgeng.symbols.DebugSymbolsInternal;
|
||||
import agent.dbgeng.impl.dbgeng.sysobj.DebugSystemObjectsInternal;
|
||||
import agent.dbgeng.jna.dbgeng.client.IDebugClient;
|
||||
import agent.dbgeng.jna.dbgeng.event.ListenerIDebugEventCallbacks;
|
||||
import agent.dbgeng.jna.dbgeng.event.MarkerEventCallbacks;
|
||||
import agent.dbgeng.jna.dbgeng.io.*;
|
||||
import ghidra.comm.util.BitmaskSet;
|
||||
|
||||
public class DebugClientImpl1 implements DebugClientInternal {
|
||||
@SuppressWarnings("unused")
|
||||
private final OpaqueCleanable cleanable;
|
||||
private final IDebugClient jnaClient;
|
||||
|
||||
private DebugAdvancedInternal advanced;
|
||||
private DebugControlInternal control;
|
||||
private DebugDataSpaces data;
|
||||
private DebugRegisters registers;
|
||||
private DebugSymbols symbols;
|
||||
private DebugSystemObjects sysobjs;
|
||||
|
||||
// Keep references to callbacks here, since JNA doesn't keep one for things handed to natives.
|
||||
protected MarkerOutputCallbacks listenerOutput;
|
||||
protected MarkerInputCallbacks listenerInput;
|
||||
protected MarkerEventCallbacks listenerEvent;
|
||||
|
||||
public DebugClientImpl1(IDebugClient jnaClient) {
|
||||
// TODO: Debug and verify COM resource management
|
||||
this.cleanable = DbgEng.releaseWhenPhantom(this, jnaClient);
|
||||
this.jnaClient = jnaClient;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IDebugClient getJNAClient() {
|
||||
return jnaClient;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DebugAdvanced getAdvanced() {
|
||||
if (advanced == null) {
|
||||
advanced = DebugAdvancedInternal.tryPreferredInterfaces(jnaClient::QueryInterface);
|
||||
}
|
||||
return advanced;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DebugControlInternal getControlInternal() {
|
||||
if (control == null) {
|
||||
control = DebugControlInternal.tryPreferredInterfaces(jnaClient::QueryInterface);
|
||||
}
|
||||
return control;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DebugControl getControl() {
|
||||
return getControlInternal();
|
||||
}
|
||||
|
||||
@Override
|
||||
public DebugDataSpaces getDataSpaces() {
|
||||
if (data == null) {
|
||||
data = DebugDataSpacesInternal.tryPreferredInterfaces(jnaClient::QueryInterface);
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DebugRegisters getRegisters() {
|
||||
if (registers == null) {
|
||||
registers = DebugRegistersInternal.tryPreferredInterfaces(jnaClient::QueryInterface);
|
||||
}
|
||||
return registers;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DebugSymbols getSymbols() {
|
||||
if (symbols == null) {
|
||||
symbols = DebugSymbolsInternal.tryPreferredInterfaces(jnaClient::QueryInterface);
|
||||
}
|
||||
return symbols;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DebugSystemObjects getSystemObjects() {
|
||||
if (sysobjs == null) {
|
||||
sysobjs = DebugSystemObjectsInternal.tryPreferredInterfaces(jnaClient::QueryInterface);
|
||||
}
|
||||
return sysobjs;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DebugServerId getLocalServer() {
|
||||
return new DebugServerId(0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void startProcessServer(String options) {
|
||||
COMUtils.checkRC(jnaClient.StartProcessServer(new ULONG(DebugClass.USER_WINDOWS.ordinal()),
|
||||
options, null));
|
||||
}
|
||||
|
||||
@Override
|
||||
public DebugServerId connectProcessServer(String options) {
|
||||
ULONGLONGByReference pulServer = new ULONGLONGByReference();
|
||||
COMUtils.checkRC(jnaClient.ConnectProcessServer(options, pulServer));
|
||||
return new DebugServerId(pulServer.getValue().longValue());
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<DebugRunningProcess> getRunningProcesses(DebugServerId si) {
|
||||
ULONGLONG server = new ULONGLONG(si.id);
|
||||
ULONGByReference actualCount = new ULONGByReference();
|
||||
COMUtils.checkRC(
|
||||
jnaClient.GetRunningProcessSystemIds(server, null, new ULONG(0), actualCount));
|
||||
|
||||
int[] ids = new int[actualCount.getValue().intValue()];
|
||||
COMUtils.checkRC(
|
||||
jnaClient.GetRunningProcessSystemIds(server, ids, actualCount.getValue(), null));
|
||||
|
||||
List<DebugRunningProcess> result = new ArrayList<>(ids.length);
|
||||
for (int id : ids) {
|
||||
result.add(new DebugRunningProcessImpl(this, si, id));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DebugRunningProcess.Description getProcessDescription(DebugServerId si, int systemId,
|
||||
BitmaskSet<DebugRunningProcess.Description.ProcessDescriptionFlags> flags) {
|
||||
ULONGLONG ullServer = new ULONGLONG(si.id);
|
||||
ULONG ulId = new ULONG(systemId);
|
||||
ULONG ulFlags = new ULONG(flags.getBitmask());
|
||||
|
||||
ULONGByReference actualExeNameSize = new ULONGByReference();
|
||||
ULONGByReference actualDescriptionSize = new ULONGByReference();
|
||||
COMUtils.checkRC(jnaClient.GetRunningProcessDescription(ullServer, ulId, ulFlags, null,
|
||||
new ULONG(0), actualExeNameSize, null, new ULONG(0), actualDescriptionSize));
|
||||
|
||||
byte[] exeName = new byte[actualExeNameSize.getValue().intValue()];
|
||||
byte[] description = new byte[actualDescriptionSize.getValue().intValue()];
|
||||
COMUtils.checkRC(jnaClient.GetRunningProcessDescription(ullServer, ulId, ulFlags, exeName,
|
||||
actualExeNameSize.getValue(), null, description, actualDescriptionSize.getValue(),
|
||||
null));
|
||||
|
||||
return new DebugRunningProcess.Description(systemId, Native.toString(exeName),
|
||||
Native.toString(description));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void attachProcess(DebugServerId si, long processId,
|
||||
BitmaskSet<DebugAttachFlags> attachFlags) {
|
||||
ULONGLONG ullServer = new ULONGLONG(si.id);
|
||||
ULONG ulPid = new ULONG(processId);
|
||||
ULONG ulFlags = new ULONG(attachFlags.getBitmask());
|
||||
COMUtils.checkRC(jnaClient.AttachProcess(ullServer, ulPid, ulFlags));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void createProcess(DebugServerId si, String commandLine,
|
||||
String unusedInitialDirectory, String unusedEnvironment,
|
||||
BitmaskSet<DebugCreateFlags> createFlags,
|
||||
BitmaskSet<DebugEngCreateFlags> unusedEngCreateFlags,
|
||||
BitmaskSet<DebugVerifierFlags> unusedVerifierFlags) {
|
||||
ULONGLONG ullServer = new ULONGLONG(si.id);
|
||||
ULONG ulFlags = new ULONG(createFlags.getBitmask());
|
||||
if (unusedInitialDirectory != null && unusedInitialDirectory.length() > 0) {
|
||||
throw new UnsupportedOperationException(
|
||||
"IDebugClient1 does not support 'initial directory'");
|
||||
}
|
||||
if (unusedEnvironment != null && unusedEnvironment.length() > 0) {
|
||||
throw new UnsupportedOperationException("IDebugClient1 does not support 'environment'");
|
||||
}
|
||||
COMUtils.checkRC(jnaClient.CreateProcess(ullServer, commandLine, ulFlags));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void createProcessAndAttach(DebugServerId si, String commandLine,
|
||||
BitmaskSet<DebugCreateFlags> createFlags, int processId,
|
||||
BitmaskSet<DebugAttachFlags> attachFlags) {
|
||||
ULONGLONG ullServer = new ULONGLONG(si.id);
|
||||
ULONG ulFlags1 = new ULONG(createFlags.getBitmask());
|
||||
ULONG ulPid = new ULONG(processId);
|
||||
ULONG ulFlags2 = new ULONG(attachFlags.getBitmask());
|
||||
COMUtils.checkRC(
|
||||
jnaClient.CreateProcessAndAttach(ullServer, commandLine, ulFlags1, ulPid, ulFlags2));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void startServer(String options) {
|
||||
COMUtils.checkRC(jnaClient.StartServer(options));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean dispatchCallbacks(int timeout) {
|
||||
HRESULT hr = jnaClient.DispatchCallbacks(new ULONG(timeout));
|
||||
COMUtils.checkRC(hr);
|
||||
return hr.equals(WinNT.S_OK);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void flushCallbacks() {
|
||||
HRESULT hr = jnaClient.FlushCallbacks();
|
||||
COMUtils.checkRC(hr);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void exitDispatch(DebugClient client) {
|
||||
DebugClientInternal ic = (DebugClientInternal) client;
|
||||
COMUtils.checkRC(jnaClient.ExitDispatch(ic.getJNAClient()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public DebugClient createClient() {
|
||||
PointerByReference ppClient = new PointerByReference();
|
||||
COMUtils.checkRC(jnaClient.CreateClient(ppClient));
|
||||
return DebugClientInternal.tryPreferredInterfaces(jnaClient::QueryInterface);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setInputCallbacks(DebugInputCallbacks cb) {
|
||||
ListenerIDebugInputCallbacks listener = null;
|
||||
if (cb != null) {
|
||||
WrapCallbackIDebugInputCallbacks callback =
|
||||
new WrapCallbackIDebugInputCallbacks(this, cb);
|
||||
listener = new ListenerIDebugInputCallbacks(callback);
|
||||
callback.setListener(listener);
|
||||
}
|
||||
COMUtils.checkRC(jnaClient.SetInputCallbacks(listener));
|
||||
listenerInput = listener;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setOutputCallbacks(DebugOutputCallbacks cb) {
|
||||
ListenerIDebugOutputCallbacks listener = null;
|
||||
if (cb != null) {
|
||||
WrapCallbackIDebugOutputCallbacks callback = new WrapCallbackIDebugOutputCallbacks(cb);
|
||||
listener = new ListenerIDebugOutputCallbacks(callback);
|
||||
callback.setListener(listener);
|
||||
}
|
||||
COMUtils.checkRC(jnaClient.SetOutputCallbacks(listener));
|
||||
listenerOutput = listener;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setEventCallbacks(DebugEventCallbacks cb) {
|
||||
ListenerIDebugEventCallbacks listener = null;
|
||||
if (cb != null) {
|
||||
WrapCallbackIDebugEventCallbacks callback =
|
||||
new WrapCallbackIDebugEventCallbacks(this, cb);
|
||||
listener = new ListenerIDebugEventCallbacks(callback);
|
||||
callback.setListener(listener);
|
||||
}
|
||||
COMUtils.checkRC(jnaClient.SetEventCallbacks(listener));
|
||||
listenerEvent = listener;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void terminateCurrentProcess() {
|
||||
throw new UnsupportedOperationException("Not implemented by this interface");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void detachCurrentProcess() {
|
||||
throw new UnsupportedOperationException("Not implemented by this interface");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void abandonCurrentProcess() {
|
||||
throw new UnsupportedOperationException("Not implemented by this interface");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void waitForProcessServerEnd(int timeout) {
|
||||
throw new UnsupportedOperationException("Not implemented by this interface");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void endSession(DebugEndSessionFlags flags) {
|
||||
COMUtils.checkRC(jnaClient.EndSession(new ULONG(flags.getValue())));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void connectSession(int flags) {
|
||||
COMUtils.checkRC(jnaClient.ConnectSession(new ULONG(flags), new ULONG(10000)));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void openDumpFileWide(String fileName) {
|
||||
throw new UnsupportedOperationException("Not implemented by this interface");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void attachKernel(long flags, String options) {
|
||||
throw new UnsupportedOperationException("Not implemented by this interface");
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,50 +0,0 @@
|
||||
/* ###
|
||||
* 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 agent.dbgeng.impl.dbgeng.client;
|
||||
|
||||
import com.sun.jna.platform.win32.WinDef.ULONG;
|
||||
import com.sun.jna.platform.win32.COM.COMUtils;
|
||||
|
||||
import agent.dbgeng.jna.dbgeng.client.IDebugClient2;
|
||||
|
||||
public class DebugClientImpl2 extends DebugClientImpl1 {
|
||||
private final IDebugClient2 jnaClient;
|
||||
|
||||
public DebugClientImpl2(IDebugClient2 jnaClient) {
|
||||
super(jnaClient);
|
||||
this.jnaClient = jnaClient;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void terminateCurrentProcess() {
|
||||
COMUtils.checkRC(jnaClient.TerminateCurrentProcess());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void detachCurrentProcess() {
|
||||
COMUtils.checkRC(jnaClient.DetachCurrentProcess());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void abandonCurrentProcess() {
|
||||
COMUtils.checkRC(jnaClient.AbandonCurrentProcess());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void waitForProcessServerEnd(int timeout) {
|
||||
COMUtils.checkRC(jnaClient.WaitForProcessServerEnd(new ULONG(timeout)));
|
||||
}
|
||||
}
|
||||
@@ -1,76 +0,0 @@
|
||||
/* ###
|
||||
* 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 agent.dbgeng.impl.dbgeng.client;
|
||||
|
||||
import com.sun.jna.Native;
|
||||
import com.sun.jna.WString;
|
||||
import com.sun.jna.platform.win32.WinDef.*;
|
||||
import com.sun.jna.platform.win32.COM.COMUtils;
|
||||
|
||||
import agent.dbgeng.dbgeng.DebugRunningProcess;
|
||||
import agent.dbgeng.dbgeng.DebugRunningProcess.Description.ProcessDescriptionFlags;
|
||||
import agent.dbgeng.dbgeng.DebugServerId;
|
||||
import agent.dbgeng.jna.dbgeng.client.IDebugClient3;
|
||||
import ghidra.comm.util.BitmaskSet;
|
||||
|
||||
public class DebugClientImpl3 extends DebugClientImpl2 {
|
||||
private final IDebugClient3 jnaClient;
|
||||
|
||||
public DebugClientImpl3(IDebugClient3 jnaClient) {
|
||||
super(jnaClient);
|
||||
this.jnaClient = jnaClient;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void createProcess(DebugServerId si, String commandLine,
|
||||
String unusedInitialDirectory, String unusedEnvironment,
|
||||
BitmaskSet<DebugCreateFlags> createFlags,
|
||||
BitmaskSet<DebugEngCreateFlags> unusedEngCreateFlags,
|
||||
BitmaskSet<DebugVerifierFlags> unusedVerifierFlags) {
|
||||
ULONGLONG ullServer = new ULONGLONG(si.id);
|
||||
ULONG ulFlags = new ULONG(createFlags.getBitmask());
|
||||
if (unusedInitialDirectory != null && unusedInitialDirectory.length() > 0) {
|
||||
throw new UnsupportedOperationException(
|
||||
"IDebugClient3 does not support 'initial directory'");
|
||||
}
|
||||
if (unusedEnvironment != null && unusedEnvironment.length() > 0) {
|
||||
throw new UnsupportedOperationException("IDebugClient3 does not support 'environment'");
|
||||
}
|
||||
COMUtils.checkRC(jnaClient.CreateProcessWide(ullServer, new WString(commandLine), ulFlags));
|
||||
}
|
||||
|
||||
@Override
|
||||
public DebugRunningProcess.Description getProcessDescription(DebugServerId si, int systemId,
|
||||
BitmaskSet<ProcessDescriptionFlags> flags) {
|
||||
ULONGLONG server = new ULONGLONG(si.id);
|
||||
ULONG id = new ULONG(systemId);
|
||||
ULONG f = new ULONG(flags.getBitmask());
|
||||
|
||||
ULONGByReference actualExeNameSize = new ULONGByReference();
|
||||
ULONGByReference actualDescriptionSize = new ULONGByReference();
|
||||
COMUtils.checkRC(jnaClient.GetRunningProcessDescriptionWide(server, id, f, null,
|
||||
new ULONG(0), actualExeNameSize, null, new ULONG(0), actualDescriptionSize));
|
||||
|
||||
char[] exeName = new char[actualExeNameSize.getValue().intValue()];
|
||||
char[] description = new char[actualDescriptionSize.getValue().intValue()];
|
||||
COMUtils.checkRC(jnaClient.GetRunningProcessDescriptionWide(server, id, f, exeName,
|
||||
actualExeNameSize.getValue(), null, description, actualDescriptionSize.getValue(),
|
||||
null));
|
||||
|
||||
return new DebugRunningProcess.Description(systemId, Native.toString(exeName),
|
||||
Native.toString(description));
|
||||
}
|
||||
}
|
||||
@@ -1,39 +0,0 @@
|
||||
/* ###
|
||||
* 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 agent.dbgeng.impl.dbgeng.client;
|
||||
|
||||
import com.sun.jna.WString;
|
||||
import com.sun.jna.platform.win32.WinDef.ULONGLONG;
|
||||
|
||||
import agent.dbgeng.jna.dbgeng.client.IDebugClient4;
|
||||
|
||||
import com.sun.jna.platform.win32.COM.COMUtils;
|
||||
|
||||
public class DebugClientImpl4 extends DebugClientImpl3 {
|
||||
@SuppressWarnings("unused")
|
||||
private final IDebugClient4 jnaClient;
|
||||
|
||||
public DebugClientImpl4(IDebugClient4 jnaClient) {
|
||||
super(jnaClient);
|
||||
this.jnaClient = jnaClient;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void openDumpFileWide(String fileName) {
|
||||
ULONGLONG ullFileHandle = new ULONGLONG(0);
|
||||
COMUtils.checkRC(jnaClient.OpenDumpFileWide(new WString(fileName), ullFileHandle));
|
||||
}
|
||||
}
|
||||
@@ -1,103 +0,0 @@
|
||||
/* ###
|
||||
* 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 agent.dbgeng.impl.dbgeng.client;
|
||||
|
||||
import com.sun.jna.WString;
|
||||
import com.sun.jna.platform.win32.WinDef.*;
|
||||
import com.sun.jna.platform.win32.COM.COMUtils;
|
||||
|
||||
import agent.dbgeng.dbgeng.*;
|
||||
import agent.dbgeng.impl.dbgeng.event.WrapCallbackIDebugEventCallbacksWide;
|
||||
import agent.dbgeng.impl.dbgeng.io.WrapCallbackIDebugOutputCallbacksWide;
|
||||
import agent.dbgeng.jna.dbgeng.DbgEngNative.DEBUG_CREATE_PROCESS_OPTIONS;
|
||||
import agent.dbgeng.jna.dbgeng.client.IDebugClient5;
|
||||
import agent.dbgeng.jna.dbgeng.event.ListenerIDebugEventCallbacksWide;
|
||||
import agent.dbgeng.jna.dbgeng.io.ListenerIDebugOutputCallbacksWide;
|
||||
import ghidra.comm.util.BitmaskSet;
|
||||
|
||||
public class DebugClientImpl5 extends DebugClientImpl4 {
|
||||
private final IDebugClient5 jnaClient;
|
||||
|
||||
public DebugClientImpl5(IDebugClient5 jnaClient) {
|
||||
super(jnaClient);
|
||||
this.jnaClient = jnaClient;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void createProcess(DebugServerId si, String commandLine,
|
||||
String initialDirectory, String environment,
|
||||
BitmaskSet<DebugCreateFlags> createFlags,
|
||||
BitmaskSet<DebugEngCreateFlags> engCreateFlags,
|
||||
BitmaskSet<DebugVerifierFlags> verifierFlags) {
|
||||
ULONGLONG ullServer = new ULONGLONG(si.id);
|
||||
DEBUG_CREATE_PROCESS_OPTIONS options = new DEBUG_CREATE_PROCESS_OPTIONS();
|
||||
options.CreateFlags = new ULONG(createFlags.getBitmask());
|
||||
options.EngCreateFlags = new ULONG(engCreateFlags.getBitmask());
|
||||
options.VerifierFlags = new ULONG(verifierFlags.getBitmask());
|
||||
ULONG ulOptionsBufferSize = new ULONG(options.size());
|
||||
WString cmdLine = new WString(commandLine);
|
||||
WString initDir = initialDirectory == null ? null : new WString(initialDirectory);
|
||||
WString env = environment == null ? null : new WString(environment);
|
||||
COMUtils.checkRC(jnaClient.CreateProcess2Wide(ullServer, cmdLine,
|
||||
options, ulOptionsBufferSize,
|
||||
initDir, env));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void attachKernel(long flags, String options) {
|
||||
ULONG connectFlags = new ULONG(flags);
|
||||
COMUtils.checkRC(jnaClient.AttachKernelWide(connectFlags, new WString(options)));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void startProcessServer(String options) {
|
||||
COMUtils.checkRC(jnaClient.StartProcessServerWide(
|
||||
new ULONG(DebugClass.USER_WINDOWS.ordinal()), new WString(options), null));
|
||||
}
|
||||
|
||||
@Override
|
||||
public DebugServerId connectProcessServer(String options) {
|
||||
ULONGLONGByReference pulServer = new ULONGLONGByReference();
|
||||
COMUtils.checkRC(jnaClient.ConnectProcessServerWide(new WString(options), pulServer));
|
||||
return new DebugServerId(pulServer.getValue().longValue());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setOutputCallbacks(DebugOutputCallbacks cb) {
|
||||
ListenerIDebugOutputCallbacksWide listener = null;
|
||||
if (cb != null) {
|
||||
WrapCallbackIDebugOutputCallbacksWide callback =
|
||||
new WrapCallbackIDebugOutputCallbacksWide(cb);
|
||||
listener = new ListenerIDebugOutputCallbacksWide(callback);
|
||||
callback.setListener(listener);
|
||||
}
|
||||
COMUtils.checkRC(jnaClient.SetOutputCallbacksWide(listener));
|
||||
listenerOutput = listener;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setEventCallbacks(DebugEventCallbacks cb) {
|
||||
ListenerIDebugEventCallbacksWide listener = null;
|
||||
if (cb != null) {
|
||||
WrapCallbackIDebugEventCallbacksWide callback =
|
||||
new WrapCallbackIDebugEventCallbacksWide(this, cb);
|
||||
listener = new ListenerIDebugEventCallbacksWide(callback);
|
||||
callback.setListener(listener);
|
||||
}
|
||||
COMUtils.checkRC(jnaClient.SetEventCallbacksWide(listener));
|
||||
listenerEvent = listener;
|
||||
}
|
||||
}
|
||||
@@ -1,35 +0,0 @@
|
||||
/* ###
|
||||
* 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 agent.dbgeng.impl.dbgeng.client;
|
||||
|
||||
import agent.dbgeng.dbgeng.DebugEventCallbacks;
|
||||
import agent.dbgeng.jna.dbgeng.client.IDebugClient6;
|
||||
|
||||
public class DebugClientImpl6 extends DebugClientImpl5 {
|
||||
@SuppressWarnings("unused")
|
||||
private final IDebugClient6 jnaClient;
|
||||
|
||||
public DebugClientImpl6(IDebugClient6 jnaClient) {
|
||||
super(jnaClient);
|
||||
this.jnaClient = jnaClient;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setEventCallbacks(DebugEventCallbacks cb) {
|
||||
// TODO: Use Context variant. Will require expanding the generic interface.
|
||||
super.setEventCallbacks(cb);
|
||||
}
|
||||
}
|
||||
@@ -1,28 +0,0 @@
|
||||
/* ###
|
||||
* 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 agent.dbgeng.impl.dbgeng.client;
|
||||
|
||||
import agent.dbgeng.jna.dbgeng.client.IDebugClient7;
|
||||
|
||||
public class DebugClientImpl7 extends DebugClientImpl6 {
|
||||
@SuppressWarnings("unused")
|
||||
private final IDebugClient7 jnaClient;
|
||||
|
||||
public DebugClientImpl7(IDebugClient7 jnaClient) {
|
||||
super(jnaClient);
|
||||
this.jnaClient = jnaClient;
|
||||
}
|
||||
}
|
||||
@@ -1,92 +0,0 @@
|
||||
/* ###
|
||||
* 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 agent.dbgeng.impl.dbgeng.client;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import com.sun.jna.Pointer;
|
||||
|
||||
import agent.dbgeng.dbgeng.DebugClient;
|
||||
import agent.dbgeng.impl.dbgeng.DbgEngUtil;
|
||||
import agent.dbgeng.impl.dbgeng.DbgEngUtil.InterfaceSupplier;
|
||||
import agent.dbgeng.impl.dbgeng.DbgEngUtil.Preferred;
|
||||
import agent.dbgeng.impl.dbgeng.control.DebugControlInternal;
|
||||
import agent.dbgeng.jna.dbgeng.client.*;
|
||||
import ghidra.util.datastruct.WeakValueHashMap;
|
||||
|
||||
public interface DebugClientInternal extends DebugClient {
|
||||
Map<Pointer, DebugClientInternal> CACHE = new WeakValueHashMap<>();
|
||||
|
||||
enum DebugClass {
|
||||
UNINITIALIZED, //
|
||||
KERNEL, //
|
||||
USER_WINDOWS, //
|
||||
IMAGE_FILE, //
|
||||
;
|
||||
}
|
||||
|
||||
static DebugClientInternal instanceFor(WrapIDebugClient client) {
|
||||
return DbgEngUtil.lazyWeakCache(CACHE, client, DebugClientImpl1::new);
|
||||
}
|
||||
|
||||
static DebugClientInternal instanceFor(WrapIDebugClient2 client) {
|
||||
return DbgEngUtil.lazyWeakCache(CACHE, client, DebugClientImpl2::new);
|
||||
}
|
||||
|
||||
static DebugClientInternal instanceFor(WrapIDebugClient3 client) {
|
||||
return DbgEngUtil.lazyWeakCache(CACHE, client, DebugClientImpl3::new);
|
||||
}
|
||||
|
||||
static DebugClientInternal instanceFor(WrapIDebugClient4 client) {
|
||||
return DbgEngUtil.lazyWeakCache(CACHE, client, DebugClientImpl4::new);
|
||||
}
|
||||
|
||||
static DebugClientInternal instanceFor(WrapIDebugClient5 client) {
|
||||
return DbgEngUtil.lazyWeakCache(CACHE, client, DebugClientImpl5::new);
|
||||
}
|
||||
|
||||
static DebugClientInternal instanceFor(WrapIDebugClient6 client) {
|
||||
return DbgEngUtil.lazyWeakCache(CACHE, client, DebugClientImpl6::new);
|
||||
}
|
||||
|
||||
static DebugClientInternal instanceFor(WrapIDebugClient7 client) {
|
||||
return DbgEngUtil.lazyWeakCache(CACHE, client, DebugClientImpl7::new);
|
||||
}
|
||||
|
||||
List<Preferred<WrapIDebugClient>> PREFERRED_CLIENT_IIDS = List.of(
|
||||
new Preferred<>(IDebugClient7.IID_IDEBUG_CLIENT7, WrapIDebugClient7.class),
|
||||
new Preferred<>(IDebugClient6.IID_IDEBUG_CLIENT6, WrapIDebugClient6.class),
|
||||
new Preferred<>(IDebugClient5.IID_IDEBUG_CLIENT5, WrapIDebugClient5.class),
|
||||
new Preferred<>(IDebugClient4.IID_IDEBUG_CLIENT4, WrapIDebugClient4.class),
|
||||
new Preferred<>(IDebugClient3.IID_IDEBUG_CLIENT3, WrapIDebugClient3.class),
|
||||
new Preferred<>(IDebugClient2.IID_IDEBUG_CLIENT2, WrapIDebugClient2.class),
|
||||
new Preferred<>(IDebugClient.IID_IDEBUG_CLIENT, WrapIDebugClient.class));
|
||||
|
||||
static DebugClientInternal tryPreferredInterfaces(InterfaceSupplier supplier) {
|
||||
return DbgEngUtil.tryPreferredInterfaces(DebugClientInternal.class, PREFERRED_CLIENT_IIDS,
|
||||
supplier);
|
||||
}
|
||||
|
||||
IDebugClient getJNAClient();
|
||||
|
||||
DebugControlInternal getControlInternal();
|
||||
|
||||
@Override
|
||||
default void endSessionReentrant() {
|
||||
endSession(DebugEndSessionFlags.DEBUG_END_REENTRANT);
|
||||
}
|
||||
}
|
||||
@@ -1,445 +0,0 @@
|
||||
/* ###
|
||||
* 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 agent.dbgeng.impl.dbgeng.control;
|
||||
|
||||
import javax.help.UnsupportedOperationException;
|
||||
|
||||
import com.sun.jna.Native;
|
||||
import com.sun.jna.platform.win32.WinDef.*;
|
||||
import com.sun.jna.platform.win32.WinError;
|
||||
import com.sun.jna.platform.win32.WinNT.HRESULT;
|
||||
import com.sun.jna.platform.win32.COM.COMUtils;
|
||||
import com.sun.jna.ptr.PointerByReference;
|
||||
|
||||
import agent.dbgeng.dbgeng.*;
|
||||
import agent.dbgeng.dbgeng.DbgEng.OpaqueCleanable;
|
||||
import agent.dbgeng.dbgeng.DebugBreakpoint.BreakType;
|
||||
import agent.dbgeng.dbgeng.DebugClient.DebugStatus;
|
||||
import agent.dbgeng.dbgeng.DebugValue.DebugValueType;
|
||||
import agent.dbgeng.impl.dbgeng.DbgEngUtil;
|
||||
import agent.dbgeng.impl.dbgeng.breakpoint.DebugBreakpointInternal;
|
||||
import agent.dbgeng.jna.dbgeng.DbgEngNative.*;
|
||||
import agent.dbgeng.jna.dbgeng.breakpoint.IDebugBreakpoint;
|
||||
import agent.dbgeng.jna.dbgeng.breakpoint.WrapIDebugBreakpoint;
|
||||
import agent.dbgeng.jna.dbgeng.control.IDebugControl;
|
||||
import ghidra.comm.util.BitmaskSet;
|
||||
|
||||
public class DebugControlImpl1 implements DebugControlInternal {
|
||||
@SuppressWarnings("unused")
|
||||
private final OpaqueCleanable cleanable;
|
||||
private final IDebugControl jnaControl;
|
||||
|
||||
public DebugControlImpl1(IDebugControl jnaControl) {
|
||||
this.cleanable = DbgEng.releaseWhenPhantom(this, jnaControl);
|
||||
this.jnaControl = jnaControl;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean getInterrupt() {
|
||||
HRESULT interrupt = jnaControl.GetInterrupt();
|
||||
if (interrupt.equals(WinError.S_OK)) {
|
||||
return true;
|
||||
}
|
||||
if (interrupt.equals(WinError.S_FALSE)) {
|
||||
return false;
|
||||
}
|
||||
COMUtils.checkRC(interrupt);
|
||||
throw new AssertionError("Shouldn't get here");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setInterrupt(DebugInterrupt interrupt) {
|
||||
ULONG flags = new ULONG(interrupt.ordinal());
|
||||
COMUtils.checkRC(jnaControl.SetInterrupt(flags));
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getInterruptTimeout() {
|
||||
ULONGByReference pulSeconds = new ULONGByReference();
|
||||
COMUtils.checkRC(jnaControl.GetInterruptTimeout(pulSeconds));
|
||||
return pulSeconds.getValue().intValue();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setInterruptTimeout(int seconds) {
|
||||
ULONG ulSeconds = new ULONG(seconds);
|
||||
COMUtils.checkRC(jnaControl.SetInterruptTimeout(ulSeconds));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void print(BitmaskSet<DebugOutputLevel> levels, String message) {
|
||||
ULONG mask = new ULONG(levels.getBitmask());
|
||||
COMUtils.checkRC(jnaControl.Output(mask, "%s", message));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void println(BitmaskSet<DebugOutputLevel> levels, String message) {
|
||||
ULONG mask = new ULONG(levels.getBitmask());
|
||||
COMUtils.checkRC(jnaControl.Output(mask, "%s", message + "\r\n"));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void prompt(BitmaskSet<DebugOutputControl> ctl, String message) {
|
||||
ULONG ctlMask = new ULONG(ctl.getBitmask());
|
||||
COMUtils.checkRC(jnaControl.OutputPrompt(ctlMask, "%s", message));
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getPromptText() {
|
||||
ULONGByReference pulTextSize = new ULONGByReference();
|
||||
COMUtils.checkRC(jnaControl.GetPromptText(null, new ULONG(0), pulTextSize));
|
||||
byte[] buffer = new byte[pulTextSize.getValue().intValue()];
|
||||
COMUtils.checkRC(jnaControl.GetPromptText(buffer, pulTextSize.getValue(), null));
|
||||
return Native.toString(buffer);
|
||||
}
|
||||
|
||||
protected DEBUG_VALUE doEval(DebugValueType type, String expression) {
|
||||
DEBUG_VALUE.ByReference value = new DEBUG_VALUE.ByReference();
|
||||
ULONGByReference pulRemainder = new ULONGByReference();
|
||||
COMUtils.checkRC(
|
||||
jnaControl.Evaluate(expression, new ULONG(type.ordinal()), value, pulRemainder));
|
||||
int remainder = pulRemainder.getValue().intValue();
|
||||
if (remainder != expression.length()) {
|
||||
throw new RuntimeException("Failed to parse: " + expression.substring(remainder));
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T extends DebugValue> T evaluate(Class<T> desiredType, String expression) {
|
||||
DebugValueType type = DebugValueType.getDebugValueTypeForClass(desiredType);
|
||||
return doEval(type, expression).convertTo(desiredType);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute(BitmaskSet<DebugOutputControl> ctl, String cmd,
|
||||
BitmaskSet<DebugExecute> flags) {
|
||||
ULONG ctlMask = new ULONG(ctl.getBitmask());
|
||||
ULONG flagMask = new ULONG(flags.getBitmask());
|
||||
HRESULT hr = jnaControl.Execute(ctlMask, cmd, flagMask);
|
||||
if (hr.equals(COMUtilsExtra.E_INTERNALEXCEPTION)) {
|
||||
return;
|
||||
}
|
||||
COMUtils.checkRC(hr);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void returnInput(String input) {
|
||||
COMUtils.checkRC(jnaControl.ReturnInput(input));
|
||||
}
|
||||
|
||||
@Override
|
||||
public DebugStatus getExecutionStatus() {
|
||||
ULONGByReference pulStatus = new ULONGByReference();
|
||||
COMUtils.checkRC(jnaControl.GetExecutionStatus(pulStatus));
|
||||
return DebugStatus.values()[pulStatus.getValue().intValue()];
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setExecutionStatus(DebugStatus status) {
|
||||
ULONG ulStatus = new ULONG(status.ordinal());
|
||||
HRESULT hr = jnaControl.SetExecutionStatus(ulStatus);
|
||||
if (!hr.equals(COMUtilsExtra.E_ACCESS_DENIED)) {
|
||||
COMUtils.checkRC(hr);
|
||||
}
|
||||
}
|
||||
|
||||
public DebugBreakpoint doAddBreakpoint(BreakType type, ULONG ulDesiredId) {
|
||||
ULONG ulType = new ULONG(type.ordinal());
|
||||
PointerByReference ppBp = new PointerByReference();
|
||||
COMUtils.checkRC(jnaControl.AddBreakpoint(ulType, ulDesiredId, ppBp));
|
||||
IDebugBreakpoint Bp = new WrapIDebugBreakpoint(ppBp.getValue());
|
||||
DebugBreakpoint bpt =
|
||||
DebugBreakpointInternal.tryPreferredInterfaces(this, Bp::QueryInterface);
|
||||
// AddRef or no? Probably not.
|
||||
return bpt;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getNumberBreakpoints() {
|
||||
ULONGByReference ulNumber = new ULONGByReference();
|
||||
COMUtils.checkRC(jnaControl.GetNumberBreakpoints(ulNumber));
|
||||
return ulNumber.getValue().intValue();
|
||||
}
|
||||
|
||||
@Override
|
||||
public DebugBreakpoint getBreakpointByIndex(int index) {
|
||||
ULONG ulIndex = new ULONG(index);
|
||||
PointerByReference ppBp = new PointerByReference();
|
||||
COMUtils.checkRC(jnaControl.GetBreakpointByIndex(ulIndex, ppBp));
|
||||
IDebugBreakpoint Bp = new WrapIDebugBreakpoint(ppBp.getValue());
|
||||
DebugBreakpoint bpt =
|
||||
DebugBreakpointInternal.tryPreferredInterfaces(this, Bp::QueryInterface);
|
||||
// NOTE: Do not AddRef. dbgeng manages lifecycle
|
||||
return bpt;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DebugBreakpoint getBreakpointById(int id) {
|
||||
ULONG ulId = new ULONG(id);
|
||||
PointerByReference ppBp = new PointerByReference();
|
||||
HRESULT hr = jnaControl.GetBreakpointById(ulId, ppBp);
|
||||
if (hr.equals(COMUtilsExtra.E_NOINTERFACE)) {
|
||||
return null;
|
||||
}
|
||||
if (hr.equals(COMUtilsExtra.E_UNEXPECTED)) {
|
||||
return null;
|
||||
}
|
||||
COMUtils.checkRC(hr);
|
||||
IDebugBreakpoint Bp = new WrapIDebugBreakpoint(ppBp.getValue());
|
||||
DebugBreakpoint bpt =
|
||||
DebugBreakpointInternal.tryPreferredInterfaces(this, Bp::QueryInterface);
|
||||
// NOTE: Do not AddRef. dbgeng manages lifecycle
|
||||
return bpt;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DebugBreakpoint addBreakpoint(BreakType type, int desiredId) {
|
||||
return doAddBreakpoint(type, new ULONG(desiredId));
|
||||
}
|
||||
|
||||
@Override
|
||||
public DebugBreakpoint addBreakpoint(BreakType type) {
|
||||
return doAddBreakpoint(type, DbgEngUtil.DEBUG_ANY_ID);
|
||||
}
|
||||
|
||||
@Override
|
||||
public DebugBreakpoint addBreakpoint2(BreakType type) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public DebugBreakpoint addBreakpoint2(BreakType type, int desiredId) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeBreakpoint(IDebugBreakpoint comBpt) {
|
||||
COMUtils.checkRC(jnaControl.RemoveBreakpoint(comBpt));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void waitForEvent(int timeout) {
|
||||
COMUtils.checkRC(jnaControl.WaitForEvent(new ULONG(0), new ULONG(timeout)));
|
||||
}
|
||||
|
||||
@Override
|
||||
public DebugEventInformation getLastEventInformation() {
|
||||
ULONGByReference pulType = new ULONGByReference();
|
||||
ULONGByReference pulProcessId = new ULONGByReference();
|
||||
ULONGByReference pulThreadId = new ULONGByReference();
|
||||
//PointerByReference pExtraInformation = new PointerByReference();
|
||||
ULONG ulExtraInformationSize = new ULONG(0);
|
||||
ULONGByReference pulExtraInformationUsed = new ULONGByReference();
|
||||
//byte[] pstrDescription = new byte[0];
|
||||
ULONG ulDescriptionSize = new ULONG(0);
|
||||
ULONGByReference pulDescriptionUsed = new ULONGByReference();
|
||||
COMUtils.checkRC(jnaControl.GetLastEventInformation(pulType, pulProcessId, pulThreadId,
|
||||
null, ulExtraInformationSize, pulExtraInformationUsed, null, ulDescriptionSize,
|
||||
pulDescriptionUsed));
|
||||
return new DebugEventInformation(pulType.getValue().intValue(),
|
||||
pulProcessId.getValue().intValue(), pulThreadId.getValue().intValue());
|
||||
}
|
||||
|
||||
@Override
|
||||
public DebugStackInformation getStackTrace(long frameOffset, long stackOffset,
|
||||
long instructionOffset) {
|
||||
ULONGLONG ullFrameOffset = new ULONGLONG(frameOffset);
|
||||
ULONGLONG ullStackOffset = new ULONGLONG(stackOffset);
|
||||
ULONGLONG ullInstructionOffset = new ULONGLONG(instructionOffset);
|
||||
ULONG ulFrameSize = new ULONG(100);
|
||||
DEBUG_STACK_FRAME[] pParams = new DEBUG_STACK_FRAME[ulFrameSize.intValue()];
|
||||
ULONGByReference pulFramesFilled = new ULONGByReference();
|
||||
COMUtils.checkRC(jnaControl.GetStackTrace(ullFrameOffset, ullStackOffset,
|
||||
ullInstructionOffset, pParams, ulFrameSize, pulFramesFilled));
|
||||
return new DebugStackInformation(pulFramesFilled.getValue().intValue(), pParams);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getActualProcessorType() {
|
||||
ULONGByReference ulType = new ULONGByReference();
|
||||
HRESULT hr = jnaControl.GetActualProcessorType(ulType);
|
||||
if (hr.equals(COMUtilsExtra.E_UNEXPECTED)) {
|
||||
return -1;
|
||||
}
|
||||
COMUtils.checkRC(hr);
|
||||
return ulType.getValue().intValue();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getEffectiveProcessorType() {
|
||||
ULONGByReference ulType = new ULONGByReference();
|
||||
COMUtils.checkRC(jnaControl.GetEffectiveProcessorType(ulType));
|
||||
return ulType.getValue().intValue();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getExecutingProcessorType() {
|
||||
ULONGByReference ulType = new ULONGByReference();
|
||||
COMUtils.checkRC(jnaControl.GetExecutingProcessorType(ulType));
|
||||
return ulType.getValue().intValue();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getDebuggeeType() {
|
||||
ULONGByReference ulClass = new ULONGByReference();
|
||||
ULONGByReference ulQualifier = new ULONGByReference();
|
||||
COMUtils.checkRC(jnaControl.GetDebuggeeType(ulClass, ulQualifier));
|
||||
return ulClass.getValue().intValue();
|
||||
}
|
||||
|
||||
@Override
|
||||
public DebugFilterInformation getNumberEventFilters() {
|
||||
ULONGByReference ulSpecificEvents = new ULONGByReference();
|
||||
ULONGByReference ulSpecificExceptions = new ULONGByReference();
|
||||
ULONGByReference ulArbitraryExceptions = new ULONGByReference();
|
||||
COMUtils.checkRC(jnaControl.GetNumberEventFilters(ulSpecificEvents, ulSpecificExceptions,
|
||||
ulArbitraryExceptions));
|
||||
return new DebugFilterInformation(
|
||||
ulSpecificEvents.getValue().intValue(),
|
||||
ulSpecificExceptions.getValue().intValue(),
|
||||
ulArbitraryExceptions.getValue().intValue());
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getEventFilterText(int index, int size) {
|
||||
ULONG ulIndex = new ULONG(index);
|
||||
ULONG ulBufferSize = new ULONG(size);
|
||||
ULONGByReference ulTextSize = new ULONGByReference();
|
||||
if (size == 0) {
|
||||
COMUtils.checkRC(
|
||||
jnaControl.GetEventFilterText(ulIndex, null, new ULONG(0), ulTextSize));
|
||||
ulBufferSize = ulTextSize.getValue();
|
||||
}
|
||||
byte[] buffer = new byte[ulBufferSize.intValue()];
|
||||
COMUtils.checkRC(jnaControl.GetEventFilterText(ulIndex, buffer, ulBufferSize, null));
|
||||
return Native.toString(buffer);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getEventFilterCommand(int index, int size) {
|
||||
ULONG ulIndex = new ULONG(index);
|
||||
ULONG ulBufferSize = new ULONG(size);
|
||||
ULONGByReference ulCommandSize = new ULONGByReference();
|
||||
if (size == 0) {
|
||||
COMUtils.checkRC(
|
||||
jnaControl.GetEventFilterCommand(ulIndex, null, new ULONG(0), ulCommandSize));
|
||||
ulBufferSize = ulCommandSize.getValue();
|
||||
}
|
||||
byte[] buffer = new byte[ulBufferSize.intValue()];
|
||||
COMUtils.checkRC(jnaControl.GetEventFilterCommand(ulIndex, buffer, ulBufferSize, null));
|
||||
return Native.toString(buffer);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setEventFilterCommand(int index, String text) {
|
||||
ULONG ulIndex = new ULONG(index);
|
||||
COMUtils.checkRC(jnaControl.SetEventFilterCommand(ulIndex, text));
|
||||
}
|
||||
|
||||
@Override
|
||||
public DebugSpecificFilterInformation getSpecificFilterParameters(int start, int count) {
|
||||
ULONG ulStart = new ULONG(start);
|
||||
ULONG ulCount = new ULONG(count);
|
||||
DEBUG_SPECIFIC_FILTER_PARAMETERS[] pParams = new DEBUG_SPECIFIC_FILTER_PARAMETERS[count];
|
||||
COMUtils.checkRC(jnaControl.GetSpecificFilterParameters(ulStart, ulCount, pParams));
|
||||
return new DebugSpecificFilterInformation(count, pParams);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setSpecificFilterParameters(int start, int count,
|
||||
DebugSpecificFilterInformation info) {
|
||||
ULONG ulStart = new ULONG(start);
|
||||
ULONG ulCount = new ULONG(count);
|
||||
COMUtils.checkRC(
|
||||
jnaControl.SetSpecificFilterParameters(ulStart, ulCount, info.getParameters()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getSpecificFilterArgument(int index, int size) {
|
||||
ULONG ulIndex = new ULONG(index);
|
||||
ULONG ulBufferSize = new ULONG(size);
|
||||
ULONGByReference ulArgumentSize = new ULONGByReference();
|
||||
if (size == 0) {
|
||||
HRESULT hr =
|
||||
jnaControl.GetSpecificFilterArgument(ulIndex, null, ulBufferSize, ulArgumentSize);
|
||||
if (hr.equals(COMUtilsExtra.E_INVALID_PARAM)) {
|
||||
return null;
|
||||
}
|
||||
COMUtils.checkRC(hr);
|
||||
ulBufferSize = ulArgumentSize.getValue();
|
||||
}
|
||||
byte[] buffer = new byte[ulBufferSize.intValue()];
|
||||
COMUtils.checkRC(
|
||||
jnaControl.GetSpecificFilterArgument(ulIndex, buffer, ulBufferSize, null));
|
||||
return Native.toString(buffer);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setSpecificFilterArgument(int index, String arg) {
|
||||
if (arg != null) {
|
||||
ULONG ulIndex = new ULONG(index);
|
||||
COMUtils.checkRC(jnaControl.SetSpecificFilterArgument(ulIndex, arg));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public DebugExceptionFilterInformation getExceptionFilterParameters(int start, int[] codes,
|
||||
int count) {
|
||||
ULONG ulStart = new ULONG(start);
|
||||
//ULONG[] ulCodes = new ULONG[codes.length];
|
||||
//for (int i = 0; i < codes.length; i++) {
|
||||
// ulCodes[i] = new ULONG(codes[i]);
|
||||
//}
|
||||
ULONG ulCount = new ULONG(count);
|
||||
DEBUG_EXCEPTION_FILTER_PARAMETERS[] pParams = new DEBUG_EXCEPTION_FILTER_PARAMETERS[count];
|
||||
COMUtils.checkRC(
|
||||
jnaControl.GetExceptionFilterParameters(ulCount, null, ulStart, pParams));
|
||||
return new DebugExceptionFilterInformation(count, pParams);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setExceptionFilterParameters(int count,
|
||||
DebugExceptionFilterInformation info) {
|
||||
ULONG ulCount = new ULONG(count);
|
||||
COMUtils.checkRC(
|
||||
jnaControl.SetExceptionFilterParameters(ulCount, info.getParameters()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getExceptionFilterSecondCommand(int index, int size) {
|
||||
ULONG ulIndex = new ULONG(index);
|
||||
ULONG ulBufferSize = new ULONG(size);
|
||||
ULONGByReference ulCommandSize = new ULONGByReference();
|
||||
if (size == 0) {
|
||||
COMUtils.checkRC(
|
||||
jnaControl.GetExceptionFilterSecondCommand(ulIndex, null, ulBufferSize,
|
||||
ulCommandSize));
|
||||
ulBufferSize = ulCommandSize.getValue();
|
||||
}
|
||||
byte[] buffer = new byte[ulBufferSize.intValue()];
|
||||
COMUtils.checkRC(
|
||||
jnaControl.GetExceptionFilterSecondCommand(ulIndex, buffer, ulBufferSize, null));
|
||||
return Native.toString(buffer);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setExceptionFilterSecondCommand(int index, String cmd) {
|
||||
ULONG ulIndex = new ULONG(index);
|
||||
COMUtils.checkRC(jnaControl.SetExceptionFilterSecondCommand(ulIndex, cmd));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,28 +0,0 @@
|
||||
/* ###
|
||||
* 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 agent.dbgeng.impl.dbgeng.control;
|
||||
|
||||
import agent.dbgeng.jna.dbgeng.control.IDebugControl2;
|
||||
|
||||
public class DebugControlImpl2 extends DebugControlImpl1 {
|
||||
@SuppressWarnings("unused")
|
||||
private final IDebugControl2 jnaControl;
|
||||
|
||||
public DebugControlImpl2(IDebugControl2 jnaControl) {
|
||||
super(jnaControl);
|
||||
this.jnaControl = jnaControl;
|
||||
}
|
||||
}
|
||||
@@ -1,28 +0,0 @@
|
||||
/* ###
|
||||
* 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 agent.dbgeng.impl.dbgeng.control;
|
||||
|
||||
import agent.dbgeng.jna.dbgeng.control.IDebugControl3;
|
||||
|
||||
public class DebugControlImpl3 extends DebugControlImpl2 {
|
||||
@SuppressWarnings("unused")
|
||||
private final IDebugControl3 jnaControl;
|
||||
|
||||
public DebugControlImpl3(IDebugControl3 jnaControl) {
|
||||
super(jnaControl);
|
||||
this.jnaControl = jnaControl;
|
||||
}
|
||||
}
|
||||
@@ -1,128 +0,0 @@
|
||||
/* ###
|
||||
* 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 agent.dbgeng.impl.dbgeng.control;
|
||||
|
||||
import com.sun.jna.Native;
|
||||
import com.sun.jna.WString;
|
||||
import com.sun.jna.platform.win32.WinDef.ULONG;
|
||||
import com.sun.jna.platform.win32.WinDef.ULONGByReference;
|
||||
import com.sun.jna.platform.win32.WinNT.HRESULT;
|
||||
import com.sun.jna.platform.win32.COM.COMUtils;
|
||||
import com.sun.jna.ptr.PointerByReference;
|
||||
|
||||
import agent.dbgeng.dbgeng.COMUtilsExtra;
|
||||
import agent.dbgeng.dbgeng.DebugBreakpoint;
|
||||
import agent.dbgeng.dbgeng.DebugBreakpoint.BreakType;
|
||||
import agent.dbgeng.dbgeng.DebugValue.DebugValueType;
|
||||
import agent.dbgeng.impl.dbgeng.DbgEngUtil;
|
||||
import agent.dbgeng.impl.dbgeng.breakpoint.DebugBreakpointInternal;
|
||||
import agent.dbgeng.jna.dbgeng.DbgEngNative.DEBUG_VALUE;
|
||||
import agent.dbgeng.jna.dbgeng.breakpoint.IDebugBreakpoint;
|
||||
import agent.dbgeng.jna.dbgeng.breakpoint.WrapIDebugBreakpoint;
|
||||
import agent.dbgeng.jna.dbgeng.control.IDebugControl4;
|
||||
import ghidra.comm.util.BitmaskSet;
|
||||
|
||||
public class DebugControlImpl4 extends DebugControlImpl3 {
|
||||
private final IDebugControl4 jnaControl;
|
||||
|
||||
public DebugControlImpl4(IDebugControl4 jnaControl) {
|
||||
super(jnaControl);
|
||||
this.jnaControl = jnaControl;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void print(BitmaskSet<DebugOutputLevel> levels, String message) {
|
||||
ULONG mask = new ULONG(levels.getBitmask());
|
||||
COMUtils.checkRC(jnaControl.OutputWide(mask, new WString("%s"), new WString(message)));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void println(BitmaskSet<DebugOutputLevel> levels, String message) {
|
||||
ULONG mask = new ULONG(levels.getBitmask());
|
||||
COMUtils
|
||||
.checkRC(
|
||||
jnaControl.OutputWide(mask, new WString("%s"), new WString(message + "\r\n")));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void prompt(BitmaskSet<DebugOutputControl> ctl, String message) {
|
||||
ULONG ctlMask = new ULONG(ctl.getBitmask());
|
||||
COMUtils
|
||||
.checkRC(
|
||||
jnaControl.OutputPromptWide(ctlMask, new WString("%s"), new WString(message)));
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getPromptText() {
|
||||
ULONGByReference pulTextSize = new ULONGByReference();
|
||||
COMUtils.checkRC(jnaControl.GetPromptTextWide(null, new ULONG(0), pulTextSize));
|
||||
char[] buffer = new char[pulTextSize.getValue().intValue()];
|
||||
COMUtils.checkRC(jnaControl.GetPromptTextWide(buffer, pulTextSize.getValue(), null));
|
||||
return Native.toString(buffer);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected DEBUG_VALUE doEval(DebugValueType type, String expression) {
|
||||
DEBUG_VALUE.ByReference value = new DEBUG_VALUE.ByReference();
|
||||
ULONGByReference pulRemainder = new ULONGByReference();
|
||||
COMUtils.checkRC(jnaControl.EvaluateWide(new WString(expression), new ULONG(type.ordinal()),
|
||||
value, pulRemainder));
|
||||
int remainder = pulRemainder.getValue().intValue();
|
||||
if (remainder != expression.length()) {
|
||||
throw new RuntimeException("Failed to parse: " + expression.substring(remainder));
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute(BitmaskSet<DebugOutputControl> ctl, String cmd,
|
||||
BitmaskSet<DebugExecute> flags) {
|
||||
ULONG ctlMask = new ULONG(ctl.getBitmask());
|
||||
ULONG flagMask = new ULONG(flags.getBitmask());
|
||||
HRESULT hr = jnaControl.ExecuteWide(ctlMask, new WString(cmd), flagMask);
|
||||
if (hr.equals(COMUtilsExtra.E_INTERNALEXCEPTION)) {
|
||||
return;
|
||||
}
|
||||
COMUtils.checkRC(hr);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void returnInput(String input) {
|
||||
COMUtils.checkRC(jnaControl.ReturnInputWide(new WString(input)));
|
||||
}
|
||||
|
||||
public DebugBreakpoint doAddBreakpoint2(BreakType type, ULONG ulDesiredId) {
|
||||
ULONG ulType = new ULONG(type.ordinal());
|
||||
PointerByReference ppBp = new PointerByReference();
|
||||
COMUtils.checkRC(jnaControl.AddBreakpoint2(ulType, ulDesiredId, ppBp));
|
||||
IDebugBreakpoint Bp = new WrapIDebugBreakpoint(ppBp.getValue());
|
||||
DebugBreakpoint bpt =
|
||||
DebugBreakpointInternal.tryPreferredInterfaces(this, Bp::QueryInterface);
|
||||
// AddRef or no? Probably not.
|
||||
return bpt;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DebugBreakpoint addBreakpoint2(BreakType type, int desiredId) {
|
||||
return doAddBreakpoint2(type, new ULONG(desiredId));
|
||||
}
|
||||
|
||||
@Override
|
||||
public DebugBreakpoint addBreakpoint2(BreakType type) {
|
||||
return doAddBreakpoint2(type, DbgEngUtil.DEBUG_ANY_ID);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,28 +0,0 @@
|
||||
/* ###
|
||||
* 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 agent.dbgeng.impl.dbgeng.control;
|
||||
|
||||
import agent.dbgeng.jna.dbgeng.control.IDebugControl5;
|
||||
|
||||
public class DebugControlImpl5 extends DebugControlImpl4 {
|
||||
@SuppressWarnings("unused")
|
||||
private final IDebugControl5 jnaControl;
|
||||
|
||||
public DebugControlImpl5(IDebugControl5 jnaControl) {
|
||||
super(jnaControl);
|
||||
this.jnaControl = jnaControl;
|
||||
}
|
||||
}
|
||||
@@ -1,28 +0,0 @@
|
||||
/* ###
|
||||
* 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 agent.dbgeng.impl.dbgeng.control;
|
||||
|
||||
import agent.dbgeng.jna.dbgeng.control.IDebugControl6;
|
||||
|
||||
public class DebugControlImpl6 extends DebugControlImpl5 {
|
||||
@SuppressWarnings("unused")
|
||||
private final IDebugControl6 jnaControl;
|
||||
|
||||
public DebugControlImpl6(IDebugControl6 jnaControl) {
|
||||
super(jnaControl);
|
||||
this.jnaControl = jnaControl;
|
||||
}
|
||||
}
|
||||
@@ -1,28 +0,0 @@
|
||||
/* ###
|
||||
* 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 agent.dbgeng.impl.dbgeng.control;
|
||||
|
||||
import agent.dbgeng.jna.dbgeng.control.IDebugControl7;
|
||||
|
||||
public class DebugControlImpl7 extends DebugControlImpl6 {
|
||||
@SuppressWarnings("unused")
|
||||
private final IDebugControl7 jnaControl;
|
||||
|
||||
public DebugControlImpl7(IDebugControl7 jnaControl) {
|
||||
super(jnaControl);
|
||||
this.jnaControl = jnaControl;
|
||||
}
|
||||
}
|
||||
@@ -1,77 +0,0 @@
|
||||
/* ###
|
||||
* 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 agent.dbgeng.impl.dbgeng.control;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import com.sun.jna.Pointer;
|
||||
|
||||
import agent.dbgeng.dbgeng.DebugControl;
|
||||
import agent.dbgeng.impl.dbgeng.DbgEngUtil;
|
||||
import agent.dbgeng.impl.dbgeng.DbgEngUtil.InterfaceSupplier;
|
||||
import agent.dbgeng.impl.dbgeng.DbgEngUtil.Preferred;
|
||||
import agent.dbgeng.jna.dbgeng.breakpoint.IDebugBreakpoint;
|
||||
import agent.dbgeng.jna.dbgeng.control.*;
|
||||
import ghidra.util.datastruct.WeakValueHashMap;
|
||||
|
||||
public interface DebugControlInternal extends DebugControl {
|
||||
Map<Pointer, DebugControlInternal> CACHE = new WeakValueHashMap<>();
|
||||
|
||||
static DebugControlInternal instanceFor(WrapIDebugControl control) {
|
||||
return DbgEngUtil.lazyWeakCache(CACHE, control, DebugControlImpl1::new);
|
||||
}
|
||||
|
||||
static DebugControlInternal instanceFor(WrapIDebugControl2 control) {
|
||||
return DbgEngUtil.lazyWeakCache(CACHE, control, DebugControlImpl2::new);
|
||||
}
|
||||
|
||||
static DebugControlInternal instanceFor(WrapIDebugControl3 control) {
|
||||
return DbgEngUtil.lazyWeakCache(CACHE, control, DebugControlImpl3::new);
|
||||
}
|
||||
|
||||
static DebugControlInternal instanceFor(WrapIDebugControl4 control) {
|
||||
return DbgEngUtil.lazyWeakCache(CACHE, control, DebugControlImpl4::new);
|
||||
}
|
||||
|
||||
static DebugControlInternal instanceFor(WrapIDebugControl5 control) {
|
||||
return DbgEngUtil.lazyWeakCache(CACHE, control, DebugControlImpl5::new);
|
||||
}
|
||||
|
||||
static DebugControlInternal instanceFor(WrapIDebugControl6 control) {
|
||||
return DbgEngUtil.lazyWeakCache(CACHE, control, DebugControlImpl6::new);
|
||||
}
|
||||
|
||||
static DebugControlInternal instanceFor(WrapIDebugControl7 control) {
|
||||
return DbgEngUtil.lazyWeakCache(CACHE, control, DebugControlImpl7::new);
|
||||
}
|
||||
|
||||
List<Preferred<WrapIDebugControl>> PREFERRED_CONTROL_IIDS = List.of(
|
||||
new Preferred<>(IDebugControl7.IID_IDEBUG_CONTROL7, WrapIDebugControl7.class),
|
||||
new Preferred<>(IDebugControl6.IID_IDEBUG_CONTROL6, WrapIDebugControl6.class),
|
||||
new Preferred<>(IDebugControl5.IID_IDEBUG_CONTROL5, WrapIDebugControl5.class),
|
||||
new Preferred<>(IDebugControl4.IID_IDEBUG_CONTROL4, WrapIDebugControl4.class),
|
||||
new Preferred<>(IDebugControl3.IID_IDEBUG_CONTROL3, WrapIDebugControl3.class),
|
||||
new Preferred<>(IDebugControl2.IID_IDEBUG_CONTROL2, WrapIDebugControl2.class),
|
||||
new Preferred<>(IDebugControl.IID_IDEBUG_CONTROL, WrapIDebugControl.class));
|
||||
|
||||
static DebugControlInternal tryPreferredInterfaces(InterfaceSupplier supplier) {
|
||||
return DbgEngUtil.tryPreferredInterfaces(DebugControlInternal.class, PREFERRED_CONTROL_IIDS,
|
||||
supplier);
|
||||
}
|
||||
|
||||
void removeBreakpoint(IDebugBreakpoint comBpt);
|
||||
}
|
||||
@@ -1,276 +0,0 @@
|
||||
/* ###
|
||||
* 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 agent.dbgeng.impl.dbgeng.dataspaces;
|
||||
|
||||
import java.nio.BufferOverflowException;
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
import javax.help.UnsupportedOperationException;
|
||||
|
||||
import com.sun.jna.platform.win32.WinDef.*;
|
||||
import com.sun.jna.platform.win32.WinNT.HRESULT;
|
||||
import com.sun.jna.platform.win32.COM.COMUtils;
|
||||
|
||||
import agent.dbgeng.dbgeng.COMUtilsExtra;
|
||||
import agent.dbgeng.dbgeng.DbgEng;
|
||||
import agent.dbgeng.dbgeng.DbgEng.OpaqueCleanable;
|
||||
import agent.dbgeng.jna.dbgeng.dataspaces.IDebugDataSpaces;
|
||||
|
||||
public class DebugDataSpacesImpl1 implements DebugDataSpacesInternal {
|
||||
@SuppressWarnings("unused")
|
||||
private final OpaqueCleanable cleanble;
|
||||
private final IDebugDataSpaces jnaData;
|
||||
|
||||
public DebugDataSpacesImpl1(IDebugDataSpaces jnaData) {
|
||||
this.cleanble = DbgEng.releaseWhenPhantom(this, jnaData);
|
||||
this.jnaData = jnaData;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DebugMemoryBasicInformation queryVirtual(long offset) {
|
||||
throw new UnsupportedOperationException("Not implemented in this interface");
|
||||
}
|
||||
|
||||
@Override
|
||||
public int readVirtual(long offset, ByteBuffer into, int len) {
|
||||
if (len > into.remaining()) {
|
||||
throw new BufferOverflowException();
|
||||
}
|
||||
ULONGLONG ullOffset = new ULONGLONG(offset);
|
||||
ULONG ulLen = new ULONG(len);
|
||||
ULONGByReference pulBytesRead = new ULONGByReference();
|
||||
HRESULT hr = jnaData.ReadVirtual(ullOffset, into, ulLen, pulBytesRead);
|
||||
if (hr.equals(COMUtilsExtra.E_CANNOT_READ)) {
|
||||
return 0;
|
||||
}
|
||||
COMUtils.checkRC(hr);
|
||||
int read = pulBytesRead.getValue().intValue();
|
||||
into.position(read + into.position());
|
||||
return read;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int writeVirtual(long offset, ByteBuffer from, int len) {
|
||||
if (len > from.remaining()) {
|
||||
throw new BufferOverflowException();
|
||||
}
|
||||
ULONGLONG ullOffset = new ULONGLONG(offset);
|
||||
ULONG ulLen = new ULONG(len);
|
||||
ULONGByReference pulBytesWritten = new ULONGByReference();
|
||||
COMUtils.checkRC(jnaData.WriteVirtual(ullOffset, from, ulLen, pulBytesWritten));
|
||||
int written = pulBytesWritten.getValue().intValue();
|
||||
from.position(written + from.position());
|
||||
return written;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int readVirtualUncached(long offset, ByteBuffer into, int len) {
|
||||
if (len > into.remaining()) {
|
||||
throw new BufferOverflowException();
|
||||
}
|
||||
ULONGLONG ullOffset = new ULONGLONG(offset);
|
||||
ULONG ulLen = new ULONG(len);
|
||||
ULONGByReference pulBytesRead = new ULONGByReference();
|
||||
COMUtils.checkRC(jnaData.ReadVirtualUncached(ullOffset, into, ulLen, pulBytesRead));
|
||||
int read = pulBytesRead.getValue().intValue();
|
||||
into.position(read + into.position());
|
||||
return read;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int writeVirtualUncached(long offset, ByteBuffer from, int len) {
|
||||
if (len > from.remaining()) {
|
||||
throw new BufferOverflowException();
|
||||
}
|
||||
ULONGLONG ullOffset = new ULONGLONG(offset);
|
||||
ULONG ulLen = new ULONG(len);
|
||||
ULONGByReference pulBytesWritten = new ULONGByReference();
|
||||
COMUtils.checkRC(jnaData.WriteVirtualUncached(ullOffset, from, ulLen, pulBytesWritten));
|
||||
int written = pulBytesWritten.getValue().intValue();
|
||||
from.position(written + from.position());
|
||||
return written;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int readPhysical(long offset, ByteBuffer into, int len) {
|
||||
if (len > into.remaining()) {
|
||||
throw new BufferOverflowException();
|
||||
}
|
||||
ULONGLONG ullOffset = new ULONGLONG(offset);
|
||||
ULONG ulLen = new ULONG(len);
|
||||
ULONGByReference pulBytesRead = new ULONGByReference();
|
||||
COMUtils.checkRC(jnaData.ReadPhysical(ullOffset, into, ulLen, pulBytesRead));
|
||||
int read = pulBytesRead.getValue().intValue();
|
||||
into.position(read + into.position());
|
||||
return read;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int writePhysical(long offset, ByteBuffer from, int len) {
|
||||
if (len > from.remaining()) {
|
||||
throw new BufferOverflowException();
|
||||
}
|
||||
ULONGLONG ullOffset = new ULONGLONG(offset);
|
||||
ULONG ulLen = new ULONG(len);
|
||||
ULONGByReference pulBytesWritten = new ULONGByReference();
|
||||
COMUtils.checkRC(jnaData.WritePhysical(ullOffset, from, ulLen, pulBytesWritten));
|
||||
int written = pulBytesWritten.getValue().intValue();
|
||||
from.position(written + from.position());
|
||||
return written;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int readControl(int processor, long offset, ByteBuffer into, int len) {
|
||||
if (len > into.remaining()) {
|
||||
throw new BufferOverflowException();
|
||||
}
|
||||
ULONG ulProcessor = new ULONG(processor);
|
||||
ULONGLONG ullOffset = new ULONGLONG(offset);
|
||||
ULONG ulLen = new ULONG(len);
|
||||
ULONGByReference pulBytesRead = new ULONGByReference();
|
||||
COMUtils.checkRC(jnaData.ReadControl(ulProcessor, ullOffset, into, ulLen, pulBytesRead));
|
||||
int read = pulBytesRead.getValue().intValue();
|
||||
into.position(read + into.position());
|
||||
return read;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int writeControl(int processor, long offset, ByteBuffer from, int len) {
|
||||
if (len > from.remaining()) {
|
||||
throw new BufferOverflowException();
|
||||
}
|
||||
ULONG ulProcessor = new ULONG(processor);
|
||||
ULONGLONG ullOffset = new ULONGLONG(offset);
|
||||
ULONG ulLen = new ULONG(len);
|
||||
ULONGByReference pulBytesWritten = new ULONGByReference();
|
||||
COMUtils.checkRC(
|
||||
jnaData.WriteControl(ulProcessor, ullOffset, from, ulLen, pulBytesWritten));
|
||||
int written = pulBytesWritten.getValue().intValue();
|
||||
from.position(written + from.position());
|
||||
return written;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int readBusData(int busDataType, int busNumber, int slotNumber, long offset,
|
||||
ByteBuffer into, int len) {
|
||||
if (len > into.remaining()) {
|
||||
throw new BufferOverflowException();
|
||||
}
|
||||
ULONG ulBusDataType = new ULONG(busDataType);
|
||||
ULONG ulBusNumber = new ULONG(busNumber);
|
||||
ULONG ulSlotNumber = new ULONG(slotNumber);
|
||||
ULONGLONG ullOffset = new ULONGLONG(offset);
|
||||
ULONG ulLen = new ULONG(len);
|
||||
ULONGByReference pulBytesRead = new ULONGByReference();
|
||||
COMUtils.checkRC(jnaData.ReadBusData(ulBusDataType, ulBusNumber, ulSlotNumber, ullOffset,
|
||||
into, ulLen, pulBytesRead));
|
||||
int read = pulBytesRead.getValue().intValue();
|
||||
into.position(read + into.position());
|
||||
return read;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int writeBusData(int busDataType, int busNumber, int slotNumber, long offset,
|
||||
ByteBuffer from, int len) {
|
||||
if (len > from.remaining()) {
|
||||
throw new BufferOverflowException();
|
||||
}
|
||||
ULONG ulBusDataType = new ULONG(busDataType);
|
||||
ULONG ulBusNumber = new ULONG(busNumber);
|
||||
ULONG ulSlotNumber = new ULONG(slotNumber);
|
||||
ULONGLONG ullOffset = new ULONGLONG(offset);
|
||||
ULONG ulLen = new ULONG(len);
|
||||
ULONGByReference pulBytesWritten = new ULONGByReference();
|
||||
COMUtils.checkRC(jnaData.WriteBusData(ulBusDataType, ulBusNumber, ulSlotNumber, ullOffset,
|
||||
from, ulLen, pulBytesWritten));
|
||||
int written = pulBytesWritten.getValue().intValue();
|
||||
from.position(written + from.position());
|
||||
return written;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int readIo(int interfaceType, int busNumber, int addressSpace, long offset,
|
||||
ByteBuffer into, int len) {
|
||||
if (len > into.remaining()) {
|
||||
throw new BufferOverflowException();
|
||||
}
|
||||
ULONG ulInterfaceType = new ULONG(interfaceType);
|
||||
ULONG ulBusNumber = new ULONG(busNumber);
|
||||
ULONG ulAddressSpace = new ULONG(addressSpace);
|
||||
ULONGLONG ullOffset = new ULONGLONG(offset);
|
||||
ULONG ulLen = new ULONG(len);
|
||||
ULONGByReference pulBytesRead = new ULONGByReference();
|
||||
COMUtils.checkRC(jnaData.ReadIo(ulInterfaceType, ulBusNumber, ulAddressSpace, ullOffset,
|
||||
into, ulLen, pulBytesRead));
|
||||
int read = pulBytesRead.getValue().intValue();
|
||||
into.position(read + into.position());
|
||||
return read;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int writeIo(int interfaceType, int busNumber, int addressSpace, long offset,
|
||||
ByteBuffer from, int len) {
|
||||
if (len > from.remaining()) {
|
||||
throw new BufferOverflowException();
|
||||
}
|
||||
ULONG ulInterfaceType = new ULONG(interfaceType);
|
||||
ULONG ulBusNumber = new ULONG(busNumber);
|
||||
ULONG ulAddressSpace = new ULONG(addressSpace);
|
||||
ULONGLONG ullOffset = new ULONGLONG(offset);
|
||||
ULONG ulLen = new ULONG(len);
|
||||
ULONGByReference pulBytesWritten = new ULONGByReference();
|
||||
COMUtils.checkRC(jnaData.WriteIo(ulInterfaceType, ulBusNumber, ulAddressSpace, ullOffset,
|
||||
from, ulLen, pulBytesWritten));
|
||||
int written = pulBytesWritten.getValue().intValue();
|
||||
from.position(written + from.position());
|
||||
return written;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long readMsr(int msr) {
|
||||
ULONG ulNumber = new ULONG(msr);
|
||||
ULONGLONGByReference pulValue = new ULONGLONGByReference();
|
||||
COMUtils.checkRC(jnaData.ReadMsr(ulNumber, pulValue));
|
||||
return pulValue.getValue().longValue();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeMsr(int msr, long value) {
|
||||
ULONG ulNumber = new ULONG(msr);
|
||||
ULONGLONG ullValue = new ULONGLONG(value);
|
||||
COMUtils.checkRC(jnaData.WriteMsr(ulNumber, ullValue));
|
||||
}
|
||||
|
||||
@Override
|
||||
public int readDebuggerData(int offset, ByteBuffer into, int len) {
|
||||
if (len > into.remaining()) {
|
||||
throw new BufferOverflowException();
|
||||
}
|
||||
ULONG ulOffset = new ULONG(offset);
|
||||
ULONG ulLen = new ULONG(len);
|
||||
ULONGByReference pulBytesRead = new ULONGByReference();
|
||||
COMUtils.checkRC(jnaData.ReadDebuggerData(ulOffset, into, ulLen, pulBytesRead));
|
||||
int read = pulBytesRead.getValue().intValue();
|
||||
into.position(read + into.position());
|
||||
return read;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long virtualToPhysical(long offset) {
|
||||
throw new UnsupportedOperationException("Not implemented in this interface");
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,69 +0,0 @@
|
||||
/* ###
|
||||
* 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 agent.dbgeng.impl.dbgeng.dataspaces;
|
||||
|
||||
import com.sun.jna.platform.win32.WinDef.ULONGLONG;
|
||||
import com.sun.jna.platform.win32.WinDef.ULONGLONGByReference;
|
||||
import com.sun.jna.platform.win32.WinNT.HRESULT;
|
||||
import com.sun.jna.platform.win32.COM.COMUtils;
|
||||
|
||||
import agent.dbgeng.dbgeng.COMUtilsExtra;
|
||||
import agent.dbgeng.jna.dbgeng.WinNTExtra.MEMORY_BASIC_INFORMATION64;
|
||||
import agent.dbgeng.jna.dbgeng.dataspaces.IDebugDataSpaces2;
|
||||
import ghidra.comm.util.BitmaskSet;
|
||||
|
||||
public class DebugDataSpacesImpl2 extends DebugDataSpacesImpl1 {
|
||||
private final IDebugDataSpaces2 jnaData;
|
||||
|
||||
public DebugDataSpacesImpl2(IDebugDataSpaces2 jnaData) {
|
||||
super(jnaData);
|
||||
this.jnaData = jnaData;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DebugMemoryBasicInformation queryVirtual(long offset) {
|
||||
ULONGLONG ullOffset = new ULONGLONG(offset);
|
||||
MEMORY_BASIC_INFORMATION64.ByReference pInfo = new MEMORY_BASIC_INFORMATION64.ByReference();
|
||||
HRESULT hr = jnaData.QueryVirtual(ullOffset, pInfo);
|
||||
if (hr.equals(COMUtilsExtra.E_UNEXPECTED)) {
|
||||
return null;
|
||||
}
|
||||
if (hr.equals(COMUtilsExtra.E_NOTIMPLEMENTED)) {
|
||||
return null;
|
||||
}
|
||||
if (hr.equals(COMUtilsExtra.E_NOINTERFACE)) {
|
||||
return null;
|
||||
}
|
||||
COMUtils.checkRC(hr);
|
||||
|
||||
return new DebugMemoryBasicInformation(pInfo.BaseAddress.longValue(),
|
||||
pInfo.AllocationBase.longValue(),
|
||||
new BitmaskSet<>(PageProtection.class, pInfo.AllocationProtect.intValue()),
|
||||
pInfo.RegionSize.longValue(), PageState.byValue(pInfo.State.intValue()),
|
||||
new BitmaskSet<>(PageProtection.class, pInfo.Protect.intValue()),
|
||||
PageType.byValue(pInfo.Type.intValue()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public long virtualToPhysical(long offsetV) {
|
||||
ULONGLONG ullOffset = new ULONGLONG(offsetV);
|
||||
ULONGLONGByReference pulOffset = new ULONGLONGByReference();
|
||||
HRESULT hr = jnaData.VirtualToPhysical(ullOffset, pulOffset);
|
||||
COMUtils.checkRC(hr);
|
||||
|
||||
return pulOffset.getValue().longValue();
|
||||
}
|
||||
}
|
||||
@@ -1,28 +0,0 @@
|
||||
/* ###
|
||||
* 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 agent.dbgeng.impl.dbgeng.dataspaces;
|
||||
|
||||
import agent.dbgeng.jna.dbgeng.dataspaces.IDebugDataSpaces3;
|
||||
|
||||
public class DebugDataSpacesImpl3 extends DebugDataSpacesImpl2 {
|
||||
@SuppressWarnings("unused")
|
||||
private final IDebugDataSpaces3 jnaData;
|
||||
|
||||
public DebugDataSpacesImpl3(IDebugDataSpaces3 jnaData) {
|
||||
super(jnaData);
|
||||
this.jnaData = jnaData;
|
||||
}
|
||||
}
|
||||
@@ -1,28 +0,0 @@
|
||||
/* ###
|
||||
* 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 agent.dbgeng.impl.dbgeng.dataspaces;
|
||||
|
||||
import agent.dbgeng.jna.dbgeng.dataspaces.IDebugDataSpaces4;
|
||||
|
||||
public class DebugDataSpacesImpl4 extends DebugDataSpacesImpl3 {
|
||||
@SuppressWarnings("unused")
|
||||
private final IDebugDataSpaces4 jnaData;
|
||||
|
||||
public DebugDataSpacesImpl4(IDebugDataSpaces4 jnaData) {
|
||||
super(jnaData);
|
||||
this.jnaData = jnaData;
|
||||
}
|
||||
}
|
||||
@@ -1,59 +0,0 @@
|
||||
/* ###
|
||||
* 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 agent.dbgeng.impl.dbgeng.dataspaces;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import com.sun.jna.Pointer;
|
||||
|
||||
import agent.dbgeng.dbgeng.DebugDataSpaces;
|
||||
import agent.dbgeng.impl.dbgeng.DbgEngUtil;
|
||||
import agent.dbgeng.impl.dbgeng.DbgEngUtil.InterfaceSupplier;
|
||||
import agent.dbgeng.impl.dbgeng.DbgEngUtil.Preferred;
|
||||
import agent.dbgeng.jna.dbgeng.dataspaces.*;
|
||||
import ghidra.util.datastruct.WeakValueHashMap;
|
||||
|
||||
public interface DebugDataSpacesInternal extends DebugDataSpaces {
|
||||
Map<Pointer, DebugDataSpacesInternal> CACHE = new WeakValueHashMap<>();
|
||||
|
||||
static DebugDataSpacesInternal instanceFor(WrapIDebugDataSpaces data) {
|
||||
return DbgEngUtil.lazyWeakCache(CACHE, data, DebugDataSpacesImpl1::new);
|
||||
}
|
||||
|
||||
static DebugDataSpacesInternal instanceFor(WrapIDebugDataSpaces2 data) {
|
||||
return DbgEngUtil.lazyWeakCache(CACHE, data, DebugDataSpacesImpl2::new);
|
||||
}
|
||||
|
||||
static DebugDataSpacesInternal instanceFor(WrapIDebugDataSpaces3 data) {
|
||||
return DbgEngUtil.lazyWeakCache(CACHE, data, DebugDataSpacesImpl3::new);
|
||||
}
|
||||
|
||||
static DebugDataSpacesInternal instanceFor(WrapIDebugDataSpaces4 data) {
|
||||
return DbgEngUtil.lazyWeakCache(CACHE, data, DebugDataSpacesImpl4::new);
|
||||
}
|
||||
|
||||
List<Preferred<WrapIDebugDataSpaces>> PREFERRED_DATA_SPACES_IIDS = List.of(
|
||||
new Preferred<>(IDebugDataSpaces4.IID_IDEBUG_DATA_SPACES4, WrapIDebugDataSpaces4.class),
|
||||
new Preferred<>(IDebugDataSpaces3.IID_IDEBUG_DATA_SPACES3, WrapIDebugDataSpaces3.class),
|
||||
new Preferred<>(IDebugDataSpaces2.IID_IDEBUG_DATA_SPACES2, WrapIDebugDataSpaces2.class),
|
||||
new Preferred<>(IDebugDataSpaces.IID_IDEBUG_DATA_SPACES, WrapIDebugDataSpaces.class));
|
||||
|
||||
static DebugDataSpacesInternal tryPreferredInterfaces(InterfaceSupplier supplier) {
|
||||
return DbgEngUtil.tryPreferredInterfaces(DebugDataSpacesInternal.class,
|
||||
PREFERRED_DATA_SPACES_IIDS, supplier);
|
||||
}
|
||||
}
|
||||
@@ -1,298 +0,0 @@
|
||||
/* ###
|
||||
* 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 agent.dbgeng.impl.dbgeng.event;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import com.sun.jna.Pointer;
|
||||
import com.sun.jna.platform.win32.Guid.REFIID;
|
||||
import com.sun.jna.platform.win32.WinDef.*;
|
||||
import com.sun.jna.platform.win32.WinError;
|
||||
import com.sun.jna.platform.win32.WinNT.HRESULT;
|
||||
import com.sun.jna.platform.win32.COM.IUnknown;
|
||||
import com.sun.jna.ptr.PointerByReference;
|
||||
|
||||
import agent.dbgeng.dbgeng.*;
|
||||
import agent.dbgeng.dbgeng.DebugClient.DebugStatus;
|
||||
import agent.dbgeng.dbgeng.DebugClient.SessionStatus;
|
||||
import agent.dbgeng.dbgeng.DebugEventCallbacks.DebugEvent;
|
||||
import agent.dbgeng.impl.dbgeng.breakpoint.DebugBreakpointInternal;
|
||||
import agent.dbgeng.impl.dbgeng.client.DebugClientImpl1;
|
||||
import agent.dbgeng.impl.dbgeng.client.DebugClientInternal;
|
||||
import agent.dbgeng.jna.dbgeng.WinNTExtra.EXCEPTION_RECORD64;
|
||||
import agent.dbgeng.jna.dbgeng.breakpoint.WrapIDebugBreakpoint;
|
||||
import agent.dbgeng.jna.dbgeng.event.*;
|
||||
import ghidra.comm.util.BitmaskSet;
|
||||
import ghidra.util.Msg;
|
||||
|
||||
public class WrapCallbackIDebugEventCallbacks implements CallbackIDebugEventCallbacks {
|
||||
private static final HRESULT ERROR_RESULT = new HRESULT(WinError.E_UNEXPECTED);
|
||||
|
||||
private final DebugClientInternal client;
|
||||
private final DebugEventCallbacks cb;
|
||||
private ListenerIDebugEventCallbacks listener;
|
||||
|
||||
public WrapCallbackIDebugEventCallbacks(DebugClientImpl1 client, DebugEventCallbacks cb) {
|
||||
this.client = client;
|
||||
this.cb = cb;
|
||||
}
|
||||
|
||||
public void setListener(ListenerIDebugEventCallbacks listener) {
|
||||
this.listener = listener;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Pointer getPointer() {
|
||||
return listener.getPointer();
|
||||
}
|
||||
|
||||
@Override
|
||||
public HRESULT QueryInterface(REFIID refid, PointerByReference ppvObject) {
|
||||
if (null == ppvObject) {
|
||||
return new HRESULT(WinError.E_POINTER);
|
||||
}
|
||||
else if (refid.getValue().equals(IDebugEventCallbacks.IID_IDEBUG_EVENT_CALLBACKS)) {
|
||||
ppvObject.setValue(this.getPointer());
|
||||
return WinError.S_OK;
|
||||
}
|
||||
else if (refid.getValue().equals(IUnknown.IID_IUNKNOWN)) {
|
||||
ppvObject.setValue(this.getPointer());
|
||||
return WinError.S_OK;
|
||||
}
|
||||
return new HRESULT(WinError.E_NOINTERFACE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int AddRef() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int Release() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public HRESULT GetInterestMask(ULONGByReference Mask) {
|
||||
try {
|
||||
BitmaskSet<DebugEvent> interest = cb.getInterestMask();
|
||||
ULONG ulInterest = new ULONG(interest.getBitmask());
|
||||
Mask.setValue(ulInterest);
|
||||
return WinError.S_OK;
|
||||
}
|
||||
catch (Throwable e) {
|
||||
Msg.error(this, "Error during callback", e);
|
||||
return new HRESULT(WinError.E_UNEXPECTED);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public HRESULT Breakpoint(WrapIDebugBreakpoint.ByReference Bp) {
|
||||
try {
|
||||
DebugBreakpoint bpt = DebugBreakpointInternal
|
||||
.tryPreferredInterfaces(client.getControlInternal(), Bp::QueryInterface);
|
||||
DebugStatus status = cb.breakpoint(bpt);
|
||||
return new HRESULT(status.ordinal());
|
||||
}
|
||||
catch (Throwable e) {
|
||||
Msg.error(this, "Error during callback", e);
|
||||
return ERROR_RESULT;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public HRESULT Exception(EXCEPTION_RECORD64.ByReference Exception, ULONG FirstChance) {
|
||||
try {
|
||||
int numParams = Exception.NumberParameters.intValue();
|
||||
List<Long> information = new ArrayList<>(numParams);
|
||||
for (int i = 0; i < numParams; i++) {
|
||||
information.set(i, Exception.ExceptionInformation[i].longValue());
|
||||
}
|
||||
DebugExceptionRecord64 exc =
|
||||
new DebugExceptionRecord64(Exception.ExceptionCode.intValue(),
|
||||
Exception.ExceptionFlags.intValue(), Exception.ExceptionRecord.longValue(),
|
||||
Exception.ExceptionAddress.longValue(), information);
|
||||
boolean firstChance = FirstChance.intValue() != 0;
|
||||
DebugStatus status = cb.exception(exc, firstChance);
|
||||
return new HRESULT(status.ordinal());
|
||||
}
|
||||
catch (Throwable e) {
|
||||
Msg.error(this, "Error during callback", e);
|
||||
return ERROR_RESULT;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public HRESULT CreateThread(ULONGLONG Handle, ULONGLONG DataOffset, ULONGLONG StartOffset) {
|
||||
try {
|
||||
DebugStatus status = cb.createThread(new DebugThreadInfo(Handle.longValue(),
|
||||
DataOffset.longValue(), StartOffset.longValue()));
|
||||
return new HRESULT(status.ordinal());
|
||||
}
|
||||
catch (Throwable e) {
|
||||
Msg.error(this, "Error during callback", e);
|
||||
return ERROR_RESULT;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public HRESULT ExitThread(ULONG ExitCode) {
|
||||
try {
|
||||
DebugStatus status = cb.exitThread(ExitCode.intValue());
|
||||
return new HRESULT(status.ordinal());
|
||||
}
|
||||
catch (Throwable e) {
|
||||
Msg.error(this, "Error during callback", e);
|
||||
return ERROR_RESULT;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public HRESULT CreateProcess(ULONGLONG ImageFileHandle, ULONGLONG Handle, ULONGLONG BaseOffset,
|
||||
ULONG ModuleSize, String ModuleName, String ImageName, ULONG CheckSum,
|
||||
ULONG TimeDateStamp, ULONGLONG InitialThreadHandle, ULONGLONG ThreadDataOffset,
|
||||
ULONGLONG StartOffset) {
|
||||
try {
|
||||
// TODO: Associate thread with process
|
||||
// TODO: Record All these other parameters?
|
||||
DebugStatus status = cb.createProcess(new DebugProcessInfo(Handle.longValue(),
|
||||
new DebugModuleInfo(ImageFileHandle.longValue(), BaseOffset.longValue(),
|
||||
ModuleSize.intValue(), ModuleName, ImageName, CheckSum.intValue(),
|
||||
TimeDateStamp.intValue()),
|
||||
new DebugThreadInfo(InitialThreadHandle.longValue(), ThreadDataOffset.longValue(),
|
||||
StartOffset.longValue())));
|
||||
return new HRESULT(status.ordinal());
|
||||
}
|
||||
catch (Throwable e) {
|
||||
Msg.error(this, "Error during callback", e);
|
||||
return ERROR_RESULT;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public HRESULT ExitProcess(ULONG ExitCode) {
|
||||
try {
|
||||
DebugStatus status = cb.exitProcess(ExitCode.intValue());
|
||||
return new HRESULT(status.ordinal());
|
||||
}
|
||||
catch (Throwable e) {
|
||||
Msg.error(this, "Error during callback", e);
|
||||
return ERROR_RESULT;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public HRESULT LoadModule(ULONGLONG ImageFileHandle, ULONGLONG BaseOffset, ULONG ModuleSize,
|
||||
String ModuleName, String ImageName, ULONG CheckSum, ULONG TimeDateStamp) {
|
||||
try {
|
||||
// All of these are potentially null
|
||||
long imageFileHandle = ImageFileHandle == null ? -1L : ImageFileHandle.longValue();
|
||||
long baseOffset = BaseOffset == null ? -1L : BaseOffset.longValue();
|
||||
int moduleSize = ModuleSize == null ? -1 : ModuleSize.intValue();
|
||||
String moduleName = ModuleName == null ? "" : ModuleName.toString();
|
||||
String imageName = ImageName == null ? "" : ImageName.toString();
|
||||
int checkSum = CheckSum == null ? -1 : CheckSum.intValue();
|
||||
|
||||
DebugStatus status = cb.loadModule(new DebugModuleInfo(imageFileHandle, baseOffset,
|
||||
moduleSize, moduleName, imageName, checkSum, TimeDateStamp.intValue()));
|
||||
return new HRESULT(status.ordinal());
|
||||
}
|
||||
catch (Throwable e) {
|
||||
Msg.error(this, "Error during callback", e);
|
||||
return ERROR_RESULT;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public HRESULT UnloadModule(String ImageBaseName, ULONGLONG BaseOffset) {
|
||||
try {
|
||||
DebugStatus status = cb.unloadModule(ImageBaseName, BaseOffset.longValue());
|
||||
return new HRESULT(status.ordinal());
|
||||
}
|
||||
catch (Throwable e) {
|
||||
Msg.error(this, "Error during callback", e);
|
||||
return ERROR_RESULT;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public HRESULT SystemError(ULONG Error, ULONG Level) {
|
||||
try {
|
||||
DebugStatus status = cb.systemError(Error.intValue(), Level.intValue());
|
||||
return new HRESULT(status.ordinal());
|
||||
}
|
||||
catch (Throwable e) {
|
||||
Msg.error(this, "Error during callback", e);
|
||||
return ERROR_RESULT;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public HRESULT SessionStatus(ULONG Status) {
|
||||
try {
|
||||
SessionStatus ss = SessionStatus.values()[Status.intValue()];
|
||||
DebugStatus status = cb.sessionStatus(ss);
|
||||
return new HRESULT(status.ordinal());
|
||||
}
|
||||
catch (Throwable e) {
|
||||
Msg.error(this, "Error during callback", e);
|
||||
return ERROR_RESULT;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public HRESULT ChangeDebuggeeState(ULONG Flags, ULONGLONG Argument) {
|
||||
try {
|
||||
BitmaskSet<DebugClient.ChangeDebuggeeState> flags =
|
||||
new BitmaskSet<>(DebugClient.ChangeDebuggeeState.class, Flags.intValue());
|
||||
DebugStatus status = cb.changeDebuggeeState(flags, Argument.longValue());
|
||||
return new HRESULT(status.ordinal());
|
||||
}
|
||||
catch (Throwable e) {
|
||||
Msg.error(this, "Error during callback", e);
|
||||
return ERROR_RESULT;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public HRESULT ChangeEngineState(ULONG Flags, ULONGLONG Argument) {
|
||||
try {
|
||||
BitmaskSet<DebugClient.ChangeEngineState> flags =
|
||||
new BitmaskSet<>(DebugClient.ChangeEngineState.class, Flags.intValue());
|
||||
DebugStatus status = cb.changeEngineState(flags, Argument.longValue());
|
||||
return new HRESULT(status.ordinal());
|
||||
}
|
||||
catch (Throwable e) {
|
||||
Msg.error(this, "Error during callback", e);
|
||||
return ERROR_RESULT;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public HRESULT ChangeSymbolState(ULONG Flags, ULONGLONG Argument) {
|
||||
try {
|
||||
BitmaskSet<DebugClient.ChangeSymbolState> flags =
|
||||
new BitmaskSet<>(DebugClient.ChangeSymbolState.class, Flags.intValue());
|
||||
DebugStatus status = cb.changeSymbolState(flags, Argument.longValue());
|
||||
return new HRESULT(status.ordinal());
|
||||
}
|
||||
catch (Throwable e) {
|
||||
Msg.error(this, "Error during callback", e);
|
||||
return ERROR_RESULT;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,297 +0,0 @@
|
||||
/* ###
|
||||
* 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 agent.dbgeng.impl.dbgeng.event;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import com.sun.jna.Pointer;
|
||||
import com.sun.jna.WString;
|
||||
import com.sun.jna.platform.win32.Guid.REFIID;
|
||||
import com.sun.jna.platform.win32.WinDef.*;
|
||||
import com.sun.jna.platform.win32.WinError;
|
||||
import com.sun.jna.platform.win32.WinNT.HRESULT;
|
||||
import com.sun.jna.platform.win32.COM.IUnknown;
|
||||
import com.sun.jna.ptr.PointerByReference;
|
||||
|
||||
import agent.dbgeng.dbgeng.*;
|
||||
import agent.dbgeng.dbgeng.DebugClient.DebugStatus;
|
||||
import agent.dbgeng.dbgeng.DebugClient.SessionStatus;
|
||||
import agent.dbgeng.dbgeng.DebugEventCallbacks.DebugEvent;
|
||||
import agent.dbgeng.impl.dbgeng.breakpoint.DebugBreakpointInternal;
|
||||
import agent.dbgeng.impl.dbgeng.client.DebugClientImpl5;
|
||||
import agent.dbgeng.impl.dbgeng.client.DebugClientInternal;
|
||||
import agent.dbgeng.jna.dbgeng.WinNTExtra.EXCEPTION_RECORD64;
|
||||
import agent.dbgeng.jna.dbgeng.breakpoint.WrapIDebugBreakpoint;
|
||||
import agent.dbgeng.jna.dbgeng.event.*;
|
||||
import ghidra.comm.util.BitmaskSet;
|
||||
import ghidra.util.Msg;
|
||||
|
||||
public class WrapCallbackIDebugEventCallbacksWide implements CallbackIDebugEventCallbacksWide {
|
||||
private static final HRESULT ERROR_RESULT = new HRESULT(WinError.E_UNEXPECTED);
|
||||
|
||||
private final DebugClientInternal client;
|
||||
private final DebugEventCallbacks cb;
|
||||
private ListenerIDebugEventCallbacksWide listener;
|
||||
|
||||
public WrapCallbackIDebugEventCallbacksWide(DebugClientImpl5 client, DebugEventCallbacks cb) {
|
||||
this.client = client;
|
||||
this.cb = cb;
|
||||
}
|
||||
|
||||
public void setListener(ListenerIDebugEventCallbacksWide listener) {
|
||||
this.listener = listener;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Pointer getPointer() {
|
||||
return listener.getPointer();
|
||||
}
|
||||
|
||||
@Override
|
||||
public HRESULT QueryInterface(REFIID refid, PointerByReference ppvObject) {
|
||||
if (null == ppvObject) {
|
||||
return new HRESULT(WinError.E_POINTER);
|
||||
}
|
||||
else if (refid.getValue()
|
||||
.equals(IDebugEventCallbacksWide.IID_IDEBUG_EVENT_CALLBACKS_WIDE)) {
|
||||
ppvObject.setValue(this.getPointer());
|
||||
return WinError.S_OK;
|
||||
}
|
||||
else if (refid.getValue().equals(IUnknown.IID_IUNKNOWN)) {
|
||||
ppvObject.setValue(this.getPointer());
|
||||
return WinError.S_OK;
|
||||
}
|
||||
return new HRESULT(WinError.E_NOINTERFACE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int AddRef() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int Release() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public HRESULT GetInterestMask(ULONGByReference Mask) {
|
||||
try {
|
||||
BitmaskSet<DebugEvent> interest = cb.getInterestMask();
|
||||
ULONG ulInterest = new ULONG(interest.getBitmask());
|
||||
Mask.setValue(ulInterest);
|
||||
return WinError.S_OK;
|
||||
}
|
||||
catch (Throwable e) {
|
||||
Msg.error(this, "Error during callback", e);
|
||||
return ERROR_RESULT;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public HRESULT Breakpoint(WrapIDebugBreakpoint.ByReference Bp) {
|
||||
try {
|
||||
DebugBreakpoint bpt = DebugBreakpointInternal
|
||||
.tryPreferredInterfaces(client.getControlInternal(), Bp::QueryInterface);
|
||||
DebugStatus status = cb.breakpoint(bpt);
|
||||
return new HRESULT(status.ordinal());
|
||||
}
|
||||
catch (Throwable e) {
|
||||
Msg.error(this, "Error during callback", e);
|
||||
return ERROR_RESULT;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public HRESULT Exception(EXCEPTION_RECORD64.ByReference Exception, ULONG FirstChance) {
|
||||
try {
|
||||
int numParams = Exception.NumberParameters.intValue();
|
||||
List<Long> information = new ArrayList<>(numParams);
|
||||
for (int i = 0; i < numParams; i++) {
|
||||
information.add(Exception.ExceptionInformation[i].longValue());
|
||||
}
|
||||
DebugExceptionRecord64 exc =
|
||||
new DebugExceptionRecord64(Exception.ExceptionCode.intValue(),
|
||||
Exception.ExceptionFlags.intValue(), Exception.ExceptionRecord.longValue(),
|
||||
Exception.ExceptionAddress.longValue(), information);
|
||||
boolean firstChance = FirstChance.intValue() != 0;
|
||||
DebugStatus status = cb.exception(exc, firstChance);
|
||||
return new HRESULT(status.ordinal());
|
||||
}
|
||||
catch (Throwable e) {
|
||||
Msg.error(this, "Error during callback", e);
|
||||
return ERROR_RESULT;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public HRESULT CreateThread(ULONGLONG Handle, ULONGLONG DataOffset, ULONGLONG StartOffset) {
|
||||
try {
|
||||
DebugStatus status = cb.createThread(new DebugThreadInfo(Handle.longValue(),
|
||||
DataOffset.longValue(), StartOffset.longValue()));
|
||||
return new HRESULT(status.ordinal());
|
||||
}
|
||||
catch (Throwable e) {
|
||||
Msg.error(this, "Error during callback", e);
|
||||
return ERROR_RESULT;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public HRESULT ExitThread(ULONG ExitCode) {
|
||||
try {
|
||||
DebugStatus status = cb.exitThread(ExitCode.intValue());
|
||||
return new HRESULT(status.ordinal());
|
||||
}
|
||||
catch (Throwable e) {
|
||||
Msg.error(this, "Error during callback", e);
|
||||
return ERROR_RESULT;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public HRESULT CreateProcess(ULONGLONG ImageFileHandle, ULONGLONG Handle, ULONGLONG BaseOffset,
|
||||
ULONG ModuleSize, WString ModuleName, WString ImageName, ULONG CheckSum,
|
||||
ULONG TimeDateStamp, ULONGLONG InitialThreadHandle, ULONGLONG ThreadDataOffset,
|
||||
ULONGLONG StartOffset) {
|
||||
try {
|
||||
DebugStatus status = cb.createProcess(new DebugProcessInfo(Handle.longValue(),
|
||||
new DebugModuleInfo(ImageFileHandle.longValue(), BaseOffset.longValue(),
|
||||
ModuleSize.intValue(), ModuleName.toString(), ImageName.toString(),
|
||||
CheckSum.intValue(), TimeDateStamp.intValue()),
|
||||
new DebugThreadInfo(InitialThreadHandle.longValue(), ThreadDataOffset.longValue(),
|
||||
StartOffset.longValue())));
|
||||
return new HRESULT(status.ordinal());
|
||||
}
|
||||
catch (Throwable e) {
|
||||
Msg.error(this, "Error during callback", e);
|
||||
return ERROR_RESULT;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public HRESULT ExitProcess(ULONG ExitCode) {
|
||||
try {
|
||||
DebugStatus status = cb.exitProcess(ExitCode.intValue());
|
||||
return new HRESULT(status.ordinal());
|
||||
}
|
||||
catch (Throwable e) {
|
||||
Msg.error(this, "Error during callback", e);
|
||||
return ERROR_RESULT;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public HRESULT LoadModule(ULONGLONG ImageFileHandle, ULONGLONG BaseOffset, ULONG ModuleSize,
|
||||
WString ModuleName, WString ImageName, ULONG CheckSum, ULONG TimeDateStamp) {
|
||||
try {
|
||||
long imageFileHandle = ImageFileHandle == null ? -1L : ImageFileHandle.longValue();
|
||||
long baseOffset = BaseOffset == null ? -1L : BaseOffset.longValue();
|
||||
int moduleSize = ModuleSize == null ? -1 : ModuleSize.intValue();
|
||||
String moduleName = ModuleName == null ? "" : ModuleName.toString();
|
||||
String imageName = ImageName == null ? "" : ImageName.toString();
|
||||
int checkSum = CheckSum == null ? -1 : CheckSum.intValue();
|
||||
|
||||
DebugStatus status = cb.loadModule(new DebugModuleInfo(imageFileHandle, baseOffset,
|
||||
moduleSize, moduleName, imageName, checkSum, TimeDateStamp.intValue()));
|
||||
return new HRESULT(status.ordinal());
|
||||
}
|
||||
catch (Throwable e) {
|
||||
Msg.error(this, "Error during callback", e);
|
||||
return ERROR_RESULT;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public HRESULT UnloadModule(WString ImageBaseName, ULONGLONG BaseOffset) {
|
||||
try {
|
||||
DebugStatus status = cb.unloadModule(ImageBaseName.toString(), BaseOffset.longValue());
|
||||
return new HRESULT(status.ordinal());
|
||||
}
|
||||
catch (Throwable e) {
|
||||
Msg.error(this, "Error during callback", e);
|
||||
return ERROR_RESULT;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public HRESULT SystemError(ULONG Error, ULONG Level) {
|
||||
try {
|
||||
DebugStatus status = cb.systemError(Error.intValue(), Level.intValue());
|
||||
return new HRESULT(status.ordinal());
|
||||
}
|
||||
catch (Throwable e) {
|
||||
Msg.error(this, "Error during callback", e);
|
||||
return ERROR_RESULT;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public HRESULT SessionStatus(ULONG Status) {
|
||||
try {
|
||||
SessionStatus ss = SessionStatus.values()[Status.intValue()];
|
||||
DebugStatus status = cb.sessionStatus(ss);
|
||||
return new HRESULT(status.ordinal());
|
||||
}
|
||||
catch (Throwable e) {
|
||||
Msg.error(this, "Error during callback", e);
|
||||
return ERROR_RESULT;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public HRESULT ChangeDebuggeeState(ULONG Flags, ULONGLONG Argument) {
|
||||
try {
|
||||
BitmaskSet<DebugClient.ChangeDebuggeeState> flags =
|
||||
new BitmaskSet<>(DebugClient.ChangeDebuggeeState.class, Flags.intValue());
|
||||
DebugStatus status = cb.changeDebuggeeState(flags, Argument.longValue());
|
||||
return new HRESULT(status.ordinal());
|
||||
}
|
||||
catch (Throwable e) {
|
||||
Msg.error(this, "Error during callback", e);
|
||||
return ERROR_RESULT;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public HRESULT ChangeEngineState(ULONG Flags, ULONGLONG Argument) {
|
||||
try {
|
||||
BitmaskSet<DebugClient.ChangeEngineState> flags =
|
||||
new BitmaskSet<>(DebugClient.ChangeEngineState.class, Flags.intValue());
|
||||
DebugStatus status = cb.changeEngineState(flags, Argument.longValue());
|
||||
return new HRESULT(status.ordinal());
|
||||
}
|
||||
catch (Throwable e) {
|
||||
Msg.error(this, "Error during callback", e);
|
||||
return ERROR_RESULT;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public HRESULT ChangeSymbolState(ULONG Flags, ULONGLONG Argument) {
|
||||
try {
|
||||
BitmaskSet<DebugClient.ChangeSymbolState> flags =
|
||||
new BitmaskSet<>(DebugClient.ChangeSymbolState.class, Flags.intValue());
|
||||
DebugStatus status = cb.changeSymbolState(flags, Argument.longValue());
|
||||
return new HRESULT(status.ordinal());
|
||||
}
|
||||
catch (Throwable e) {
|
||||
Msg.error(this, "Error during callback", e);
|
||||
return ERROR_RESULT;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,96 +0,0 @@
|
||||
/* ###
|
||||
* 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 agent.dbgeng.impl.dbgeng.io;
|
||||
|
||||
import com.sun.jna.Pointer;
|
||||
import com.sun.jna.platform.win32.Guid.REFIID;
|
||||
import com.sun.jna.platform.win32.WinDef.ULONG;
|
||||
import com.sun.jna.platform.win32.WinError;
|
||||
import com.sun.jna.platform.win32.WinNT.HRESULT;
|
||||
import com.sun.jna.platform.win32.COM.IUnknown;
|
||||
import com.sun.jna.ptr.PointerByReference;
|
||||
|
||||
import agent.dbgeng.dbgeng.DebugInputCallbacks;
|
||||
import agent.dbgeng.impl.dbgeng.client.DebugClientImpl1;
|
||||
import agent.dbgeng.jna.dbgeng.io.*;
|
||||
|
||||
public class WrapCallbackIDebugInputCallbacks implements CallbackIDebugInputCallbacks {
|
||||
private final DebugClientImpl1 client;
|
||||
private final DebugInputCallbacks cb;
|
||||
private ListenerIDebugInputCallbacks listener;
|
||||
|
||||
public WrapCallbackIDebugInputCallbacks(DebugClientImpl1 client, DebugInputCallbacks cb) {
|
||||
this.client = client;
|
||||
this.cb = cb;
|
||||
}
|
||||
|
||||
public void setListener(ListenerIDebugInputCallbacks listener) {
|
||||
this.listener = listener;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Pointer getPointer() {
|
||||
return listener.getPointer();
|
||||
}
|
||||
|
||||
@Override
|
||||
public HRESULT QueryInterface(REFIID refid, PointerByReference ppvObject) {
|
||||
if (null == ppvObject) {
|
||||
return new HRESULT(WinError.E_POINTER);
|
||||
}
|
||||
else if (refid.getValue().equals(IDebugInputCallbacks.IID_IDEBUG_INPUT_CALLBACKS)) {
|
||||
ppvObject.setValue(this.getPointer());
|
||||
return WinError.S_OK;
|
||||
}
|
||||
else if (refid.getValue().equals(IUnknown.IID_IUNKNOWN)) {
|
||||
ppvObject.setValue(this.getPointer());
|
||||
return WinError.S_OK;
|
||||
}
|
||||
return new HRESULT(WinError.E_NOINTERFACE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int AddRef() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int Release() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public HRESULT StartInput(ULONG BufferSize) {
|
||||
try {
|
||||
cb.startInput(BufferSize.longValue());
|
||||
return WinError.S_OK;
|
||||
}
|
||||
catch (Throwable e) {
|
||||
return new HRESULT(WinError.E_UNEXPECTED);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public HRESULT EndInput() {
|
||||
try {
|
||||
cb.endInput();
|
||||
return WinError.S_OK;
|
||||
}
|
||||
catch (Throwable e) {
|
||||
return new HRESULT(WinError.E_UNEXPECTED);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,82 +0,0 @@
|
||||
/* ###
|
||||
* 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 agent.dbgeng.impl.dbgeng.io;
|
||||
|
||||
import com.sun.jna.Pointer;
|
||||
import com.sun.jna.platform.win32.Guid.REFIID;
|
||||
import com.sun.jna.platform.win32.WinDef.ULONG;
|
||||
import com.sun.jna.platform.win32.WinError;
|
||||
import com.sun.jna.platform.win32.WinNT.HRESULT;
|
||||
import com.sun.jna.platform.win32.COM.IUnknown;
|
||||
import com.sun.jna.ptr.PointerByReference;
|
||||
|
||||
import agent.dbgeng.dbgeng.DebugOutputCallbacks;
|
||||
import agent.dbgeng.jna.dbgeng.io.*;
|
||||
|
||||
public class WrapCallbackIDebugOutputCallbacks implements CallbackIDebugOutputCallbacks {
|
||||
private final DebugOutputCallbacks cb;
|
||||
private ListenerIDebugOutputCallbacks listener;
|
||||
|
||||
public WrapCallbackIDebugOutputCallbacks(DebugOutputCallbacks cb) {
|
||||
this.cb = cb;
|
||||
}
|
||||
|
||||
public void setListener(ListenerIDebugOutputCallbacks listener) {
|
||||
this.listener = listener;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Pointer getPointer() {
|
||||
return listener.getPointer();
|
||||
}
|
||||
|
||||
@Override
|
||||
public HRESULT QueryInterface(REFIID refid, PointerByReference ppvObject) {
|
||||
if (null == ppvObject) {
|
||||
return new HRESULT(WinError.E_POINTER);
|
||||
}
|
||||
else if (refid.getValue().equals(IDebugOutputCallbacks.IID_IDEBUG_OUTPUT_CALLBACKS)) {
|
||||
ppvObject.setValue(this.getPointer());
|
||||
return WinError.S_OK;
|
||||
}
|
||||
else if (refid.getValue().equals(IUnknown.IID_IUNKNOWN)) {
|
||||
ppvObject.setValue(this.getPointer());
|
||||
return WinError.S_OK;
|
||||
}
|
||||
return new HRESULT(WinError.E_NOINTERFACE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int AddRef() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int Release() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public HRESULT Output(ULONG Mask, String Text) {
|
||||
try {
|
||||
cb.output(Mask.intValue(), Text);
|
||||
return WinError.S_OK;
|
||||
}
|
||||
catch (Throwable e) {
|
||||
return new HRESULT(WinError.E_UNEXPECTED);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,84 +0,0 @@
|
||||
/* ###
|
||||
* 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 agent.dbgeng.impl.dbgeng.io;
|
||||
|
||||
import com.sun.jna.Pointer;
|
||||
import com.sun.jna.WString;
|
||||
import com.sun.jna.platform.win32.Guid.REFIID;
|
||||
import com.sun.jna.platform.win32.WinDef.ULONG;
|
||||
import com.sun.jna.platform.win32.WinError;
|
||||
import com.sun.jna.platform.win32.WinNT.HRESULT;
|
||||
import com.sun.jna.platform.win32.COM.IUnknown;
|
||||
import com.sun.jna.ptr.PointerByReference;
|
||||
|
||||
import agent.dbgeng.dbgeng.DebugOutputCallbacks;
|
||||
import agent.dbgeng.jna.dbgeng.io.*;
|
||||
|
||||
public class WrapCallbackIDebugOutputCallbacksWide implements CallbackIDebugOutputCallbacksWide {
|
||||
private final DebugOutputCallbacks cb;
|
||||
private ListenerIDebugOutputCallbacksWide listener;
|
||||
|
||||
public WrapCallbackIDebugOutputCallbacksWide(DebugOutputCallbacks cb) {
|
||||
this.cb = cb;
|
||||
}
|
||||
|
||||
public void setListener(ListenerIDebugOutputCallbacksWide listener) {
|
||||
this.listener = listener;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Pointer getPointer() {
|
||||
return listener.getPointer();
|
||||
}
|
||||
|
||||
@Override
|
||||
public HRESULT QueryInterface(REFIID refid, PointerByReference ppvObject) {
|
||||
if (null == ppvObject) {
|
||||
return new HRESULT(WinError.E_POINTER);
|
||||
}
|
||||
else if (refid.getValue()
|
||||
.equals(IDebugOutputCallbacksWide.IID_IDEBUG_OUTPUT_CALLBACKS_WIDE)) {
|
||||
ppvObject.setValue(this.getPointer());
|
||||
return WinError.S_OK;
|
||||
}
|
||||
else if (refid.getValue().equals(IUnknown.IID_IUNKNOWN)) {
|
||||
ppvObject.setValue(this.getPointer());
|
||||
return WinError.S_OK;
|
||||
}
|
||||
return new HRESULT(WinError.E_NOINTERFACE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int AddRef() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int Release() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public HRESULT Output(ULONG Mask, WString Text) {
|
||||
try {
|
||||
cb.output(Mask.intValue(), Text.toString());
|
||||
return WinError.S_OK;
|
||||
}
|
||||
catch (Throwable e) {
|
||||
return new HRESULT(WinError.E_UNEXPECTED);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,154 +0,0 @@
|
||||
/* ###
|
||||
* 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 agent.dbgeng.impl.dbgeng.registers;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
import com.sun.jna.Native;
|
||||
import com.sun.jna.platform.win32.WinDef.ULONG;
|
||||
import com.sun.jna.platform.win32.WinDef.ULONGByReference;
|
||||
import com.sun.jna.platform.win32.WinNT.HRESULT;
|
||||
import com.sun.jna.platform.win32.COM.COMUtils;
|
||||
|
||||
import agent.dbgeng.dbgeng.*;
|
||||
import agent.dbgeng.dbgeng.DbgEng.OpaqueCleanable;
|
||||
import agent.dbgeng.dbgeng.DebugValue.DebugValueType;
|
||||
import agent.dbgeng.jna.dbgeng.DbgEngNative.DEBUG_REGISTER_DESCRIPTION;
|
||||
import agent.dbgeng.jna.dbgeng.DbgEngNative.DEBUG_VALUE;
|
||||
import agent.dbgeng.jna.dbgeng.registers.IDebugRegisters;
|
||||
import ghidra.comm.util.BitmaskSet;
|
||||
|
||||
public class DebugRegistersImpl1 implements DebugRegistersInternal {
|
||||
@SuppressWarnings("unused")
|
||||
private final OpaqueCleanable cleanable;
|
||||
private final IDebugRegisters jnaRegisters;
|
||||
|
||||
public DebugRegistersImpl1(IDebugRegisters jnaRegisters) {
|
||||
this.cleanable = DbgEng.releaseWhenPhantom(this, jnaRegisters);
|
||||
this.jnaRegisters = jnaRegisters;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getNumberRegisters() {
|
||||
ULONGByReference pulNumber = new ULONGByReference();
|
||||
COMUtils.checkRC(jnaRegisters.GetNumberRegisters(pulNumber));
|
||||
return pulNumber.getValue().intValue();
|
||||
}
|
||||
|
||||
@Override
|
||||
public DebugRegisterDescription getDescription(int registerIndex) {
|
||||
ULONG ulRegIdx = new ULONG(registerIndex);
|
||||
ULONGByReference pulNameSize = new ULONGByReference();
|
||||
COMUtils.checkRC(
|
||||
jnaRegisters.GetDescription(ulRegIdx, null, new ULONG(0), pulNameSize, null));
|
||||
byte[] name = new byte[pulNameSize.getValue().intValue()];
|
||||
DEBUG_REGISTER_DESCRIPTION.ByReference desc = new DEBUG_REGISTER_DESCRIPTION.ByReference();
|
||||
COMUtils.checkRC(
|
||||
jnaRegisters.GetDescription(ulRegIdx, name, pulNameSize.getValue(), null, desc));
|
||||
|
||||
return new DebugRegisterDescription(Native.toString(name), registerIndex,
|
||||
DebugValueType.values()[desc.Type.intValue()],
|
||||
new BitmaskSet<>(DebugRegisterFlags.class, desc.Flags.intValue()),
|
||||
desc.SubregMaster.intValue(), desc.SubregLength.intValue(), desc.SubregMask.longValue(),
|
||||
desc.SubregShift.intValue());
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getIndexByName(String name) {
|
||||
ULONGByReference pulIndex = new ULONGByReference();
|
||||
HRESULT hr = jnaRegisters.GetIndexByName(name, pulIndex);
|
||||
if (hr.equals(COMUtilsExtra.E_NOINTERFACE)) {
|
||||
// This happens for 32-bit WOW execution
|
||||
return -1;
|
||||
}
|
||||
COMUtils.checkRC(hr);
|
||||
return pulIndex.getValue().intValue();
|
||||
}
|
||||
|
||||
@Override
|
||||
public DebugValue getValue(int index) {
|
||||
ULONG ulIndex = new ULONG(index);
|
||||
DEBUG_VALUE.ByReference dvVal = new DEBUG_VALUE.ByReference();
|
||||
COMUtils.checkRC(jnaRegisters.GetValue(ulIndex, dvVal));
|
||||
return dvVal.convertTo(DebugValue.class);
|
||||
}
|
||||
|
||||
protected void doGetValues(DebugRegisterSource source, ULONG ulCount, ULONG[] pulIndices,
|
||||
DEBUG_VALUE[] pValues) {
|
||||
if (source != DebugRegisterSource.DEBUG_REGSRC_DEBUGGEE) {
|
||||
throw new IllegalArgumentException("This interface only permits DEBUG_REGSRC_DEBUGGEE");
|
||||
}
|
||||
COMUtils.checkRC(jnaRegisters.GetValues(ulCount, pulIndices, new ULONG(0), pValues));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<Integer, DebugValue> getValues(DebugRegisterSource source,
|
||||
Collection<Integer> indices) {
|
||||
if (source != DebugRegisterSource.DEBUG_REGSRC_DEBUGGEE) {
|
||||
throw new IllegalArgumentException("This interface only permits DEBUG_REGSRC_DEBUGGEE");
|
||||
}
|
||||
if (indices.isEmpty()) {
|
||||
return Collections.emptyMap();
|
||||
}
|
||||
List<Integer> li = new ArrayList<>(indices);
|
||||
ULONG ulCount = new ULONG(li.size());
|
||||
ULONG[] pulIndices = new ULONG[li.size()];
|
||||
DEBUG_VALUE[] pValues = (DEBUG_VALUE[]) new DEBUG_VALUE().toArray(li.size());
|
||||
for (int i = 0; i < indices.size(); i++) {
|
||||
pulIndices[i] = new ULONG(li.get(i));
|
||||
}
|
||||
doGetValues(source, ulCount, pulIndices, pValues);
|
||||
Map<Integer, DebugValue> result = new LinkedHashMap<>();
|
||||
for (int i = 0; i < li.size(); i++) {
|
||||
result.put(li.get(i), pValues[i].convertTo(DebugValue.class));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setValue(int index, DebugValue value) {
|
||||
ULONG ulIndex = new ULONG(index);
|
||||
DEBUG_VALUE.ByReference dvVal = new DEBUG_VALUE.ByReference();
|
||||
DEBUG_VALUE.fromDebugValue(dvVal, value);
|
||||
COMUtils.checkRC(jnaRegisters.SetValue(ulIndex, dvVal));
|
||||
}
|
||||
|
||||
protected void doSetValues(DebugRegisterSource source, ULONG ulCount, ULONG[] pulIndices,
|
||||
DEBUG_VALUE[] pValues) {
|
||||
if (source != DebugRegisterSource.DEBUG_REGSRC_DEBUGGEE) {
|
||||
throw new IllegalArgumentException("This interface only permits DEBUG_REGSRC_DEBUGGEE");
|
||||
}
|
||||
|
||||
COMUtils.checkRC(jnaRegisters.SetValues(ulCount, pulIndices, new ULONG(0), pValues));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setValues(DebugRegisterSource source, Map<Integer, DebugValue> values) {
|
||||
if (values.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
ULONG ulCount = new ULONG(values.size());
|
||||
ULONG[] pulIndices = new ULONG[values.size()];
|
||||
DEBUG_VALUE[] pValues = (DEBUG_VALUE[]) new DEBUG_VALUE().toArray(values.size());
|
||||
int i = 0;
|
||||
for (Map.Entry<Integer, DebugValue> ent : values.entrySet()) {
|
||||
pulIndices[i] = new ULONG(ent.getKey());
|
||||
DEBUG_VALUE.fromDebugValue(pValues[i], ent.getValue());
|
||||
i++;
|
||||
}
|
||||
doSetValues(source, ulCount, pulIndices, pValues);
|
||||
}
|
||||
}
|
||||
@@ -1,50 +0,0 @@
|
||||
/* ###
|
||||
* 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 agent.dbgeng.impl.dbgeng.registers;
|
||||
|
||||
import com.sun.jna.platform.win32.WinDef.ULONG;
|
||||
|
||||
import agent.dbgeng.jna.dbgeng.DbgEngNative.DEBUG_VALUE;
|
||||
import agent.dbgeng.jna.dbgeng.registers.IDebugRegisters2;
|
||||
|
||||
import com.sun.jna.platform.win32.COM.COMUtils;
|
||||
|
||||
public class DebugRegistersImpl2 extends DebugRegistersImpl1 {
|
||||
private final IDebugRegisters2 jnaRegisters;
|
||||
|
||||
public DebugRegistersImpl2(IDebugRegisters2 jnaRegisters) {
|
||||
super(jnaRegisters);
|
||||
this.jnaRegisters = jnaRegisters;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doGetValues(DebugRegisterSource source, ULONG ulCount, ULONG[] pulIndices,
|
||||
DEBUG_VALUE[] pValues) {
|
||||
ULONG ulSource = new ULONG(source.ordinal());
|
||||
COMUtils
|
||||
.checkRC(
|
||||
jnaRegisters.GetValues2(ulSource, ulCount, pulIndices, new ULONG(0), pValues));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doSetValues(DebugRegisterSource source, ULONG ulCount, ULONG[] pulIndices,
|
||||
DEBUG_VALUE[] pValues) {
|
||||
ULONG ulSource = new ULONG(source.ordinal());
|
||||
COMUtils
|
||||
.checkRC(
|
||||
jnaRegisters.SetValues2(ulSource, ulCount, pulIndices, new ULONG(0), pValues));
|
||||
}
|
||||
}
|
||||
@@ -1,49 +0,0 @@
|
||||
/* ###
|
||||
* 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 agent.dbgeng.impl.dbgeng.registers;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import com.sun.jna.Pointer;
|
||||
|
||||
import agent.dbgeng.dbgeng.DebugRegisters;
|
||||
import agent.dbgeng.impl.dbgeng.DbgEngUtil;
|
||||
import agent.dbgeng.impl.dbgeng.DbgEngUtil.InterfaceSupplier;
|
||||
import agent.dbgeng.impl.dbgeng.DbgEngUtil.Preferred;
|
||||
import agent.dbgeng.jna.dbgeng.registers.*;
|
||||
import ghidra.util.datastruct.WeakValueHashMap;
|
||||
|
||||
public interface DebugRegistersInternal extends DebugRegisters {
|
||||
Map<Pointer, DebugRegistersInternal> CACHE = new WeakValueHashMap<>();
|
||||
|
||||
static DebugRegistersInternal instanceFor(WrapIDebugRegisters registers) {
|
||||
return DbgEngUtil.lazyWeakCache(CACHE, registers, DebugRegistersImpl1::new);
|
||||
}
|
||||
|
||||
static DebugRegistersInternal instanceFor(WrapIDebugRegisters2 registers) {
|
||||
return DbgEngUtil.lazyWeakCache(CACHE, registers, DebugRegistersImpl2::new);
|
||||
}
|
||||
|
||||
List<Preferred<WrapIDebugRegisters>> PREFERRED_REGISTERS_IIDS = List.of(
|
||||
new Preferred<>(IDebugRegisters2.IID_IDEBUG_REGISTERS2, WrapIDebugRegisters2.class),
|
||||
new Preferred<>(IDebugRegisters.IID_IDEBUG_REGISTERS, WrapIDebugRegisters.class));
|
||||
|
||||
static DebugRegistersInternal tryPreferredInterfaces(InterfaceSupplier supplier) {
|
||||
return DbgEngUtil.tryPreferredInterfaces(DebugRegistersInternal.class,
|
||||
PREFERRED_REGISTERS_IIDS, supplier);
|
||||
}
|
||||
}
|
||||
@@ -1,72 +0,0 @@
|
||||
/* ###
|
||||
* 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 agent.dbgeng.impl.dbgeng.symbols;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
import agent.dbgeng.dbgeng.DebugModule;
|
||||
import agent.dbgeng.dbgeng.DebugModuleInfo;
|
||||
|
||||
public class DebugModuleImpl implements DebugModule {
|
||||
private final DebugSymbolsInternal symbols;
|
||||
final int index;
|
||||
final long base;
|
||||
DebugModuleInfo info;
|
||||
|
||||
DebugModuleImpl(DebugSymbolsInternal symbols, int index, long base) {
|
||||
this.symbols = symbols;
|
||||
this.index = index;
|
||||
this.base = base;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(symbols, index, base);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (!(obj instanceof DebugModuleImpl)) {
|
||||
return false;
|
||||
}
|
||||
DebugModuleImpl that = (DebugModuleImpl) obj;
|
||||
if (!this.symbols.equals(that.symbols)) {
|
||||
return false;
|
||||
}
|
||||
if (this.index != that.index) {
|
||||
return false;
|
||||
}
|
||||
if (this.base != that.base) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName(DebugModuleName which) {
|
||||
return symbols.getModuleName(which, this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getIndex() {
|
||||
return index;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getBase() {
|
||||
return base;
|
||||
}
|
||||
}
|
||||
@@ -1,232 +0,0 @@
|
||||
/* ###
|
||||
* 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 agent.dbgeng.impl.dbgeng.symbols;
|
||||
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
|
||||
import com.sun.jna.Native;
|
||||
import com.sun.jna.platform.win32.WinDef.*;
|
||||
import com.sun.jna.platform.win32.COM.COMException;
|
||||
import com.sun.jna.platform.win32.COM.COMUtils;
|
||||
|
||||
import agent.dbgeng.dbgeng.*;
|
||||
import agent.dbgeng.dbgeng.DbgEng.OpaqueCleanable;
|
||||
import agent.dbgeng.dbgeng.DebugModule.DebugModuleName;
|
||||
import agent.dbgeng.impl.dbgeng.DbgEngUtil;
|
||||
import agent.dbgeng.jna.dbgeng.DbgEngNative.DEBUG_MODULE_PARAMETERS;
|
||||
import agent.dbgeng.jna.dbgeng.symbols.IDebugSymbols;
|
||||
|
||||
public class DebugSymbolsImpl1 implements DebugSymbolsInternal {
|
||||
@SuppressWarnings("unused")
|
||||
private final OpaqueCleanable cleanable;
|
||||
private final IDebugSymbols jnaSymbols;
|
||||
|
||||
public DebugSymbolsImpl1(IDebugSymbols jnaSymbols) {
|
||||
this.cleanable = DbgEng.releaseWhenPhantom(this, jnaSymbols);
|
||||
this.jnaSymbols = jnaSymbols;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getNumberLoadedModules() {
|
||||
ULONGByReference pulLoaded = new ULONGByReference();
|
||||
ULONGByReference pulUnloaded = new ULONGByReference();
|
||||
COMUtils.checkRC(jnaSymbols.GetNumberModules(pulLoaded, pulUnloaded));
|
||||
return pulLoaded.getValue().intValue();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getNumberUnloadedModules() {
|
||||
ULONGByReference pulLoaded = new ULONGByReference();
|
||||
ULONGByReference pulUnloaded = new ULONGByReference();
|
||||
COMUtils.checkRC(jnaSymbols.GetNumberModules(pulLoaded, pulUnloaded));
|
||||
return pulUnloaded.getValue().intValue();
|
||||
}
|
||||
|
||||
@Override
|
||||
public DebugModule getModuleByIndex(int index) {
|
||||
ULONG ulIndex = new ULONG(index);
|
||||
ULONGLONGByReference pullBase = new ULONGLONGByReference();
|
||||
COMUtils.checkRC(jnaSymbols.GetModuleByIndex(ulIndex, pullBase));
|
||||
return new DebugModuleImpl(this, index, pullBase.getValue().longValue());
|
||||
}
|
||||
|
||||
@Override
|
||||
public DebugModule getModuleByModuleName(String name, int startIndex) {
|
||||
ULONG ulStartIndex = new ULONG(startIndex);
|
||||
ULONGByReference pulIndex = new ULONGByReference();
|
||||
ULONGLONGByReference pullBase = new ULONGLONGByReference();
|
||||
COMUtils.checkRC(jnaSymbols.GetModuleByModuleName(name, ulStartIndex, pulIndex, pullBase));
|
||||
return new DebugModuleImpl(this, pulIndex.getValue().intValue(),
|
||||
pullBase.getValue().longValue());
|
||||
}
|
||||
|
||||
@Override
|
||||
public DebugModule getModuleByOffset(long offset, int startIndex) {
|
||||
ULONGLONG ullOffset = new ULONGLONG(offset);
|
||||
ULONG ulStartIndex = new ULONG(startIndex);
|
||||
ULONGByReference pulIndex = new ULONGByReference();
|
||||
ULONGLONGByReference pullBase = new ULONGLONGByReference();
|
||||
COMUtils.checkRC(jnaSymbols.GetModuleByOffset(ullOffset, ulStartIndex, pulIndex, pullBase));
|
||||
return new DebugModuleImpl(this, pulIndex.getValue().intValue(),
|
||||
pullBase.getValue().longValue());
|
||||
}
|
||||
|
||||
protected void callNamesForWhich(DebugModuleName which, ULONG Index, ULONGLONG Base,
|
||||
byte[] Buffer, ULONG BufferSize, ULONGByReference NameSize) {
|
||||
switch (which) {
|
||||
case IMAGE:
|
||||
COMUtils.checkRC(jnaSymbols.GetModuleNames(Index, Base, Buffer, BufferSize,
|
||||
NameSize, null, new ULONG(0), null, null, new ULONG(0), null));
|
||||
case MODULE:
|
||||
COMUtils.checkRC(jnaSymbols.GetModuleNames(Index, Base, null, new ULONG(0), null,
|
||||
Buffer, BufferSize, NameSize, null, new ULONG(0), null));
|
||||
case LOADED_IMAGE:
|
||||
COMUtils.checkRC(jnaSymbols.GetModuleNames(Index, Base, null, new ULONG(0), null,
|
||||
null, new ULONG(0), null, Buffer, BufferSize, NameSize));
|
||||
default:
|
||||
throw new UnsupportedOperationException("Interface does not support " + which);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getModuleName(DebugModuleName which, DebugModule module) {
|
||||
ULONGLONG ullBase = new ULONGLONG(module.getBase());
|
||||
ULONGByReference pulNameSize = new ULONGByReference();
|
||||
callNamesForWhich(which, DbgEngUtil.DEBUG_ANY_ID, ullBase, null, new ULONG(0), pulNameSize);
|
||||
byte[] aBuffer = new byte[pulNameSize.getValue().intValue()];
|
||||
callNamesForWhich(which, DbgEngUtil.DEBUG_ANY_ID, ullBase, aBuffer, pulNameSize.getValue(),
|
||||
null);
|
||||
return Native.toString(aBuffer);
|
||||
}
|
||||
|
||||
@Override
|
||||
public DebugModuleInfo getModuleParameters(int count, int startIndex) {
|
||||
ULONG ulCount = new ULONG(count);
|
||||
ULONG ulStartIndex = new ULONG(startIndex);
|
||||
DEBUG_MODULE_PARAMETERS.ByReference pInfo = new DEBUG_MODULE_PARAMETERS.ByReference();
|
||||
COMUtils.checkRC(jnaSymbols.GetModuleParameters(ulCount, null, ulStartIndex, pInfo));
|
||||
return new DebugModuleInfo(0L, pInfo.Base.longValue(), pInfo.Size.intValue(), "", "",
|
||||
pInfo.Checksum.intValue(), pInfo.TimeDateStamp.intValue());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterable<DebugSymbolName> iterateSymbolMatches(String pattern) {
|
||||
ULONGLONGByReference pullHandle = new ULONGLONGByReference();
|
||||
return new Iterable<DebugSymbolName>() {
|
||||
@Override
|
||||
public Iterator<DebugSymbolName> iterator() {
|
||||
COMUtils.checkRC(jnaSymbols.StartSymbolMatch(pattern, pullHandle));
|
||||
return new Iterator<DebugSymbolName>() {
|
||||
ULONGByReference pulMatchSize = new ULONGByReference();
|
||||
ULONGLONGByReference pullOffset = new ULONGLONGByReference();
|
||||
|
||||
@Override
|
||||
public boolean hasNext() {
|
||||
try {
|
||||
COMUtils.checkRC(jnaSymbols.GetNextSymbolMatch(pullHandle.getValue(),
|
||||
null, new ULONG(0), pulMatchSize, null));
|
||||
}
|
||||
catch (COMException e) {
|
||||
if (!COMUtilsExtra.isE_NOINTERFACE(e)) {
|
||||
throw e;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DebugSymbolName next() {
|
||||
try {
|
||||
if (pulMatchSize.getValue().intValue() == 0) {
|
||||
COMUtils.checkRC(jnaSymbols.GetNextSymbolMatch(
|
||||
pullHandle.getValue(), null, new ULONG(0), pulMatchSize, null));
|
||||
}
|
||||
byte[] aBuffer = new byte[pulMatchSize.getValue().intValue()];
|
||||
COMUtils.checkRC(jnaSymbols.GetNextSymbolMatch(pullHandle.getValue(),
|
||||
aBuffer, pulMatchSize.getValue(), null, pullOffset));
|
||||
return new DebugSymbolName(Native.toString(aBuffer),
|
||||
pullOffset.getValue().longValue());
|
||||
}
|
||||
catch (COMException e) {
|
||||
if (!COMUtilsExtra.isE_NOINTERFACE(e)) {
|
||||
throw e;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
finally {
|
||||
pulMatchSize.getValue().setValue(0);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void finalize() throws Throwable {
|
||||
COMUtils.checkRC(jnaSymbols.EndSymbolMatch(pullHandle.getValue()));
|
||||
}
|
||||
};
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<DebugSymbolId> getSymbolIdsByName(String pattern) {
|
||||
throw new UnsupportedOperationException("Not supported by this interface");
|
||||
}
|
||||
|
||||
@Override
|
||||
public DebugSymbolEntry getSymbolEntry(DebugSymbolId id) {
|
||||
throw new UnsupportedOperationException("Not supported by this interface");
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getSymbolPath() {
|
||||
ULONGByReference pulPathLength = new ULONGByReference();
|
||||
COMUtils.checkRC(jnaSymbols.GetSymbolPath(null, new ULONG(0), pulPathLength));
|
||||
byte[] aBuffer = new byte[pulPathLength.getValue().intValue()];
|
||||
COMUtils.checkRC(jnaSymbols.GetSymbolPath(aBuffer, pulPathLength.getValue(), null));
|
||||
return Native.toString(aBuffer);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setSymbolPath(String path) {
|
||||
//WString wPath = new WString(path);
|
||||
COMUtils.checkRC(jnaSymbols.SetSymbolPath(path));
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getSymbolOptions() {
|
||||
ULONGByReference pulOptions = new ULONGByReference();
|
||||
COMUtils.checkRC(jnaSymbols.GetSymbolPath(null, new ULONG(0), pulOptions));
|
||||
return pulOptions.getValue().intValue();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setSymbolOptions(int options) {
|
||||
ULONG ulOptions = new ULONG(options);
|
||||
COMUtils.checkRC(jnaSymbols.SetSymbolOptions(ulOptions));
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getCurrentScopeFrameIndex() {
|
||||
throw new UnsupportedOperationException("Not supported by this interface");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setCurrentScopeFrameIndex(int index) {
|
||||
throw new UnsupportedOperationException("Not supported by this interface");
|
||||
}
|
||||
}
|
||||
@@ -1,48 +0,0 @@
|
||||
/* ###
|
||||
* 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 agent.dbgeng.impl.dbgeng.symbols;
|
||||
|
||||
import com.sun.jna.Native;
|
||||
import com.sun.jna.platform.win32.WinDef.*;
|
||||
|
||||
import agent.dbgeng.dbgeng.DebugModule;
|
||||
import agent.dbgeng.dbgeng.DebugModule.DebugModuleName;
|
||||
import agent.dbgeng.impl.dbgeng.DbgEngUtil;
|
||||
import agent.dbgeng.jna.dbgeng.symbols.IDebugSymbols2;
|
||||
|
||||
import com.sun.jna.platform.win32.COM.COMUtils;
|
||||
|
||||
public class DebugSymbolsImpl2 extends DebugSymbolsImpl1 {
|
||||
private final IDebugSymbols2 jnaSymbols;
|
||||
|
||||
public DebugSymbolsImpl2(IDebugSymbols2 jnaSymbols) {
|
||||
super(jnaSymbols);
|
||||
this.jnaSymbols = jnaSymbols;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getModuleName(DebugModuleName which, DebugModule module) {
|
||||
ULONG ulWhich = new ULONG(which.ordinal());
|
||||
ULONGLONG ullBase = new ULONGLONG(module.getBase());
|
||||
ULONGByReference pulNameSize = new ULONGByReference();
|
||||
COMUtils.checkRC(jnaSymbols.GetModuleNameString(ulWhich, DbgEngUtil.DEBUG_ANY_ID, ullBase,
|
||||
null, new ULONG(0), pulNameSize));
|
||||
byte[] aBuffer = new byte[pulNameSize.getValue().intValue()];
|
||||
COMUtils.checkRC(jnaSymbols.GetModuleNameString(ulWhich, DbgEngUtil.DEBUG_ANY_ID, ullBase,
|
||||
aBuffer, pulNameSize.getValue(), null));
|
||||
return Native.toString(aBuffer);
|
||||
}
|
||||
}
|
||||
@@ -1,115 +0,0 @@
|
||||
/* ###
|
||||
* 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 agent.dbgeng.impl.dbgeng.symbols;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
import com.sun.jna.Native;
|
||||
import com.sun.jna.WString;
|
||||
import com.sun.jna.platform.win32.WinDef.*;
|
||||
import com.sun.jna.platform.win32.WinNT.HRESULT;
|
||||
import com.sun.jna.platform.win32.COM.COMUtils;
|
||||
|
||||
import agent.dbgeng.dbgeng.*;
|
||||
import agent.dbgeng.dbgeng.DebugModule.DebugModuleName;
|
||||
import agent.dbgeng.impl.dbgeng.DbgEngUtil;
|
||||
import agent.dbgeng.jna.dbgeng.DbgEngNative.DEBUG_MODULE_AND_ID;
|
||||
import agent.dbgeng.jna.dbgeng.DbgEngNative.DEBUG_SYMBOL_ENTRY;
|
||||
import agent.dbgeng.jna.dbgeng.symbols.IDebugSymbols3;
|
||||
|
||||
public class DebugSymbolsImpl3 extends DebugSymbolsImpl2 {
|
||||
private final IDebugSymbols3 jnaSymbols;
|
||||
|
||||
public DebugSymbolsImpl3(IDebugSymbols3 jnaSymbols) {
|
||||
super(jnaSymbols);
|
||||
this.jnaSymbols = jnaSymbols;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getCurrentScopeFrameIndex() {
|
||||
ULONGByReference pulIndex = new ULONGByReference();
|
||||
COMUtils.checkRC(jnaSymbols.GetCurrentScopeFrameIndex(pulIndex));
|
||||
return pulIndex.getValue().intValue();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setCurrentScopeFrameIndex(int index) {
|
||||
ULONG ulIndex = new ULONG(index);
|
||||
HRESULT hr = jnaSymbols.SetCurrentScopeFrameIndex(ulIndex);
|
||||
COMUtils.checkRC(hr);
|
||||
}
|
||||
|
||||
@Override
|
||||
public DebugModule getModuleByModuleName(String name, int startIndex) {
|
||||
ULONG ulStartIndex = new ULONG(startIndex);
|
||||
ULONGByReference pulIndex = new ULONGByReference();
|
||||
ULONGLONGByReference pullBase = new ULONGLONGByReference();
|
||||
COMUtils.checkRC(jnaSymbols.GetModuleByModuleNameWide(new WString(name), ulStartIndex,
|
||||
pulIndex, pullBase));
|
||||
return new DebugModuleImpl(this, pulIndex.getValue().intValue(),
|
||||
pullBase.getValue().longValue());
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getModuleName(DebugModuleName which, DebugModule module) {
|
||||
ULONG ulWhich = new ULONG(which.ordinal());
|
||||
ULONGLONG ullBase = new ULONGLONG(module.getBase());
|
||||
ULONGByReference pulNameSize = new ULONGByReference();
|
||||
COMUtils.checkRC(jnaSymbols.GetModuleNameStringWide(ulWhich, DbgEngUtil.DEBUG_ANY_ID,
|
||||
ullBase, null, new ULONG(0), pulNameSize));
|
||||
char[] aBuffer = new char[pulNameSize.getValue().intValue()];
|
||||
COMUtils.checkRC(jnaSymbols.GetModuleNameStringWide(ulWhich, DbgEngUtil.DEBUG_ANY_ID,
|
||||
ullBase, aBuffer, pulNameSize.getValue(), null));
|
||||
return Native.toString(aBuffer);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<DebugSymbolId> getSymbolIdsByName(String pattern) {
|
||||
ULONGByReference pulEntries = new ULONGByReference();
|
||||
WString wsPattern = new WString(pattern);
|
||||
COMUtils.checkRC(jnaSymbols.GetSymbolEntriesByNameWide(wsPattern, new ULONG(0), null,
|
||||
new ULONG(0), pulEntries));
|
||||
if (pulEntries.getValue().intValue() == 0) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
DEBUG_MODULE_AND_ID[] aIds = (DEBUG_MODULE_AND_ID[]) new DEBUG_MODULE_AND_ID()
|
||||
.toArray(pulEntries.getValue().intValue());
|
||||
COMUtils.checkRC(jnaSymbols.GetSymbolEntriesByNameWide(wsPattern, new ULONG(0), aIds,
|
||||
pulEntries.getValue(), null));
|
||||
List<DebugSymbolId> result = new ArrayList<>(aIds.length);
|
||||
for (int i = 0; i < aIds.length; i++) {
|
||||
result.add(new DebugSymbolId(aIds[i].ModuleBase.longValue(), aIds[i].Id.longValue()));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DebugSymbolEntry getSymbolEntry(DebugSymbolId id) {
|
||||
DEBUG_MODULE_AND_ID sId = new DEBUG_MODULE_AND_ID();
|
||||
sId.ModuleBase = new ULONGLONG(id.moduleBase);
|
||||
sId.Id = new ULONGLONG(id.symbolIndex);
|
||||
DEBUG_SYMBOL_ENTRY.ByReference pInfo = new DEBUG_SYMBOL_ENTRY.ByReference();
|
||||
COMUtils.checkRC(jnaSymbols.GetSymbolEntryInformation(sId, pInfo));
|
||||
// Get the name while I'm here
|
||||
char[] aName = new char[pInfo.NameSize.intValue() + 1];
|
||||
COMUtils.checkRC(jnaSymbols.GetSymbolEntryStringWide(sId, new ULONG(0), aName,
|
||||
new ULONG(aName.length), null));
|
||||
return new DebugSymbolEntry(pInfo.ModuleBase.longValue(), pInfo.Offset.longValue(),
|
||||
pInfo.Id.longValue(), pInfo.Size.longValue(), pInfo.Flags.intValue(),
|
||||
pInfo.TypeId.intValue()/* TODO */, Native.toString(aName),
|
||||
pInfo.Tag.intValue()/* TODO */);
|
||||
}
|
||||
}
|
||||
@@ -1,28 +0,0 @@
|
||||
/* ###
|
||||
* 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 agent.dbgeng.impl.dbgeng.symbols;
|
||||
|
||||
import agent.dbgeng.jna.dbgeng.symbols.IDebugSymbols4;
|
||||
|
||||
public class DebugSymbolsImpl4 extends DebugSymbolsImpl3 {
|
||||
@SuppressWarnings("unused")
|
||||
private final IDebugSymbols4 jnaSymbols;
|
||||
|
||||
public DebugSymbolsImpl4(IDebugSymbols4 jnaSymbols) {
|
||||
super(jnaSymbols);
|
||||
this.jnaSymbols = jnaSymbols;
|
||||
}
|
||||
}
|
||||
@@ -1,28 +0,0 @@
|
||||
/* ###
|
||||
* 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 agent.dbgeng.impl.dbgeng.symbols;
|
||||
|
||||
import agent.dbgeng.jna.dbgeng.symbols.IDebugSymbols5;
|
||||
|
||||
public class DebugSymbolsImpl5 extends DebugSymbolsImpl4 {
|
||||
@SuppressWarnings("unused")
|
||||
private final IDebugSymbols5 jnaSymbols;
|
||||
|
||||
public DebugSymbolsImpl5(IDebugSymbols5 jnaSymbols) {
|
||||
super(jnaSymbols);
|
||||
this.jnaSymbols = jnaSymbols;
|
||||
}
|
||||
}
|
||||
@@ -1,71 +0,0 @@
|
||||
/* ###
|
||||
* 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 agent.dbgeng.impl.dbgeng.symbols;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import com.sun.jna.Pointer;
|
||||
|
||||
import agent.dbgeng.dbgeng.*;
|
||||
import agent.dbgeng.dbgeng.DebugModule.DebugModuleName;
|
||||
import agent.dbgeng.impl.dbgeng.DbgEngUtil;
|
||||
import agent.dbgeng.impl.dbgeng.DbgEngUtil.InterfaceSupplier;
|
||||
import agent.dbgeng.impl.dbgeng.DbgEngUtil.Preferred;
|
||||
import agent.dbgeng.jna.dbgeng.symbols.*;
|
||||
import ghidra.util.datastruct.WeakValueHashMap;
|
||||
|
||||
public interface DebugSymbolsInternal extends DebugSymbols {
|
||||
final Map<Pointer, DebugSymbolsInternal> CACHE = new WeakValueHashMap<>();
|
||||
|
||||
static DebugSymbolsInternal instanceFor(WrapIDebugSymbols symbols) {
|
||||
return DbgEngUtil.lazyWeakCache(CACHE, symbols, DebugSymbolsImpl1::new);
|
||||
}
|
||||
|
||||
static DebugSymbolsInternal instanceFor(WrapIDebugSymbols2 symbols) {
|
||||
return DbgEngUtil.lazyWeakCache(CACHE, symbols, DebugSymbolsImpl2::new);
|
||||
}
|
||||
|
||||
static DebugSymbolsInternal instanceFor(WrapIDebugSymbols3 symbols) {
|
||||
return DbgEngUtil.lazyWeakCache(CACHE, symbols, DebugSymbolsImpl3::new);
|
||||
}
|
||||
|
||||
static DebugSymbolsInternal instanceFor(WrapIDebugSymbols4 symbols) {
|
||||
return DbgEngUtil.lazyWeakCache(CACHE, symbols, DebugSymbolsImpl4::new);
|
||||
}
|
||||
|
||||
static DebugSymbolsInternal instanceFor(WrapIDebugSymbols5 symbols) {
|
||||
return DbgEngUtil.lazyWeakCache(CACHE, symbols, DebugSymbolsImpl5::new);
|
||||
}
|
||||
|
||||
List<Preferred<WrapIDebugSymbols>> PREFFERED_SYMBOLS_IIDS = List.of(
|
||||
new Preferred<>(IDebugSymbols5.IID_IDEBUG_SYMBOLS5, WrapIDebugSymbols5.class),
|
||||
new Preferred<>(IDebugSymbols4.IID_IDEBUG_SYMBOLS4, WrapIDebugSymbols4.class),
|
||||
new Preferred<>(IDebugSymbols3.IID_IDEBUG_SYMBOLS3, WrapIDebugSymbols3.class),
|
||||
new Preferred<>(IDebugSymbols2.IID_IDEBUG_SYMBOLS2, WrapIDebugSymbols2.class),
|
||||
new Preferred<>(IDebugSymbols.IID_IDEBUG_SYMBOLS, WrapIDebugSymbols.class));
|
||||
|
||||
static DebugSymbolsInternal tryPreferredInterfaces(InterfaceSupplier supplier) {
|
||||
return DbgEngUtil.tryPreferredInterfaces(DebugSymbolsInternal.class, PREFFERED_SYMBOLS_IIDS,
|
||||
supplier);
|
||||
}
|
||||
|
||||
String getModuleName(DebugModuleName which, DebugModule module);
|
||||
|
||||
@Override
|
||||
DebugModuleInfo getModuleParameters(int count, int startIndex);
|
||||
|
||||
}
|
||||
@@ -1,323 +0,0 @@
|
||||
/* ###
|
||||
* 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 agent.dbgeng.impl.dbgeng.sysobj;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import com.sun.jna.platform.win32.WinDef.ULONG;
|
||||
import com.sun.jna.platform.win32.WinDef.ULONGByReference;
|
||||
import com.sun.jna.platform.win32.WinDef.ULONGLONG;
|
||||
import com.sun.jna.platform.win32.WinDef.ULONGLONGByReference;
|
||||
import com.sun.jna.platform.win32.WinNT.HRESULT;
|
||||
import com.sun.jna.Native;
|
||||
import com.sun.jna.platform.win32.COM.COMUtils;
|
||||
|
||||
import agent.dbgeng.dbgeng.COMUtilsExtra;
|
||||
import agent.dbgeng.dbgeng.DbgEng;
|
||||
import agent.dbgeng.dbgeng.DbgEng.OpaqueCleanable;
|
||||
import agent.dbgeng.dbgeng.DebugProcessId;
|
||||
import agent.dbgeng.dbgeng.DebugProcessRecord;
|
||||
import agent.dbgeng.dbgeng.DebugSessionId;
|
||||
import agent.dbgeng.dbgeng.DebugThreadId;
|
||||
import agent.dbgeng.dbgeng.DebugThreadRecord;
|
||||
import agent.dbgeng.jna.dbgeng.sysobj.IDebugSystemObjects;
|
||||
|
||||
public class DebugSystemObjectsImpl1 implements DebugSystemObjectsInternal {
|
||||
@SuppressWarnings("unused")
|
||||
private final OpaqueCleanable cleanable;
|
||||
private final IDebugSystemObjects jnaSysobj;
|
||||
|
||||
public DebugSystemObjectsImpl1(IDebugSystemObjects jnaSysobj) {
|
||||
this.cleanable = DbgEng.releaseWhenPhantom(this, jnaSysobj);
|
||||
this.jnaSysobj = jnaSysobj;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DebugThreadId getEventThread() {
|
||||
ULONGByReference pulId = new ULONGByReference();
|
||||
HRESULT hr = jnaSysobj.GetEventThread(pulId);
|
||||
if (hr.equals(COMUtilsExtra.E_UNEXPECTED)) {
|
||||
return new DebugThreadRecord(-1);
|
||||
}
|
||||
COMUtils.checkRC(hr);
|
||||
return new DebugThreadRecord(pulId.getValue().intValue());
|
||||
}
|
||||
|
||||
@Override
|
||||
public DebugProcessId getEventProcess() {
|
||||
ULONGByReference pulId = new ULONGByReference();
|
||||
HRESULT hr = jnaSysobj.GetEventProcess(pulId);
|
||||
if (hr.equals(COMUtilsExtra.E_UNEXPECTED)) {
|
||||
return new DebugProcessRecord(-1);
|
||||
}
|
||||
COMUtils.checkRC(hr);
|
||||
return new DebugProcessRecord(pulId.getValue().intValue());
|
||||
}
|
||||
|
||||
@Override
|
||||
public DebugThreadId getCurrentThreadId() {
|
||||
ULONGByReference pulId = new ULONGByReference();
|
||||
HRESULT hr = jnaSysobj.GetCurrentThreadId(pulId);
|
||||
if (hr.equals(COMUtilsExtra.E_UNEXPECTED)) {
|
||||
return new DebugThreadRecord(-1);
|
||||
}
|
||||
COMUtils.checkRC(hr);
|
||||
return new DebugThreadRecord(pulId.getValue().intValue());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setCurrentThreadId(DebugThreadId id) {
|
||||
HRESULT hr = jnaSysobj.SetCurrentThreadId(new ULONG(id.value()));
|
||||
if (!hr.equals(COMUtilsExtra.E_UNEXPECTED) && !hr.equals(COMUtilsExtra.E_NOINTERFACE)) {
|
||||
COMUtils.checkRC(hr);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public DebugProcessId getCurrentProcessId() {
|
||||
ULONGByReference pulId = new ULONGByReference();
|
||||
HRESULT hr = jnaSysobj.GetCurrentProcessId(pulId);
|
||||
if (hr.equals(COMUtilsExtra.E_UNEXPECTED)) {
|
||||
return new DebugProcessRecord(-1);
|
||||
}
|
||||
COMUtils.checkRC(hr);
|
||||
return new DebugProcessRecord(pulId.getValue().intValue());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setCurrentProcessId(DebugProcessId id) {
|
||||
HRESULT hr = jnaSysobj.SetCurrentProcessId(new ULONG(id.value()));
|
||||
if (hr.equals(COMUtilsExtra.E_UNEXPECTED)) {
|
||||
//System.err.println("Failure on setCurrentProcessId(" + id + ")");
|
||||
return;
|
||||
}
|
||||
if (hr.equals(COMUtilsExtra.E_NOINTERFACE)) {
|
||||
return;
|
||||
}
|
||||
COMUtils.checkRC(hr);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getNumberThreads() {
|
||||
ULONGByReference pulNumber = new ULONGByReference();
|
||||
HRESULT hr = jnaSysobj.GetNumberThreads(pulNumber);
|
||||
if (hr.equals(COMUtilsExtra.E_UNEXPECTED)) {
|
||||
return 0;
|
||||
}
|
||||
COMUtils.checkRC(hr);
|
||||
return pulNumber.getValue().intValue();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getTotalNumberThreads() {
|
||||
ULONGByReference pulTotal = new ULONGByReference();
|
||||
ULONGByReference pulLargestProcess = new ULONGByReference();
|
||||
COMUtils.checkRC(jnaSysobj.GetTotalNumberThreads(pulTotal, pulLargestProcess));
|
||||
return pulTotal.getValue().intValue();
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<DebugThreadId> getThreads(int start, int count) {
|
||||
if (count == 0) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
// TODO: Does dbgeng do the bounds checking?
|
||||
ULONG ulStart = new ULONG(start);
|
||||
ULONG ulCount = new ULONG(count);
|
||||
ULONG[] aulIds = new ULONG[count];
|
||||
COMUtils.checkRC(jnaSysobj.GetThreadIdsByIndex(ulStart, ulCount, aulIds, null));
|
||||
List<DebugThreadId> result = new ArrayList<>(count);
|
||||
for (int i = 0; i < count; i++) {
|
||||
result.add(new DebugThreadRecord(aulIds[i].intValue()));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DebugThreadId getThreadIdByHandle(long handle) {
|
||||
ULONGLONG ullHandle = new ULONGLONG(handle);
|
||||
ULONGByReference pulId = new ULONGByReference();
|
||||
COMUtils.checkRC(jnaSysobj.GetThreadIdByHandle(ullHandle, pulId));
|
||||
return new DebugThreadRecord(pulId.getValue().intValue());
|
||||
}
|
||||
|
||||
@Override
|
||||
public DebugThreadId getThreadIdBySystemId(int systemId) {
|
||||
ULONG ulHandle = new ULONG(systemId);
|
||||
ULONGByReference pulId = new ULONGByReference();
|
||||
HRESULT hr = jnaSysobj.GetThreadIdBySystemId(ulHandle, pulId);
|
||||
if (hr.equals(COMUtilsExtra.E_UNEXPECTED) || hr.equals(COMUtilsExtra.E_NOTIMPLEMENTED) ||
|
||||
hr.equals(COMUtilsExtra.E_NOINTERFACE)) {
|
||||
return null;
|
||||
}
|
||||
COMUtils.checkRC(hr);
|
||||
return new DebugThreadRecord(pulId.getValue().intValue());
|
||||
}
|
||||
|
||||
@Override
|
||||
public DebugProcessId getProcessIdByHandle(long handle) {
|
||||
ULONGLONG ullHandle = new ULONGLONG(handle);
|
||||
ULONGByReference pulId = new ULONGByReference();
|
||||
COMUtils.checkRC(jnaSysobj.GetProcessIdByHandle(ullHandle, pulId));
|
||||
return new DebugProcessRecord(pulId.getValue().intValue());
|
||||
}
|
||||
|
||||
@Override
|
||||
public DebugProcessId getProcessIdBySystemId(int systemId) {
|
||||
ULONG ulHandle = new ULONG(systemId);
|
||||
ULONGByReference pulId = new ULONGByReference();
|
||||
HRESULT hr = jnaSysobj.GetProcessIdBySystemId(ulHandle, pulId);
|
||||
if (hr.equals(COMUtilsExtra.E_UNEXPECTED) || hr.equals(COMUtilsExtra.E_NOTIMPLEMENTED) ||
|
||||
hr.equals(COMUtilsExtra.E_NOINTERFACE)) {
|
||||
return null;
|
||||
}
|
||||
COMUtils.checkRC(hr);
|
||||
return new DebugProcessRecord(pulId.getValue().intValue());
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getNumberProcesses() {
|
||||
ULONGByReference pulNumber = new ULONGByReference();
|
||||
HRESULT hr = jnaSysobj.GetNumberProcesses(pulNumber);
|
||||
if (hr.equals(COMUtilsExtra.E_UNEXPECTED)) {
|
||||
return -1;
|
||||
}
|
||||
COMUtils.checkRC(hr);
|
||||
return pulNumber.getValue().intValue();
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<DebugProcessId> getProcesses(int start, int count) {
|
||||
if (count == 0) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
// TODO: Does dbgeng do the bounds checking?
|
||||
ULONG ulStart = new ULONG(start);
|
||||
ULONG ulCount = new ULONG(count);
|
||||
ULONG[] aulIds = new ULONG[count];
|
||||
COMUtils.checkRC(jnaSysobj.GetProcessIdsByIndex(ulStart, ulCount, aulIds, null));
|
||||
List<DebugProcessId> result = new ArrayList<>(count);
|
||||
for (int i = 0; i < count; i++) {
|
||||
result.add(new DebugProcessRecord(aulIds[i].intValue()));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getCurrentThreadSystemId() {
|
||||
ULONGByReference pulSysId = new ULONGByReference();
|
||||
HRESULT hr = jnaSysobj.GetCurrentThreadSystemId(pulSysId);
|
||||
if (hr.equals(COMUtilsExtra.E_UNEXPECTED) || hr.equals(COMUtilsExtra.E_NOTIMPLEMENTED)) {
|
||||
return -1;
|
||||
}
|
||||
COMUtils.checkRC(hr);
|
||||
return pulSysId.getValue().intValue();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getCurrentProcessSystemId() {
|
||||
ULONGByReference pulSysId = new ULONGByReference();
|
||||
HRESULT hr = jnaSysobj.GetCurrentProcessSystemId(pulSysId);
|
||||
if (hr.equals(COMUtilsExtra.E_UNEXPECTED) || hr.equals(COMUtilsExtra.E_NOTIMPLEMENTED)) {
|
||||
return -1;
|
||||
}
|
||||
COMUtils.checkRC(hr);
|
||||
return pulSysId.getValue().intValue();
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getCurrentThreadDataOffset() {
|
||||
ULONGLONGByReference pulSysOffset = new ULONGLONGByReference();
|
||||
HRESULT hr = jnaSysobj.GetCurrentThreadDataOffset(pulSysOffset);
|
||||
if (hr.equals(COMUtilsExtra.E_UNEXPECTED) || hr.equals(COMUtilsExtra.E_NOTIMPLEMENTED)) {
|
||||
return -1;
|
||||
}
|
||||
COMUtils.checkRC(hr);
|
||||
return pulSysOffset.getValue().longValue();
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getCurrentProcessDataOffset() {
|
||||
ULONGLONGByReference pulSysOffset = new ULONGLONGByReference();
|
||||
HRESULT hr = jnaSysobj.GetCurrentProcessDataOffset(pulSysOffset);
|
||||
if (hr.equals(COMUtilsExtra.E_UNEXPECTED) || hr.equals(COMUtilsExtra.E_NOTIMPLEMENTED)) {
|
||||
return -1;
|
||||
}
|
||||
COMUtils.checkRC(hr);
|
||||
return pulSysOffset.getValue().longValue();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getCurrentProcessExecutableName() {
|
||||
ULONGByReference pulPathLength = new ULONGByReference();
|
||||
COMUtils.checkRC(jnaSysobj.GetCurrentProcessExecutableName(null, new ULONG(0), pulPathLength));
|
||||
byte[] aBuffer = new byte[pulPathLength.getValue().intValue()];
|
||||
HRESULT hr = jnaSysobj.GetCurrentProcessExecutableName(aBuffer, pulPathLength.getValue(), null);
|
||||
if (hr.equals(COMUtilsExtra.E_UNEXPECTED) || hr.equals(COMUtilsExtra.E_NOTIMPLEMENTED)) {
|
||||
return null;
|
||||
}
|
||||
return Native.toString(aBuffer);
|
||||
}
|
||||
|
||||
@Override
|
||||
public DebugSessionId getEventSystem() {
|
||||
throw new UnsupportedOperationException("Not supported by this interface");
|
||||
}
|
||||
|
||||
@Override
|
||||
public DebugSessionId getCurrentSystemId() {
|
||||
throw new UnsupportedOperationException("Not supported by this interface");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setCurrentSystemId(DebugSessionId id) {
|
||||
throw new UnsupportedOperationException("Not supported by this interface");
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getNumberSystems() {
|
||||
throw new UnsupportedOperationException("Not supported by this interface");
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<DebugSessionId> getSystems(int start, int count) {
|
||||
throw new UnsupportedOperationException("Not supported by this interface");
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getImplicitThreadDataOffset() {
|
||||
throw new UnsupportedOperationException("Not supported by this interface");
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getImplicitProcessDataOffset() {
|
||||
throw new UnsupportedOperationException("Not supported by this interface");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setImplicitThreadDataOffset(long offset) {
|
||||
throw new UnsupportedOperationException("Not supported by this interface");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setImplicitProcessDataOffset(long offset) {
|
||||
throw new UnsupportedOperationException("Not supported by this interface");
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -1,75 +0,0 @@
|
||||
/* ###
|
||||
* 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 agent.dbgeng.impl.dbgeng.sysobj;
|
||||
|
||||
import com.sun.jna.platform.win32.COM.COMUtils;
|
||||
import com.sun.jna.platform.win32.WinDef.ULONGLONG;
|
||||
import com.sun.jna.platform.win32.WinDef.ULONGLONGByReference;
|
||||
import com.sun.jna.platform.win32.WinNT.HRESULT;
|
||||
|
||||
import agent.dbgeng.dbgeng.COMUtilsExtra;
|
||||
import agent.dbgeng.jna.dbgeng.sysobj.IDebugSystemObjects2;
|
||||
|
||||
public class DebugSystemObjectsImpl2 extends DebugSystemObjectsImpl1 {
|
||||
@SuppressWarnings("unused")
|
||||
private final IDebugSystemObjects2 jnaSysobj;
|
||||
|
||||
public DebugSystemObjectsImpl2(IDebugSystemObjects2 jnaSysobj) {
|
||||
super(jnaSysobj);
|
||||
this.jnaSysobj = jnaSysobj;
|
||||
}
|
||||
|
||||
public long getImplicitThreadDataOffset() {
|
||||
ULONGLONGByReference pulSysOffset = new ULONGLONGByReference();
|
||||
HRESULT hr = jnaSysobj.GetImplicitThreadDataOffset(pulSysOffset);
|
||||
if (hr.equals(COMUtilsExtra.E_UNEXPECTED) || hr.equals(COMUtilsExtra.E_NOTIMPLEMENTED)) {
|
||||
return -1;
|
||||
}
|
||||
COMUtils.checkRC(hr);
|
||||
return pulSysOffset.getValue().longValue();
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getImplicitProcessDataOffset() {
|
||||
ULONGLONGByReference pulSysOffset = new ULONGLONGByReference();
|
||||
HRESULT hr = jnaSysobj.GetImplicitProcessDataOffset(pulSysOffset);
|
||||
if (hr.equals(COMUtilsExtra.E_UNEXPECTED) || hr.equals(COMUtilsExtra.E_NOTIMPLEMENTED)) {
|
||||
return -1;
|
||||
}
|
||||
COMUtils.checkRC(hr);
|
||||
return pulSysOffset.getValue().longValue();
|
||||
}
|
||||
|
||||
public void setImplicitThreadDataOffset(long offset) {
|
||||
ULONGLONG ulSysOffset = new ULONGLONG(offset);
|
||||
HRESULT hr = jnaSysobj.SetImplicitThreadDataOffset(ulSysOffset);
|
||||
if (hr.equals(COMUtilsExtra.E_UNEXPECTED) || hr.equals(COMUtilsExtra.E_NOTIMPLEMENTED)) {
|
||||
return;
|
||||
}
|
||||
COMUtils.checkRC(hr);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setImplicitProcessDataOffset(long offset) {
|
||||
ULONGLONG ulSysOffset = new ULONGLONG(offset);
|
||||
HRESULT hr = jnaSysobj.SetImplicitProcessDataOffset(ulSysOffset);
|
||||
if (hr.equals(COMUtilsExtra.E_UNEXPECTED) || hr.equals(COMUtilsExtra.E_NOTIMPLEMENTED)) {
|
||||
return;
|
||||
}
|
||||
COMUtils.checkRC(hr);
|
||||
}
|
||||
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user