/* ### * 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. */ import java.nio.charset.Charset; import java.util.List; import ghidra.app.plugin.processors.sleigh.SleighLanguage; import ghidra.app.script.GhidraScript; import ghidra.pcode.exec.*; import ghidra.pcode.struct.StructuredSleigh; import ghidra.pcode.utils.Utils; import ghidra.program.model.address.AddressSpace; import ghidra.program.model.lang.CompilerSpec; import ghidra.program.model.pcode.Varnode; /** * A userop library for the emulator * *
* If you do not have need of a custom userop library, use {@link PcodeUseropLibrary#NIL}. These * libraries allow you to implement userop, including those declared by the language. Without these, * the emulator must interrupt whenever a userop ({@code CALLOTHER}) is encountered. You can also * define new userops, which can be invoked from Sleigh code injected into the emulator. * *
* These libraries can have both Java-callback and p-code implementations of userops. If only using
* p-code implementations, the library can be parameterized with type {@code
* Methods in this class (not including those in its nested classes) are implemented as Java
* callbacks.
*/
public class DemoPcodeUseropLibrary extends AnnotatedPcodeUseropLibrary
* Because we want to dereference start, we will need access to the emulator's state, so we
* employ the {@link OpState} annotation. {@code start} takes the one input we expect. Because
* its type is the value type rather than {@link Varnode}, we will get the input's value.
* Similarly, we can just return the resulting value, and the emulator will place that into the
* output variable for us.
*
* @param state the calling thread's state
* @param start the offset of the first character
* @return the length of the string in bytes
*/
@PcodeUserop
public byte[] print_utf8(@OpState PcodeExecutorStatePiece
* In cases where the userop expects parameters, you would annotate them with {@link Param}
* and use them just like other {@link Var}s. See the javadocs.
*
*
* This is just a cheesy demo: If RAX is 1, then this method computes the number of bytes in
* the C-style string pointed to by RCX and stores the result in RAX. Otherwise, interrupt
* the emulator. See {@link DemoSyscallLibrary} for actual system call simulation.
*/
@StructuredUserop
public void syscall() {
_if(RAX.eq(1), () -> {
Var i = local("i", RCX);
_while(i.deref().neq(0), () -> {
i.inc();
});
RAX.set(i.subi(RAX));
})._else(() -> {
emu_swi.call();
});
}
}
}