From 31e712b993a8d9aec12bec8199bb686368fbdc0f Mon Sep 17 00:00:00 2001 From: caheckman <48068198+caheckman@users.noreply.github.com> Date: Wed, 29 Jan 2020 11:57:33 -0500 Subject: [PATCH] Reworking decompiler documentation --- .../Decompiler/certification.manifest | 4 + .../Features/Decompiler/src/main/doc/Makefile | 20 + .../src/main/doc/decompileplugin.xml | 2942 +++++++++++++++++ .../src/main/doc/decompileplugin_common.xsl | 59 + .../src/main/doc/decompileplugin_html.xsl | 56 + 5 files changed, 3081 insertions(+) create mode 100644 Ghidra/Features/Decompiler/src/main/doc/Makefile create mode 100644 Ghidra/Features/Decompiler/src/main/doc/decompileplugin.xml create mode 100644 Ghidra/Features/Decompiler/src/main/doc/decompileplugin_common.xsl create mode 100644 Ghidra/Features/Decompiler/src/main/doc/decompileplugin_html.xsl diff --git a/Ghidra/Features/Decompiler/certification.manifest b/Ghidra/Features/Decompiler/certification.manifest index 6028dc4c12..b6e0e2d458 100644 --- a/Ghidra/Features/Decompiler/certification.manifest +++ b/Ghidra/Features/Decompiler/certification.manifest @@ -10,8 +10,12 @@ src/decompile/build.gradle||GHIDRA||||END| src/decompile/cpp/.gitignore||GHIDRA||||END| src/decompile/cpp/Doxyfile||GHIDRA|||Most of this file is autogenerated by doxygen which falls under the GPL - output from GPL products are NOT GPL! - mjbell4|END| src/decompile/cpp/Makefile||GHIDRA||||END| +src/main/doc/Makefile||GHIDRA|exclude|||END| src/main/doc/cspec.xml||GHIDRA|exclude|||END| src/main/doc/cspec_html.xsl||GHIDRA|exclude|||END| +src/main/doc/decompileplugin.xml||GHIDRA|exclude|||END| +src/main/doc/decompileplugin_common.xsl||GHIDRA|exclude|||END| +src/main/doc/decompileplugin_html.xsl||GHIDRA|exclude|||END| src/main/doc/main.xml||GHIDRA|exclude|reviewed||END| src/main/doc/main_html.xsl||GHIDRA|exclude|reviewed||END| src/main/doc/pcoderef.xml||GHIDRA|exclude|||END| diff --git a/Ghidra/Features/Decompiler/src/main/doc/Makefile b/Ghidra/Features/Decompiler/src/main/doc/Makefile new file mode 100644 index 0000000000..9912fd43a6 --- /dev/null +++ b/Ghidra/Features/Decompiler/src/main/doc/Makefile @@ -0,0 +1,20 @@ + +BUILDDIR=html + +Decompiler.html: decompileplugin.xml + rm -rf ${BUILDDIR} + mkdir ${BUILDDIR} + mkdir ${BUILDDIR}/images + cp ../../../src/main/help/help/shared/Frontpage.css ${BUILDDIR} + cp ../../../src/main/help/help/shared/languages.css ${BUILDDIR} + cp ../../../src/main/help/help/topics/DecompilePlugin/images/DecompWindow.png ${BUILDDIR}/images + cp ../../../src/main/help/help/topics/DecompilePlugin/images/EditFunctionSignature.png ${BUILDDIR}/images + cp ../../../src/main/help/help/topics/DecompilePlugin/images/ForwardSlice.png ${BUILDDIR}/images + cp ../../../src/main/help/help/topics/DecompilePlugin/images/decompileFunction.gif ${BUILDDIR}/images + cp ../../../src/main/help/help/topics/DecompilePlugin/images/page_edit.png ${BUILDDIR}/images + cp ../../../../Base/src/main/help/help/topics/Snapshots/images/camera-photo.png ${BUILDDIR}/images + cp ../../../../Base/src/main/help/help/topics/ClipboardPlugin/images/page_white_copy.png ${BUILDDIR}/images + cp ../../../../../Framework/Generic/src/main/resources/images/reload3.png ${BUILDDIR}/images + cp ../../../src/main/help/help/shared/note.png ${BUILDDIR}/images + xsltproc --stringparam base.dir ${BUILDDIR} --stringparam root.filename Decompiler decompileplugin_html.xsl decompileplugin.xml + sed -i -e '/Frontpage.css/ { p; s/Frontpage.css/languages.css/; }' ${BUILDDIR}/*.html diff --git a/Ghidra/Features/Decompiler/src/main/doc/decompileplugin.xml b/Ghidra/Features/Decompiler/src/main/doc/decompileplugin.xml new file mode 100644 index 0000000000..7f32a1b340 --- /dev/null +++ b/Ghidra/Features/Decompiler/src/main/doc/decompileplugin.xml @@ -0,0 +1,2942 @@ + + + + Decompiler + + + Decompiler + + + + + +
+ Overview + + The Decompiler plug-in is a sophisticated transformation engine + which automatically converts the binary representation of + individual functions into a high-level C representation. The + Decompiler presents a view of a program which is interactive and + dynamically updated as the user adds or makes changes to the + annotations associated with the program. A Decompiler window + maintains the correspondence between the C representation and the + assembly representation displayed in the Code Browser window, to + the extent possible. The window allows instant visual association + and navigation between C language expressions and their + corresponding assembly instructions. + + + Enabling the Plug-in + + The Decompiler is a full Plug-in within Ghidra and can be configured to be enabled or + disabled within any particular tool. Default configurations will have the + plug-in enabled, but if its disabled for some reason, it can be enabled from within + a Code Browser by selecting the menu option + + File -> Configure + + Then click on the Configure link under the + Ghidra Core section and check the box next to + DecompilePlugin. + + + + + Showing the Decompiler Window + + From the Code Browser, either: + + + + Press the icon + in the tool bar, or + + + Select the Decompile option from the + Window menu. + + + + + + The window automatically decompiles and displays the function at the + current address. The address is set typically by left-clicking in the Listing window, + or invoking the Goto command (pressing the 'g' key) and manually entering + the address or some other label, but the Decompiler window + follows any type of navigation in the Code Browser. Navigating to a new address + or making a change to the underlying Program causes the the window to (re)decompile and display + the new function. + + + + + Capabilities + + Some of the primary capabilities of the decompiler include: + + + + + Recovers Expressions: The + decompiler does full data-flow analysis which allows it to + perform slicing on functions. The most tangible benefit to the + user is that complicated expressions, which have been split into + distinct operations/instructions and then mixed together with + other instructions by the compiling/optimizing process, are + reconstituted into a single expression again by the decompiler. + + + Recovers High-Level Scoped + Variables: The decompiler understands how compilers + use processor stacks and registers to implement variables with + different scopes within a function. Data-flow allows it to + follow what was originally a single variable as it moves from + the stack, into a register, into a different register, etc. Thus + it can effectively recover the original programs concept of a + variable, minimizing the need to introduce artificial variables + in the output. + + + Recovers Function Parameters: + The decompiler understands the parameter passing conventions of + the compiler and can reconstruct the form of the original + function call. + + + Uses Data-type, Name, and Signature + Annotations: The decompiler automatically pulls in + all the different data types and variable names that the user + has applied to functions, and the C output is altered to reflect + this. High-level variables are appropriately named, structure + fields and array indices are calculated and displayed with + correct syntax, constant char pointers are replaced with + appropriate quoted strings, etc. + + + Performs Local Data-type + Propagation: In the absence of information, the + decompiler does its best to fill in information from what it + does know. Variables whose data-type has not been explicitly + labeled by the user can often by recovered by seeing how the + variable is used or by allowing the known data-types to + propagate. + + + Can be used to Automatically Recover + Structure Fields: The decompiler can be leveraged to + recover references to a structure. + + + + + +
+
+ + + Concepts + +
+ P-code + + P-code is Ghidra's Intermediate Representation (IR) language. When analyzing a function, + the decompiler translates every machine instruction into p-code first and performs its + analysis directly on the operators and variables of the language. Output of the decompiler + is also best understood in terms of p-code. This section presents the key concepts of + p-code. For a more detailed discussion see the document "P-Code Reference Manual". + + + Address Space + + P-code defines all data in terms of an address space. An address space + is defined simply as an indexed sequence of bytes that can be read and written by p-code operations. + For a specific byte, the unique index that labels it is called the byte's address. + Each address space has a: + + + + name - a formal name for the space + + + size - the maximum number of bytes that can be addressed + + + endianess - how groups of bytes are interpreted as integers + + + + + + For a p-code model of a specific processor, all elements of the processor state (including RAM, registers, + flags, etc.) must be contained in some address space. The model will define multiple address spaces + to accomplish this, and beyond the raw translation of machine instructions to p-code, the decompiler + can add additional spaces. Address space definitions that are common across many different processors include: + + + + + ram + + + A space that models memory accessible via the processors's main data bus. Depending on + the architecture, different spaces might be substituted for ram, + such as separate code and data spaces. + + + + + register + + + A space that models the processor's general purpose registers. Ghidra still uses + the standard names to refer to registers for the processor, but internally each register maps to a + specific address in this space. + + + + + unique + + + A space dedicated to temporary registers. + It is used to hold intermediate values when modeling instruction behavior, and the decompiler + uses it to allocate space for variables that don't directly correspond to the low level + processor state. The name unique is reserved for this purpose and + is present in all processor models. + + + + + stack + + + A space that represents bytes explicitly indexed through a stack pointer. + This is an example of an address space added by the decompiler beyond what the raw processor + model defines. The stack space is a logical construction representing the set of bytes a + single function might access through its stack pointer. Each stack address represents + the offset of a byte in some underlying space (usually ram) relative + to the initial value of the stack pointer upon entry to the function. The stack space is + always referenced in the context of a single function, and in this sense, each function + can be viewed as having its own distinct stack space. + + + + + constant + + + A special space for encoding constants in p-code. + For complete generality, even constants that the processor might manipulate are + assigned to their own address space. For an address in the constant + space, the index itself represents the constant. + + + + + + + + + + Varnodes + + A varnode is defined as a sequence of bytes in + an address space. It represents the storage for a single value (variable) being + acted on by the processor. + All manipulation of data by p-code operations occurs on varnodes. + A varnode can always be represented as the formal triple: + + (address space,offset,size) + + Both offset and size are integer values + specified in terms of bytes. + The first two elements, address space and offset, taken together represent the + address of the varnode. + + + Varnodes by themselves do not necessarily have a data-type associated with them. + The decompiler ultimately assigns a formal data-type, but at the lowest level of p-code, + varnodes inherit one the building block data-types from the p-code operations that + act on them: + + + + Integer + + + Boolean + + + Floating Point + + + + The integer data-type assumes a twos complement encoding in the endianness of the + address space containing the varnode. Similarly, the floating point data-type assumes + an IEEE 754 standard encoding. The precision of the integer or floating point value is + determined by the varnode's size. A boolean data-type assumes the varnode has a size + of 1 byte and takes either a value of 0, for false, or a value of + 1 for true. + + + + + + P-code Operations + + A p-code operation is defined as a formal operator, + labeled by its opcode, acting on 1 or more varnodes as input and + storing a result in at most 1 varnode. Each p-code operation is associated with an + address, which is usually the address of the machine instruction from which the p-code + operation was translated. As most instructions require more than one p-code operation + to fully model it, a separate 1-up counter is used to distinguish p-code operations + associated with the same address. Together the address and the counter are referred + to as the operation's sequence number. + + + The formal opcodes break up into categories similar to many programming languages. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
P-code Operations
CategoryOperations
Data MovingCOPY, LOAD, STORE
Integer ArithmeticINT_ADD, INT_SUB, + INT_2COMP, INT_MULT, INT_DIV, INT_SDIV, INT_REM, INT_SREM
Integer ShiftsINT_LEFT, INT_RIGHT, INT_SRIGHT
Integer ComparisonINT_EQUAL, INT_NOTEQUAL, INT_SLESS, INT_SLESSEQUAL, INT_LESS, INT_LESSEQUAL
LogicalINT_NEGATE, INT_XOR, INT_AND, INT_OR, POPCOUNT
BooleanBOOL_NEGATE, BOOL_XOR, BOOL_AND, BOOL_OR
Floating Point ArithmeticFLOAT_ADD, FLOAT_SUB, FLOAT_MULT, FLOAT_DIV, FLOAT_NEG, + FLOAT_ABS, FLOAT_SQRT
Floating Point ComparisonFLOAT_EQUAL, FLOAT_NOTEQUAL, FLOAT_LESS, FLOAT_LESSEQUAL
Floating Point ConversionINT2FLOAT, FLOAT2FLOAT, TRUNC, CEIL, FLOOR, ROUND
BranchingBRANCH, CBRANCH, BRANCHIND, CALL, CALLIND, RETURN
Extension/TruncationINT_ZEXT, INT_SEXT, PIECE, SUBPIECE
Overflow TestsINT_CARRY, INT_SCARRY, INT_SBORROW, FLOAT_NAN
Managed CodeCPOOLREF, NEW
+
+
+ + + Operator Tokens + + Most opcodes naturally correspond to a particular C operator token, + and in decompiler output, many of the operator tokens displayed correspond + directly to a p-code operation present in the decompiler's internal + representation. The biggest exception are the Branching + operations; the decompiler uses standard high-level language control-flow + structures, like if/else, switch, and + do/while blocks, instead of the + low-level branching operations. But even here, there is some correspondence + between operations and keywords in the high-level language. + + + Operations in the Extension/Truncation and + Floating Point Conversion categories tend to be + represented as cast operations in the high-level language, + and so don't have an explicit operator token representing them. Many p-code + operations share the same operator token, such as the integer and floating-point + addition operations INT_ADD and + FLOAT_ADD. The high-level language distinguishes + between them via the underlying data-type of the variables. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameOperator TokenDescription
COPY=Copy one varnode into another.
LOAD* or ->Dereference a pointer, or load a value from memory.
STORE* or ->Store a value to memory, through a pointer.
BRANCHgotoBranch execution to a specific address.
CBRANCHif (...) gotoBranch execution to an address if the condition is true.
BRANCHINDswitch(...)Branch execution to a computed address.
CALLfuncname(...)Branch to a subfunction.
CALLIND(*funcptr)(...)Branch through a pointer to a subfunction.
RETURNreturnReturn execution to the calling function.
PIECECONCATConcatenate two varnodes.
SUBPIECESUBExtract a subset of bytes.
POPCOUNTPOPCOUNTCount the 1 bits.
INT_EQUAL==True if input varnodes are equal.
INT_NOTEQUAL!=True if input varnodes are not equal.
INT_LESS< or >True if one varnode is less than the other as unsigned integers.
INT_SLESS< or >True if one varnode is less than the other as signed integers.
INT_LESSEQUAL<= or >=True if one varnode is less than or equal to the other as unsigned integers.
INT_SLESSEQUAL<= or >=True if one varnode is less than or equal to the other as signed integers.
INT_ZEXTZEXTZero extension.
INT_SEXTSEXTSigned extension.
INT_ADD+Add as integers.
INT_SUB-Subtract as integers.
INT_CARRYCARRYTrue if adding produces an unsigned carry.
INT_SCARRYSCARRYTrue if adding produces a signed carry.
INT_SBORROWSBORROWTrue if subtracting produces a signed borrow.
INT_2COMP-Twos complement.
INT_NEGATE~Bitwise negation.
INT_XOR^Bitwise exclusive-or.
INT_AND&Bitwise logical-and.
INT_OR|Bitwise logical-or.
INT_LEFT<<Left shift.
INT_RIGHT>>Unsigned (logical) right shift.
INT_SRIGHT>>Signed (arithmetic) right shift.
INT_MULT*Integer multiplication.
INT_DIV/Unsigned integer division.
INT_REM%Unsigned remainder.
INT_SDIV/Signed division.
INT_SREM%Signed remainder.
BOOL_NEGATE!Boolean negation.
BOOL_XOR^^Boolean exclusive-or.
BOOL_AND&&Boolean logical-and.
BOOL_OR||Boolean logical-or.
FLOAT_EQUAL==True if inputs are equal as floating-point numbers.
FLOAT_NOTEQUAL!=True if inputs are not equal as floating-point numbers.
FLOAT_LESS< or >True if one input is less than the other as floating-point numbers.
FLOAT_LESSEQUAL<= or >=True if one input is less than or equal to the other as floating-point numbers.
FLOAT_ADD+Add as floating-point numbers.
FLOAT_SUB-Subtract as floating-point numbers.
FLOAT_MULT*Multiply as floating-point numbers.
FLOAT_DIV/Divide as floating-point numbers.
FLOAT_NEG-Negate a floating-point number.
FLOAT_ABSABSAbsolute value of a floating-point number.
FLOAT_SQRTSQRTSquare root of a floating-point number.
FLOAT_CEILCEILCeiling function.
FLOAT_FLOORFLOORFloor function.
FLOAT_ROUNDROUNDNearest integral value.
FLOAT_NANNANTrue if input is not a valid floating-point number (NaN).
INT2FLOAT<na>Convert integer to floating-point.
FLOAT2FLOAT<na>Convert between different floating-point precisions.
TRUNC<na>Convert floating-point to integer.
CPOOLREF<na>Obtain constant pool value.
NEWnewAllocate an object or an array of objects.
MULTIEQUAL<na>Compiler phi-node: merge values from multiple control-flow paths.
INDIRECT<na>Indirect effect on a varnode.
CAST<na>Copy a value, changing its data-type.
PTRADD+Add an offset to a pointer.
PTRSUB. or ->Dereference a subfield from a pointer.
INSERT<na>Insert a bit-range.
EXTRACT<na>Extract a bit-range.
+
+
+ + + Internal Decompiler Functions + + Certain p-code operations can show up in decompiler output that cannot be represented + as either an operator token, a cast operation, or other depiction that is natural to + the language. The decompiler generally tries to eliminate these, but this isn't always + possible. The decompiler resorts to a functional syntax for these kinds + of p-code operations, displaying them as if they were built-in functions for the language. + + + + + SUB41(x,c) - Truncation operation - SUBPIECE + + The digit '4' indicates the size of the input operand 'x' in bytes. + The digit '1' indicates the size of the output value in bytes. + The parameter 'x' is the value being truncated. + The parameter 'c' is the number of least significant bytes being truncated. + + + SUB42(0xaabbccdd,1) = 0xbbcc + + + Extract a contiguous subset of the bytes from 'x'. + When 'c' is 0, the operation is a simple integer truncation. + + + + + SUB41(x,0) + truncates from a 4-byte integer to a 1-byte (char + or byte) integer. + + + SUB42(x,0) + truncates from a 4-byte integer to a 2-byte (short) integer. + + + SUB84(x,4) extracts the high 4 bytes from the 8 byte integer. + + + + + + CONCAT31(x,y) - Concatenation operator - PIECE + + The digit '3' indicates the size of the input operand 'x' in bytes. + The digit '1' indicates the size of the input operand 'y' in bytes. + The parameters 'x' and 'y' hold the values being concatenated. + + + CONCAT31(0xaabbcc,0xdd) = 0xaabbccdd + + + Concatenate the bytes in 'x' with the bytes in 'y'. 'x' becomes the most significant + bytes, and 'y' the least significant bytes, in the result. + + + + ZEXT14(x) - Zero-extension operator - INT_ZEXT + + The digit '1' indicates the size of the input operand 'x' in bytes. + The digit '4' indicates the size of the output in bytes. + + + ZEXT24(0xaabb) = 0x0000aabb + + + Extend the operand 'x' to a larger size by appending zero bytes, which become the most + significant bytes of the result. + + + + SEXT14(x) - Sign-extension operator - INT_SEXT + + The digit '1' indicates the size of the input operand 'x' in bytes. + The digit '4' indicates the size of the output in bytes. + + + SEXT48(0xaabbccdd) = 0xffffffffaabbccdd + + + Extend the operand 'x' to a larger size by duplicating the sign + bit of 'x' into the most significant bytes of the result. + + + + SBORROW4(x,y) - Test for signed borrow operator - INT_SBORROW + + The digit '4' indicates the size of both input operands 'x' and 'y' in bytes. + + + Return true if there is an arithmetic overflow when subtracting 'y' from 'x' + as signed integers. + + + + CARRY4(x,y) - Test for unsigned overflow operator - INT_CARRY + + The digit '4' indicates the size of both input operands 'x' and 'y' in bytes. + + + Return true if there is an arithmetic overflow when adding 'x' and 'y' + as unsigned integers. + + + + SCARRY4(x,y) - Test for signed overflow operator - INT_SCARRY + + The digit '4' indicates the size of both input operands 'x' and 'y' in bytes. + + + Return true if there is an arithmetic overflow when adding 'x' and 'y' + as signed integers. + + + + + +
+ + + The HighFunction + + A HighFunction is the collection of specific information + produced by the decompiler about a function, referring to the root class in the Ghidra + source which holds this information. + The HighFunction is made up of the following explicit objects: + + + + A control-flow representation of the function + in terms of basic blocks. + + + A data-flow representation of the function + in terms of varnodes and p-code operations. + + + A symbol-table of variables accessed by the function. + + + + + + The decompiler's output provides a standalone view of the function which is distinct + from any annotations about the function that are present in the Program database + and displayed in the Listing view (although the output may be informed by these annotations). + The terms HighFunction, HighVariable, and + HighSymbol refer to this decompiler specific view of the function. + + + + HighSymbol + + A HighSymbol is one of the explicit symbols recovered by the + decompiler. It is made up of a name and data-type and can describe either: + + + + a formal parameter of the function, + + + a local variable of the function, or + + + a global variable accessed by the function. + + + + + + An important aspect of HighSymbols is that they are distinct from + the standard Ghidra symbols stored in the Program database and are part of + the decompiler's separate view of the function. When the decompiler displays + declarations for symbols in its output for instance, it is displaying + HighSymbols, which may not directly match up with database symbols. + The decompiler is generally + informed by annotations in the database and may + copy specific symbols from the database into its view, but it is + generally free to invent new symbols discovered during its analysis. + + + Various actions within Ghidra allow the user to commit + specific HighSymbols to the database as a permanent annotation, but this + does not happen by default. + + + + + Varnodes in the Decompiler + + Varnodes are the central variable concept for the decompiler. + They form the individual nodes in the decompiler's data-flow representation + of functions and are used during all stages of analysis. During the initial stages + of analysis, varnodes simply represent specific storage locations that are accessed + in sequence by individual p-code operations. The decompiler immediately converts + the p-code into a graph based data-flow representation, called Static Single + Assignment (SSA) form. In this form, the varnodes take on some additional attributes. + + + In SSA form, each write of an operation to a storage location defines a new varnode. + Write operations at different points in the code to the same storage location, still + produce different varnodes. In this context, each varnode has a lifetime + or scope within the function. The scope starts at: + + + + + The defining p-code operation which has the + varnode as its output. Or + + + + + The beginning of the function, if the varnode is an input + to the function. + + + + + The scope extends via control-flow to each p-code operation that reads the + specific varnode as an operand. The value of the varnode between the definining p-code operation + and the reading operations does not change. The scope of a varnode can be thought of as a set + of addresses within the function's body connected by control-flow. The address of the defining + p-code operation is referred to as the varnode's first use point + or first use offset. + + + In the decompiler output for a specific high-level language like C or Java, + a varnode still has a scope and represents a variable + in the high-level language only across this connected region of the code. + A set of varnodes, with disjoint scopes, provides a complete + description of a high-level variable that can be written to at more than one point + in the function. + + + + + HighVariable + + A HighVariable is a set varnodes that, taken + together, represent the storage of an entire variable in the high-level language + being output by the decompiler. Each varnode describes where the variable's + value is stored across some section of code. + + + There is generally a one-to-one correspondence between HighVariables and + HighSymbols. HighVariables can be thought of as the detailed storage description + of the high-level variable, while the HighSymbol provides its name and data-type. + However, there are some technical caveats to this correspondence to keep in mind. + + + A HighVariable always describes explicit manipulation of + data by instructions in the function. In some cases, a HighVariable may only describe part + of the storage for a HighSymbol. Particularly for structured or composite data-types, a + function may operate on different parts of the variable at different points of the code, + so a HighVariable may only encompass one field of the structure. + + + A symbol may be referenced in a function, but the symbol's value may not be explicitly + manipulated. Constant pointers may refer to variables either + on the stack or in main memory, but the variable's value is neither read nor written + within the function. In this case, the HighSymbol exists, but there + is no corresponding HighVariable. + + + + Merging + + Merging is the part of the analysis process where + the decompiler decides what varnodes get grouped together to create the final + HighVariables in the output. Each varnode's scope (see the discussion in + ) provides the fundamental restriction on this process. + Two varnodes cannot be merged if their scopes intersect. But this leaves a lot of + leeway in what varnodes can be merged. + + + Certain varnodes must be merged; if they use the same storage but in different + control-flow paths that come together, for instance, or if it is explicitly + known that the varnodes must represent the same variable. This is referred + to as forced merging. + + + The decompiler may also merge varnodes that could just as easily exist as separate + variables. This is called speculative merging. + In addition to the intersection condition on varnode scopes, the decompiler only + speculatively merges variables that share the same data-type. Beyond this, the decompiler + prioritizes variable pairs that are read and written within the same instruction and + then pairs that are "near" each other in the control-flow of the function. + To a limited extent, users are able to control this kind of merging + (See ). + + + + +
+ +
+ + + Program Annotations Affecting the Decompiler + +
+ Machine Instructions + + Individual machine instructions + make up the biggest source of information when the + decompiler analyzes a function. Instructions are translated from their + processor specific form into Ghidra's IR language (see ), + which provides both the control-flow behavior of the instruction and the detailed + semantics describing how the processor and memory state is affected. The translation is controlled by + the underlying processor model and cannot be directly altered from the tool. Users + can modify the model specification itself, however. + See the document "SLEIGH: A Language for Rapid Processor Specification". + + + Decompiling a function starts by analyzing control-flow starting from the function's + first instruction. Control-flow is traced to additional instructions using flow information + from the underlying processor model. All paths are traced through instructions with + fall through, conditional jump, and other + semantics until an instruction with terminator semantics is + reached, which is usually a "return from subroutine" + instruction. Flow is not traced into subfunctions, in this situation. Instructions + with call semantics are treated only as if they fall through. + + + An entry point is the address of the function's first instruction. + + + A function body is the set of addresses reached by control-flow + analysis (and the machine instructions at those addresses). + + + Entry Point + + The entry point address for a function plays a pivotal role for + analysis using the Ghidra decompiler. Ghidra generally associates + a formal Function Symbol and an underlying + Function object at this address, which are the key elements that + need to be present to trigger decompilation. + (See Functions) + The Function object stores the function body, parameters, local variables, and + other information critical to the decompilation process. + + + Function Symbols and Function objects are generally created automatically by a Ghidra + analyzer when initially importing a binary executable and running auto-analysis. + If necessary however, a user can manually create a Function object from the Listing window + by using Create Function command (pressing the 'f' key), when the cursor + is placed on the function's entry point. + (See Create Function) + + + + Formal Function Body + + When a function is created, Ghidra stores its function body as a set of addresses in the + Program database. This formal function body delineates the function + from all the other kinds of data within the Program and lets Ghidra immediately link addresses + in the middle of the function to the entry point and the Function object. Decompiler windows + in particular use the formal function body to know which function to decompile in response + to a navigation event to an arbitrary address. + + + The decompiler does not use the formal function body when it computes + control-flow; it recomputes its own idea of the function body starting from the entry point + it is handed. If the formal function body was created manually, using a selection for instance, + or in other extreme circumstances, the decompiler's view of the function body may not match + the formal view. This can lead to confusing behavior, where clicking in a decompiler window + may unexpectedly navigate the window away from the function. + + + + + Flow Overrides + + Control-flow behavior for machine instructions is generally determined by the underlying + Processor model. But this flow can be overridden for individual instructions by various + Analyzers or manually by the user. The decompiler incorporates these overrides into its + analysis, and they can have a significant impact on results. Current + flow overrides include: + + + + + BRANCH Override + + + Treats the primary CALL or RETURN + behavior of the instruction as if it were a BRANCH + within the function. For CALL instructions, + the call target becomes the branch destination, + and the instruction is no longer assumed + to fall through. RETURN instructions become an + indirect branch, and the decompiler will attempt to recover branch + destinations using switch analysis. + + + + + CALL Override + + + Treats the primary BRANCH or RETURN + behavior of the instruction as if it were a CALL. + A BRANCH becomes a fall through instruction, and the destination address becomes + the call target, which may no longer be considered part of the function. The computed + address for an indirect BRANCH or RETURN instruction becomes + the target address of an indirect CALL. + + + + + CALL_RETURN Override + + + Treats the primary BRANCH or RETURN + behavior of the instruction as if it executed a CALL followed + by a RETURN operation. + The destination address of a BRANCH becomes the call target, + which may no longer be considered part of the function. The computed address for + an indirect BRANCH or RETURN instruction becomes + the target address of an indirect CALL. + + + + + RETURN Override + + + Treats an indirect BRANCH or CALL + instruction as if it were a RETURN instruction, terminating + the control-flow path within the function. The computed destination address is + considered part of the return mechanism of the function and may no longer be + explicitly displayed in the output. + An indirect BRANCH no longer invokes switch analysis during + decompilation. + + + + + + + +
+ +
+ Comments + + The decompiler automatically incorporates comments from the Program database into its + output. Comments in Ghidra are centralized and can be created and displayed by multiple + Program views, including the decompiler. Comments created from a decompiler window will + show up in the Listing window for instance, and vice versa. + + + For the purposes of understanding comments within the decompiler, keep in mind that: + + + + An individual comment is associated with a specific address in the Program. + + + There are 5 different kinds of comments. + + + Plate + + + Pre + + + Post + + + End-of-line (EOL) + + + Repeatable + + + + + + + + For general documentation on creating and editing comments within Ghidra, see + Comments. + + + + Display + + The decompiler collects and displays comments associated with any address in the + formal function body currently decompiling. + The comments are integrated line by line into the decompiled code, and an + individual comment is displayed on the line before the + line of code incorporating the instruction associated with the comment's + address. + + + Because a single line of code typically encompasses multiple machine instructions, + there is a possibility that multiple comments at different addresses apply to + the same line. In this case, the decompiler displays each comment on its + own line, in address order, directly before the line of code. + + + Because the output of the decompiler can be a heavily transformed version compared + to the original machine instructions, its possible that individual instructions + no longer have explicit tokens representing them in the output. Comments attached + to these instruction will still be displayed in the decompiler output with the + closest associated line of code, usually within the same basic block. + + + By default, the decompiler displays only the Pre comments + within the body of the function. It also displays Plate + comments, but only if they are attached to the entry point + of the function. In this case, they are displayed first in the decompiler output, + along with WARNING comments, before the function declaration. Other comment + types can be configured to display in decompiler output, by changing the + decompiler Display options (See ). + + + Unlike the Listing window, the decompiler does not alter how a comment is + displayed based on its type. + All enabled types of comment are displayed in the same way, on + a separate line before the line of code associated with the address. + + + + + Unreachable Blocks + + The decompiler may decide as part of its analysis that individual + basic blocks are unreachable and not display them in the output. + In this case, any comments associated with addresses in the unreachable block + will also not be displayed. + + + + + Warning Comments + + The decompiler can generate internal warnings during its analysis and will incorporate + them into the output as comments in the same way as the user defined + comments described above. They are not part of Ghidra's comment system however and + cannot be edited. They can be distinguished from normal comments by the word + 'WARNING' at the beginning of the comment. + + /* WARNING: ... */ + + + +
+ +
+ Variable Annotations + + Variable annotations are the most important way to get names and data-types + that are meaningful to the user incorporated into the decompiler's output. + A variable in this context is loosely defined + as any piece of memory that code in the Program treats as a logical entity. + The decompiler works to incorporate all forms of annotation into its output + for any variable pertinent to the function being analyzed. + + + At a minimum, a variable annotation in Ghidra provides a: + + + + Symbol name, + + + Data-type, and + + + Storage location. + + + + + + + Creating Variable Annotations + + Ghidra provides various ways that a name and other attributes can be ascribed + to a variable. These break up roughly into global variables, + defined directly on memory in the Program image, and variables that are + local to a function. + + + Global variables annotations are created from the tool by applying a data-type to a memory + location in the Listing window, either by invoking a command from the Data + pop-up menu, or dragging a data-type from the Data Type Manager + window directly onto the memory location. Refer to the documentation: + + + + Applying Data Type + + + + + + Local variables annotations are created from the Listing from various editor dialogs. See in particular: + + + + Function Signature Dialog + + + Stack Frame Editor + + + Creating a Default Reference + + + + + + The Decompiler window also provides numerous ways of annotating variables, both local and global. In particular, + see the commands: + + + + + + + + + + + + + + + + + + + + + Variable Symbols + + Ghidra maintains its own symbol table that supports namespaces and function + scopes, and variable names are automatically incorporated into this. + In order to widely accommodate different use cases, Ghidra's symbol + table has extremely lax naming rules. Ghidra + may allow names that conflict with the stricter rules of the language + the decompiler is attempting to produce. The decompiler does not currently + have an option that checks for this. Users should be aware of: + + + + + Illegal Characters + + + Ghidra symbols allow almost every printable character except + a space in a symbol name; punctuation and keywords can be incorporated. + + + + + Duplicate Symbols + + + Ghidra allows duplicate symbols, including duplicate function names, in + any scope higher than a function. + + + + + + + + + Variable Scope + + All variables belong either to a global or local + scope, which directly affects how the variable is treated in the decompiler's data-flow + analysis. + Annotations created by applying a data-type directly to a memory location in the listing + are automatically added to the formal global namespace. + Ghidra can create other custom namespaces that are considered global in this sense, and + renaming actions provide options that let individual global annotations be moved into + these namespaces. + Dialogs that are brought up in the context of a function, like the Function Signature Editor, + create variable annotations that are local to that function. + + + A global variable annotation forces the decompiler to treat the memory location as if its value + persists beyond the end of the function. The variable must exist + at all points of the function body, generally at the same memory location. + + + Local variables, + in constrast, do not generally exist across the whole function, but come into scope + at the instruction that first writes to them, and then exist only up to the last + instruction that reads them. The memory location storing a local variable + at one point of the function may be reused for different variables at other points. + This can cause ambiguity in how the decompiler should treat a given memory location used + for storing local variables, which the user may want to steer. See the discussion + in . + + + + + + + + + Variable Data-types + + Ghidra provides extensive support for naming and describing + data-types that are tailored for the Program + being analyzed. Data-types that are explicitly part of a variable annotation + are, to the extent possible, automatically incorporated + into the decompiler's analysis. + + + Data-types Supported by the Decompiler + + The decompiler understands traditional primitive data-types, in all their various sizes, + like integers, floating-point numbers, booleans, and characters. It also understands + pointers, structures, and arrays, letting it support + arbitrarily complicated composite data-types. Ghidra provides + some data-types with specialized display capabilities that don't have a natural representation + in the high-level language output by the decompiler. The decompiler treats these as + black-box data-types, preserving the name, but treating the underlying data either as an integer + or simply as an array of bytes. + + + + Undefined + + The undefined data-types are supported, in their various sizes: + undefined1, undefined2, + undefined4, etc. In Ghidra, the undefined + data-types, let the user specify the size of a variable, while formally declaring that + other details about the data-type are unknown. + + + For the decompiler, undefined data-types as an annotation have the important special meaning + that the decompiler should let its analysis determine the final data-type presented in the + output for the variable (See below). + + + + Void + + The void data-type is supported but treated specially by + the decompiler, as does Ghidra in general. A void can be + used to indicate the absence of a return value in function prototypes, but cannot be used + as a general annotation on variables. A void pointer, void *, + is possible; the decompiler treats it as a pointer to an unknown data-type. + + + + Integer + + Integer data-types, both signed and unsigned, are supported up to a size of 8 bytes. Larger + sizes are supported internally but are generally represented as an array of bytes in + decompiler output. Odd integer sizes are also supported. + + + The standard C data-type names: int, short, + long, and long long are mapped to specific sizes + based on the processor and compiler selected when importing the Program. + + + + Boolean + + A 1-byte boolean data-type is supported. + + + + Floating-point + + Floating-point sizes of 4, 8, 10, and 16 are supported, mapping in all cases currently to the + float, double, + float10, and float16 + data-types respectively. The decompiler currently cannot display floating-point constants + that are bigger than 8 bytes. + + + + Character + + ASCII or unicode encoded character data-types are supported for sizes of 1, 2, and 4. The size affectively + chooses between the UTF8, UTF16, and UTF32 character encodings respectively. The standard + C data-type names char and wchar_t are + mapped to one of these sizes based on the + processor and compiler selected when importing the Program. + + + + String + + Terminated strings, encoded either in ASCII or Unicode, are supported. The decompiler converts + Ghidra's dedicated string data-types like string to + an "array of characters" data-type, such as char[], + where the character size matches the encoding. + A "pointer to character" data-type like + + + + char * or + + + wchar_t * + + + + is also treated as a potential string reference. The decompiler can infer terminated strings if this + kind of data-type propagates to constant values during its analysis. + + + Strings should be fully rendered in decompiler output, + with non-printable characters escaped using either traditional sequences like '\r', '\n' or using unicode + escape sequences like '\xFF'. + + + + Pointer + + Pointer data-types are fully supported. A pointer to any other supported data-type is + possible. The data-type being pointed to, whether its a primitive, structure, or another pointer, + informs how the decompiler renders a dereferenced pointer. + The decompiler assumes that a pointer variable may refer to an array of + the underlying data-type and will use array notation if there is evidence of more than + one element. + + + The default pointer size is set based on the processor and compiler selected when the Program is + imported and generally matches the size of the ram (or equivalent) + address space. Different pointer sizes within the same Program are possible. The decompiler generally + expects the pointer size to match the size of the address space being pointed to, but individual + architectures can model different size pointers into the space (such as near pointers). + + + For processors with more than one memory address space, pointer data-types currently cannot be directly + annotated to indicate a preferred address space. Where there is ambiguity, the decompiler attempts to + determine the correct address space from the context of its use within the function. + + + + Array + + Array data-types are fully supported. The array element can be any other supported data-type + with a fixed size. + + + + Structure + + Structured data-types are fully supported. The decompiler does not automatically infer structures + when analyzing a function; it propagates structured data-types into the function from explicitly + annotated sources, like input parameters or global variables. Decompiler directed creation of + structures can be triggered by the user, see . + + + + Enumeration + + Enumerations are fully supported. The decompiler can propagate enumerations from explicitly + annotated sources throughout a function onto constants, which are then displayed with the + appropriate label from the definition of the enumeration. If the constant does not match a + single value in the enumeration definition, the decompiler attempts to build a matching + value by or-ing together multiple labels. + The decompiler can be made to break out constants representing packed flags, + for instance, by labeling individal bit values within an enumeration. + + + + Function Definition + + A Function Definition in Ghidra is a data-type that encodes + information about the parameters and return value for a generic/unspecified function. + A formal function pointer is supported by the decompiler as a pointer + data-type that points to a Function Definition. A Function Definition specifically encodes: + + + + The name and data-type of each parameter. + + + Whether the function takes a variable number of parameters. + + + The data-type associated with the return value. + + + An indicator of the prototype model that should be + associated with the function. + + + + + + The Function Definition itself does not encode any storage information. Once the Function + Definition is associated with a Program, the indicator maps to one of the prototype models for the + specific processor and compiler. A Function Definition is currently limited to a prototype model + with one of the following names: + + + + __stdcall + + + __thiscall + + + __fastcall + + + __cdecl + + + __vectorcall + + + + + + + + + Forcing Data-types + + The decompiler performs type propagation as part of its analysis + on functions. Data-type information is collected from variable annotations (and other sources), + which is then propagated via data-flow throughout the function to other variables and + constants where the data-type may not be immediately apparent. + + + With few exceptions, a variable annotation is forcing on the decompiler in the sense + that the storage location being annotated is considered an unalterable data-type source. During + type propagation, the data-type may propagate to other variables, + but the variable representing the storage location being annotated is guaranteed to have + the given name and that data-type; it will not be overridden. + + + Users should be aware that variable annotations are forcing on the decompiler and may directly + override aspects of its analysis. Because of this, variable annotations are the most powerful way + for the user to affect decompiler output, but setting an incomplete (or incorrect) data-type as + part of an annotation may produce poorer decompiler output. + + + The major exception to forcing annotations is if the data-type in the annotation is undefined. + Ghidra reserves the following names to represent formally undefined data-types: + + + undefined1 + undefined2 + undefined4 + undefined8 + ... + + + These allow annotations to be made even when the user doesn't have information about a variable's data-type. + The number in the name only specifies the number of bytes in the variable. + + + The decompiler views a variable annotation with an undefined data-type only as an indication of what name + should be used if a variable at that storage address exists. The data-type for the variable is filled in, + using type propagation from other sources. + + + For annotations that specifically label a function's formal parameters or return value, + the Signature Source-Type also affects how they're treated by the decompiler. + If the Source-Type is set to anything other than DEFAULT, there is a forced + one-to-one correspondence between variables annotations and actual parameters in the decompiler's + view of the function. This is stronger than just forcing the data-type; the existence (or not) of + the variable itself is forced by the annotation in this case. A Source-Type other than + DEFAULT is set typically if debug symbols for the function are read in during + Program import (IMPORTED), or if the user manually edits the function prototype + directly (USER_DEFINED). + + + If an annotation and the Signature Source-Type force a parameter to exist, specifying an + undefined data-type in the annotation still directs the decompiler to fill in + the variable's data-type using type propagation. The same holds true for the return value; an + undefined annotation fixes the size of the return value, but the decompiler + fills in its own data-type. + + + The decompiler may still use an undefined data-type to label a variable, + even after type propagation. If a variable is simply copied around within a function and there + are no other substantive operations or annotations on the variable, the decompiler may decide the undefined + data-type is appropriate. + + + + + + + Variable Storage + + Every variable annotation is associated with a single storage location, where the + value of the variable is stored during execution: generally a register, stack location, or an address + in the load image of the Program. The storage location does not necessarily hold the value for that + variable at all points of execution, and its possible for the variable value to be held in + different storage locations at different points of execution. The set of execution + points where the storage location does hold the variable value is called the annotation + scope; this is distinct from (but influenced by) the scope of the + variable itself. The different types of storage location are listed below. + + + Load-image Address + + A load-image address is a concrete address in the load image of the Program, + typically in the ram address space. This kind of + storage must be backed by a formal memory block for the Program, which typically corresponds to a specific + program section (such as the .text or .bss section). Because it is in the + load image directly, an annotation with this storage shows up directly in the Listing + window and can be directly manipulated there. In much of the Ghidra documentation, these annotations + are referred to as Data. See the section + Data in particular. + + + Although specific architectures may vary, generally a storage location at a load image address + represents a formal global variable, and the annotation is in scope + across all Program execution. For the decompiler, the storage location is treated as a + a single persistent variable in all functions that reference it. Within a + function, all distinct references to the storage location (varnodes) are merged. The decompiler + expects a value at the storage location to exist from before the start of + the function, and any change to the value must be explicitly represented as an assignment to + the variable in decompiler output. + + + + Stack Address + + A stack address is an address in the stack frame + of a particular function in the Program. Formally, a stack address is defined as an offset relative to the + incoming value of the stack pointer and exists in the + stack address space associated with the function. See the discussion + in . A stack annotation then is a variable annotation + with a stack address as its storage location. It exists only in the scope of a + single function and the variable must be local to that function. + + + Within the Listing window, a stack annotation is displayed as part of the function header + (at the entry point address of the function), with a syntax similar to: + + undefined4 Stack[-0x14]:4 local_14 + + The middle field (the Variable Location field) indicates that the storage location is on the + stack, and the value in brackets indicates the offset of the storage location, relative to the incoming + stack pointer. The value after the colon indicates the number of bytes in the storage location. + + + Currently, the entire body of the function is included + in the scope of any stack annotation, and the decompiler will allow only a single variable to exist + at the stack address. A stack annotation can be a formal parameter to the function, but otherwise the + decompiler does not expect to see a value that exists before the start of the function. Similarly, + because the value is not expected to persist after the function executes, a write to the stack + address may not show up as an explicit assignment to the variable if the value is simply + propagated through to another expression. + + + + Register + + A variable annotation can refer to a specific register for the processor associated + with the Program. In general, such an annotation will be for a variable local to a particular function. + Within the Listing window, this annotation is displayed as part of the function header, with + syntax like: + + int EAX:4 iVar1 + + The Variable Location field displays the name of the particular register attached to + the annotation, and the value after the colon indicates the number of bytes in the register. + + + For a local variable annotations with a register storage location, there is an expectation that the + register may be reused for different variables at different points of execution within the function. + There may be more than one annotation, for different variables, that share the same register + storage location. + An annotation is associated with a first use point that describes where + the register first holds a value for the particular variable. (See the discussion - ) + The entire scope of the annotation is limited to the address regions between the first use point + and any points where the value is read. The decompiler may extend the scope as part of its + merging process, but the full extent is not stored in the annotation. + + + + Temporary Registers + + Variable annotations can have a temporary register as a storage location. + A temporary register is not specific to a processor but is produced at various stages of + the decompilation process. See the discussion of the unique + space in . These registers do not have a meaningful name, and + the specific storage address may change on successive decompilations. So within the + Listing window, this annotation is displayed as part of the function header, + with syntax like: + + int HASH:5f96367122:4 iVar2 + + The Variable Location field displays the internal hash used to uniquely + identify the temporary register within the data-flow of the function. + + + A temporary register annotation must be for a local variable, and as with an ordinary register, + the annotation is associated with a first use point that describes + where the temporary register first holds a value for the variable. + + + +
+ +
+ + + Decompiler Options + + + This lists configuration options that explicitly affect the behavior of the decompiler or + its output, independent of the code that is being decompiled. The bulk of these are + accessible by selecting the Code Browser menu + + Edit -> Tool Options + + and then picking the Decompiler sub-folder. These options are associated + with the particular tool (Code Browser) being used and will apply to decompilation of any Program + being analyzed by that tool. The three categories of options are: + + + affecting the engine behavior + affecting the decompiler's transformation process + affecting the final presentation of decompiler output + + + + + Another source of options can be accessed by selecting the Code Browser menu + + Edit -> Options for <Program> + + and the picking the Decompiler tab. These + are specific to the particular Program being analyzed. + + +
+ General Options + + + + + + Cache Size (Functions) + + + Decompilation results for a single function can be compute intensive to produce. + This option specifies the number of functions whose decompilation results + can be cached simultaneously. When navigating to a function that + has been recently cached, as when navigating back and forth between a few functions, + a new decompilation is not triggered. + + + + + Decompiler Max-Payload (MBytes) + + + This is a limit on the number of bytes that can be produced by the decompiler process as output + when decompiling a single function. A payload includes the actual characters to be displayed in + the window, additional token markup, symbol information, and other details of the underlying + syntax tree. The limit is specified in megabytes of data. If the limit is exceeded for a single + function, decompilation is aborted for that function, and an error message + "Decompiler results exceeded payload limit ..." is displayed. + + + + + Decompiler Timeout (seconds) + + + This option sets an upper limit on the number of seconds the decompiler spends attempting + to analyze one function before aborting. + It is currently not enforced for the Decompilation + Window. Instead it applies to the DecompilerSwitchAnalyzer, the analyzeHeadless command, scripts, or other + plug-ins that make use of the decompiler service. + + + + + + +
+ +
+ Analysis Options + + + + + + Alias Blocking + + + When deciding if an individual stack location has become dead, the decompiler + must consider aliases, pointers onto the stack that could + be used to modify the location within a sub-function. One strong heuristic the decompiler + uses is; if the user has explicitly created a variable on the stack between the + base location referenced by the pointer and the individual stack location, then + the decompiler can assume that the pointer is not an alias of the stack location. + The alias is blocked by the explicit variable. + However, if the user's explicit variable is labeling something that isn't + really an explicit variable, like a field within a larger structure for instance, + the decompiler may incorrectly consider the stack location as dead and start removing + live code. + + + In order to support the exploratory labeling of stack locations, the user can use this + setting to specify what data-types should be considered blocking. The four options are: + + + None - No data-type is considered blocking. + Structures - Only structured data-types are blocking. + Structures and Arrays + All Data-types - All data-types are blocking. + + + Selecting None is the equivalent of turning off the heuristic. Selecting anything + except All Data-types allows users to safely label small variables without + knowing immediately if the stack location is part of a larger structure or array. + + + + + Eliminate unreachable code + + + When this is toggled on, the decompiler eliminates code that it + considers unreachable. This usually happens when, due to constant propagation and other + analysis, the decompiler decides that a boolean value controlling a conditional branch can + only take one possible value and removes the branch corresponding to the other value. Toggling + this to off lets the user see the dead code, which is typically demarcated + by the control-flow structure -- if (false) { ... }. + + + + + Ignore unimplemented instructions + + + When toggled on, the decompiler treats instructions whose semantics + have been formally marked unimplemented as if they do + nothing (no operation). Crucially, control-flow falls through to the next instruction. + In this case, the decompiler inserts the warning "Control flow ignored unimplemented + instructions" as a comment in the function header, but the exact point at which + instruction was ignored may not be clear. + If this option is toggled off, the decompiler inserts the built-in + function halt_unimplemented() at the point of the unimplemented instruction, and + control-flow does not fall through. + + + + + Infer constant pointers + + + When toggled on, the decompiler infers a data-type for constants + it determines are likely pointers. In the basic heuristic, + each constant is considered as an address, and if that address starts a known data or function element + in the program, the constant is assumed to be a pointer. The constants are treated like + any other source of data-type information, and the inferred data-types are freely propagated by + the decompiler to other parts of the function. + + + + + Respect read-only flags + + + When toggled on, the decompiler treats any values in memory + marked read-only as constant. If a read-only memory location is explicitly + referenced by the function being decompiled, it is considered to be unchanging, and the initial + value present in the Program is pulled in to the data-flow of the function as a constant. + Due to Constant Propagation and other transformations, read-only memory + can have a large effect on decompiler output. + + + Typically as part of the import process, Ghidra marks memory blocks as read-only if they + are tagged as such by a section header or other meta-data in the original binary. + Users can actively set whether specific memory regions are considered read-only through the + Memory Manager, and individual data elements can be marked + as constant via the Mutability setting + (See ). + + + + + Simplify extended integer operations + + + This toggles whether the decompiler attempts to simplify double precision arithmetic operations, + where a single logical operation is split into two parts, calculating the high and low pieces + of the result in separate instructions. Decompiler support for this kind of transform is currently + limited, and only certain constructions are simplified. + + + + + Simplify predication + + + When this option is active, the decompiler simplifies codes sequences containing + predicated instructions. A predicated instruction is executed + conditionally based on a boolean value, the predicate, + and a sequence of instructions can share the same predicate. The decompiler merges the + resulting if/else blocks that share the same predicate so that the condition is only + printed once. + + + + + Use in-place assignment operators + + + When toggled on, the decompiler employs in-place assignment operators, + such as += and <<=, in its output syntax. + + + + + + +
+
+ + + Decompiler Window + + To display the decompiler window, position the cursor on a + function in the Code Browser, then select the + icon from the tool bar, or the + Decompile option from the + Window menu in the tool. + + + A decompiler window always displays one function at a time. + The initial window that comes up in the Code Browser is called the Main + window (See ), and it automatically decompiles and displays the function at the + current address, following the user's navigation. Other + Snapshot windows can also + be opened that show different functions at the same time (See ). But any window + only shows one function at a time. + + + Decompilation for a window is performed "on-the-fly". It automatically + incorporates the most recent labels, data-types, comments, and other annotations applied by the user. Any change + to the Program annotations (renaming, setting data-types, etc.) automatically causes each window to redecompile + its function. + + + The time it takes to decompile a single function is generally proportional to the number of instructions that make + up the body of the function. Large functions may require a significant amount of time to decompile, and because + decompilation is performed on-the-fly, closing a window or navigating away from a function + runs the risk of losing results that took a long time to compute. + + +
+ Display + + The window shows the decompiled output for the function associated with the window in C or some other + high-level programming language. The output is tokenized following conventions of the language. Possible + token types include: + + + Data-type Name + Variable Name + Variable Sub-field Name + Function Name + Operator + Label + Comment + Syntax + + + + + The type of token provides context for the pop-up menus, which can trigger + highlighting, navigation, renaming, and other actions within the window. + + + + If the window starts to decompile but ultimately fails to complete the decompilation, due + to an error or cancellation, it displays a brief description of what caused the failure + instead of the normal output. Decompilation may also successfully produce output but issue + one or more warnings during the process. These warnings are integrated into the output as + source code comments starting with label WARNING:. They occur either at the + beginning of the function as part of the function header or at the point in the code directly + associated with the warning. (See ) + +
+ +
+ Main Window + + Initially pushing or selecting + Decompile from Window menu in the tool + brings up the main window. The main window always displays the function + at the current address within the Code Browser and follows as the user navigates + within the Program. Any mouse click, menu option, or other action causing the cursor to move to a new + address in the Listing also causes the main window to display the function containing that address. + Navigation to new functions is also possible from within the window by double-clicking on function + tokens (See ). + + + + Cross Highlighting + + The main window maintains a map between the individual variable and operator tokens displayed in + the window and the machine instructions which correspond to them. This can give the user instant + feedback about the correspondence between the decompiler and disassembly views of the function, + and it is frequently useful to have both the Listing window and the Decompiler window side + by side. Clicking on tokens in the Decompiler window causes the Listing window to navigate + to the corresponding instruction, and clicking instructions in the Listing window + causes the Decompiler window to navigate to the corresponding line. Highlighting a region of + code in either window causes the corresponding region in the other window to be highlighted. + + + Variable Name and Variable Sub-field Name tokens + map to the machine instruction which wrote to the variable at that point in function. + + + Operator tokens map to the machine instruction which performed that operation. + + + Function Name tokens, if they represent a call to a sub-function, map to the + machine instruction executing the call. + + + Comment tokens map to the machine address associated with the comment. + + + In general, the map between machine instructions and tokens is not one to one because the decompiler + transforms its underlying representation of the function. + An instruction may no longer have any operator that corresponds to it in the decompiled result. + Tokens may be transformed from the natural operation of the machine instruction they are associated + with or may represent the effect of multiple instructions. + + +
+ +
+ Snapshot Windows + + Pressing the + icon in another Decompiler window's toolbar causes a Snapshot window + to be created, which initially shows decompilation of the same function. Multiple + Snapshot windows can be brought up to show decompilation of different functions + simultaneously. Snapshot + windows are visually distinguished from the main Decompiler window + by their colored outline. + + + The Snapshot + window, unlike the main window, is not linked to the Listing window + and does not change the function it displays in response to external navigation events. + A Snapshot window can be used to hold a function fixed while the user navigates to + different functions in the Listing or other windows. + + + Navigating to new functions within a Snapshot window is possible when the window is + active. The window responds to the actions + + + Go To ... (pressing the 'g' key) + Go to previous location (Back) + Go to next location (Forward) + + + +
+ +
+ Tool Bar + + This is a group of actions that can be triggered by pressing a button in the tool/title + bar at the top of individual decompiler windows, both main and + Snapshot. The action applies to the function and decompiler results + displayed in that particular window. + + + Export to C + + - button + + + Exports the decompiled result of the current function to a file. A file chooser + dialog is displayed to select the name of the output file. If a file extension + is not specified, a ".c" is appended to the filename. If the file already exists, + a final dialog is presented to confirm that the file should be overwritten. + + + + + Snapshot + + - button + + + Creates a new Snapshot window. The Snapshot window + initially displays the same function as the decompiler window on which the action was triggered, + but if that window navigates to other functions, the Snapshot does not + follow and continues to display the original function. (See ) + + + + + Re-decompile + + - button + + + Triggers a re-decompilation of the current function displayed in the window. + Any cached results are discarded, and a full decompile is performed. + + + This action is not necessary for normal reverse + engineering tasks. Re-decompilation is automatically triggered for all + decompiler windows by any change to the Program, so the most up-to-date decompilation is + always available to the user without this action. This action is a primarily a debugging + aid for plug-in developers. + + + + + Copy + + - button + + + Copies the currently selected text in the decompiler window to the clipboard. + + + + + Debug Function Decompilation + + This action is located in the drop-down menu on the right side of the decompiler + window tool/title bar. + + + Information suitable for debugging the decompilation process for + the current function is collected and saved to an output file in + XML format. A file chooser dialog is presented to the user to + choose the output file. The file is useful when submitting bug reports + about the decompiler as it is generally much smaller than + the entire Program and only contains information specific to the + function. Information is generated by performing the full + decompilation of the function and collecting all the data and + annotations required during the process, including instruction + bytes, symbols, data-types, and other settings affecting + decompilation. + + + +
+ +
+ Mouse Actions + + Left Click + + Moves the decompiler window cursor and highlights the token. Within the + main window, if a token has a machine address + associated with it, a left click generates a + navigation event to that address, which may cause other + windows to display code near that address. + (See ) + + + Selecting a '(' or ')' token causes it and its matching parenthesis to be + highlighted along with the entire expression they surround. + + + Selecting a '{' or '}' token causes it and its matching brace to be highlighted. + + + + + Right Click + + Moves the decompiler window cursor, highlights the token, and brings up the menu of + context sensitive actions. Any highlighting and navigation is identical to a + left click. The menu actions presented depend primarily on the token type and + are tailored to the context at that point in the code. + + + + + Double Click + + Navigates based on the selected symbol or other token (See below). If the selected token represents a formal symbol, + such as a function name or a global variable, double clicking causes a + navigation event to the address associated with the symbol. + + + + + Sub-function Symbols + + Double clicking a sub-function name causes the + window itself to navigate away from its current function to the sub-function, triggering + a new decompilation if necessary and changing its display. + + + + Global Variables + + Double clicking a global + variable name does not have any effect on the decompiler window itself, + but other windows, like the Listing window, may navigate to the + storage address of the global variable. + + + + Constants + + Double clicking a token representing a constant causes the constant to be treated + as an address, and a navigation event to that address is generated. The decompiler + window itself navigates depending again on whether the address represents a new function or not. + + + + Labels + + Double clicking the label within a goto statement causes the window to navigate + to the target of the goto, within the function. The cursor is set and the window view is adjusted if + necessary to ensure that the target is visible. + + + + Braces + + Double clicking a '{' or '}' token, causes the window to navigate to the matching brace + within the window. The cursor is set and the window view is adjusted if + necessary to ensure that the matching brace is visible. + + + + + + + + + Control Double Click + + Opens a new Snapshot window, navigating it to the selected symbol. + This is a convenience for immediately decompiling and displaying a sub-function in a + new window, without disturbing the active window. The behavior is similar to the + Double Click action, the selected token must represent a function name symbol or possibly + a constant address, but the navigation occurs in the new Snapshot window. + + + + + Control Shift Click + + Generates a navigation event to the address, within the current function, associated with + the clicked token. This allows Snapshot windows to do basic + cross-highlighting in the same way as the main decompiler window. + A Control double-click causes the Listing and other windows to navigate to and display the same + portion of code currently being displayed in the Snapshot window. (See ) + + + + + Middle Click + + Highlights every occurrence of a variable, constant, or operator under the current + cursor location, within the decompiler window. + + + +
+ + + +
+ +
diff --git a/Ghidra/Features/Decompiler/src/main/doc/decompileplugin_common.xsl b/Ghidra/Features/Decompiler/src/main/doc/decompileplugin_common.xsl new file mode 100644 index 0000000000..3bc53ab61b --- /dev/null +++ b/Ghidra/Features/Decompiler/src/main/doc/decompileplugin_common.xsl @@ -0,0 +1,59 @@ + + + + + article/appendix nop + article title + book title,example,equation + chapter nop + part toc,title + preface toc,title + qandadiv toc + qandaset toc + reference toc,title + sect1 nop + sect2 nop + sect3 nop + sect4 nop + sect5 nop + section nop + set toc,title + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +figure after +example before +equation before +table before +procedure before +task before + + + diff --git a/Ghidra/Features/Decompiler/src/main/doc/decompileplugin_html.xsl b/Ghidra/Features/Decompiler/src/main/doc/decompileplugin_html.xsl new file mode 100644 index 0000000000..4b1e388948 --- /dev/null +++ b/Ghidra/Features/Decompiler/src/main/doc/decompileplugin_html.xsl @@ -0,0 +1,56 @@ + + + + + + + + + + + + + + + + + + 6 + 5 + 4 + 3 + 2 + 1 + + + + + + + title + + + + + + + + + + + + + + + + + + + + + + + +