GP-2834: Add Unwind Stack action, hovers for dynamic variable values.

This commit is contained in:
Dan 2023-01-12 13:38:17 -05:00
parent 01dfe6cab5
commit df9a1e2756
105 changed files with 12292 additions and 482 deletions

View file

@ -82,12 +82,54 @@ public class AssemblyBuffer {
return emit(asm.assembleLine(getNext(), line));
}
/**
* Assemble a line and patch into the buffer
*
* <p>
* This will not grow the buffer, so the instruction being patched must already exist in the
* buffer. The typical use case is to fix up a reference:
*
* <pre>
* AssemblyBuffer buf = new AssemblyBuffer(asm, entry);
* // ...
* Address jumpCheck = buf.getNext();
* buf.assemble("JMP 0x" + buf.getNext()); // Template must accommodate expected jump distance
* // ...
* Address labelCheck = buf.getNext();
* buf.assemble(jumpCheck, "JMP 0x" + labelCheck);
* buf.assemble("CMP ECX, 0");
* // ...
* </pre>
*
* <p>
* This does not check that the patched instruction matches length with the new instruction. In
* fact, the buffer does not remember instruction boundaries at all. If verification is needed,
* the caller should check the lengths of the returned byte arrays for the template and the
* patch.
*
* @param at the address of the instruction to patch
* @param line the line
* @return the resulting bytes for the assembled instruction
* @throws AssemblySyntaxException if the instruction cannot be parsed
* @throws AssemblySemanticException if the instruction cannot be encoded
* @throws IOException if the buffer cannot be written
*/
public byte[] assemble(Address at, String line)
throws AssemblySyntaxException, AssemblySemanticException, IOException {
byte[] full = baos.toByteArray();
byte[] bytes = asm.assembleLine(at, line);
System.arraycopy(bytes, 0, full, (int) at.subtract(entry), bytes.length);
baos.reset();
baos.write(full);
return bytes;
}
/**
* Append arbitrary bytes to the buffer
*
* @param bytes the bytes to append
* @return bytes
* @throws IOException if the bufgfer cannot be written
* @throws IOException if the buffer cannot be written
*/
public byte[] emit(byte[] bytes) throws IOException {
baos.write(bytes);

View file

@ -82,6 +82,7 @@ public class AssemblySelector {
*/
public Collection<AssemblyParseResult> filterParse(Collection<AssemblyParseResult> parse)
throws AssemblySyntaxException {
syntaxErrors.clear();
boolean gotOne = false;
for (AssemblyParseResult pr : parse) {
if (pr.isError()) {
@ -97,6 +98,26 @@ public class AssemblySelector {
return parse;
}
protected List<AssemblyResolvedPatterns> filterCompatibleAndSort(AssemblyResolutionResults rr,
AssemblyPatternBlock ctx) throws AssemblySemanticException {
semanticErrors.clear();
List<AssemblyResolvedPatterns> sorted = new ArrayList<>();
// Select only non-erroneous results whose contexts are compatible.
for (AssemblyResolution ar : rr) {
if (ar.isError()) {
semanticErrors.add((AssemblyResolvedError) ar);
continue;
}
AssemblyResolvedPatterns rc = (AssemblyResolvedPatterns) ar;
sorted.add(rc);
}
if (sorted.isEmpty()) {
throw new AssemblySemanticException(semanticErrors);
}
sorted.sort(compareBySizeThenBits);
return sorted;
}
/**
* Select an instruction from the possible results.
*
@ -117,21 +138,7 @@ public class AssemblySelector {
*/
public AssemblyResolvedPatterns select(AssemblyResolutionResults rr,
AssemblyPatternBlock ctx) throws AssemblySemanticException {
List<AssemblyResolvedPatterns> sorted = new ArrayList<>();
// Select only non-erroneous results whose contexts are compatible.
for (AssemblyResolution ar : rr) {
if (ar.isError()) {
semanticErrors.add((AssemblyResolvedError) ar);
continue;
}
AssemblyResolvedPatterns rc = (AssemblyResolvedPatterns) ar;
sorted.add(rc);
}
if (sorted.isEmpty()) {
throw new AssemblySemanticException(semanticErrors);
}
// Sort them
sorted.sort(compareBySizeThenBits);
List<AssemblyResolvedPatterns> sorted = filterCompatibleAndSort(rr, ctx);
// Pick just the first
AssemblyResolvedPatterns res = sorted.get(0);