Repository navigation
Replies: 11 comments
|
The Python exception system is mostly hardcoded which makes extensions of it very complicated. You can see the level of hacking that was required to get the stack frames to connect to each other. I have some outstanding tickets with the Python developers regarding providing methods to connect the two together but as I can't contribute to Python (seeing as my employer refuses to sign the contributor agreement) I remain stuck. As for As for making a ValueError appear as a BaseException. This is possible with the reverse bridge. The only issue it that we still having not recruited enough people to serve as beta testers/developers to complete the epypj code. I know that writing 1000 test routines and solving the pile of edge cases are not fun tasks, but it would be required to release that code. |
|
I looked into this some further. It is possible for me to wire up the I see that that whole system CFrame system is being reworked from 3.11 so it is very unclear if there is any way this can be accomplished in a cross version fashion. At least as far as I can tell, there is no public API for creating tracebacks (so we are hacking that in place), and there is no way in the public API to push a marker into the Python traceback and pop it after the Java call returns such that if an exception took place in Java that we can splice out exception information in. However, perhaps @markshannon be so kind as pointing me towards the API if it exists. |
|
I am currently trying to get PyGhidra to output the full Java stacktrace when a I detect a |
|
I'm wondering if I should make a new ticket to to include the "cause" in the |
|
I believe that stacktrace is in the Python layer which should be patchable easily. Are you sure that the cause is not attached? According the Java documentation it should be included. Test.java test.py: Output: So unfortunately I can't fix what I can't reproduce. I recommend checking to see if something in the type chain has perhaps overridden |
|
Here is some context for those 2 outputs Left red output (JPype used): from jpype import JImplements, JOverride
from ghidra.pcode.exec.PcodeExecutorStatePiece import Reason
from ghidra.pcode.exec import (
BytesPcodeArithmetic, PcodeExecutor, PcodeExecutorState, PcodeUseropLibrary, SleighProgramCompiler)
print("Test")
@JImplements(PcodeExecutorState)
class MyState():
@JOverride
def getLanguage(self, *args):
raise Exception("Blargh")
@JOverride
def getArithmetic(self, *args):
raise Exception("Blargh")
@JOverride
def getVar(self, *args):
raise Exception("Blargh")
@JOverride
def getVarInternal(self, *args):
raise Exception("Blargh")
@JOverride
def getConcreteBuffer(self, *args):
raise Exception("Blargh")
@JOverride
def setVar(self, *args):
raise Exception("Blargh")
@JOverride
def setVarInternal(self, *args):
raise Exception("Blargh")
@JOverride
def getRegisterValues(self, *args):
raise Exception("Blargh")
@JOverride
def fork(self, *args):
raise Exception("Blargh")
@JOverride
def clear(self, *args):
raise Exception("Blargh")
@JOverride
def streamPieces(self, *args):
raise Exception("Blargh")
language = currentProgram.language
st = MyState()
arithmetic = BytesPcodeArithmetic.forLanguage(language)
pcex = PcodeExecutor(language, arithmetic, st, Reason.EXECUTE_READ)
prog = SleighProgramCompiler.compileProgram(
language, "Test", "RIP = 0xdeadbeef;", PcodeUseropLibrary.NIL)
pcex.execute(prog, PcodeUseropLibrary.NIL)Right output (pure java) import java.util.Map;
import java.util.stream.Stream;
import ghidra.app.plugin.processors.sleigh.SleighLanguage;
import ghidra.app.script.GhidraScript;
import ghidra.pcode.exec.*;
import ghidra.pcode.exec.PcodeArithmetic.Purpose;
import ghidra.pcode.exec.PcodeExecutorStatePiece.Reason;
import ghidra.program.model.address.Address;
import ghidra.program.model.address.AddressSpace;
import ghidra.program.model.lang.Language;
import ghidra.program.model.lang.Register;
import ghidra.program.model.mem.MemBuffer;
public class TestGP6664Script extends GhidraScript {
static class MyState implements PcodeExecutorState<byte[]> {
@Override
public Language getLanguage() {
throw new RuntimeException("Blargh");
}
@Override
public PcodeArithmetic<byte[]> getArithmetic() {
throw new RuntimeException("Blargh");
}
@Override
public Stream<PcodeExecutorStatePiece<?, ?>> streamPieces() {
throw new RuntimeException("Blargh");
}
@Override
public void setVar(AddressSpace space, byte[] offset, int size, boolean quantize,
byte[] val) {
throw new RuntimeException("Blargh");
}
@Override
public void setVarInternal(AddressSpace space, byte[] offset, int size, byte[] val) {
throw new RuntimeException("Blargh");
}
@Override
public byte[] getVar(AddressSpace space, byte[] offset, int size, boolean quantize,
Reason reason) {
throw new RuntimeException("Blargh");
}
@Override
public byte[] getVarInternal(AddressSpace space, byte[] offset, int size, Reason reason) {
throw new RuntimeException("Blargh");
}
@Override
public Map<Register, byte[]> getRegisterValues() {
throw new RuntimeException("Blargh");
}
@Override
public MemBuffer getConcreteBuffer(Address address, Purpose purpose) {
throw new RuntimeException("Blargh");
}
@Override
public void clear() {
throw new RuntimeException("Blargh");
}
@Override
public PcodeExecutorState<byte[]> fork(PcodeStateCallbacks cb) {
throw new RuntimeException("Blargh");
}
}
@Override
protected void run() throws Exception {
var language = (SleighLanguage) currentProgram.getLanguage();
var st = new MyState();
var arithmetic = BytesPcodeArithmetic.forLanguage(language);
var pcex = new PcodeExecutor<>(language, arithmetic, st, Reason.EXECUTE_READ);
var prog = SleighProgramCompiler.compileProgram(language, "Test", "RIP = 0xdeadbeef;",
PcodeUseropLibrary.nil());
pcex.execute(prog, PcodeUseropLibrary.nil());
}
} |
|
Seems like the root of the problem is calling If I raise a pure Java exception, i get the desired strack traces and messages. But if the user raises a Python exception, some info seems be lost. Is this behavior difference by design? |
|
One is a Python exception which captures only the python state, the other is a java exception that will trigger both sides of the bridge to dump their stack traces. Unfortunately, I think that is inherent unless we get a throw on the Java side via a proxy. Right now the proxy just passes the python exception straight through without the java state. Now that I have a reproduced I can look to see whether there is a clean way to add the cause chain after it comes back down. I suspect this is something that may be possible with reverse bridge, but may be limited by the CPython api. The place you are looking for is in If I get a chance I can analyze the specific path. |
|
Ok, thank you for taking a look! |
|
I'm not convinced this should be a discussion - it is a limitation in the JPype implementation that we can overcome in the future. Perhaps @Thrameos you have a desire to discuss and agree on a shape of a solution, before we formalise it as a feature request? |

Uh oh!
There was an error while loading. Please reload this page.
Both Python and Java have exception chaining (
Throwable.getCause()in Java,exception.__cause__in Python).This information doesn't make it across from Java to Python though. Take the following snippet:
When we inspect the object:
By adding the exception to
__cause__(viae2.__cause__ = e1) we get an improved exception:In investigating this, I also wondered if I could pass a Python exception as a cause for a
Throwable, but unfortunately that wasn't possible:I'm not sure on the practicalities, but it would be also interesting if we could make
BaseExceptionbe understood as aThrowable.All reactions