mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2024-11-23 20:59:58 +00:00
GP-3142: fix for read registers
GP-3142: adding Populate to schema GP-3142: adding session id to the records GP-3142: post-review id->record GP-3142: post-review id->record GP-3142: post-review adds to interface GP-3142: post-review try-finally (missed two) GP-3142: post-review try-finally (missed one) GP-3142: post-review try-finally; clearer reset logic GP-3142: post-review better use of TargetMethod.Export GP-3142: minor fixes GP-3142: first pass at dbgeng kernel mods GP-3142: temp holdGP-3142: mods to differentiate system and engine idsGP-3142: fixes for bad system/engine differentationGP-3142: fixes for bad pid/tid <0 testGP-3142: fixes for selection logicGP-3142: attempting to mininize work done, esp. by expensive callsGP-3142: fix for stack framesGP-3142: minor bug fix for sys threadsGP-3142: better register/stack reads for non-system threadsGP-3142: warningsGP-3142: post-squash and rebaseGP-3142: missed a few RefreshBehavior candidatesGP-3142: miscellaneous fixesGP-3142: minimize workloadGP-3142: display fixes; refresh==true for resolved process/threadGP-3142: added re-populate methodsGP-3142: better kernel/user code re-useGP-3142: re-fix for fact that thread 0 belongs to process 0
This commit is contained in:
parent
18bf2fbe30
commit
9690254616
@ -27,8 +27,8 @@ public class DebugEventInformation {
|
||||
|
||||
public DebugEventInformation(int type, int pid, int tid) {
|
||||
this.type = type;
|
||||
this.pid = new DebugProcessId(pid);
|
||||
this.tid = new DebugThreadId(tid);
|
||||
this.pid = new DebugProcessRecord(pid);
|
||||
this.tid = new DebugThreadRecord(tid);
|
||||
}
|
||||
|
||||
public int getType() {
|
||||
|
@ -25,37 +25,14 @@ package agent.dbgeng.dbgeng;
|
||||
* with other integral values. In particular, this prevents confusion of engine PIDs with system
|
||||
* PIDs.
|
||||
*/
|
||||
public class DebugProcessId implements Comparable<DebugProcessId> {
|
||||
public final long id;
|
||||
|
||||
public DebugProcessId(long id) {
|
||||
this.id = id;
|
||||
}
|
||||
public interface DebugProcessId extends Comparable<DebugProcessId> {
|
||||
|
||||
public String id();
|
||||
public long value();
|
||||
public boolean isSystem();
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Long.hashCode(id);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (!(obj instanceof DebugProcessId)) {
|
||||
return false;
|
||||
}
|
||||
DebugProcessId that = (DebugProcessId) obj;
|
||||
if (this.id != that.id) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int compareTo(DebugProcessId that) {
|
||||
return Long.compare(this.id, that.id);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "<dbgeng.dll Engine PID " + id + ">";
|
||||
public default int compareTo(DebugProcessId that) {
|
||||
return this.id().compareTo(that.id());
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,34 @@
|
||||
/* ###
|
||||
* 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) + ">";
|
||||
}
|
||||
}
|
@ -25,37 +25,14 @@ package agent.dbgeng.dbgeng;
|
||||
* with other integral values. In particular, this prevents confusion of engine PIDs with system
|
||||
* PIDs.
|
||||
*/
|
||||
public class DebugSessionId implements Comparable<DebugSessionId> {
|
||||
public final int id;
|
||||
|
||||
public DebugSessionId(int id) {
|
||||
this.id = id;
|
||||
}
|
||||
public interface DebugSessionId extends Comparable<DebugSessionId> {
|
||||
|
||||
public String id();
|
||||
public long value();
|
||||
public boolean isSystem();
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Integer.hashCode(id);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (!(obj instanceof DebugSessionId)) {
|
||||
return false;
|
||||
}
|
||||
DebugSessionId that = (DebugSessionId) obj;
|
||||
if (this.id != that.id) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int compareTo(DebugSessionId that) {
|
||||
return Integer.compare(this.id, that.id);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "<dbgeng.dll Engine SYSID " + id + ">";
|
||||
public default int compareTo(DebugSessionId that) {
|
||||
return this.id().compareTo(that.id());
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,34 @@
|
||||
/* ###
|
||||
* 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) + ">";
|
||||
}
|
||||
}
|
@ -0,0 +1,34 @@
|
||||
/* ###
|
||||
* 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) + ">";
|
||||
}
|
||||
}
|
@ -0,0 +1,34 @@
|
||||
/* ###
|
||||
* 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) + ">";
|
||||
}
|
||||
}
|
@ -0,0 +1,34 @@
|
||||
/* ###
|
||||
* 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) + ">";
|
||||
}
|
||||
}
|
@ -25,37 +25,15 @@ package agent.dbgeng.dbgeng;
|
||||
* with other integral values. In particular, this prevents confusion of engine TIDs with system
|
||||
* TIDs.
|
||||
*/
|
||||
public class DebugThreadId implements Comparable<DebugThreadId> {
|
||||
public final long id;
|
||||
|
||||
public DebugThreadId(long id) {
|
||||
this.id = id;
|
||||
}
|
||||
public interface DebugThreadId extends Comparable<DebugThreadId> {
|
||||
|
||||
public String id();
|
||||
public long value();
|
||||
public boolean isSystem();
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Long.hashCode(id);
|
||||
public default int compareTo(DebugThreadId that) {
|
||||
return this.id().compareTo(that.id());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (!(obj instanceof DebugThreadId)) {
|
||||
return false;
|
||||
}
|
||||
DebugThreadId that = (DebugThreadId) obj;
|
||||
if (this.id != that.id) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int compareTo(DebugThreadId that) {
|
||||
return Long.compare(this.id, that.id);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "<dbgeng.dll Engine TID " + id + ">";
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,34 @@
|
||||
/* ###
|
||||
* 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) + ">";
|
||||
}
|
||||
}
|
@ -38,7 +38,7 @@ public class DebugAdvancedImpl2 extends DebugAdvancedImpl1 {
|
||||
public DebugThreadBasicInformation getThreadBasicInformation(DebugThreadId tid) {
|
||||
ULONG ulWhich = new ULONG(WhichSystemObjectInformation.THREAD_BASIC_INFORMATION.ordinal());
|
||||
ULONGLONG ullUnused = new ULONGLONG(0);
|
||||
ULONG ulThreadId = new ULONG(tid.id);
|
||||
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,
|
||||
|
@ -15,14 +15,25 @@
|
||||
*/
|
||||
package agent.dbgeng.impl.dbgeng.sysobj;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import com.sun.jna.platform.win32.WinDef.*;
|
||||
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.platform.win32.COM.COMUtils;
|
||||
|
||||
import agent.dbgeng.dbgeng.*;
|
||||
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 {
|
||||
@ -40,10 +51,10 @@ public class DebugSystemObjectsImpl1 implements DebugSystemObjectsInternal {
|
||||
ULONGByReference pulId = new ULONGByReference();
|
||||
HRESULT hr = jnaSysobj.GetEventThread(pulId);
|
||||
if (hr.equals(COMUtilsExtra.E_UNEXPECTED)) {
|
||||
return new DebugThreadId(-1);
|
||||
return new DebugThreadRecord(-1);
|
||||
}
|
||||
COMUtils.checkRC(hr);
|
||||
return new DebugThreadId(pulId.getValue().intValue());
|
||||
return new DebugThreadRecord(pulId.getValue().intValue());
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -51,10 +62,10 @@ public class DebugSystemObjectsImpl1 implements DebugSystemObjectsInternal {
|
||||
ULONGByReference pulId = new ULONGByReference();
|
||||
HRESULT hr = jnaSysobj.GetEventProcess(pulId);
|
||||
if (hr.equals(COMUtilsExtra.E_UNEXPECTED)) {
|
||||
return new DebugProcessId(-1);
|
||||
return new DebugProcessRecord(-1);
|
||||
}
|
||||
COMUtils.checkRC(hr);
|
||||
return new DebugProcessId(pulId.getValue().intValue());
|
||||
return new DebugProcessRecord(pulId.getValue().intValue());
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -62,15 +73,15 @@ public class DebugSystemObjectsImpl1 implements DebugSystemObjectsInternal {
|
||||
ULONGByReference pulId = new ULONGByReference();
|
||||
HRESULT hr = jnaSysobj.GetCurrentThreadId(pulId);
|
||||
if (hr.equals(COMUtilsExtra.E_UNEXPECTED)) {
|
||||
return new DebugThreadId(-1);
|
||||
return new DebugThreadRecord(-1);
|
||||
}
|
||||
COMUtils.checkRC(hr);
|
||||
return new DebugThreadId(pulId.getValue().intValue());
|
||||
return new DebugThreadRecord(pulId.getValue().intValue());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setCurrentThreadId(DebugThreadId id) {
|
||||
HRESULT hr = jnaSysobj.SetCurrentThreadId(new ULONG(id.id));
|
||||
HRESULT hr = jnaSysobj.SetCurrentThreadId(new ULONG(id.value()));
|
||||
if (!hr.equals(COMUtilsExtra.E_UNEXPECTED) && !hr.equals(COMUtilsExtra.E_NOINTERFACE)) {
|
||||
COMUtils.checkRC(hr);
|
||||
}
|
||||
@ -81,15 +92,15 @@ public class DebugSystemObjectsImpl1 implements DebugSystemObjectsInternal {
|
||||
ULONGByReference pulId = new ULONGByReference();
|
||||
HRESULT hr = jnaSysobj.GetCurrentProcessId(pulId);
|
||||
if (hr.equals(COMUtilsExtra.E_UNEXPECTED)) {
|
||||
return new DebugProcessId(-1);
|
||||
return new DebugProcessRecord(-1);
|
||||
}
|
||||
COMUtils.checkRC(hr);
|
||||
return new DebugProcessId(pulId.getValue().intValue());
|
||||
return new DebugProcessRecord(pulId.getValue().intValue());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setCurrentProcessId(DebugProcessId id) {
|
||||
HRESULT hr = jnaSysobj.SetCurrentProcessId(new ULONG(id.id));
|
||||
HRESULT hr = jnaSysobj.SetCurrentProcessId(new ULONG(id.value()));
|
||||
if (hr.equals(COMUtilsExtra.E_UNEXPECTED)) {
|
||||
//System.err.println("Failure on setCurrentProcessId(" + id + ")");
|
||||
return;
|
||||
@ -131,7 +142,7 @@ public class DebugSystemObjectsImpl1 implements DebugSystemObjectsInternal {
|
||||
COMUtils.checkRC(jnaSysobj.GetThreadIdsByIndex(ulStart, ulCount, aulIds, null));
|
||||
List<DebugThreadId> result = new ArrayList<>(count);
|
||||
for (int i = 0; i < count; i++) {
|
||||
result.add(new DebugThreadId(aulIds[i].intValue()));
|
||||
result.add(new DebugThreadRecord(aulIds[i].intValue()));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
@ -141,7 +152,7 @@ public class DebugSystemObjectsImpl1 implements DebugSystemObjectsInternal {
|
||||
ULONGLONG ullHandle = new ULONGLONG(handle);
|
||||
ULONGByReference pulId = new ULONGByReference();
|
||||
COMUtils.checkRC(jnaSysobj.GetThreadIdByHandle(ullHandle, pulId));
|
||||
return new DebugThreadId(pulId.getValue().intValue());
|
||||
return new DebugThreadRecord(pulId.getValue().intValue());
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -154,7 +165,7 @@ public class DebugSystemObjectsImpl1 implements DebugSystemObjectsInternal {
|
||||
return null;
|
||||
}
|
||||
COMUtils.checkRC(hr);
|
||||
return new DebugThreadId(pulId.getValue().intValue());
|
||||
return new DebugThreadRecord(pulId.getValue().intValue());
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -162,7 +173,7 @@ public class DebugSystemObjectsImpl1 implements DebugSystemObjectsInternal {
|
||||
ULONGLONG ullHandle = new ULONGLONG(handle);
|
||||
ULONGByReference pulId = new ULONGByReference();
|
||||
COMUtils.checkRC(jnaSysobj.GetProcessIdByHandle(ullHandle, pulId));
|
||||
return new DebugProcessId(pulId.getValue().intValue());
|
||||
return new DebugProcessRecord(pulId.getValue().intValue());
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -175,7 +186,7 @@ public class DebugSystemObjectsImpl1 implements DebugSystemObjectsInternal {
|
||||
return null;
|
||||
}
|
||||
COMUtils.checkRC(hr);
|
||||
return new DebugProcessId(pulId.getValue().intValue());
|
||||
return new DebugProcessRecord(pulId.getValue().intValue());
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -201,7 +212,7 @@ public class DebugSystemObjectsImpl1 implements DebugSystemObjectsInternal {
|
||||
COMUtils.checkRC(jnaSysobj.GetProcessIdsByIndex(ulStart, ulCount, aulIds, null));
|
||||
List<DebugProcessId> result = new ArrayList<>(count);
|
||||
for (int i = 0; i < count; i++) {
|
||||
result.add(new DebugProcessId(aulIds[i].intValue()));
|
||||
result.add(new DebugProcessRecord(aulIds[i].intValue()));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
@ -15,7 +15,9 @@
|
||||
*/
|
||||
package agent.dbgeng.impl.dbgeng.sysobj;
|
||||
|
||||
import java.util.*;
|
||||
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;
|
||||
@ -24,6 +26,7 @@ import com.sun.jna.platform.win32.COM.COMUtils;
|
||||
|
||||
import agent.dbgeng.dbgeng.COMUtilsExtra;
|
||||
import agent.dbgeng.dbgeng.DebugSessionId;
|
||||
import agent.dbgeng.dbgeng.DebugSessionRecord;
|
||||
import agent.dbgeng.jna.dbgeng.sysobj.IDebugSystemObjects3;
|
||||
|
||||
public class DebugSystemObjectsImpl3 extends DebugSystemObjectsImpl2 {
|
||||
@ -40,10 +43,10 @@ public class DebugSystemObjectsImpl3 extends DebugSystemObjectsImpl2 {
|
||||
ULONGByReference pulId = new ULONGByReference();
|
||||
HRESULT hr = jnaSysobj.GetEventSystem(pulId);
|
||||
if (hr.equals(COMUtilsExtra.E_UNEXPECTED)) {
|
||||
return new DebugSessionId(-1);
|
||||
return new DebugSessionRecord(-1);
|
||||
}
|
||||
COMUtils.checkRC(hr);
|
||||
return new DebugSessionId(pulId.getValue().intValue());
|
||||
return new DebugSessionRecord(pulId.getValue().intValue());
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -51,15 +54,15 @@ public class DebugSystemObjectsImpl3 extends DebugSystemObjectsImpl2 {
|
||||
ULONGByReference pulId = new ULONGByReference();
|
||||
HRESULT hr = jnaSysobj.GetCurrentSystemId(pulId);
|
||||
if (hr.equals(COMUtilsExtra.E_UNEXPECTED)) {
|
||||
return new DebugSessionId(-1);
|
||||
return new DebugSessionRecord(-1);
|
||||
}
|
||||
COMUtils.checkRC(hr);
|
||||
return new DebugSessionId(pulId.getValue().intValue());
|
||||
return new DebugSessionRecord(pulId.getValue().intValue());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setCurrentSystemId(DebugSessionId id) {
|
||||
HRESULT hr = jnaSysobj.SetCurrentSystemId(new ULONG(id.id));
|
||||
HRESULT hr = jnaSysobj.SetCurrentSystemId(new ULONG(id.value()));
|
||||
if (!hr.equals(COMUtilsExtra.E_UNEXPECTED)) {
|
||||
COMUtils.checkRC(hr);
|
||||
}
|
||||
@ -88,7 +91,7 @@ public class DebugSystemObjectsImpl3 extends DebugSystemObjectsImpl2 {
|
||||
COMUtils.checkRC(jnaSysobj.GetSystemIdsByIndex(ulStart, ulCount, aulIds, null));
|
||||
List<DebugSessionId> result = new ArrayList<>(count);
|
||||
for (int i = 0; i < count; i++) {
|
||||
result.add(new DebugSessionId(aulIds[i].intValue()));
|
||||
result.add(new DebugSessionRecord(aulIds[i].intValue()));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
@ -24,7 +24,10 @@ import org.apache.commons.lang3.tuple.Pair;
|
||||
import agent.dbgeng.dbgeng.*;
|
||||
import agent.dbgeng.manager.breakpoint.DbgBreakpointInfo;
|
||||
import agent.dbgeng.manager.breakpoint.DbgBreakpointInsertions;
|
||||
import agent.dbgeng.manager.cmd.DbgListOSMemoryRegionsCommand;
|
||||
import agent.dbgeng.manager.cmd.DbgListOSProcessesCommand;
|
||||
import agent.dbgeng.manager.impl.DbgManagerImpl;
|
||||
import agent.dbgeng.manager.impl.DbgProcessImpl;
|
||||
|
||||
public interface DbgManager extends AutoCloseable, DbgBreakpointInsertions {
|
||||
|
||||
@ -297,6 +300,27 @@ public interface DbgManager extends AutoCloseable, DbgBreakpointInsertions {
|
||||
*/
|
||||
CompletableFuture<Map<DebugProcessId, DbgProcess>> listProcesses();
|
||||
|
||||
/**
|
||||
* List dbgeng's processes
|
||||
*
|
||||
* @return a future that completes with a kernel-mode map of process IDs to process handles
|
||||
*/
|
||||
CompletableFuture<Map<DebugProcessId, DbgProcess>> listOSProcesses();
|
||||
|
||||
/**
|
||||
* List dbgeng's processes
|
||||
*
|
||||
* @return a future that completes with a kernel-mode list of process memory
|
||||
*/
|
||||
CompletableFuture<List<DbgModuleMemory>> listOSMemory();
|
||||
|
||||
/**
|
||||
* List dbgeng's threads
|
||||
*
|
||||
* @return a future that completes with a kernel-mode map of thread IDs to thread handles
|
||||
*/
|
||||
CompletableFuture<Map<DebugThreadId, DbgThread>> listOSThreads(DbgProcessImpl proc);
|
||||
|
||||
/**
|
||||
* List the available processes on target
|
||||
*
|
||||
|
@ -15,7 +15,14 @@
|
||||
*/
|
||||
package agent.dbgeng.manager.cmd;
|
||||
|
||||
import agent.dbgeng.manager.*;
|
||||
import agent.dbgeng.dbgeng.DebugProcessId;
|
||||
import agent.dbgeng.dbgeng.DebugSystemObjects;
|
||||
import agent.dbgeng.dbgeng.DebugThreadId;
|
||||
import agent.dbgeng.manager.DbgCommand;
|
||||
import agent.dbgeng.manager.DbgEvent;
|
||||
import agent.dbgeng.manager.DbgProcess;
|
||||
import agent.dbgeng.manager.DbgState;
|
||||
import agent.dbgeng.manager.DbgThread;
|
||||
import agent.dbgeng.manager.evt.DbgCommandDoneEvent;
|
||||
import agent.dbgeng.manager.impl.DbgManagerImpl;
|
||||
|
||||
@ -26,6 +33,12 @@ import agent.dbgeng.manager.impl.DbgManagerImpl;
|
||||
*/
|
||||
public abstract class AbstractDbgCommand<T> implements DbgCommand<T> {
|
||||
protected final DbgManagerImpl manager;
|
||||
DbgProcess previousProcess;
|
||||
Long previousProcessOffset;
|
||||
DebugProcessId previousProcessId;
|
||||
DbgThread previousThread;
|
||||
Long previousThreadOffset;
|
||||
DebugThreadId previousThreadId;
|
||||
|
||||
/**
|
||||
* Construct a new command to be executed by the given manager
|
||||
@ -60,4 +73,52 @@ public abstract class AbstractDbgCommand<T> implements DbgCommand<T> {
|
||||
public void invoke() {
|
||||
// Nothing
|
||||
}
|
||||
|
||||
public void setProcess(DbgProcess process) {
|
||||
DebugSystemObjects so = manager.getSystemObjects();
|
||||
previousProcess = process;
|
||||
if (manager.isKernelMode() && !process.getId().isSystem()) {
|
||||
previousProcessOffset = so.getCurrentProcessDataOffset();
|
||||
so.setImplicitProcessDataOffset(process.getOffset());
|
||||
}
|
||||
else {
|
||||
previousProcessId = so.getCurrentProcessId();
|
||||
so.setCurrentProcessId(process.getId());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void resetProcess() {
|
||||
DebugSystemObjects so = manager.getSystemObjects();
|
||||
if (manager.isKernelMode() && !previousProcess.getId().isSystem()) {
|
||||
so.setImplicitProcessDataOffset(previousProcessOffset);
|
||||
}
|
||||
else {
|
||||
so.setCurrentProcessId(previousProcessId);
|
||||
}
|
||||
}
|
||||
|
||||
public void setThread(DbgThread thread) {
|
||||
DebugSystemObjects so = manager.getSystemObjects();
|
||||
previousThread = thread;
|
||||
if (manager.isKernelMode() && !thread.getId().isSystem()) {
|
||||
previousThreadOffset = so.getCurrentThreadDataOffset();
|
||||
so.setImplicitThreadDataOffset(thread.getOffset());
|
||||
}
|
||||
else {
|
||||
previousThreadId = so.getCurrentThreadId();
|
||||
so.setCurrentThreadId(thread.getId());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void resetThread() {
|
||||
DebugSystemObjects so = manager.getSystemObjects();
|
||||
if (manager.isKernelMode() && !previousThread.getId().isSystem()) {
|
||||
so.setImplicitThreadDataOffset(previousThreadOffset);
|
||||
}
|
||||
else {
|
||||
so.setCurrentThreadId((DebugThreadId) previousThreadId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -54,7 +54,7 @@ public abstract class AbstractDbgExecToAddressCommand extends AbstractDbgCommand
|
||||
@Override
|
||||
public void invoke() {
|
||||
String cmd = generateCommand(address);
|
||||
String prefix = id == null ? "" : "~" + id.id + " ";
|
||||
String prefix = id == null ? "" : "~" + id.id() + " ";
|
||||
DebugControl control = manager.getControl();
|
||||
DbgThreadImpl eventThread = manager.getEventThread();
|
||||
if (eventThread != null && eventThread.getId().equals(id)) {
|
||||
|
@ -58,17 +58,27 @@ public class DbgListModulesCommand extends AbstractDbgCommand<Map<String, DbgMod
|
||||
|
||||
@Override
|
||||
public void invoke() {
|
||||
DebugSystemObjects so = manager.getSystemObjects();
|
||||
so.setCurrentProcessId(process.getId());
|
||||
DebugSymbols symbols = manager.getSymbols();
|
||||
for (DebugModule module : symbols.iterateModules(0)) {
|
||||
DebugModuleInfo info = symbols.getModuleParameters(1, module.getIndex());
|
||||
String imageName = module.getName(DebugModuleName.IMAGE);
|
||||
String moduleName = module.getName(DebugModuleName.MODULE);
|
||||
info.setImageName(imageName);
|
||||
info.setModuleName(moduleName);
|
||||
updatedModules.put(info.toString(), module);
|
||||
moduleInfo.put(module, info);
|
||||
try {
|
||||
setProcess(process);
|
||||
DebugSymbols symbols = manager.getSymbols();
|
||||
for (DebugModule module : symbols.iterateModules(0)) {
|
||||
DebugModuleInfo info = symbols.getModuleParameters(1, module.getIndex());
|
||||
String imageName = "UNKNOWN";
|
||||
String moduleName = "UNKNOWN";
|
||||
try {
|
||||
imageName = module.getName(DebugModuleName.IMAGE);
|
||||
moduleName = module.getName(DebugModuleName.MODULE);
|
||||
} catch (UnsupportedOperationException uoe) {
|
||||
//Skip
|
||||
}
|
||||
info.setImageName(imageName);
|
||||
info.setModuleName(moduleName);
|
||||
updatedModules.put(info.toString(), module);
|
||||
moduleInfo.put(module, info);
|
||||
}
|
||||
}
|
||||
finally {
|
||||
resetProcess();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -28,11 +28,11 @@ import agent.dbgeng.manager.impl.DbgManagerImpl;
|
||||
import agent.dbgeng.manager.impl.DbgModuleMemoryImpl;
|
||||
import ghidra.util.Msg;
|
||||
|
||||
public class DbgListMemoryRegionsCommandAlt extends AbstractDbgCommand<List<DbgModuleMemory>> {
|
||||
public class DbgListOSMemoryRegionsCommand extends AbstractDbgCommand<List<DbgModuleMemory>> {
|
||||
|
||||
private List<DbgModuleMemory> memoryRegions = new ArrayList<>();
|
||||
|
||||
public DbgListMemoryRegionsCommandAlt(DbgManagerImpl manager) {
|
||||
public DbgListOSMemoryRegionsCommand(DbgManagerImpl manager) {
|
||||
super(manager);
|
||||
}
|
||||
|
@ -0,0 +1,100 @@
|
||||
/* ###
|
||||
* 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.manager.cmd;
|
||||
|
||||
import java.math.BigInteger;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import agent.dbgeng.dbgeng.DebugControl;
|
||||
import agent.dbgeng.dbgeng.DebugProcessId;
|
||||
import agent.dbgeng.dbgeng.DebugProcessRecord;
|
||||
import agent.dbgeng.manager.DbgEvent;
|
||||
import agent.dbgeng.manager.DbgManager;
|
||||
import agent.dbgeng.manager.DbgProcess;
|
||||
import agent.dbgeng.manager.evt.AbstractDbgCompletedCommandEvent;
|
||||
import agent.dbgeng.manager.evt.DbgConsoleOutputEvent;
|
||||
import agent.dbgeng.manager.impl.DbgManagerImpl;
|
||||
import agent.dbgeng.manager.impl.DbgProcessImpl;
|
||||
import ghidra.util.Msg;
|
||||
|
||||
/**
|
||||
* Implementation of {@link DbgManager#listProcesses()}
|
||||
*/
|
||||
public class DbgListOSProcessesCommand extends AbstractDbgCommand<Map<DebugProcessId, DbgProcess>> {
|
||||
private List<DebugProcessId> updatedProcessIds = new ArrayList<>();
|
||||
|
||||
public DbgListOSProcessesCommand(DbgManagerImpl manager) {
|
||||
super(manager);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean handle(DbgEvent<?> evt, DbgPendingCommand<?> pending) {
|
||||
if (evt instanceof AbstractDbgCompletedCommandEvent && pending.getCommand().equals(this)) {
|
||||
return true;
|
||||
}
|
||||
else if (evt instanceof DbgConsoleOutputEvent) {
|
||||
pending.steal(evt);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<DebugProcessId, DbgProcess> complete(DbgPendingCommand<?> pending) {
|
||||
StringBuilder builder = new StringBuilder();
|
||||
for (DbgConsoleOutputEvent out : pending.findAllOf(DbgConsoleOutputEvent.class)) {
|
||||
builder.append(out.getOutput());
|
||||
}
|
||||
parse(builder.toString());
|
||||
Msg.warn(this, "Completed OS process list");
|
||||
return manager.getKnownProcesses();
|
||||
}
|
||||
|
||||
private void parse(String result) {
|
||||
String[] lines = result.split("\n");
|
||||
Long offset = null;
|
||||
for (int i = 0; i < lines.length; i++) {
|
||||
String line = lines[i];
|
||||
if (line.contains("PROCESS")) {
|
||||
offset = null;
|
||||
String[] fields = line.trim().split("\\s+");
|
||||
if (fields.length > 1 && fields[0].equals("PROCESS")) {
|
||||
BigInteger val = new BigInteger(fields[1], 16);
|
||||
offset = val.longValue();
|
||||
}
|
||||
}
|
||||
if (line.contains("Cid:")) {
|
||||
String[] fields = line.trim().split("\\s+");
|
||||
if (fields.length > 3 && fields[2].equals("Cid:")) {
|
||||
Long pid = Long.parseLong(fields[3], 16);
|
||||
DbgProcessImpl mirror = manager.getProcessComputeIfAbsent(new DebugProcessRecord(pid), pid, false);
|
||||
if (offset != null) {
|
||||
mirror.setOffset(offset);
|
||||
updatedProcessIds.add(mirror.getId());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void invoke() {
|
||||
Msg.warn(this, "Retrieving OS process list");
|
||||
DebugControl control = manager.getControl();
|
||||
control.execute("!process 0 0");
|
||||
}
|
||||
}
|
@ -15,10 +15,14 @@
|
||||
*/
|
||||
package agent.dbgeng.manager.cmd;
|
||||
|
||||
import java.math.BigInteger;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import agent.dbgeng.dbgeng.DebugControl;
|
||||
import agent.dbgeng.dbgeng.DebugProcessId;
|
||||
import agent.dbgeng.dbgeng.DebugSystemObjects;
|
||||
import agent.dbgeng.dbgeng.DebugThreadId;
|
||||
import agent.dbgeng.dbgeng.DebugThreadRecord;
|
||||
import agent.dbgeng.manager.DbgEvent;
|
||||
import agent.dbgeng.manager.DbgThread;
|
||||
import agent.dbgeng.manager.evt.AbstractDbgCompletedCommandEvent;
|
||||
@ -28,15 +32,13 @@ import agent.dbgeng.manager.impl.DbgProcessImpl;
|
||||
import agent.dbgeng.manager.impl.DbgThreadImpl;
|
||||
import ghidra.util.Msg;
|
||||
|
||||
public class DbgSetCurrentState extends AbstractDbgCommand<DbgThread> {
|
||||
public class DbgListOSThreadsCommand extends AbstractDbgCommand<Map<DebugThreadId, DbgThread>> {
|
||||
protected final DbgProcessImpl process;
|
||||
private List<DebugThreadId> updatedThreadIds = new ArrayList<>();;
|
||||
|
||||
private long pid;
|
||||
private long tid;
|
||||
private DebugProcessId pID;
|
||||
private DebugThreadId tID;
|
||||
|
||||
public DbgSetCurrentState(DbgManagerImpl manager) {
|
||||
public DbgListOSThreadsCommand(DbgManagerImpl manager, DbgProcessImpl process) {
|
||||
super(manager);
|
||||
this.process = process;
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -51,52 +53,46 @@ public class DbgSetCurrentState extends AbstractDbgCommand<DbgThread> {
|
||||
}
|
||||
|
||||
@Override
|
||||
public DbgThread complete(DbgPendingCommand<?> pending) {
|
||||
public Map<DebugThreadId, DbgThread> complete(DbgPendingCommand<?> pending) {
|
||||
StringBuilder builder = new StringBuilder();
|
||||
for (DbgConsoleOutputEvent out : pending.findAllOf(DbgConsoleOutputEvent.class)) {
|
||||
builder.append(out.getOutput());
|
||||
}
|
||||
parse(builder.toString());
|
||||
|
||||
if (pID == null) {
|
||||
return null;
|
||||
}
|
||||
DbgProcessImpl proc = manager.getProcessComputeIfAbsent(pID, pid, true);
|
||||
DbgThreadImpl thread = manager.getThreadComputeIfAbsent(tID, proc, tid, true);
|
||||
try {
|
||||
DebugSystemObjects so = manager.getSystemObjects();
|
||||
proc.setOffset(so.getCurrentProcessDataOffset());
|
||||
thread.setOffset(so.getCurrentThreadDataOffset());
|
||||
} catch (Exception e) {
|
||||
Msg.error(this, e.getMessage());
|
||||
}
|
||||
return thread;
|
||||
Msg.warn(this, "Completed OS thread list for pid="+Long.toHexString(process.getPid()));
|
||||
Map<DebugThreadId, DbgThread> threads = process.getKnownThreads();
|
||||
return threads;
|
||||
}
|
||||
|
||||
private void parse(String result) {
|
||||
String[] lines = result.split("\n");
|
||||
Long offset = null;
|
||||
for (int i = 0; i < lines.length; i++) {
|
||||
String line = lines[i];
|
||||
if (line.contains("THREAD")) {
|
||||
String[] fields = line.trim().split("\\s+");
|
||||
if (fields.length > 3 && fields[2].equals("Cid")) {
|
||||
if (fields.length > 4 && fields[0].equals("THREAD")) {
|
||||
BigInteger val = new BigInteger(fields[1], 16);
|
||||
offset = val.longValue();
|
||||
String[] split = fields[3].split("\\.");
|
||||
if (split.length == 2) {
|
||||
pid = Long.parseLong(split[0], 16);
|
||||
tid = Long.parseLong(split[1], 16);
|
||||
pID = new DebugProcessId(pid);
|
||||
tID = new DebugThreadId(tid);
|
||||
Long tid = Long.parseLong(split[1], 16);
|
||||
DbgThreadImpl mirror = manager.getThreadComputeIfAbsent(new DebugThreadRecord(tid), process, tid, false);
|
||||
if (offset != null) {
|
||||
mirror.setOffset(offset);
|
||||
updatedThreadIds.add(mirror.getId());
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void invoke() {
|
||||
Msg.warn(this, "Retrieving OS thread list for pid="+Long.toHexString(process.getPid()));
|
||||
DebugControl control = manager.getControl();
|
||||
control.execute("!thread");
|
||||
control.execute("!process "+Long.toHexString(process.getOffset())+" 2");
|
||||
}
|
||||
|
||||
}
|
@ -15,14 +15,19 @@
|
||||
*/
|
||||
package agent.dbgeng.manager.cmd;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import agent.dbgeng.dbgeng.DebugProcessId;
|
||||
import agent.dbgeng.dbgeng.DebugSystemObjects;
|
||||
import agent.dbgeng.dbgeng.DebugSystemProcessRecord;
|
||||
import agent.dbgeng.manager.DbgCause.Causes;
|
||||
import agent.dbgeng.manager.DbgManager;
|
||||
import agent.dbgeng.manager.DbgProcess;
|
||||
import agent.dbgeng.manager.impl.DbgManagerImpl;
|
||||
import agent.dbgeng.manager.impl.DbgProcessImpl;
|
||||
import ghidra.util.Msg;
|
||||
|
||||
/**
|
||||
@ -44,19 +49,29 @@ public class DbgListProcessesCommand extends AbstractDbgCommand<Map<DebugProcess
|
||||
continue; // Do nothing, we're in sync
|
||||
}
|
||||
// Need to create the inferior as if we received =thread-group-created
|
||||
Msg.warn(this, "Resync: Was missing group: i" + id);
|
||||
DebugSystemObjects so = manager.getSystemObjects();
|
||||
so.setCurrentProcessId(id);
|
||||
int pid = so.getCurrentProcessSystemId();
|
||||
manager.getProcessComputeIfAbsent(id, pid, true);
|
||||
long pid;
|
||||
if (!manager.isKernelMode()) {
|
||||
Msg.warn(this, "Resync: Was missing group: i" + id);
|
||||
so.setCurrentProcessId(id);
|
||||
pid = so.getCurrentProcessSystemId();
|
||||
}
|
||||
else {
|
||||
id = new DebugSystemProcessRecord(id.value());
|
||||
pid = -1;
|
||||
}
|
||||
DbgProcessImpl proc = manager.getProcessComputeIfAbsent(id, pid, true);
|
||||
Long offset = so.getCurrentProcessDataOffset();
|
||||
proc.setOffset(offset);
|
||||
}
|
||||
for (DebugProcessId id : new ArrayList<>(cur)) {
|
||||
if (updatedProcessIds.contains(id)) {
|
||||
continue; // Do nothing, we're in sync
|
||||
}
|
||||
// Need to remove the inferior as if we received =thread-group-removed
|
||||
Msg.warn(this, "Resync: Had extra group: i" + id);
|
||||
manager.removeProcess(id, Causes.UNCLAIMED);
|
||||
if (!manager.isKernelMode()) {
|
||||
Msg.warn(this, "Resync: Had extra group: i" + id);
|
||||
manager.removeProcess(id, Causes.UNCLAIMED);
|
||||
}
|
||||
}
|
||||
return allProcesses;
|
||||
}
|
||||
|
@ -48,16 +48,20 @@ public class DbgListSymbolsCommand extends AbstractDbgCommand<Map<String, DbgMin
|
||||
|
||||
@Override
|
||||
public void invoke() {
|
||||
DebugSystemObjects so = manager.getSystemObjects();
|
||||
so.setCurrentProcessId(process.getId());
|
||||
DebugSymbols symbols = manager.getSymbols();
|
||||
|
||||
for (DebugSymbolName symbol : symbols.iterateSymbolMatches(module.getName() + "!*")) {
|
||||
List<DebugSymbolId> symbolIdsByName = symbols.getSymbolIdsByName(symbol.name);
|
||||
for (DebugSymbolId symbolId : symbolIdsByName) {
|
||||
DebugSymbolEntry symbolEntry = symbols.getSymbolEntry(symbolId);
|
||||
symbolEntries.put(symbolId, symbolEntry);
|
||||
try {
|
||||
setProcess(process);
|
||||
DebugSymbols symbols = manager.getSymbols();
|
||||
|
||||
for (DebugSymbolName symbol : symbols.iterateSymbolMatches(module.getName() + "!*")) {
|
||||
List<DebugSymbolId> symbolIdsByName = symbols.getSymbolIdsByName(symbol.name);
|
||||
for (DebugSymbolId symbolId : symbolIdsByName) {
|
||||
DebugSymbolEntry symbolEntry = symbols.getSymbolEntry(symbolId);
|
||||
symbolEntries.put(symbolId, symbolEntry);
|
||||
}
|
||||
}
|
||||
}
|
||||
finally {
|
||||
resetProcess();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -15,13 +15,18 @@
|
||||
*/
|
||||
package agent.dbgeng.manager.cmd;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import agent.dbgeng.dbgeng.DebugSystemObjects;
|
||||
import agent.dbgeng.dbgeng.DebugSystemThreadRecord;
|
||||
import agent.dbgeng.dbgeng.DebugThreadId;
|
||||
import agent.dbgeng.manager.DbgThread;
|
||||
import agent.dbgeng.manager.impl.DbgManagerImpl;
|
||||
import agent.dbgeng.manager.impl.DbgProcessImpl;
|
||||
import agent.dbgeng.manager.impl.DbgThreadImpl;
|
||||
import ghidra.util.Msg;
|
||||
|
||||
public class DbgListThreadsCommand extends AbstractDbgCommand<Map<DebugThreadId, DbgThread>> {
|
||||
@ -41,30 +46,44 @@ public class DbgListThreadsCommand extends AbstractDbgCommand<Map<DebugThreadId,
|
||||
if (cur.contains(id)) {
|
||||
continue; // Do nothing, we're in sync
|
||||
}
|
||||
// Need to create the thread as if we receive =thread-created
|
||||
Msg.warn(this, "Resync: Was missing thread: " + id);
|
||||
DebugSystemObjects so = manager.getSystemObjects();
|
||||
so.setCurrentThreadId(id);
|
||||
int tid = so.getCurrentThreadSystemId();
|
||||
manager.getThreadComputeIfAbsent(id, process, tid, false);
|
||||
long tid;
|
||||
if (!manager.isKernelMode()) {
|
||||
Msg.warn(this, "Resync: Was missing thread: " + id);
|
||||
so.setCurrentThreadId(id);
|
||||
tid = (long) so.getCurrentThreadSystemId();
|
||||
}
|
||||
else {
|
||||
id = new DebugSystemThreadRecord(id.value());
|
||||
tid = -1;
|
||||
}
|
||||
DbgThreadImpl thread = manager.getThreadComputeIfAbsent(id, process, tid, false);
|
||||
Long offset = so.getCurrentThreadDataOffset();
|
||||
thread.setOffset(offset);
|
||||
}
|
||||
for (DebugThreadId id : new ArrayList<>(cur)) {
|
||||
if (updatedThreadIds.contains(id)) {
|
||||
continue; // Do nothing, we're in sync
|
||||
}
|
||||
// Need to remove the thread as if we received =thread-exited
|
||||
Msg.warn(this, "Resync: Had extra thread: " + id);
|
||||
process.removeThread(id);
|
||||
manager.removeThread(id);
|
||||
if (!manager.isKernelMode()) {
|
||||
Msg.warn(this, "Resync: Had extra thread: " + id);
|
||||
process.removeThread(id);
|
||||
manager.removeThread(id);
|
||||
}
|
||||
}
|
||||
return process.getKnownThreads();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void invoke() {
|
||||
DebugSystemObjects so = manager.getSystemObjects();
|
||||
so.setCurrentProcessId(process.getId());
|
||||
updatedThreadIds = so.getThreads();
|
||||
try {
|
||||
setProcess(process);
|
||||
DebugSystemObjects so = manager.getSystemObjects();
|
||||
updatedThreadIds = so.getThreads();
|
||||
}
|
||||
finally {
|
||||
resetProcess();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -30,7 +30,7 @@ public class DbgReadRegistersCommand extends AbstractDbgCommand<Map<DbgRegister,
|
||||
private final DbgThreadImpl thread;
|
||||
private final Set<DbgRegister> regs;
|
||||
private DebugRegisters registers;
|
||||
private DebugThreadId previous;
|
||||
private Map<DbgRegister, BigInteger> result = new LinkedHashMap<>();
|
||||
|
||||
public DbgReadRegistersCommand(DbgManagerImpl manager, DbgThreadImpl thread, Integer frameId,
|
||||
Set<DbgRegister> regs) {
|
||||
@ -41,31 +41,31 @@ public class DbgReadRegistersCommand extends AbstractDbgCommand<Map<DbgRegister,
|
||||
|
||||
@Override
|
||||
public Map<DbgRegister, BigInteger> complete(DbgPendingCommand<?> pending) {
|
||||
DebugSystemObjects so = manager.getSystemObjects();
|
||||
if (regs.isEmpty()) {
|
||||
return Collections.emptyMap();
|
||||
}
|
||||
Map<DbgRegister, BigInteger> result = new LinkedHashMap<>();
|
||||
if (registers != null) {
|
||||
for (DbgRegister r : regs) {
|
||||
if (r.isBaseRegister()) {
|
||||
DebugValue value = registers.getValueByName(r.getName());
|
||||
if (value != null) {
|
||||
BigInteger bval = new BigInteger(value.encodeAsBytes());
|
||||
result.put(r, bval);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
so.setCurrentThreadId(previous);
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void invoke() {
|
||||
DebugSystemObjects so = manager.getSystemObjects();
|
||||
previous = so.getCurrentThreadId();
|
||||
so.setCurrentThreadId(thread.getId());
|
||||
registers = manager.getClient().getRegisters();
|
||||
try {
|
||||
setThread(thread);
|
||||
registers = manager.getClient().getRegisters();
|
||||
if (registers != null) {
|
||||
for (DbgRegister r : regs) {
|
||||
if (r.isBaseRegister()) {
|
||||
DebugValue value = registers.getValueByName(r.getName());
|
||||
if (value != null) {
|
||||
BigInteger bval = new BigInteger(value.encodeAsBytes());
|
||||
result.put(r, bval);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
finally {
|
||||
resetThread();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -18,7 +18,6 @@ package agent.dbgeng.manager.cmd;
|
||||
import java.math.BigInteger;
|
||||
|
||||
import agent.dbgeng.dbgeng.DebugControl;
|
||||
import agent.dbgeng.dbgeng.DebugProcessId;
|
||||
import agent.dbgeng.manager.DbgEvent;
|
||||
import agent.dbgeng.manager.DbgProcess;
|
||||
import agent.dbgeng.manager.evt.AbstractDbgCompletedCommandEvent;
|
||||
@ -94,11 +93,9 @@ public class DbgResolveProcessCommand extends AbstractDbgCommand<DbgProcess> {
|
||||
@Override
|
||||
public void invoke() {
|
||||
if (process != null) {
|
||||
DebugProcessId id = process.getId();
|
||||
if (id != null) {
|
||||
DebugControl control = manager.getControl();
|
||||
control.execute("!process "+Long.toHexString(id.id)+" 0");
|
||||
}
|
||||
DebugControl control = manager.getControl();
|
||||
Long key = process.getOffset() != null ? process.getOffset() : process.getPid();
|
||||
control.execute("!process "+Long.toHexString(key)+" 0");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -93,10 +93,8 @@ public class DbgResolveThreadCommand extends AbstractDbgCommand<DbgThread> {
|
||||
|
||||
@Override
|
||||
public void invoke() {
|
||||
DebugThreadId id = thread.getId();
|
||||
if (id != null) {
|
||||
DebugControl control = manager.getControl();
|
||||
control.execute("!thread "+Long.toHexString(id.id)+" 0");
|
||||
}
|
||||
DebugControl control = manager.getControl();
|
||||
Long key = thread.getOffset() != null ? thread.getOffset() : thread.getTid();
|
||||
control.execute("!thread "+Long.toHexString(key)+" 0");
|
||||
}
|
||||
}
|
||||
|
@ -98,7 +98,7 @@ public class DbgSetActiveProcessCommand extends AbstractDbgCommand<Void> {
|
||||
} else {
|
||||
so.setCurrentProcessId(id);
|
||||
DebugProcessId currentProcessId = so.getCurrentProcessId();
|
||||
if (id.id != currentProcessId.id) {
|
||||
if (!id.id().equals(currentProcessId.id())) {
|
||||
so.setCurrentProcessId(id);
|
||||
}
|
||||
}
|
||||
|
@ -41,28 +41,30 @@ public class DbgStackListFramesCommand extends AbstractDbgCommand<List<DbgStackF
|
||||
@Override
|
||||
public void invoke() {
|
||||
result = new ArrayList<>();
|
||||
DebugSystemObjects so = manager.getSystemObjects();
|
||||
DebugThreadId previous = so.getCurrentThreadId();
|
||||
so.setCurrentThreadId(thread.getId());
|
||||
DebugStackInformation stackTrace = manager.getControl().getStackTrace(0L, 0L, 0L);
|
||||
for (int i = 0; i < stackTrace.getNumberOfFrames(); i++) {
|
||||
DEBUG_STACK_FRAME tf = stackTrace.getFrame(i);
|
||||
//DbgStackFrame frame = new DbgStackFrameImpl(thread, tf.FrameNumber.intValue(),
|
||||
// new BigInteger(Long.toHexString(tf.InstructionOffset.longValue()), 16), null);
|
||||
DbgStackFrame frame = new DbgStackFrameImpl(thread, //
|
||||
tf.FrameNumber.intValue(), //
|
||||
new BigInteger(Long.toHexString(tf.InstructionOffset.longValue()), 16), //
|
||||
tf.FuncTableEntry.longValue(), //
|
||||
tf.FrameOffset.longValue(), //
|
||||
tf.ReturnOffset.longValue(), //
|
||||
tf.StackOffset.longValue(), //
|
||||
tf.Virtual.booleanValue(), //
|
||||
tf.Params[0].longValue(), //
|
||||
tf.Params[1].longValue(), //
|
||||
tf.Params[2].longValue(), //
|
||||
tf.Params[3].longValue());
|
||||
result.add(frame);
|
||||
try {
|
||||
setThread(thread);
|
||||
DebugStackInformation stackTrace = manager.getControl().getStackTrace(0L, 0L, 0L);
|
||||
for (int i = 0; i < stackTrace.getNumberOfFrames(); i++) {
|
||||
DEBUG_STACK_FRAME tf = stackTrace.getFrame(i);
|
||||
//DbgStackFrame frame = new DbgStackFrameImpl(thread, tf.FrameNumber.intValue(),
|
||||
// new BigInteger(Long.toHexString(tf.InstructionOffset.longValue()), 16), null);
|
||||
DbgStackFrame frame = new DbgStackFrameImpl(thread, //
|
||||
tf.FrameNumber.intValue(), //
|
||||
new BigInteger(Long.toHexString(tf.InstructionOffset.longValue()), 16), //
|
||||
tf.FuncTableEntry.longValue(), //
|
||||
tf.FrameOffset.longValue(), //
|
||||
tf.ReturnOffset.longValue(), //
|
||||
tf.StackOffset.longValue(), //
|
||||
tf.Virtual.booleanValue(), //
|
||||
tf.Params[0].longValue(), //
|
||||
tf.Params[1].longValue(), //
|
||||
tf.Params[2].longValue(), //
|
||||
tf.Params[3].longValue());
|
||||
result.add(frame);
|
||||
}
|
||||
}
|
||||
finally {
|
||||
resetThread();
|
||||
}
|
||||
so.setCurrentThreadId(previous);
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,119 @@
|
||||
/* ###
|
||||
* 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.manager.cmd;
|
||||
|
||||
import java.math.BigInteger;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import agent.dbgeng.dbgeng.DebugControl;
|
||||
import agent.dbgeng.manager.DbgEvent;
|
||||
import agent.dbgeng.manager.DbgStackFrame;
|
||||
import agent.dbgeng.manager.evt.AbstractDbgCompletedCommandEvent;
|
||||
import agent.dbgeng.manager.evt.DbgConsoleOutputEvent;
|
||||
import agent.dbgeng.manager.impl.DbgManagerImpl;
|
||||
import agent.dbgeng.manager.impl.DbgStackFrameImpl;
|
||||
import agent.dbgeng.manager.impl.DbgThreadImpl;
|
||||
|
||||
public class DbgStackListOSFramesCommand extends AbstractDbgCommand<List<DbgStackFrame>> {
|
||||
protected final DbgThreadImpl thread;
|
||||
private List<DbgStackFrame> result = new ArrayList<>();
|
||||
|
||||
public DbgStackListOSFramesCommand(DbgManagerImpl manager, DbgThreadImpl thread) {
|
||||
super(manager);
|
||||
this.thread = thread;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean handle(DbgEvent<?> evt, DbgPendingCommand<?> pending) {
|
||||
if (evt instanceof AbstractDbgCompletedCommandEvent && pending.getCommand().equals(this)) {
|
||||
return true;
|
||||
}
|
||||
else if (evt instanceof DbgConsoleOutputEvent) {
|
||||
pending.steal(evt);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<DbgStackFrame> complete(DbgPendingCommand<?> pending) {
|
||||
StringBuilder builder = new StringBuilder();
|
||||
for (DbgConsoleOutputEvent out : pending.findAllOf(DbgConsoleOutputEvent.class)) {
|
||||
builder.append(out.getOutput());
|
||||
}
|
||||
parse(builder.toString());
|
||||
return result;
|
||||
}
|
||||
|
||||
private void parse(String output) {
|
||||
String[] lines = output.split("\n");
|
||||
int fcount = 0;
|
||||
for (int i = 0; i < lines.length; i++) {
|
||||
String line = lines[i];
|
||||
if (line.contains(" : ") && !line.startsWith("Child") && !line.startsWith("THREAD")) {
|
||||
String[] fields = line.trim().split("\\s+");
|
||||
DbgStackFrame frame = new DbgStackFrameImpl(thread, //
|
||||
fcount++, //
|
||||
parseToBig(fields[1]), // return
|
||||
fields.length > 8 ? fields[8] : ""
|
||||
);
|
||||
result.add(frame);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private BigInteger parseToBig(String lval) {
|
||||
if (lval.contains("`")) {
|
||||
lval = lval.replaceAll("`", "");
|
||||
}
|
||||
return new BigInteger(lval, 16);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void invoke() {
|
||||
DebugControl control = manager.getControl();
|
||||
control.execute("!thread "+Long.toHexString(thread.getOffset())+" 6");
|
||||
|
||||
}
|
||||
|
||||
// @Override
|
||||
// public void invoke() {
|
||||
// result = new ArrayList<>();
|
||||
// DebugSystemObjects so = manager.getSystemObjects();
|
||||
// DebugThreadId previous = so.getCurrentThreadId();
|
||||
// so.setCurrentThreadId(thread.getId());
|
||||
// DebugStackInformation stackTrace = manager.getControl().getStackTrace(0L, 0L, 0L);
|
||||
// for (int i = 0; i < stackTrace.getNumberOfFrames(); i++) {
|
||||
// DEBUG_STACK_FRAME tf = stackTrace.getFrame(i);
|
||||
// //DbgStackFrame frame = new DbgStackFrameImpl(thread, tf.FrameNumber.intValue(),
|
||||
// // new BigInteger(Long.toHexString(tf.InstructionOffset.longValue()), 16), null);
|
||||
// DbgStackFrame frame = new DbgStackFrameImpl(thread, //
|
||||
// tf.FrameNumber.intValue(), //
|
||||
// new BigInteger(Long.toHexString(tf.InstructionOffset.longValue()), 16), //
|
||||
// tf.FuncTableEntry.longValue(), //
|
||||
// tf.FrameOffset.longValue(), //
|
||||
// tf.ReturnOffset.longValue(), //
|
||||
// tf.StackOffset.longValue(), //
|
||||
// tf.Virtual.booleanValue(), //
|
||||
// tf.Params[0].longValue(), //
|
||||
// tf.Params[1].longValue(), //
|
||||
// tf.Params[2].longValue(), //
|
||||
// tf.Params[3].longValue());
|
||||
// result.add(frame);
|
||||
// }
|
||||
// so.setCurrentThreadId(previous);
|
||||
// }
|
||||
}
|
@ -73,7 +73,7 @@ public class DbgStepCommand extends AbstractDbgCommand<Void> {
|
||||
@Override
|
||||
public void invoke() {
|
||||
String cmd = "";
|
||||
String prefix = id == null ? "" : "~" + id.id + " ";
|
||||
String prefix = id == null ? "" : "~" + id.id() + " ";
|
||||
DebugControl control = manager.getControl();
|
||||
if (suffix.equals(ExecSuffix.STEP_INSTRUCTION)) {
|
||||
cmd = "t";
|
||||
|
@ -60,12 +60,16 @@ import agent.dbgeng.dbgeng.DebugExceptionRecord64;
|
||||
import agent.dbgeng.dbgeng.DebugModuleInfo;
|
||||
import agent.dbgeng.dbgeng.DebugProcessId;
|
||||
import agent.dbgeng.dbgeng.DebugProcessInfo;
|
||||
import agent.dbgeng.dbgeng.DebugProcessRecord;
|
||||
import agent.dbgeng.dbgeng.DebugRegisters;
|
||||
import agent.dbgeng.dbgeng.DebugSessionId;
|
||||
import agent.dbgeng.dbgeng.DebugSymbols;
|
||||
import agent.dbgeng.dbgeng.DebugSystemObjects;
|
||||
import agent.dbgeng.dbgeng.DebugSystemProcessRecord;
|
||||
import agent.dbgeng.dbgeng.DebugSystemThreadRecord;
|
||||
import agent.dbgeng.dbgeng.DebugThreadId;
|
||||
import agent.dbgeng.dbgeng.DebugThreadInfo;
|
||||
import agent.dbgeng.dbgeng.DebugThreadRecord;
|
||||
import agent.dbgeng.gadp.impl.AbstractClientThreadExecutor;
|
||||
import agent.dbgeng.gadp.impl.DbgEngClientThreadExecutor;
|
||||
import agent.dbgeng.impl.dbgeng.DbgEngUtil;
|
||||
@ -96,6 +100,9 @@ import agent.dbgeng.manager.cmd.DbgInsertBreakpointCommand;
|
||||
import agent.dbgeng.manager.cmd.DbgLaunchProcessCommand;
|
||||
import agent.dbgeng.manager.cmd.DbgListAvailableProcessesCommand;
|
||||
import agent.dbgeng.manager.cmd.DbgListBreakpointsCommand;
|
||||
import agent.dbgeng.manager.cmd.DbgListOSMemoryRegionsCommand;
|
||||
import agent.dbgeng.manager.cmd.DbgListOSProcessesCommand;
|
||||
import agent.dbgeng.manager.cmd.DbgListOSThreadsCommand;
|
||||
import agent.dbgeng.manager.cmd.DbgListProcessesCommand;
|
||||
import agent.dbgeng.manager.cmd.DbgOpenDumpCommand;
|
||||
import agent.dbgeng.manager.cmd.DbgPendingCommand;
|
||||
@ -145,7 +152,6 @@ import ghidra.dbg.target.TargetLauncher.CmdLineParser;
|
||||
import ghidra.dbg.target.TargetLauncher.TargetCmdLineLauncher;
|
||||
import ghidra.dbg.target.TargetObject;
|
||||
import ghidra.dbg.util.HandlerMap;
|
||||
import ghidra.dbg.util.PathUtils;
|
||||
import ghidra.lifecycle.Internal;
|
||||
import ghidra.util.Msg;
|
||||
import ghidra.util.datastruct.ListenerSet;
|
||||
@ -236,17 +242,6 @@ public class DbgManagerImpl implements DbgManager {
|
||||
}
|
||||
}
|
||||
|
||||
public DbgThreadImpl getThreadComputeIfAbsent(String key, DbgProcessImpl proc, boolean fire) {
|
||||
String index = PathUtils.parseIndex(key);
|
||||
Integer tid = Integer.decode(index);
|
||||
DebugThreadId id = getSystemObjects().getThreadIdBySystemId(tid);
|
||||
if (id == null) {
|
||||
id = new DebugThreadId(tid);
|
||||
return getThreadComputeIfAbsent(id, proc, tid, fire);
|
||||
}
|
||||
return getThreadComputeIfAbsent(id, proc, tid, fire);
|
||||
}
|
||||
|
||||
public DbgThreadImpl getThreadComputeIfAbsent(DebugThreadId id, DbgProcessImpl process,
|
||||
long tid, boolean fire) {
|
||||
synchronized (threads) {
|
||||
@ -368,7 +363,7 @@ public class DbgManagerImpl implements DbgManager {
|
||||
|
||||
public DbgSessionImpl getSessionComputeIfAbsent(DebugSessionId id, boolean fire) {
|
||||
synchronized (sessions) {
|
||||
if (!sessions.containsKey(id) && id.id >= 0) {
|
||||
if (!sessions.containsKey(id) && id.value() >= 0) {
|
||||
DbgSessionImpl session = new DbgSessionImpl(this, id);
|
||||
session.add();
|
||||
if (fire) {
|
||||
@ -727,7 +722,7 @@ public class DbgManagerImpl implements DbgManager {
|
||||
if (eventThread != null) {
|
||||
((DbgThreadImpl) eventThread).setInfo(lastEventInformation);
|
||||
}
|
||||
return currentThread == null ? new DebugThreadId(-1) : currentThread.getId();
|
||||
return currentThread == null ? new DebugThreadRecord(-1) : currentThread.getId();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -799,7 +794,7 @@ public class DbgManagerImpl implements DbgManager {
|
||||
getEventListeners().fire.threadCreated(thread, DbgCause.Causes.UNCLAIMED);
|
||||
getEventListeners().fire.threadSelected(thread, null, evt.getCause());
|
||||
|
||||
String key = Long.toHexString(eventId.id);
|
||||
String key = eventId.id();
|
||||
if (statusByNameMap.containsKey(key)) {
|
||||
return statusByNameMap.get(key);
|
||||
}
|
||||
@ -824,7 +819,7 @@ public class DbgManagerImpl implements DbgManager {
|
||||
getEventListeners().fire.eventSelected(evt, evt.getCause());
|
||||
getEventListeners().fire.threadExited(eventId, process, evt.getCause());
|
||||
|
||||
String key = Long.toHexString(eventId.id);
|
||||
String key = eventId.id();
|
||||
if (statusByNameMap.containsKey(key)) {
|
||||
return statusByNameMap.get(key);
|
||||
}
|
||||
@ -846,11 +841,11 @@ public class DbgManagerImpl implements DbgManager {
|
||||
}
|
||||
DebugThreadId eventId = updateState();
|
||||
|
||||
currentThread = evt.getThread();
|
||||
//currentThread = evt.getThread();
|
||||
currentThread.setState(evt.getState(), evt.getCause(), evt.getReason());
|
||||
getEventListeners().fire.threadSelected(currentThread, evt.getFrame(), evt.getCause());
|
||||
|
||||
String key = Long.toHexString(eventId.id);
|
||||
String key = eventId.id();
|
||||
if (statusByNameMap.containsKey(key)) {
|
||||
return statusByNameMap.get(key);
|
||||
}
|
||||
@ -878,7 +873,7 @@ public class DbgManagerImpl implements DbgManager {
|
||||
//proc.moduleLoaded(info.moduleInfo);
|
||||
//getEventListeners().fire.moduleLoaded(proc, info.moduleInfo, evt.getCause());
|
||||
|
||||
String key = Long.toHexString(proc.getId().id);
|
||||
String key = proc.getId().id();
|
||||
if (statusByNameMap.containsKey(key)) {
|
||||
return statusByNameMap.get(key);
|
||||
}
|
||||
@ -911,7 +906,7 @@ public class DbgManagerImpl implements DbgManager {
|
||||
process.remove(evt.getCause());
|
||||
getEventListeners().fire.processRemoved(process.getId(), evt.getCause());
|
||||
|
||||
String key = Long.toHexString(process.getId().id);
|
||||
String key = process.getId().id();
|
||||
if (statusByNameMap.containsKey(key)) {
|
||||
return statusByNameMap.get(key);
|
||||
}
|
||||
@ -931,7 +926,7 @@ public class DbgManagerImpl implements DbgManager {
|
||||
currentProcess = evt.getProcess();
|
||||
getEventListeners().fire.processSelected(currentProcess, evt.getCause());
|
||||
|
||||
String key = Long.toHexString(eventId.id);
|
||||
String key = eventId.id();
|
||||
if (statusByNameMap.containsKey(key)) {
|
||||
return statusByNameMap.get(key);
|
||||
}
|
||||
@ -1059,7 +1054,7 @@ public class DbgManagerImpl implements DbgManager {
|
||||
if (flags.contains(ChangeEngineState.CURRENT_THREAD)) {
|
||||
long id = evt.getArgument();
|
||||
for (DebugThreadId key : getThreads()) {
|
||||
if (key.id == id) {
|
||||
if (key.value() == id) {
|
||||
DbgThread thread = getThread(key);
|
||||
if (thread != null) {
|
||||
getEventListeners().fire.threadSelected(thread, null, evt.getCause());
|
||||
@ -1088,7 +1083,7 @@ public class DbgManagerImpl implements DbgManager {
|
||||
currentSession = evt.getSession();
|
||||
getEventListeners().fire.sessionSelected(currentSession, evt.getCause());
|
||||
|
||||
String key = Long.toHexString(eventId.id);
|
||||
String key = eventId.id();
|
||||
if (statusByNameMap.containsKey(key)) {
|
||||
return statusByNameMap.get(key);
|
||||
}
|
||||
@ -1113,9 +1108,9 @@ public class DbgManagerImpl implements DbgManager {
|
||||
else {
|
||||
processCount--;
|
||||
}
|
||||
DebugProcessId id = new DebugProcessId(info.intValue());
|
||||
DebugProcessId id = new DebugProcessRecord(info.intValue());
|
||||
|
||||
String key = Long.toHexString(id.id);
|
||||
String key = id.id();
|
||||
if (statusByNameMap.containsKey(key)) {
|
||||
return statusByNameMap.get(key);
|
||||
}
|
||||
@ -1316,32 +1311,13 @@ public class DbgManagerImpl implements DbgManager {
|
||||
if (tag == null) {
|
||||
for (DebugThreadId tid : tids) {
|
||||
Msg.debug(this, "TRAP Added: " + id + " on " + tid);
|
||||
if (!claimsBreakpointAdded.satisfy(tid)) {
|
||||
/*
|
||||
AbstractSctlTrapSpec spec =
|
||||
server.getDialect().create(AbstractSctlTrapSpec.class);
|
||||
spec.setActionStop();
|
||||
spec.setAddress(newOffset);
|
||||
synth.synthSetTrap(null, tid.id, spec, id);
|
||||
*/
|
||||
}
|
||||
else {
|
||||
if (claimsBreakpointAdded.satisfy(tid)) {
|
||||
Msg.debug(this, " claimed");
|
||||
}
|
||||
breaksById.put(id, new BreakpointTag(newOffset));
|
||||
}
|
||||
}
|
||||
else if (tag.offset != newOffset) {
|
||||
/*
|
||||
for (DebugThreadId tid : tids) {
|
||||
synth.synthClearTrap(null, tid.id, id);
|
||||
AbstractSctlTrapSpec spec =
|
||||
server.getDialect().create(AbstractSctlTrapSpec.class);
|
||||
spec.setActionStop();
|
||||
spec.setAddress(newOffset);
|
||||
synth.synthSetTrap(null, tid.id, spec, id);
|
||||
}
|
||||
*/
|
||||
tag.offset = newOffset;
|
||||
} // else the breakpoint is unchanged
|
||||
}
|
||||
@ -1353,12 +1329,7 @@ public class DbgManagerImpl implements DbgManager {
|
||||
}
|
||||
for (DebugThreadId tid : tids) {
|
||||
Msg.debug(this, "TRAP Removed: " + id + " on " + tid);
|
||||
if (!claimsBreakpointRemoved.satisfy(new BreakId(tid, id))) {
|
||||
/*
|
||||
synth.synthClearTrap(null, tid.id, id);
|
||||
*/
|
||||
}
|
||||
else {
|
||||
if (claimsBreakpointRemoved.satisfy(new BreakId(tid, id))) {
|
||||
Msg.debug(this, " claimed");
|
||||
}
|
||||
}
|
||||
@ -1376,6 +1347,21 @@ public class DbgManagerImpl implements DbgManager {
|
||||
return execute(new DbgListProcessesCommand(this));
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompletableFuture<Map<DebugProcessId, DbgProcess>> listOSProcesses() {
|
||||
return execute(new DbgListOSProcessesCommand(this));
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompletableFuture<List<DbgModuleMemory>> listOSMemory() {
|
||||
return execute(new DbgListOSMemoryRegionsCommand(this));
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompletableFuture<Map<DebugThreadId, DbgThread>> listOSThreads(DbgProcessImpl proc) {
|
||||
return execute(new DbgListOSThreadsCommand(this, proc));
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompletableFuture<List<Pair<Integer, String>>> listAvailableProcesses() {
|
||||
return execute(new DbgListAvailableProcessesCommand(this));
|
||||
@ -1682,7 +1668,6 @@ public class DbgManagerImpl implements DbgManager {
|
||||
//System.err.println("EXIT");
|
||||
waiting = false;
|
||||
updateState();
|
||||
getEventListeners().fire.threadSelected(eventThread, null, Causes.UNCLAIMED);
|
||||
return CompletableFuture.completedFuture(null);
|
||||
}
|
||||
|
||||
@ -1782,28 +1767,32 @@ public class DbgManagerImpl implements DbgManager {
|
||||
DebugSystemObjects so = getSystemObjects();
|
||||
currentSession = eventSession = getSessionComputeIfAbsent(esid, true);
|
||||
if (kernelMode) {
|
||||
long poffset = so.getCurrentProcessDataOffset();
|
||||
currentProcess = eventProcess = getProcessComputeIfAbsent(new DebugProcessId(poffset), -1, true);
|
||||
if (currentProcess.getPid() < 0) {
|
||||
DbgProcessImpl cp = getProcessComputeIfAbsent(new DebugSystemProcessRecord(epid.value()), -1, true);
|
||||
cp.setOffset(so.getCurrentProcessDataOffset());
|
||||
currentProcess = eventProcess = cp;
|
||||
if (currentProcess.getId().isSystem()) {
|
||||
execute(new DbgResolveProcessCommand(this, currentProcess)).thenAccept(proc -> {
|
||||
currentProcess = eventProcess = proc;
|
||||
// As you now have both pid & offset, update the id==pid version
|
||||
DbgProcessImpl mirror = getProcessComputeIfAbsent(new DebugProcessId(proc.getPid()), -1, false);
|
||||
DbgProcessImpl mirror = getProcessComputeIfAbsent(new DebugProcessRecord(proc.getPid()), proc.getPid(), true);
|
||||
if (mirror != null) {
|
||||
mirror.setOffset(currentProcess.getOffset());
|
||||
currentProcess = eventProcess = mirror;
|
||||
getEventListeners().fire.processSelected(eventProcess, Causes.UNCLAIMED);
|
||||
}
|
||||
});
|
||||
}
|
||||
long toffset = so.getCurrentThreadDataOffset();
|
||||
currentThread = eventThread = getThreadComputeIfAbsent(new DebugThreadId(toffset), (DbgProcessImpl) eventProcess, -1, false);
|
||||
if (currentThread.getTid() < 0) {
|
||||
DbgThreadImpl ct = getThreadComputeIfAbsent(new DebugSystemThreadRecord(etid.value()), cp, -1, false);
|
||||
ct.setOffset(so.getCurrentThreadDataOffset());
|
||||
currentThread = eventThread = ct;
|
||||
if (currentThread.getId().isSystem()) {
|
||||
execute(new DbgResolveThreadCommand(this, currentThread)).thenAccept(thread -> {
|
||||
currentThread = eventThread = thread;
|
||||
// As you now have both tid & offset, update the id==tid version
|
||||
DbgThreadImpl mirror = getThreadComputeIfAbsent(new DebugThreadId(thread.getTid()), (DbgProcessImpl) eventProcess, -1, false);
|
||||
DbgThreadImpl mirror = getThreadComputeIfAbsent(new DebugThreadRecord(thread.getTid()), (DbgProcessImpl) eventProcess, thread.getTid(), true);
|
||||
if (mirror != null) {
|
||||
mirror.setOffset(currentThread.getOffset());
|
||||
currentThread = eventThread = mirror;
|
||||
getEventListeners().fire.threadSelected(eventThread, null, Causes.UNCLAIMED);
|
||||
}
|
||||
});
|
||||
@ -1813,6 +1802,7 @@ public class DbgManagerImpl implements DbgManager {
|
||||
eventProcess = getProcessComputeIfAbsent(epid, so.getCurrentProcessSystemId(), true);
|
||||
currentThread = eventThread = getThreadComputeIfAbsent(etid, (DbgProcessImpl) eventProcess,
|
||||
so.getCurrentThreadSystemId(), false);
|
||||
getEventListeners().fire.threadSelected(eventThread, null, Causes.UNCLAIMED);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -133,6 +133,7 @@ public class DbgProcessImpl implements DbgProcess {
|
||||
* @param thread the thread to add
|
||||
*/
|
||||
public void addThread(DbgThreadImpl thread) {
|
||||
assert(thread.getProcess().equals(this));
|
||||
DbgThreadImpl exists = threads.get(thread.getId());
|
||||
if (exists != null) {
|
||||
Msg.warn(this, "Adding pre-existing thread " + exists);
|
||||
@ -207,6 +208,9 @@ public class DbgProcessImpl implements DbgProcess {
|
||||
|
||||
@Override
|
||||
public CompletableFuture<Map<DebugThreadId, DbgThread>> listThreads() {
|
||||
if (manager.isKernelMode() && !id.isSystem()) {
|
||||
return CompletableFuture.completedFuture(getKnownThreads());
|
||||
}
|
||||
return manager.execute(new DbgListThreadsCommand(manager, this));
|
||||
}
|
||||
|
||||
|
@ -18,6 +18,7 @@ package agent.dbgeng.model.iface2;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
|
||||
import agent.dbgeng.dbgeng.DebugProcessId;
|
||||
import agent.dbgeng.dbgeng.DebugProcessRecord;
|
||||
import agent.dbgeng.manager.DbgEventsListenerAdapter;
|
||||
import agent.dbgeng.manager.DbgProcess;
|
||||
import agent.dbgeng.manager.DbgState;
|
||||
@ -73,7 +74,7 @@ public interface DbgModelTargetProcess extends //
|
||||
try {
|
||||
String index = PathUtils.parseIndex(getName());
|
||||
Long pid = Long.decode(index);
|
||||
DebugProcessId id = new DebugProcessId(pid);
|
||||
DebugProcessId id = new DebugProcessRecord(pid);
|
||||
return manager.getProcessComputeIfAbsent(id, pid, fire);
|
||||
}
|
||||
catch (IllegalArgumentException e) {
|
||||
|
@ -82,11 +82,12 @@ public interface DbgModelTargetRegisterBank extends DbgModelTargetObject, Target
|
||||
VALUE_ATTRIBUTE_NAME, value.toString(16) //
|
||||
), "Refreshed");
|
||||
if (value.longValue() != 0) {
|
||||
String newval = reg.getName() + " : " + value.toString(16);
|
||||
String valstr = Long.toUnsignedString(value.longValue(), 16); //value.toString(16);
|
||||
String newval = reg.getName() + " : " + valstr;
|
||||
reg.changeAttributes(List.of(), Map.of( //
|
||||
DISPLAY_ATTRIBUTE_NAME, newval //
|
||||
), "Refreshed");
|
||||
reg.setModified(value.toString(16).equals(oldval));
|
||||
reg.setModified(valstr.equals(oldval));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -21,10 +21,16 @@ import java.util.concurrent.CompletableFuture;
|
||||
|
||||
import agent.dbgeng.dbgeng.DebugClient.DebugOutputFlags;
|
||||
import agent.dbgeng.dbgeng.DebugSessionId;
|
||||
import agent.dbgeng.dbgeng.DebugSessionRecord;
|
||||
import agent.dbgeng.manager.DbgEventsListenerAdapter;
|
||||
import agent.dbgeng.manager.DbgSession;
|
||||
import agent.dbgeng.manager.impl.DbgManagerImpl;
|
||||
import agent.dbgeng.model.iface1.*;
|
||||
import agent.dbgeng.model.iface1.DbgModelSelectableObject;
|
||||
import agent.dbgeng.model.iface1.DbgModelTargetAccessConditioned;
|
||||
import agent.dbgeng.model.iface1.DbgModelTargetExecutionStateful;
|
||||
import agent.dbgeng.model.iface1.DbgModelTargetInterpreter;
|
||||
import agent.dbgeng.model.iface1.DbgModelTargetInterruptible;
|
||||
import agent.dbgeng.model.iface1.DbgModelTargetResumable;
|
||||
import ghidra.dbg.target.TargetAggregate;
|
||||
import ghidra.dbg.target.TargetConsole;
|
||||
import ghidra.dbg.target.TargetConsole.Channel;
|
||||
@ -52,7 +58,7 @@ public interface DbgModelTargetSession extends //
|
||||
try {
|
||||
String index = PathUtils.parseIndex(getName());
|
||||
Integer sid = Integer.decode(index);
|
||||
DebugSessionId id = new DebugSessionId(sid);
|
||||
DebugSessionId id = new DebugSessionRecord(sid);
|
||||
return manager.getSessionComputeIfAbsent(id, fire);
|
||||
}
|
||||
catch (IllegalArgumentException e) {
|
||||
|
@ -18,6 +18,7 @@ package agent.dbgeng.model.iface2;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
|
||||
import agent.dbgeng.dbgeng.DebugThreadId;
|
||||
import agent.dbgeng.dbgeng.DebugThreadRecord;
|
||||
import agent.dbgeng.manager.DbgEventsListenerAdapter;
|
||||
import agent.dbgeng.manager.DbgReason;
|
||||
import agent.dbgeng.manager.DbgState;
|
||||
@ -30,7 +31,9 @@ import agent.dbgeng.model.iface1.DbgModelTargetAccessConditioned;
|
||||
import agent.dbgeng.model.iface1.DbgModelTargetExecutionStateful;
|
||||
import agent.dbgeng.model.iface1.DbgModelTargetSteppable;
|
||||
import agent.dbgeng.model.impl.DbgModelTargetStackImpl;
|
||||
import ghidra.dbg.target.*;
|
||||
import ghidra.dbg.target.TargetAggregate;
|
||||
import ghidra.dbg.target.TargetMethod;
|
||||
import ghidra.dbg.target.TargetThread;
|
||||
import ghidra.dbg.util.PathUtils;
|
||||
import ghidra.program.model.address.Address;
|
||||
|
||||
@ -54,7 +57,7 @@ public interface DbgModelTargetThread extends //
|
||||
DbgProcessImpl process = parentProcess == null ? null : (DbgProcessImpl) parentProcess.getProcess();
|
||||
String index = PathUtils.parseIndex(getName());
|
||||
Long tid = Long.decode(index);
|
||||
DebugThreadId id = new DebugThreadId(tid);
|
||||
DebugThreadId id = new DebugThreadRecord(tid);
|
||||
DbgThreadImpl thread = manager.getThreadComputeIfAbsent(id, process, tid, fire);
|
||||
return thread;
|
||||
}
|
||||
|
@ -23,11 +23,13 @@ import java.util.concurrent.RejectedExecutionException;
|
||||
|
||||
import org.apache.commons.lang3.exception.ExceptionUtils;
|
||||
|
||||
import agent.dbgeng.dbgeng.DebugSessionId;
|
||||
import agent.dbgeng.dbgeng.DebugSessionRecord;
|
||||
import agent.dbgeng.manager.DbgManager;
|
||||
import agent.dbgeng.manager.DbgSession;
|
||||
import agent.dbgeng.model.AbstractDbgModel;
|
||||
import agent.dbgeng.model.iface2.*;
|
||||
import agent.dbgeng.model.iface2.DbgModelTargetProcess;
|
||||
import agent.dbgeng.model.iface2.DbgModelTargetSession;
|
||||
import agent.dbgeng.model.iface2.DbgModelTargetSessionContainer;
|
||||
import ghidra.async.AsyncUtils;
|
||||
import ghidra.dbg.DebuggerModelClosedReason;
|
||||
import ghidra.dbg.DebuggerObjectModelWithMemory;
|
||||
@ -36,7 +38,11 @@ import ghidra.dbg.target.TargetMemory;
|
||||
import ghidra.dbg.target.TargetObject;
|
||||
import ghidra.dbg.target.schema.AnnotatedSchemaContext;
|
||||
import ghidra.dbg.target.schema.TargetObjectSchema;
|
||||
import ghidra.program.model.address.*;
|
||||
import ghidra.program.model.address.Address;
|
||||
import ghidra.program.model.address.AddressFactory;
|
||||
import ghidra.program.model.address.AddressSpace;
|
||||
import ghidra.program.model.address.DefaultAddressFactory;
|
||||
import ghidra.program.model.address.GenericAddressSpace;
|
||||
|
||||
public class DbgModelImpl extends AbstractDbgModel implements DebuggerObjectModelWithMemory {
|
||||
// TODO: Need some minimal memory modeling per architecture on the model/agent side.
|
||||
@ -67,7 +73,7 @@ public class DbgModelImpl extends AbstractDbgModel implements DebuggerObjectMode
|
||||
//System.out.println(XmlSchemaContext.serialize(SCHEMA_CTX));
|
||||
this.root = new DbgModelTargetRootImpl(this, ROOT_SCHEMA);
|
||||
this.completedRoot = CompletableFuture.completedFuture(root);
|
||||
DbgSession s = dbg.getSessionComputeIfAbsent(new DebugSessionId(0), true);
|
||||
DbgSession s = dbg.getSessionComputeIfAbsent(new DebugSessionRecord(0), true);
|
||||
DbgModelTargetSessionContainer sessions = root.sessions;
|
||||
this.session = (DbgModelTargetSessionImpl) sessions.getTargetSession(s);
|
||||
addModelRoot(root);
|
||||
|
@ -15,24 +15,46 @@
|
||||
*/
|
||||
package agent.dbgeng.model.impl;
|
||||
|
||||
import java.lang.invoke.MethodHandles;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.*;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import agent.dbgeng.manager.DbgModuleMemory;
|
||||
import agent.dbgeng.manager.cmd.*;
|
||||
import agent.dbgeng.manager.cmd.DbgListKernelMemoryRegionsCommand;
|
||||
import agent.dbgeng.manager.cmd.DbgListMemoryRegionsCommand;
|
||||
import agent.dbgeng.manager.cmd.DbgListOSMemoryRegionsCommand;
|
||||
import agent.dbgeng.manager.cmd.DbgReadBusDataCommand;
|
||||
import agent.dbgeng.manager.cmd.DbgReadControlCommand;
|
||||
import agent.dbgeng.manager.cmd.DbgReadDebuggerDataCommand;
|
||||
import agent.dbgeng.manager.cmd.DbgReadIoCommand;
|
||||
import agent.dbgeng.manager.cmd.DbgReadMemoryCommand;
|
||||
import agent.dbgeng.manager.cmd.DbgReadPhysicalMemoryCommand;
|
||||
import agent.dbgeng.manager.cmd.DbgWriteBusDataCommand;
|
||||
import agent.dbgeng.manager.cmd.DbgWriteControlCommand;
|
||||
import agent.dbgeng.manager.cmd.DbgWriteIoCommand;
|
||||
import agent.dbgeng.manager.cmd.DbgWriteMemoryCommand;
|
||||
import agent.dbgeng.manager.cmd.DbgWritePhysicalMemoryCommand;
|
||||
import agent.dbgeng.manager.impl.DbgManagerImpl;
|
||||
import agent.dbgeng.manager.impl.DbgProcessImpl;
|
||||
import agent.dbgeng.model.iface2.*;
|
||||
import agent.dbgeng.model.iface2.DbgModelTargetMemoryContainer;
|
||||
import agent.dbgeng.model.iface2.DbgModelTargetMemoryRegion;
|
||||
import agent.dbgeng.model.iface2.DbgModelTargetProcess;
|
||||
import generic.ULongSpan;
|
||||
import generic.ULongSpan.ULongSpanSet;
|
||||
import ghidra.async.AsyncUtils;
|
||||
import ghidra.dbg.DebuggerObjectModel.RefreshBehavior;
|
||||
import ghidra.dbg.error.DebuggerMemoryAccessException;
|
||||
import ghidra.dbg.error.DebuggerModelAccessException;
|
||||
import ghidra.dbg.target.TargetMethod;
|
||||
import ghidra.dbg.target.TargetMethod.AnnotatedTargetMethod;
|
||||
import ghidra.dbg.target.TargetObject;
|
||||
import ghidra.dbg.target.schema.*;
|
||||
import ghidra.dbg.target.schema.TargetAttributeType;
|
||||
import ghidra.dbg.target.schema.TargetElementType;
|
||||
import ghidra.dbg.target.schema.TargetObjectSchemaInfo;
|
||||
import ghidra.program.model.address.Address;
|
||||
import ghidra.util.datastruct.WeakValueHashMap;
|
||||
|
||||
@ -41,6 +63,7 @@ import ghidra.util.datastruct.WeakValueHashMap;
|
||||
elements = {
|
||||
@TargetElementType(type = DbgModelTargetMemoryRegionImpl.class) },
|
||||
attributes = {
|
||||
@TargetAttributeType(name = "Populate", type = TargetMethod.class),
|
||||
@TargetAttributeType(type = Void.class) },
|
||||
canonicalContainer = true)
|
||||
public class DbgModelTargetMemoryContainerImpl extends DbgModelTargetObjectImpl
|
||||
@ -57,6 +80,12 @@ public class DbgModelTargetMemoryContainerImpl extends DbgModelTargetObjectImpl
|
||||
if (!getModel().isSuppressDescent()) {
|
||||
requestElements(RefreshBehavior.REFRESH_ALWAYS);
|
||||
}
|
||||
DbgManagerImpl manager = getManager();
|
||||
if (manager.isKernelMode()) {
|
||||
changeAttributes(List.of(), List.of(),
|
||||
AnnotatedTargetMethod.collectExports(MethodHandles.lookup(), getModel(), this),
|
||||
"Methods");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -96,7 +125,7 @@ public class DbgModelTargetMemoryContainerImpl extends DbgModelTargetObjectImpl
|
||||
return manager.execute(new DbgListKernelMemoryRegionsCommand(manager));
|
||||
}
|
||||
if (manager.useAltMemoryQuery()) {
|
||||
return manager.execute(new DbgListMemoryRegionsCommandAlt(manager));
|
||||
return manager.execute(new DbgListOSMemoryRegionsCommand(manager));
|
||||
}
|
||||
return manager.execute(new DbgListMemoryRegionsCommand(manager));
|
||||
}
|
||||
@ -271,4 +300,13 @@ public class DbgModelTargetMemoryContainerImpl extends DbgModelTargetObjectImpl
|
||||
return CompletableFuture.completedFuture(null);
|
||||
}
|
||||
|
||||
}
|
||||
@TargetMethod.Export("Populate")
|
||||
public CompletableFuture<Void> populate() {
|
||||
return getManager().listOSMemory().thenAccept(byName -> {
|
||||
List<TargetObject> sections;
|
||||
synchronized (this) {
|
||||
sections = byName.stream().map(this::getTargetMemory).collect(Collectors.toList());
|
||||
}
|
||||
setElements(sections, Map.of(), "Refreshed");
|
||||
});
|
||||
}}
|
||||
|
@ -20,6 +20,7 @@ import java.util.concurrent.CompletableFuture;
|
||||
|
||||
import agent.dbgeng.manager.DbgModule;
|
||||
import agent.dbgeng.manager.DbgProcess;
|
||||
import agent.dbgeng.manager.impl.DbgManagerImpl;
|
||||
import agent.dbgeng.model.iface2.DbgModelTargetModule;
|
||||
import agent.dbgeng.model.iface2.DbgModelTargetModuleContainer;
|
||||
import ghidra.dbg.DebuggerObjectModel.RefreshBehavior;
|
||||
@ -49,9 +50,16 @@ public class DbgModelTargetModuleContainerImpl extends DbgModelTargetObjectImpl
|
||||
super(process.getModel(), process, "Modules", "ModuleContainer");
|
||||
this.targetProcess = process;
|
||||
this.process = process.process;
|
||||
if (!getModel().isSuppressDescent()) {
|
||||
requestElements(RefreshBehavior.REFRESH_NEVER);
|
||||
DbgManagerImpl manager = getManager();
|
||||
if (manager.isKernelMode()) {
|
||||
if (!this.process.getId().isSystem()) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (getModel().isSuppressDescent()) {
|
||||
return;
|
||||
}
|
||||
requestElements(RefreshBehavior.REFRESH_NEVER);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -125,9 +125,18 @@ public class DbgModelTargetObjectImpl extends DefaultTargetObject<TargetObject,
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (this instanceof DbgModelTargetExecutionStateful) {
|
||||
DbgModelTargetExecutionStateful stateful = (DbgModelTargetExecutionStateful) this;
|
||||
stateful.setExecutionState(exec, "Refreshed");
|
||||
if (proxy instanceof DbgModelTargetExecutionStateful stateful) {
|
||||
if (proxy instanceof DbgModelTargetSession) {
|
||||
if (state != DbgState.EXIT) {
|
||||
stateful.setExecutionState(exec, "Refreshed");
|
||||
}
|
||||
}
|
||||
else {
|
||||
TargetExecutionState previous = stateful.getExecutionState();
|
||||
if (!previous.equals(TargetExecutionState.INACTIVE)) {
|
||||
stateful.setExecutionState(exec, "Refreshed");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -15,22 +15,38 @@
|
||||
*/
|
||||
package agent.dbgeng.model.impl;
|
||||
|
||||
import java.lang.invoke.MethodHandles;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import agent.dbgeng.dbgeng.*;
|
||||
import agent.dbgeng.manager.*;
|
||||
import agent.dbgeng.dbgeng.DebugModuleInfo;
|
||||
import agent.dbgeng.dbgeng.DebugProcessId;
|
||||
import agent.dbgeng.dbgeng.DebugThreadId;
|
||||
import agent.dbgeng.manager.DbgCause;
|
||||
import agent.dbgeng.manager.DbgProcess;
|
||||
import agent.dbgeng.manager.DbgReason;
|
||||
import agent.dbgeng.manager.DbgState;
|
||||
import agent.dbgeng.manager.DbgThread;
|
||||
import agent.dbgeng.manager.breakpoint.DbgBreakpointInfo;
|
||||
import agent.dbgeng.manager.impl.DbgManagerImpl;
|
||||
import agent.dbgeng.model.iface1.DbgModelTargetConfigurable;
|
||||
import agent.dbgeng.model.iface2.*;
|
||||
import agent.dbgeng.model.iface2.DbgModelTargetMemoryContainer;
|
||||
import agent.dbgeng.model.iface2.DbgModelTargetModuleContainer;
|
||||
import agent.dbgeng.model.iface2.DbgModelTargetProcess;
|
||||
import agent.dbgeng.model.iface2.DbgModelTargetProcessContainer;
|
||||
import agent.dbgeng.model.iface2.DbgModelTargetSession;
|
||||
import ghidra.async.AsyncUtils;
|
||||
import ghidra.dbg.DebuggerObjectModel.RefreshBehavior;
|
||||
import ghidra.dbg.error.DebuggerIllegalArgumentException;
|
||||
import ghidra.dbg.target.TargetConfigurable;
|
||||
import ghidra.dbg.target.TargetMethod;
|
||||
import ghidra.dbg.target.TargetMethod.AnnotatedTargetMethod;
|
||||
import ghidra.dbg.target.TargetObject;
|
||||
import ghidra.dbg.target.schema.*;
|
||||
import ghidra.dbg.target.schema.TargetAttributeType;
|
||||
import ghidra.dbg.target.schema.TargetElementType;
|
||||
import ghidra.dbg.target.schema.TargetObjectSchemaInfo;
|
||||
|
||||
@TargetObjectSchemaInfo(
|
||||
name = "ProcessContainer",
|
||||
@ -39,6 +55,7 @@ import ghidra.dbg.target.schema.*;
|
||||
},
|
||||
attributes = {
|
||||
@TargetAttributeType(name = TargetConfigurable.BASE_ATTRIBUTE_NAME, type = Integer.class),
|
||||
@TargetAttributeType(name = "Populate", type = TargetMethod.class),
|
||||
@TargetAttributeType(type = Void.class)
|
||||
},
|
||||
canonicalContainer = true)
|
||||
@ -49,7 +66,8 @@ public class DbgModelTargetProcessContainerImpl extends DbgModelTargetObjectImpl
|
||||
super(session.getModel(), session, "Processes", "ProcessContainer");
|
||||
this.changeAttributes(List.of(), Map.of(BASE_ATTRIBUTE_NAME, 16), "Initialized");
|
||||
|
||||
getManager().addEventsListener(this);
|
||||
DbgManagerImpl manager = getManager();
|
||||
manager.addEventsListener(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -62,7 +80,14 @@ public class DbgModelTargetProcessContainerImpl extends DbgModelTargetObjectImpl
|
||||
broadcast().event(getProxy(), null, TargetEventType.PROCESS_CREATED,
|
||||
"Process " + proc.getId() + " started " + process.getName() + "pid=" + proc.getPid(),
|
||||
List.of(process));
|
||||
}
|
||||
|
||||
DbgManagerImpl manager = getManager();
|
||||
if (manager.isKernelMode()) {
|
||||
changeAttributes(List.of(), List.of(),
|
||||
AnnotatedTargetMethod.collectExports(MethodHandles.lookup(), getModel(), this),
|
||||
"Methods");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void processStarted(DbgProcess proc, DbgCause cause) {
|
||||
@ -133,7 +158,8 @@ public class DbgModelTargetProcessContainerImpl extends DbgModelTargetObjectImpl
|
||||
|
||||
@Override
|
||||
public CompletableFuture<Void> requestElements(RefreshBehavior refresh) {
|
||||
return getManager().listProcesses().thenAccept(byIID -> {
|
||||
DbgManagerImpl manager = getManager();
|
||||
return manager.listProcesses().thenAccept(byIID -> {
|
||||
List<TargetObject> processes;
|
||||
synchronized (this) {
|
||||
processes = byIID.values()
|
||||
@ -188,4 +214,15 @@ public class DbgModelTargetProcessContainerImpl extends DbgModelTargetObjectImpl
|
||||
return AsyncUtils.NIL;
|
||||
}
|
||||
|
||||
@TargetMethod.Export("Populate")
|
||||
public CompletableFuture<Void> populate() {
|
||||
return getManager().listOSProcesses().thenAccept(byPID -> {
|
||||
List<TargetObject> processes;
|
||||
synchronized (this) {
|
||||
processes =
|
||||
byPID.values().stream().map(this::getTargetProcess).collect(Collectors.toList());
|
||||
}
|
||||
setElements(processes, Map.of(), "Refreshed");
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -20,14 +20,24 @@ import java.util.Map;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
|
||||
import agent.dbgeng.dbgeng.DebugProcessId;
|
||||
import agent.dbgeng.manager.*;
|
||||
import agent.dbgeng.manager.DbgCause;
|
||||
import agent.dbgeng.manager.DbgProcess;
|
||||
import agent.dbgeng.manager.DbgState;
|
||||
import agent.dbgeng.manager.DbgThread;
|
||||
import agent.dbgeng.manager.impl.DbgManagerImpl;
|
||||
import agent.dbgeng.model.iface1.DbgModelTargetFocusScope;
|
||||
import agent.dbgeng.model.iface2.*;
|
||||
import agent.dbgeng.model.iface2.DbgModelTargetDebugContainer;
|
||||
import agent.dbgeng.model.iface2.DbgModelTargetMemoryContainer;
|
||||
import agent.dbgeng.model.iface2.DbgModelTargetModuleContainer;
|
||||
import agent.dbgeng.model.iface2.DbgModelTargetProcess;
|
||||
import agent.dbgeng.model.iface2.DbgModelTargetProcessContainer;
|
||||
import agent.dbgeng.model.iface2.DbgModelTargetThreadContainer;
|
||||
import ghidra.dbg.DebuggerObjectModel.RefreshBehavior;
|
||||
import ghidra.dbg.target.*;
|
||||
import ghidra.dbg.target.TargetAttachable;
|
||||
import ghidra.dbg.target.TargetEventScope.TargetEventType;
|
||||
import ghidra.dbg.target.schema.*;
|
||||
import ghidra.dbg.target.TargetObject;
|
||||
import ghidra.dbg.target.schema.TargetAttributeType;
|
||||
import ghidra.dbg.target.schema.TargetElementType;
|
||||
import ghidra.dbg.target.schema.TargetObjectSchemaInfo;
|
||||
import ghidra.dbg.util.PathUtils;
|
||||
|
||||
@TargetObjectSchemaInfo(
|
||||
@ -69,7 +79,7 @@ public class DbgModelTargetProcessImpl extends DbgModelTargetObjectImpl
|
||||
TargetAttachKind.BY_OBJECT_REF, TargetAttachKind.BY_ID);
|
||||
|
||||
protected static String indexProcess(DebugProcessId debugProcessId) {
|
||||
return PathUtils.makeIndex(debugProcessId.id);
|
||||
return debugProcessId.id();
|
||||
}
|
||||
|
||||
protected static String indexProcess(DbgProcess process) {
|
||||
@ -111,32 +121,42 @@ public class DbgModelTargetProcessImpl extends DbgModelTargetObjectImpl
|
||||
SUPPORTED_ATTACH_KINDS_ATTRIBUTE_NAME, SUPPORTED_KINDS, //
|
||||
SUPPORTED_STEP_KINDS_ATTRIBUTE_NAME, DbgModelTargetThreadImpl.SUPPORTED_KINDS //
|
||||
), "Initialized");
|
||||
setExecutionState(TargetExecutionState.ALIVE, "Initialized");
|
||||
if (getManager().isKernelMode()) {
|
||||
TargetExecutionState state = process.getPid() > 0 ?
|
||||
TargetExecutionState.INACTIVE : TargetExecutionState.ALIVE;
|
||||
setExecutionState(state, "Initialized");
|
||||
}
|
||||
else {
|
||||
setExecutionState(TargetExecutionState.ALIVE, "Initialized");
|
||||
}
|
||||
|
||||
getManager().addEventsListener(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDisplay() {
|
||||
if (getManager().isKernelMode()) {
|
||||
return "[kernel]";
|
||||
}
|
||||
|
||||
DebugProcessId id = process.getId();
|
||||
Long pid = process.getPid();
|
||||
if (pid < 0) {
|
||||
return "[" + process.getId().id + "]";
|
||||
if (getManager().isKernelMode()) {
|
||||
if (id.isSystem()) {
|
||||
return "["+id.id()+"]";
|
||||
}
|
||||
String pidstr = Long.toString(pid, base);
|
||||
if (base == 16) {
|
||||
pidstr = "0x" + pidstr;
|
||||
}
|
||||
Long offset = process.getOffset();
|
||||
return offset == null ? "[" + pidstr + "]" : "[" + pidstr + " : " + Long.toHexString(offset) + "]";
|
||||
}
|
||||
String pidstr = Long.toString(pid, base);
|
||||
if (base == 16) {
|
||||
pidstr = "0x" + pidstr;
|
||||
}
|
||||
return "[" + process.getId().id + ":" + pidstr + "]";
|
||||
}
|
||||
|
||||
@Override
|
||||
public void processSelected(DbgProcess eventProcess, DbgCause cause) {
|
||||
if (eventProcess.equals(process)) {
|
||||
((DbgModelTargetFocusScope) searchForSuitable(TargetFocusScope.class)).setFocus(this);
|
||||
else {
|
||||
if (pid < 0) {
|
||||
return "[" + id.id() + "]";
|
||||
}
|
||||
String pidstr = Long.toString(pid, base);
|
||||
if (base == 16) {
|
||||
pidstr = "0x" + pidstr;
|
||||
}
|
||||
return "[" + id.id() + ":" + pidstr + "]";
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -170,13 +170,14 @@ public class DbgModelTargetRegisterContainerImpl extends DbgModelTargetObjectImp
|
||||
|
||||
private void changeAttrs(DbgModelTargetRegister reg, BigInteger value) {
|
||||
String oldval = (String) reg.getCachedAttributes().get(VALUE_ATTRIBUTE_NAME);
|
||||
String valstr = Long.toUnsignedString(value.longValue(), 16); //value.toString(16);
|
||||
String newval = (value.longValue() == 0) ? reg.getName()
|
||||
: reg.getName() + " : " + value.toString(16);
|
||||
: reg.getName() + " : " + valstr;
|
||||
reg.changeAttributes(List.of(), Map.of( //
|
||||
VALUE_ATTRIBUTE_NAME, value.toString(16), //
|
||||
VALUE_ATTRIBUTE_NAME, valstr, //
|
||||
DISPLAY_ATTRIBUTE_NAME, newval //
|
||||
), "Refreshed");
|
||||
reg.setModified(!value.toString(16).equals(oldval));
|
||||
reg.setModified(!valstr.equals(oldval));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -15,16 +15,41 @@
|
||||
*/
|
||||
package agent.dbgeng.model.impl;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
|
||||
import agent.dbgeng.manager.*;
|
||||
import agent.dbgeng.dbgeng.DebugProcessId;
|
||||
import agent.dbgeng.dbgeng.DebugThreadId;
|
||||
import agent.dbgeng.manager.DbgCause;
|
||||
import agent.dbgeng.manager.DbgProcess;
|
||||
import agent.dbgeng.manager.DbgReason;
|
||||
import agent.dbgeng.manager.DbgSession;
|
||||
import agent.dbgeng.manager.DbgStackFrame;
|
||||
import agent.dbgeng.manager.DbgState;
|
||||
import agent.dbgeng.manager.DbgThread;
|
||||
import agent.dbgeng.manager.impl.DbgManagerImpl;
|
||||
import agent.dbgeng.manager.impl.DbgProcessImpl;
|
||||
import agent.dbgeng.model.AbstractDbgModel;
|
||||
import agent.dbgeng.model.iface1.DbgModelSelectableObject;
|
||||
import agent.dbgeng.model.iface2.*;
|
||||
import agent.dbgeng.model.iface1.DbgModelTargetExecutionStateful;
|
||||
import agent.dbgeng.model.iface2.DbgModelTargetConnector;
|
||||
import agent.dbgeng.model.iface2.DbgModelTargetRoot;
|
||||
import agent.dbgeng.model.iface2.DbgModelTargetThread;
|
||||
import ghidra.dbg.DebuggerObjectModel.RefreshBehavior;
|
||||
import ghidra.dbg.error.DebuggerUserException;
|
||||
import ghidra.dbg.target.*;
|
||||
import ghidra.dbg.target.schema.*;
|
||||
import ghidra.dbg.target.TargetEventScope;
|
||||
import ghidra.dbg.target.TargetExecutionStateful;
|
||||
import ghidra.dbg.target.TargetExecutionStateful.TargetExecutionState;
|
||||
import ghidra.dbg.target.TargetFocusScope;
|
||||
import ghidra.dbg.target.TargetMethod;
|
||||
import ghidra.dbg.target.TargetObject;
|
||||
import ghidra.dbg.target.schema.TargetAttributeType;
|
||||
import ghidra.dbg.target.schema.TargetElementType;
|
||||
import ghidra.dbg.target.schema.TargetObjectSchema;
|
||||
import ghidra.dbg.target.schema.TargetObjectSchemaInfo;
|
||||
import ghidra.dbg.util.PathUtils;
|
||||
|
||||
@TargetObjectSchemaInfo(
|
||||
@ -142,6 +167,117 @@ public class DbgModelTargetRootImpl extends DbgModelDefaultTargetModelRoot
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void processSelected(DbgProcess process, DbgCause cause) {
|
||||
if (process != null) {
|
||||
objectSelected(process);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void threadSelected(DbgThread thread, DbgStackFrame frame, DbgCause cause) {
|
||||
if (thread != null) {
|
||||
objectSelected(thread);
|
||||
if (frame != null) {
|
||||
objectSelected(frame);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void objectSelected(Object object) {
|
||||
AbstractDbgModel model = getModel();
|
||||
List<String> objPath = findObject(object);
|
||||
model.fetchModelObject(objPath, RefreshBehavior.REFRESH_WHEN_ABSENT).thenAccept(obj ->
|
||||
update(obj)
|
||||
);
|
||||
}
|
||||
|
||||
private List<String> findObject(Object obj) {
|
||||
DbgManagerImpl manager = getManager();
|
||||
List<String> objpath = new ArrayList<>();
|
||||
if (obj == null) {
|
||||
return objpath;
|
||||
}
|
||||
DbgSession session = manager.getCurrentSession();
|
||||
if (obj instanceof DbgSession) {
|
||||
session = (DbgSession) obj;
|
||||
}
|
||||
if (session == null) {
|
||||
return objpath;
|
||||
}
|
||||
String skey = DbgModelTargetSessionImpl.keySession(session);
|
||||
if (obj instanceof DbgSession || obj instanceof String) {
|
||||
objpath = List.of("Sessions", skey);
|
||||
return objpath;
|
||||
}
|
||||
|
||||
DbgProcess process = manager.getCurrentProcess();
|
||||
if (obj instanceof DbgProcess) {
|
||||
process = (DbgProcess) obj;
|
||||
}
|
||||
if (process == null) {
|
||||
return objpath;
|
||||
}
|
||||
String pkey = DbgModelTargetProcessImpl.keyProcess(process);
|
||||
if (obj instanceof DbgProcess || obj instanceof DebugProcessId) {
|
||||
objpath = List.of("Sessions", skey, "Processes", pkey);
|
||||
return objpath;
|
||||
}
|
||||
|
||||
DbgThread thread = manager.getCurrentThread();
|
||||
if (obj instanceof DbgThread) {
|
||||
thread = (DbgThread) obj;
|
||||
process = thread.getProcess();
|
||||
pkey = DbgModelTargetProcessImpl.keyProcess(process);
|
||||
}
|
||||
if (thread == null) {
|
||||
return objpath;
|
||||
}
|
||||
String tkey = DbgModelTargetThreadImpl.keyThread(thread);
|
||||
if (getManager().isKernelMode()) {
|
||||
if (tkey.equals("[0x0]")) {
|
||||
// Weird, but necessary...
|
||||
pkey = "[0x0]";
|
||||
}
|
||||
}
|
||||
if (obj instanceof DbgThread || obj instanceof DebugThreadId) {
|
||||
objpath = List.of("Sessions", skey, "Processes", pkey, "Threads", tkey);
|
||||
return objpath;
|
||||
}
|
||||
|
||||
if (obj instanceof DbgStackFrame) {
|
||||
DbgStackFrame frame = (DbgStackFrame) obj;
|
||||
thread = frame.getThread();
|
||||
process = thread.getProcess();
|
||||
String fkey = DbgModelTargetStackFrameImpl.keyFrame(frame);
|
||||
tkey = DbgModelTargetThreadImpl.keyThread(thread);
|
||||
pkey = DbgModelTargetProcessImpl.keyProcess(process);
|
||||
objpath = List.of("Sessions", skey, "Processes", pkey, "Threads", tkey, "Stack",
|
||||
"Frames", fkey);
|
||||
return objpath;
|
||||
}
|
||||
return objpath;
|
||||
}
|
||||
|
||||
private void update(TargetObject obj) {
|
||||
if (obj instanceof DbgModelSelectableObject) {
|
||||
setFocus((DbgModelSelectableObject) obj);
|
||||
}
|
||||
if (obj instanceof DbgModelTargetExecutionStateful) {
|
||||
activate((DbgModelTargetExecutionStateful) obj);
|
||||
}
|
||||
}
|
||||
|
||||
private void activate(DbgModelTargetExecutionStateful stateful) {
|
||||
TargetExecutionState state = stateful.getExecutionState();
|
||||
if (state.equals(TargetExecutionState.INACTIVE)) {
|
||||
stateful.changeAttributes(List.of(), Map.of( //
|
||||
TargetExecutionStateful.STATE_ATTRIBUTE_NAME, TargetExecutionState.ALIVE //
|
||||
), "Selected");
|
||||
stateful.fetchAttributes(RefreshBehavior.REFRESH_ALWAYS);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAccessible() {
|
||||
return accessible;
|
||||
|
@ -52,7 +52,7 @@ public class DbgModelTargetSessionImpl extends DbgModelTargetObjectImpl
|
||||
// NB: This should almost certainly always be implemented by the root of the object tree
|
||||
|
||||
protected static String indexSession(DebugSessionId debugSystemId) {
|
||||
return PathUtils.makeIndex(debugSystemId.id);
|
||||
return debugSystemId.id();
|
||||
}
|
||||
|
||||
protected static String indexSession(DbgSession session) {
|
||||
|
@ -109,7 +109,7 @@ public class DbgModelTargetStackFrameImpl extends DbgModelTargetObjectImpl
|
||||
if (frame.getFunction() == null) {
|
||||
return String.format("#%d 0x%s", frame.getLevel(), frame.getAddress().toString(16));
|
||||
}
|
||||
return String.format("#%d 0x%s in %s ()", frame.getLevel(), frame.getAddress().toString(16),
|
||||
return String.format("#%d 0x%s in %s", frame.getLevel(), frame.getAddress().toString(16),
|
||||
frame.getFunction());
|
||||
}
|
||||
|
||||
|
@ -15,30 +15,47 @@
|
||||
*/
|
||||
package agent.dbgeng.model.impl;
|
||||
|
||||
import java.lang.invoke.MethodHandles;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import agent.dbgeng.dbgeng.DebugThreadId;
|
||||
import agent.dbgeng.manager.*;
|
||||
import agent.dbgeng.manager.reason.*;
|
||||
import agent.dbgeng.manager.DbgCause;
|
||||
import agent.dbgeng.manager.DbgProcess;
|
||||
import agent.dbgeng.manager.DbgReason;
|
||||
import agent.dbgeng.manager.DbgState;
|
||||
import agent.dbgeng.manager.DbgThread;
|
||||
import agent.dbgeng.manager.impl.DbgManagerImpl;
|
||||
import agent.dbgeng.manager.impl.DbgProcessImpl;
|
||||
import agent.dbgeng.manager.reason.DbgEndSteppingRangeReason;
|
||||
import agent.dbgeng.manager.reason.DbgExitNormallyReason;
|
||||
import agent.dbgeng.manager.reason.DbgExitedReason;
|
||||
import agent.dbgeng.manager.reason.DbgSignalReceivedReason;
|
||||
import agent.dbgeng.model.iface1.DbgModelTargetConfigurable;
|
||||
import agent.dbgeng.model.iface2.*;
|
||||
import agent.dbgeng.model.iface2.DbgModelTargetProcess;
|
||||
import agent.dbgeng.model.iface2.DbgModelTargetThread;
|
||||
import agent.dbgeng.model.iface2.DbgModelTargetThreadContainer;
|
||||
import ghidra.async.AsyncUtils;
|
||||
import ghidra.dbg.DebuggerObjectModel.RefreshBehavior;
|
||||
import ghidra.dbg.error.DebuggerIllegalArgumentException;
|
||||
import ghidra.dbg.target.TargetConfigurable;
|
||||
import ghidra.dbg.target.TargetMethod;
|
||||
import ghidra.dbg.target.TargetMethod.AnnotatedTargetMethod;
|
||||
import ghidra.dbg.target.TargetObject;
|
||||
import ghidra.dbg.target.schema.*;
|
||||
import ghidra.dbg.target.schema.TargetAttributeType;
|
||||
import ghidra.dbg.target.schema.TargetElementType;
|
||||
import ghidra.dbg.target.schema.TargetObjectSchemaInfo;
|
||||
|
||||
@TargetObjectSchemaInfo(
|
||||
name = "ThreadContainer",
|
||||
elements = {
|
||||
@TargetElementType(type = DbgModelTargetThreadImpl.class)
|
||||
},
|
||||
},
|
||||
attributes = {
|
||||
@TargetAttributeType(name = TargetConfigurable.BASE_ATTRIBUTE_NAME, type = Integer.class),
|
||||
@TargetAttributeType(name = "Populate", type = TargetMethod.class),
|
||||
@TargetAttributeType(type = Void.class)
|
||||
},
|
||||
canonicalContainer = true)
|
||||
@ -50,11 +67,16 @@ public class DbgModelTargetThreadContainerImpl extends DbgModelTargetObjectImpl
|
||||
public DbgModelTargetThreadContainerImpl(DbgModelTargetProcessImpl process) {
|
||||
super(process.getModel(), process, "Threads", "ThreadContainer");
|
||||
this.process = process.process;
|
||||
this.changeAttributes(List.of(), Map.of(BASE_ATTRIBUTE_NAME, 16), "Initialized");
|
||||
this.changeAttributes(List.of(), Map.of(
|
||||
BASE_ATTRIBUTE_NAME, 16 //
|
||||
), "Initialized");
|
||||
|
||||
getManager().addEventsListener(this);
|
||||
if (!getModel().isSuppressDescent()) {
|
||||
requestElements(RefreshBehavior.REFRESH_NEVER);
|
||||
DbgManagerImpl manager = getManager();
|
||||
manager.addEventsListener(this);
|
||||
if (manager.isKernelMode() && !process.getProcess().getId().isSystem()) {
|
||||
changeAttributes(List.of(), List.of(),
|
||||
AnnotatedTargetMethod.collectExports(MethodHandles.lookup(), getModel(), this),
|
||||
"Methods");
|
||||
}
|
||||
}
|
||||
|
||||
@ -71,6 +93,9 @@ public class DbgModelTargetThreadContainerImpl extends DbgModelTargetObjectImpl
|
||||
@Override
|
||||
public void threadStateChanged(DbgThread thread, DbgState state, DbgCause cause,
|
||||
DbgReason reason) {
|
||||
if (!thread.getProcess().equals(process)) {
|
||||
return;
|
||||
}
|
||||
DbgModelTargetThread targetThread = getTargetThread(thread);
|
||||
TargetEventType eventType = getEventType(state, cause, reason);
|
||||
broadcast().event(getProxy(), targetThread, eventType,
|
||||
@ -163,4 +188,17 @@ public class DbgModelTargetThreadContainerImpl extends DbgModelTargetObjectImpl
|
||||
}
|
||||
return AsyncUtils.NIL;
|
||||
}
|
||||
|
||||
@TargetMethod.Export("Populate")
|
||||
public CompletableFuture<Void> populate() {
|
||||
return getManager().listOSThreads((DbgProcessImpl) process).thenAccept(byTID -> {
|
||||
List<TargetObject> threads;
|
||||
synchronized (this) {
|
||||
threads =
|
||||
byTID.values().stream().map(this::getTargetThread).collect(Collectors.toList());
|
||||
}
|
||||
setElements(threads, Map.of(), "Refreshed");
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -21,14 +21,19 @@ import java.util.Map;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
|
||||
import agent.dbgeng.dbgeng.DebugThreadId;
|
||||
import agent.dbgeng.manager.*;
|
||||
import agent.dbgeng.manager.DbgReason;
|
||||
import agent.dbgeng.manager.DbgState;
|
||||
import agent.dbgeng.manager.DbgThread;
|
||||
import agent.dbgeng.manager.impl.DbgManagerImpl;
|
||||
import agent.dbgeng.model.iface1.DbgModelTargetFocusScope;
|
||||
import agent.dbgeng.model.iface2.*;
|
||||
import agent.dbgeng.model.iface2.DbgModelTargetProcess;
|
||||
import agent.dbgeng.model.iface2.DbgModelTargetRegisterContainerAndBank;
|
||||
import agent.dbgeng.model.iface2.DbgModelTargetThread;
|
||||
import agent.dbgeng.model.iface2.DbgModelTargetThreadContainer;
|
||||
import ghidra.dbg.target.TargetEnvironment;
|
||||
import ghidra.dbg.target.TargetFocusScope;
|
||||
import ghidra.dbg.target.TargetMethod.AnnotatedTargetMethod;
|
||||
import ghidra.dbg.target.schema.*;
|
||||
import ghidra.dbg.target.schema.TargetAttributeType;
|
||||
import ghidra.dbg.target.schema.TargetElementType;
|
||||
import ghidra.dbg.target.schema.TargetObjectSchemaInfo;
|
||||
import ghidra.dbg.util.PathUtils;
|
||||
|
||||
@TargetObjectSchemaInfo(
|
||||
@ -61,7 +66,7 @@ public class DbgModelTargetThreadImpl extends DbgModelTargetObjectImpl
|
||||
TargetStepKind.EXTENDED);
|
||||
|
||||
protected static String indexThread(DebugThreadId debugThreadId) {
|
||||
return PathUtils.makeIndex(debugThreadId.id);
|
||||
return debugThreadId.id();
|
||||
}
|
||||
|
||||
protected static String indexThread(DbgThread thread) {
|
||||
@ -110,24 +115,31 @@ public class DbgModelTargetThreadImpl extends DbgModelTargetObjectImpl
|
||||
|
||||
@Override
|
||||
public String getDisplay() {
|
||||
if (getManager().isKernelMode()) {
|
||||
return "[PR" + thread.getId().id + "]";
|
||||
if (thread == null) {
|
||||
return "[unknown]";
|
||||
}
|
||||
DebugThreadId id = thread.getId();
|
||||
Long tid = thread.getTid();
|
||||
if (tid < 0) {
|
||||
return "[" + thread.getId().id + "]";
|
||||
if (getManager().isKernelMode()) {
|
||||
if (id.isSystem()) {
|
||||
return "[" + id.id() + "]";
|
||||
}
|
||||
String tidstr = Long.toString(tid, base);
|
||||
if (base == 16) {
|
||||
tidstr = "0x" + tidstr;
|
||||
}
|
||||
Long offset = thread.getOffset();
|
||||
return offset == null ? "[" + tidstr + "]" : "[" + tidstr + " : " + Long.toHexString(offset) + "]";
|
||||
}
|
||||
String tidstr = Long.toString(tid, base);
|
||||
if (base == 16) {
|
||||
tidstr = "0x" + tidstr;
|
||||
}
|
||||
return "[" + thread.getId().id + ":" + tidstr + "]";
|
||||
}
|
||||
|
||||
@Override
|
||||
public void threadSelected(DbgThread eventThread, DbgStackFrame frame, DbgCause cause) {
|
||||
if (eventThread.equals(thread)) {
|
||||
((DbgModelTargetFocusScope) searchForSuitable(TargetFocusScope.class)).setFocus(this);
|
||||
else {
|
||||
if (tid < 0) {
|
||||
return "[" + id.id() + "]";
|
||||
}
|
||||
String tidstr = Long.toString(tid, base);
|
||||
if (base == 16) {
|
||||
tidstr = "0x" + tidstr;
|
||||
}
|
||||
return "[" + id.id() + ":" + tidstr + "]";
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -16,17 +16,52 @@
|
||||
package agent.dbgmodel.gadp.impl;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.*;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import com.sun.jna.platform.win32.WinDef.ULONGLONG;
|
||||
import com.sun.jna.platform.win32.COM.COMException;
|
||||
|
||||
import agent.dbgeng.dbgeng.*;
|
||||
import agent.dbgeng.dbgeng.DebugAdvanced;
|
||||
import agent.dbgeng.dbgeng.DebugClient;
|
||||
import agent.dbgeng.dbgeng.DebugControl;
|
||||
import agent.dbgeng.dbgeng.DebugDataSpaces;
|
||||
import agent.dbgeng.dbgeng.DebugEventCallbacks;
|
||||
import agent.dbgeng.dbgeng.DebugInputCallbacks;
|
||||
import agent.dbgeng.dbgeng.DebugModule;
|
||||
import agent.dbgeng.dbgeng.DebugModuleInfo;
|
||||
import agent.dbgeng.dbgeng.DebugOutputCallbacks;
|
||||
import agent.dbgeng.dbgeng.DebugProcessId;
|
||||
import agent.dbgeng.dbgeng.DebugProcessRecord;
|
||||
import agent.dbgeng.dbgeng.DebugRegisters;
|
||||
import agent.dbgeng.dbgeng.DebugRunningProcess;
|
||||
import agent.dbgeng.dbgeng.DebugRunningProcess.Description;
|
||||
import agent.dbgeng.dbgeng.DebugRunningProcess.Description.ProcessDescriptionFlags;
|
||||
import agent.dbgeng.dbgeng.DebugValue.*;
|
||||
import agent.dbgeng.dbgeng.DebugServerId;
|
||||
import agent.dbgeng.dbgeng.DebugSessionId;
|
||||
import agent.dbgeng.dbgeng.DebugSymbolEntry;
|
||||
import agent.dbgeng.dbgeng.DebugSymbolId;
|
||||
import agent.dbgeng.dbgeng.DebugSymbolName;
|
||||
import agent.dbgeng.dbgeng.DebugSymbols;
|
||||
import agent.dbgeng.dbgeng.DebugSystemObjects;
|
||||
import agent.dbgeng.dbgeng.DebugThreadId;
|
||||
import agent.dbgeng.dbgeng.DebugValue;
|
||||
import agent.dbgeng.dbgeng.DebugValue.DebugInt16Value;
|
||||
import agent.dbgeng.dbgeng.DebugValue.DebugInt32Value;
|
||||
import agent.dbgeng.dbgeng.DebugValue.DebugInt64Value;
|
||||
import agent.dbgeng.dbgeng.DebugValue.DebugValueType;
|
||||
import agent.dbgmodel.dbgmodel.bridge.HostDataModelAccess;
|
||||
import agent.dbgmodel.dbgmodel.debughost.*;
|
||||
import agent.dbgmodel.dbgmodel.debughost.DebugHost;
|
||||
import agent.dbgmodel.dbgmodel.debughost.DebugHostContext;
|
||||
import agent.dbgmodel.dbgmodel.debughost.DebugHostMemory1;
|
||||
import agent.dbgmodel.dbgmodel.debughost.DebugHostModule1;
|
||||
import agent.dbgmodel.dbgmodel.debughost.DebugHostSymbol1;
|
||||
import agent.dbgmodel.dbgmodel.debughost.DebugHostSymbolEnumerator;
|
||||
import agent.dbgmodel.dbgmodel.debughost.DebugHostSymbols;
|
||||
import agent.dbgmodel.dbgmodel.main.ModelObject;
|
||||
import agent.dbgmodel.impl.dbgmodel.DebugRunningProcessImpl;
|
||||
import agent.dbgmodel.impl.dbgmodel.bridge.HDMAUtil;
|
||||
@ -592,7 +627,7 @@ public class WrappedDbgModel
|
||||
public void setCurrentThreadId(DebugThreadId dti) {
|
||||
DebugSystemObjects so = client.getSystemObjects();
|
||||
DebugThreadId currentThreadId = so.getCurrentThreadId();
|
||||
if (dti.id != currentThreadId.id) {
|
||||
if (!dti.id().equals(currentThreadId.id())) {
|
||||
so.setCurrentThreadId(dti);
|
||||
}
|
||||
/*
|
||||
@ -919,7 +954,7 @@ public class WrappedDbgModel
|
||||
}
|
||||
int pid = Integer.decode(id);
|
||||
if (pid == 0) {
|
||||
return new DebugProcessId(-1);
|
||||
return new DebugProcessRecord(-1);
|
||||
}
|
||||
DebugProcessId dpi = client.getSystemObjects().getProcessIdBySystemId(pid);
|
||||
addObj(dpi, id);
|
||||
|
@ -164,30 +164,26 @@ public class DbgModel2TargetRootImpl extends DbgModel2DefaultTargetModelRoot
|
||||
|
||||
@Override
|
||||
public void processSelected(DbgProcess process, DbgCause cause) {
|
||||
objectSelected(process);
|
||||
if (getManager().isKernelMode()) {
|
||||
processActivated(process);
|
||||
if (process != null) {
|
||||
objectSelected(process);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void threadSelected(DbgThread thread, DbgStackFrame frame, DbgCause cause) {
|
||||
objectSelected(thread);
|
||||
if (getManager().isKernelMode() && thread != null) {
|
||||
processActivated(thread.getProcess());
|
||||
threadActivated(thread);
|
||||
}
|
||||
if (frame != null) {
|
||||
objectSelected(frame);
|
||||
if (thread != null) {
|
||||
objectSelected(thread);
|
||||
if (frame != null) {
|
||||
objectSelected(frame);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void objectSelected(Object object) {
|
||||
List<String> objPath = findObject(object);
|
||||
TargetObject obj = getModel().getModelObject(objPath);
|
||||
if (obj instanceof DbgModelSelectableObject) {
|
||||
setFocus((DbgModelSelectableObject) obj);
|
||||
}
|
||||
model.fetchModelObject(objPath, RefreshBehavior.REFRESH_WHEN_ABSENT).thenAccept(obj ->
|
||||
update(obj)
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -217,21 +213,6 @@ public class DbgModel2TargetRootImpl extends DbgModel2DefaultTargetModelRoot
|
||||
});
|
||||
}
|
||||
|
||||
public void processActivated(DbgProcess proc) {
|
||||
List<String> objPath = findObject(proc);
|
||||
DbgModelTargetExecutionStateful stateful = (DbgModelTargetExecutionStateful) getModel().getModelObject(objPath);
|
||||
if (stateful == null) {
|
||||
return;
|
||||
}
|
||||
TargetExecutionState state = stateful.getExecutionState();
|
||||
if (state.equals(TargetExecutionState.INACTIVE)) {
|
||||
stateful.changeAttributes(List.of(), Map.of( //
|
||||
TargetExecutionStateful.STATE_ATTRIBUTE_NAME, TargetExecutionState.ALIVE //
|
||||
), "Selected");
|
||||
stateful.fetchAttributes(RefreshBehavior.REFRESH_ALWAYS);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void threadCreated(DbgThread thread, DbgCause cause) {
|
||||
getObject(thread).thenAccept(obj -> {
|
||||
@ -253,21 +234,6 @@ public class DbgModel2TargetRootImpl extends DbgModel2DefaultTargetModelRoot
|
||||
});
|
||||
}
|
||||
|
||||
public void threadActivated(DbgThread thread) {
|
||||
List<String> objPath = findObject(thread);
|
||||
DbgModelTargetExecutionStateful stateful = (DbgModelTargetExecutionStateful) getModel().getModelObject(objPath);
|
||||
if (stateful == null) {
|
||||
return;
|
||||
}
|
||||
TargetExecutionState state = stateful.getExecutionState();
|
||||
if (state.equals(TargetExecutionState.INACTIVE)) {
|
||||
stateful.changeAttributes(List.of(), Map.of( //
|
||||
TargetExecutionStateful.STATE_ATTRIBUTE_NAME, TargetExecutionState.ALIVE //
|
||||
), "Selected");
|
||||
stateful.fetchAttributes(RefreshBehavior.REFRESH_ALWAYS);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void moduleLoaded(DbgProcess proc, DebugModuleInfo info, DbgCause cause) {
|
||||
getObjectRevisited(proc, List.of("Modules"), info).thenAccept(obj -> {
|
||||
@ -340,7 +306,7 @@ public class DbgModel2TargetRootImpl extends DbgModel2DefaultTargetModelRoot
|
||||
xpath.addAll(ext);
|
||||
// NB: fetchModelObject may have to be called with false
|
||||
return AsyncUtils.sequence(TypeSpec.cls(DbgModelTargetObject.class)).then(seq -> {
|
||||
getModel().fetchModelObject(xpath, false).handle(seq::next);
|
||||
getModel().fetchModelObject(xpath, RefreshBehavior.REFRESH_NEVER).handle(seq::next);
|
||||
}, TypeSpec.cls(TargetObject.class)).then((pobj, seq) -> {
|
||||
if (pobj == null) {
|
||||
seq.exit();
|
||||
@ -564,11 +530,11 @@ public class DbgModel2TargetRootImpl extends DbgModel2DefaultTargetModelRoot
|
||||
DebugSystemObjects so = getManager().getSystemObjects();
|
||||
List<String> objpath = new ArrayList<>();
|
||||
DebugSessionId sid = so.getCurrentSystemId();
|
||||
String skey = sid.id < 0 ? PathUtils.makeKey("0x0")
|
||||
: PathUtils.makeKey("0x" + Integer.toHexString(sid.id));
|
||||
String skey = sid.value() < 0 ? PathUtils.makeKey("0x0")
|
||||
: PathUtils.makeKey("0x" + sid.id());
|
||||
if (obj instanceof DbgSession) {
|
||||
DbgSession session = (DbgSession) obj;
|
||||
skey = PathUtils.makeKey("0x" + Long.toHexString(session.getId().id));
|
||||
skey = PathUtils.makeKey("0x" + session.getId().id());
|
||||
}
|
||||
if (obj instanceof DbgSession || obj instanceof String) {
|
||||
objpath = List.of("Sessions", skey);
|
||||
@ -615,6 +581,30 @@ public class DbgModel2TargetRootImpl extends DbgModel2DefaultTargetModelRoot
|
||||
return objpath;
|
||||
}
|
||||
|
||||
private void update(TargetObject obj) {
|
||||
if (obj instanceof DbgModelSelectableObject) {
|
||||
setFocus((DbgModelSelectableObject) obj);
|
||||
}
|
||||
if (obj instanceof DbgModelTargetExecutionStateful) {
|
||||
activate((DbgModelTargetExecutionStateful) obj);
|
||||
// OK, this sucks, but not all threads are parented to activated objects
|
||||
DbgModelTargetProcess parentProcess = ((DbgModelTargetObject) obj).getParentProcess();
|
||||
if (obj instanceof DbgModelTargetExecutionStateful) {
|
||||
activate(parentProcess);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void activate(DbgModelTargetExecutionStateful stateful) {
|
||||
TargetExecutionState state = stateful.getExecutionState();
|
||||
if (state.equals(TargetExecutionState.INACTIVE)) {
|
||||
stateful.changeAttributes(List.of(), Map.of( //
|
||||
TargetExecutionStateful.STATE_ATTRIBUTE_NAME, TargetExecutionState.ALIVE //
|
||||
), "Selected");
|
||||
stateful.fetchAttributes(RefreshBehavior.REFRESH_ALWAYS);
|
||||
}
|
||||
}
|
||||
|
||||
private TargetEventType getEventType(DbgState state, DbgCause cause, DbgReason reason) {
|
||||
switch (state) {
|
||||
case RUNNING:
|
||||
|
@ -83,7 +83,7 @@ public class DbgModelSetContextMWETest extends AbstractGhidraHeadlessIntegration
|
||||
|
||||
private void dumpRegsViaDX() {
|
||||
DebugThreadId id = so.getCurrentThreadId();
|
||||
if (id.id == -1) {
|
||||
if (id.value() == -1) {
|
||||
return;
|
||||
}
|
||||
|
||||
@ -102,7 +102,7 @@ public class DbgModelSetContextMWETest extends AbstractGhidraHeadlessIntegration
|
||||
|
||||
private void dumpFrame0ViaDX() {
|
||||
DebugThreadId id = so.getCurrentThreadId();
|
||||
if (id.id == -1) {
|
||||
if (id.value() == -1) {
|
||||
return;
|
||||
}
|
||||
|
||||
@ -135,44 +135,44 @@ public class DbgModelSetContextMWETest extends AbstractGhidraHeadlessIntegration
|
||||
|
||||
private void dumpFrame0ViaK() {
|
||||
DebugThreadId id = so.getCurrentThreadId();
|
||||
if (id.id == -1) {
|
||||
if (id.value() == -1) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
DebugStackInformation stackInfo = control.getStackTrace(0, 0, 0);
|
||||
if (stackInfo.getNumberOfFrames() == 0) {
|
||||
Msg.info(this, "t" + id.id + ".Stack is empty?");
|
||||
Msg.info(this, "t" + id.id() + ".Stack is empty?");
|
||||
}
|
||||
else {
|
||||
DEBUG_STACK_FRAME frame = stackInfo.getFrame(0);
|
||||
Msg.info(this,
|
||||
String.format("t%d.Frame[0].io=%08x", id.id,
|
||||
String.format("t%d.Frame[0].io=%08x", id.id(),
|
||||
frame.InstructionOffset.longValue()));
|
||||
}
|
||||
}
|
||||
catch (Exception e) {
|
||||
Msg.info(this, "Could not read t" + id.id + ".Frame[0].io: " + e);
|
||||
Msg.info(this, "Could not read t" + id.id() + ".Frame[0].io: " + e);
|
||||
}
|
||||
}
|
||||
|
||||
private void dumpPCViaRegsAPI() {
|
||||
DebugThreadId id = so.getCurrentThreadId();
|
||||
if (id.id == -1) {
|
||||
if (id.value() == -1) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
Msg.info(this, String.format("t%d.rip=%s", id.id,
|
||||
Msg.info(this, String.format("t%d.rip=%s", id.id(),
|
||||
registers.getValueByName("rip")));
|
||||
}
|
||||
catch (Exception e) {
|
||||
Msg.info(this, "Could not read t" + id.id + ".RIP: " + e);
|
||||
Msg.info(this, "Could not read t" + id.id() + ".RIP: " + e);
|
||||
}
|
||||
try {
|
||||
Msg.info(this, String.format("t%d.eip=%s", id.id,
|
||||
Msg.info(this, String.format("t%d.eip=%s", id.id(),
|
||||
registers.getValueByName("eip")));
|
||||
}
|
||||
catch (Exception e) {
|
||||
Msg.info(this, "Could not read t" + id.id + ".EIP: " + e);
|
||||
Msg.info(this, "Could not read t" + id.id() + ".EIP: " + e);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -31,6 +31,7 @@ import java.util.concurrent.TimeoutException;
|
||||
import org.junit.Test;
|
||||
|
||||
import ghidra.async.*;
|
||||
import ghidra.dbg.DebuggerObjectModel.RefreshBehavior;
|
||||
import ghidra.dbg.gadp.GadpVersion;
|
||||
import ghidra.dbg.gadp.protocol.Gadp;
|
||||
import ghidra.dbg.gadp.util.AsyncProtobufMessageChannel;
|
||||
@ -400,7 +401,7 @@ public class GadpClientTest implements AsyncTestUtils {
|
||||
assertEquals(HELLO_WORLD, waitOn(fetchVal1));
|
||||
assertEquals(HELLO_WORLD, waitOn(fetchVal2));
|
||||
|
||||
CompletableFuture<?> fetchVal3 = client.fetchModelValue(PathUtils.parse("value"), true);
|
||||
CompletableFuture<?> fetchVal3 = client.fetchModelValue(PathUtils.parse("value"), RefreshBehavior.REFRESH_ALWAYS);
|
||||
srv.handleResyncAttributes(List.of(), true, null, Map.of("value", "Hi"));
|
||||
assertEquals("Hi", waitOn(fetchVal3));
|
||||
}
|
||||
|
@ -20,8 +20,14 @@ import java.awt.Color;
|
||||
import java.awt.event.MouseEvent;
|
||||
import java.io.PrintWriter;
|
||||
import java.lang.invoke.MethodHandles;
|
||||
import java.util.*;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
@ -36,7 +42,10 @@ import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import docking.ActionContext;
|
||||
import docking.WindowPosition;
|
||||
import docking.action.*;
|
||||
import docking.action.DockingAction;
|
||||
import docking.action.DockingActionIf;
|
||||
import docking.action.MenuData;
|
||||
import docking.action.ToggleDockingAction;
|
||||
import docking.action.builder.ActionBuilder;
|
||||
import docking.action.builder.ToggleActionBuilder;
|
||||
import docking.widgets.OptionDialog;
|
||||
@ -47,29 +56,107 @@ import generic.theme.GColor;
|
||||
import ghidra.app.plugin.core.debug.DebuggerCoordinates;
|
||||
import ghidra.app.plugin.core.debug.DebuggerPluginPackage;
|
||||
import ghidra.app.plugin.core.debug.gui.DebuggerResources;
|
||||
import ghidra.app.plugin.core.debug.gui.DebuggerResources.*;
|
||||
import ghidra.app.plugin.core.debug.gui.objects.actions.*;
|
||||
import ghidra.app.plugin.core.debug.gui.objects.components.*;
|
||||
import ghidra.app.plugin.core.debug.gui.DebuggerResources.AbstractAttachAction;
|
||||
import ghidra.app.plugin.core.debug.gui.DebuggerResources.AbstractConsoleAction;
|
||||
import ghidra.app.plugin.core.debug.gui.DebuggerResources.AbstractDetachAction;
|
||||
import ghidra.app.plugin.core.debug.gui.DebuggerResources.AbstractInterruptAction;
|
||||
import ghidra.app.plugin.core.debug.gui.DebuggerResources.AbstractKillAction;
|
||||
import ghidra.app.plugin.core.debug.gui.DebuggerResources.AbstractLaunchAction;
|
||||
import ghidra.app.plugin.core.debug.gui.DebuggerResources.AbstractQuickLaunchAction;
|
||||
import ghidra.app.plugin.core.debug.gui.DebuggerResources.AbstractRecordAction;
|
||||
import ghidra.app.plugin.core.debug.gui.DebuggerResources.AbstractRefreshAction;
|
||||
import ghidra.app.plugin.core.debug.gui.DebuggerResources.AbstractResumeAction;
|
||||
import ghidra.app.plugin.core.debug.gui.DebuggerResources.AbstractSetBreakpointAction;
|
||||
import ghidra.app.plugin.core.debug.gui.DebuggerResources.AbstractStepFinishAction;
|
||||
import ghidra.app.plugin.core.debug.gui.DebuggerResources.AbstractStepIntoAction;
|
||||
import ghidra.app.plugin.core.debug.gui.DebuggerResources.AbstractStepLastAction;
|
||||
import ghidra.app.plugin.core.debug.gui.DebuggerResources.AbstractStepOverAction;
|
||||
import ghidra.app.plugin.core.debug.gui.DebuggerResources.AbstractToggleAction;
|
||||
import ghidra.app.plugin.core.debug.gui.objects.actions.DisplayAsGraphAction;
|
||||
import ghidra.app.plugin.core.debug.gui.objects.actions.DisplayAsTableAction;
|
||||
import ghidra.app.plugin.core.debug.gui.objects.actions.DisplayAsTreeAction;
|
||||
import ghidra.app.plugin.core.debug.gui.objects.actions.DisplayAsXMLAction;
|
||||
import ghidra.app.plugin.core.debug.gui.objects.actions.DisplayFilteredGraphAction;
|
||||
import ghidra.app.plugin.core.debug.gui.objects.actions.DisplayFilteredTableAction;
|
||||
import ghidra.app.plugin.core.debug.gui.objects.actions.DisplayFilteredTreeAction;
|
||||
import ghidra.app.plugin.core.debug.gui.objects.actions.DisplayFilteredXMLAction;
|
||||
import ghidra.app.plugin.core.debug.gui.objects.actions.DisplayMethodsAction;
|
||||
import ghidra.app.plugin.core.debug.gui.objects.actions.ExportAsFactsAction;
|
||||
import ghidra.app.plugin.core.debug.gui.objects.actions.ExportAsXMLAction;
|
||||
import ghidra.app.plugin.core.debug.gui.objects.actions.ImportFromFactsAction;
|
||||
import ghidra.app.plugin.core.debug.gui.objects.actions.ImportFromXMLAction;
|
||||
import ghidra.app.plugin.core.debug.gui.objects.actions.OpenWinDbgTraceAction;
|
||||
import ghidra.app.plugin.core.debug.gui.objects.actions.SetTimeoutAction;
|
||||
import ghidra.app.plugin.core.debug.gui.objects.components.DebuggerAttachDialog;
|
||||
import ghidra.app.plugin.core.debug.gui.objects.components.DebuggerBreakpointDialog;
|
||||
import ghidra.app.plugin.core.debug.gui.objects.components.DebuggerMethodInvocationDialog;
|
||||
import ghidra.app.plugin.core.debug.gui.objects.components.DummyTargetObject;
|
||||
import ghidra.app.plugin.core.debug.gui.objects.components.GenericDebuggerProgramLaunchOffer;
|
||||
import ghidra.app.plugin.core.debug.gui.objects.components.ObjectAttributeColumn;
|
||||
import ghidra.app.plugin.core.debug.gui.objects.components.ObjectAttributeRow;
|
||||
import ghidra.app.plugin.core.debug.gui.objects.components.ObjectElementColumn;
|
||||
import ghidra.app.plugin.core.debug.gui.objects.components.ObjectElementRow;
|
||||
import ghidra.app.plugin.core.debug.gui.objects.components.ObjectEnumeratedColumnTableModel;
|
||||
import ghidra.app.plugin.core.debug.gui.objects.components.ObjectNode;
|
||||
import ghidra.app.plugin.core.debug.gui.objects.components.ObjectPane;
|
||||
import ghidra.app.plugin.core.debug.gui.objects.components.ObjectTable;
|
||||
import ghidra.app.plugin.core.debug.gui.objects.components.ObjectTree;
|
||||
import ghidra.app.plugin.core.debug.mapping.DebuggerMemoryMapper;
|
||||
import ghidra.app.script.*;
|
||||
import ghidra.app.services.*;
|
||||
import ghidra.app.script.GhidraScript;
|
||||
import ghidra.app.script.GhidraScriptLoadException;
|
||||
import ghidra.app.script.GhidraScriptProvider;
|
||||
import ghidra.app.script.GhidraScriptUtil;
|
||||
import ghidra.app.script.GhidraState;
|
||||
import ghidra.app.services.ConsoleService;
|
||||
import ghidra.app.services.DebuggerListingService;
|
||||
import ghidra.app.services.DebuggerModelService;
|
||||
import ghidra.app.services.DebuggerStaticMappingService;
|
||||
import ghidra.app.services.DebuggerTraceManagerService;
|
||||
import ghidra.app.services.DebuggerTraceManagerService.ActivationCause;
|
||||
import ghidra.async.*;
|
||||
import ghidra.dbg.*;
|
||||
import ghidra.app.services.GraphDisplayBroker;
|
||||
import ghidra.app.services.TraceRecorder;
|
||||
import ghidra.async.AsyncFence;
|
||||
import ghidra.async.AsyncUtils;
|
||||
import ghidra.async.TypeSpec;
|
||||
import ghidra.dbg.AnnotatedDebuggerAttributeListener;
|
||||
import ghidra.dbg.DebugModelConventions;
|
||||
import ghidra.dbg.DebuggerModelListener;
|
||||
import ghidra.dbg.DebuggerObjectModel;
|
||||
import ghidra.dbg.DebuggerObjectModel.RefreshBehavior;
|
||||
import ghidra.dbg.error.DebuggerMemoryAccessException;
|
||||
import ghidra.dbg.target.*;
|
||||
import ghidra.dbg.target.TargetAccessConditioned;
|
||||
import ghidra.dbg.target.TargetAttachable;
|
||||
import ghidra.dbg.target.TargetAttacher;
|
||||
import ghidra.dbg.target.TargetBreakpointSpec;
|
||||
import ghidra.dbg.target.TargetBreakpointSpecContainer;
|
||||
import ghidra.dbg.target.TargetConfigurable;
|
||||
import ghidra.dbg.target.TargetConsole.Channel;
|
||||
import ghidra.dbg.target.TargetDetachable;
|
||||
import ghidra.dbg.target.TargetExecutionStateful;
|
||||
import ghidra.dbg.target.TargetExecutionStateful.TargetExecutionState;
|
||||
import ghidra.dbg.target.TargetFocusScope;
|
||||
import ghidra.dbg.target.TargetInterpreter;
|
||||
import ghidra.dbg.target.TargetInterruptible;
|
||||
import ghidra.dbg.target.TargetKillable;
|
||||
import ghidra.dbg.target.TargetLauncher;
|
||||
import ghidra.dbg.target.TargetMethod;
|
||||
import ghidra.dbg.target.TargetMethod.ParameterDescription;
|
||||
import ghidra.dbg.target.TargetMethod.TargetParameterMap;
|
||||
import ghidra.dbg.target.TargetObject;
|
||||
import ghidra.dbg.target.TargetProcess;
|
||||
import ghidra.dbg.target.TargetResumable;
|
||||
import ghidra.dbg.target.TargetSteppable;
|
||||
import ghidra.dbg.target.TargetSteppable.TargetStepKind;
|
||||
import ghidra.dbg.target.TargetTogglable;
|
||||
import ghidra.dbg.util.DebuggerCallbackReorderer;
|
||||
import ghidra.dbg.util.PathUtils;
|
||||
import ghidra.framework.model.Project;
|
||||
import ghidra.framework.options.AutoOptions;
|
||||
import ghidra.framework.options.SaveState;
|
||||
import ghidra.framework.options.annotation.AutoOptionDefined;
|
||||
import ghidra.framework.plugintool.*;
|
||||
import ghidra.framework.plugintool.AutoConfigState;
|
||||
import ghidra.framework.plugintool.AutoService;
|
||||
import ghidra.framework.plugintool.ComponentProviderAdapter;
|
||||
import ghidra.framework.plugintool.annotation.AutoConfigStateField;
|
||||
import ghidra.framework.plugintool.annotation.AutoServiceConsumed;
|
||||
import ghidra.program.model.address.Address;
|
||||
@ -79,7 +166,9 @@ import ghidra.program.util.ProgramLocation;
|
||||
import ghidra.program.util.ProgramSelection;
|
||||
import ghidra.trace.model.Trace;
|
||||
import ghidra.trace.model.thread.TraceThread;
|
||||
import ghidra.util.*;
|
||||
import ghidra.util.HelpLocation;
|
||||
import ghidra.util.Msg;
|
||||
import ghidra.util.Swing;
|
||||
import ghidra.util.datastruct.PrivatelyQueuedListener;
|
||||
import ghidra.util.table.GhidraTable;
|
||||
import ghidra.util.task.TaskMonitor;
|
||||
@ -1412,7 +1501,15 @@ public class DebuggerObjectsProvider extends ComponentProviderAdapter
|
||||
list.toArray(new String[] {}), lastMethod, OptionDialog.QUESTION_MESSAGE);
|
||||
if (choice != null) {
|
||||
TargetMethod method = (TargetMethod) attributes.get(choice);
|
||||
Map<String, ?> args = methodDialog.promptArguments(method.getParameters());
|
||||
TargetParameterMap parameters = method.getParameters();
|
||||
if (parameters.isEmpty()) {
|
||||
method.invoke(new HashMap<String, Object>());
|
||||
if (!choice.equals("unload")) {
|
||||
lastMethod = choice;
|
||||
}
|
||||
return;
|
||||
}
|
||||
Map<String, ?> args = methodDialog.promptArguments(parameters);
|
||||
if (args != null) {
|
||||
String script = (String) args.get("Script");
|
||||
if (script != null && !script.isEmpty()) {
|
||||
|
@ -27,6 +27,7 @@ import ghidra.app.plugin.core.debug.gui.objects.DebuggerObjectsProvider;
|
||||
import ghidra.app.plugin.core.debug.gui.objects.ObjectContainer;
|
||||
import ghidra.app.script.AskDialog;
|
||||
import ghidra.dbg.DebuggerObjectModel;
|
||||
import ghidra.dbg.DebuggerObjectModel.RefreshBehavior;
|
||||
import ghidra.dbg.target.TargetObject;
|
||||
import ghidra.framework.plugintool.PluginTool;
|
||||
|
||||
@ -77,7 +78,7 @@ public abstract class DisplayFilteredAction extends DockingAction {
|
||||
final List<String> path) {
|
||||
TargetObject to = container.getTargetObject();
|
||||
DebuggerObjectModel model = to.getModel();
|
||||
model.fetchModelObject(path, true).thenAccept(obj -> {
|
||||
model.fetchModelObject(path, RefreshBehavior.REFRESH_ALWAYS).thenAccept(obj -> {
|
||||
container.setTargetObject(obj);
|
||||
finishGetOffspring(container, path);
|
||||
});
|
||||
|
@ -353,7 +353,7 @@ public interface DebuggerObjectModel {
|
||||
* @param refresh true to refresh caches
|
||||
* @return the found value, or {@code null} if it does not exist
|
||||
*/
|
||||
public CompletableFuture<?> fetchModelValue(List<String> path, boolean refresh);
|
||||
public CompletableFuture<?> fetchModelValue(List<String> path, RefreshBehavior refresh);
|
||||
|
||||
/**
|
||||
* @see #fetchModelValue(List)
|
||||
@ -406,7 +406,7 @@ public interface DebuggerObjectModel {
|
||||
* @throws DebuggerModelTypeException if the value at the path is not a {@link TargetObject}
|
||||
*/
|
||||
public default CompletableFuture<? extends TargetObject> fetchModelObject(List<String> path,
|
||||
boolean refresh) {
|
||||
RefreshBehavior refresh) {
|
||||
return fetchModelValue(path, refresh).thenApply(v -> {
|
||||
if (v == null) {
|
||||
return null;
|
||||
@ -431,7 +431,7 @@ public interface DebuggerObjectModel {
|
||||
*/
|
||||
@Deprecated
|
||||
public default CompletableFuture<? extends TargetObject> fetchModelObject(List<String> path) {
|
||||
return fetchModelObject(path, false);
|
||||
return fetchModelObject(path, RefreshBehavior.REFRESH_NEVER);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -21,7 +21,6 @@ import java.util.concurrent.CompletableFuture;
|
||||
|
||||
import ghidra.async.AsyncUtils;
|
||||
import ghidra.dbg.DebuggerObjectModel;
|
||||
import ghidra.dbg.DebuggerObjectModel.RefreshBehavior;
|
||||
import ghidra.dbg.error.DebuggerModelTypeException;
|
||||
import ghidra.dbg.target.TargetObject;
|
||||
import ghidra.dbg.util.PathUtils;
|
||||
@ -50,17 +49,26 @@ public interface SpiDebuggerObjectModel extends DebuggerObjectModel {
|
||||
}
|
||||
|
||||
public static CompletableFuture<Object> fetchSuccessorValue(TargetObject obj,
|
||||
List<String> path, boolean refresh, boolean followLinks) {
|
||||
List<String> path, RefreshBehavior refresh, boolean followLinks) {
|
||||
if (path.isEmpty()) {
|
||||
return CompletableFuture.completedFuture(obj);
|
||||
}
|
||||
String key = path.get(0);
|
||||
CompletableFuture<?> futureChild;
|
||||
if (refresh) {
|
||||
futureChild = fetchFreshChild(obj, key);
|
||||
}
|
||||
else {
|
||||
futureChild = obj.fetchChild(key);
|
||||
switch (refresh) {
|
||||
case REFRESH_ALWAYS:
|
||||
futureChild = fetchFreshChild(obj, key);
|
||||
break;
|
||||
case REFRESH_NEVER:
|
||||
futureChild = obj.fetchChild(key);
|
||||
break;
|
||||
case REFRESH_WHEN_ABSENT:
|
||||
default:
|
||||
CompletableFuture<?> futureChild0 = obj.fetchChild(key);
|
||||
futureChild = futureChild0.thenCompose(c -> {
|
||||
return c == null ? fetchFreshChild(obj, key) : CompletableFuture.completedFuture(c);
|
||||
});
|
||||
break;
|
||||
}
|
||||
return futureChild.thenCompose(c -> {
|
||||
if (c == null) {
|
||||
@ -91,7 +99,7 @@ public interface SpiDebuggerObjectModel extends DebuggerObjectModel {
|
||||
}
|
||||
|
||||
@Override
|
||||
public default CompletableFuture<?> fetchModelValue(List<String> path, boolean refresh) {
|
||||
public default CompletableFuture<?> fetchModelValue(List<String> path, RefreshBehavior refresh) {
|
||||
return fetchModelRoot().thenCompose(root -> {
|
||||
return fetchSuccessorValue(root, path, refresh, true);
|
||||
});
|
||||
@ -99,7 +107,45 @@ public interface SpiDebuggerObjectModel extends DebuggerObjectModel {
|
||||
|
||||
@Override
|
||||
public default CompletableFuture<?> fetchModelValue(List<String> path) {
|
||||
return fetchModelValue(path, false);
|
||||
return fetchModelValue(path, RefreshBehavior.REFRESH_NEVER);
|
||||
}
|
||||
|
||||
public static CompletableFuture<Object> fetchSuccessorValueUsingAvailableCache(TargetObject obj,
|
||||
List<String> path, boolean followLinks) {
|
||||
if (path.isEmpty()) {
|
||||
return CompletableFuture.completedFuture(obj);
|
||||
}
|
||||
String key = path.get(0);
|
||||
CompletableFuture<?> futureChild = obj.fetchChild(key);
|
||||
CompletableFuture<?> ffutureChild = futureChild.thenCompose(c -> {
|
||||
return c == null ? fetchFreshChild(obj, key) : CompletableFuture.completedFuture(c);
|
||||
});
|
||||
return ffutureChild.thenCompose(c -> {
|
||||
if (c == null) {
|
||||
return AsyncUtils.nil();
|
||||
}
|
||||
if (!(c instanceof TargetObject)) {
|
||||
if (path.size() == 1) {
|
||||
return CompletableFuture.completedFuture(c);
|
||||
}
|
||||
else {
|
||||
List<String> p = PathUtils.extend(obj.getPath(), key);
|
||||
throw DebuggerModelTypeException.typeRequired(c, p, TargetObject.class);
|
||||
}
|
||||
}
|
||||
TargetObject child = (TargetObject) c;
|
||||
if (PathUtils.isLink(obj.getPath(), key, child.getPath()) && !followLinks) {
|
||||
if (path.size() == 1) {
|
||||
return CompletableFuture.completedFuture(c);
|
||||
}
|
||||
else {
|
||||
List<String> p = PathUtils.extend(obj.getPath(), key);
|
||||
throw DebuggerModelTypeException.linkForbidden(child, p);
|
||||
}
|
||||
}
|
||||
List<String> remains = path.subList(1, path.size());
|
||||
return fetchSuccessorValueUsingAvailableCache(child, remains, followLinks);
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
|
Loading…
Reference in New Issue
Block a user