From 188b69652c282db26e0beb167da353ff95029e48 Mon Sep 17 00:00:00 2001 From: caheckman <48068198+caheckman@users.noreply.github.com> Date: Tue, 1 Sep 2020 10:24:59 -0400 Subject: [PATCH] PrototypeModel documentation --- .../src/main/doc/decompileplugin.xml | 196 +++++++++++++++++- 1 file changed, 193 insertions(+), 3 deletions(-) diff --git a/Ghidra/Features/Decompiler/src/main/doc/decompileplugin.xml b/Ghidra/Features/Decompiler/src/main/doc/decompileplugin.xml index 0af41c4ab4..38b30de7c5 100644 --- a/Ghidra/Features/Decompiler/src/main/doc/decompileplugin.xml +++ b/Ghidra/Features/Decompiler/src/main/doc/decompileplugin.xml @@ -1049,6 +1049,69 @@ + + Prototype Model + + Functions in high-level languages manipulate symbols like parameters and return values that + are implicitly stored in a way that doesn't collide with other functions and variables. To + actually map these symbols to physical registers and memory locations, compilers establish a + calling convention for the function. + Loosely, this is a set of memory resources, whether it is registers or stack locations, + and a procedure for sequentially assigning resources to parameters based on their properties. + A prototype model is the formal object in Ghidra that represents + a calling convention and holds its specific rules and resource details. + + + Prototype models are architecture specific, and depending on the compiler, a single Program may make + use of multiple models. Subsequently, each distinct model has a name like __stdcall or + __thiscall. The decompiler makes use of the prototype model, as assigned to the function by the user or + discovered in some other way, when performing its analysis of parameters. + + + A prototype model is typically used as a whole and is assigned by name to individual functions. But some of + the sub-concepts of the model may be relevant to reverse engineers. + + + Incoming and Outgoing Storage Locations + + A formal input parameter is always assigned a specific memory location to hold its value coming into the function. + The storage location can be a register, a stack location, or other memory location. The storage + location may be reused later by other variables in the function; only the incoming value stored there is guaranteed + to be that of input parameter. + + + If the parameter + is stored on the stack, the storage location is viewed as a constant offset in the stack + space, where the offset is relative to the incoming value of stack pointer + (See the discussion in ). + + + The return value for the function, similarly, is stored at a single memory location. It + is guaranteed to be at that location only at points where the function is exited. There may be multiple exit + points, but they all share the same return value storage location. + + + + Unaffected + + Prototype models can specify a set of unaffectedmemory locations, + whose value must be preserved across the function. I.e. each location + must hold the same value at a function's exit that it held coming into the function. + These encompass a calling convention's saved registers, where a calling function + can store values it doesn't want to change unexpectedly, but also may include other registers that are + known not to change, like the stack pointer. + The decompiler uses the information to determine which locations can be safely propagated across + a sub-function. + + + + Killed by Call + + In constrast to unaffected memory locations, a prototype model may specify + killed by call locations that are guaranteed not + to be used to hold a value across the function. + + @@ -1726,10 +1789,14 @@ 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 + one-to-one correspondence between variables annotation 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 + the variable itself is forced by the annotation in this case. If the Source-Type is forcing and + there are no parameter annotations, a void prototype is forced on the function. + + + A forcing Source-Type, with a value 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). @@ -1866,6 +1933,129 @@ +
+ Function Prototypes + + Every formal Function in Ghidra is associated with a set of variable annotations and other properties that + make up the function prototype. Due to the nature of reverse engineering, + the function prototype may only include partial information and may be built up over time. Individual + elements include: + + + + + Input Parameters + + + Each formal input to the function can have a Variable Annotation that describes its name, data-type, + and storage location, at the moment control-flow enters the function. If the annotations exist, they are shown + in the Listing Window as part of the Function header, and they usually correspond directly with symbols in the + function declaration produced by the decompiler. + + + + + Return Value + + + The value returned by a function can have a special Variable Annotation that describes its data-type + and storage location, at the moment control-flow exits the function. If it exists, the annotation is shown + in the Listing Window as part of the Function header with the name <RETURN>, and it usually + corresponds directly with the return value in the function declaration produced by + the decompiler. + + + + + Calling Convention + + + The calling convention used by the function can be specified as part of the function prototype. The convention + is specified by name, referring to the formal Variable Arguments + + + Functions have a boolean property called variable argments, which can be turned on + if the function is capable of being passed a variable number of inputs. This property informs the decompiler that + the function may take additional parameters beyond any with an explicit variable annotation. + This affects decompilation of any function which calls the variable arguments function, allowing + the decompiler to discover unlisted parameters at a given call site. + + + + + No Return + + + A function can be marked explicitly as not returning, meaning that once + a call is made to the function, execution will never return to the caller. The decompiler uses this to + compute the correct control-flow in any calling functions. + + + + + In-Line + + + If the boolean property in-line is turned on for a particular function, + it directs the decompiler to inline the effects of the function into the decompilation of any of its calling functions. + The function will no longer appear as a direct subfunction call in the decompilation, but all of its data-flow + will be incorporated into the calling function. + + + This is useful for bookkeeping functions, where its important for the decompiler to + see its effects on the calling function. Functions that set up the stack frame for a caller or + functions that look up or dispatch a switch destination are typical examples that should be marked in-line. + + + + + Call-fixup + + + This property is similar in spirit to marking a function as in-line. + A call-fixup directs the decompiler to replace any call to the function with a specific + chunk of raw p-code. The decompilation of any calling function no longer shows the subfunction call, but the chunk + of p-code incorporates the subfunction's effects. + + + Call-fixups are more flexible than just inlining a function. The call-fixup chunk can be tailored to incorporate all of, + just a part of, or something different to the behavior of the function. + + + Call-fixups are specified by name. The name and associated p-code chunk are typically defined in the + compiler specification for the Program. + + + + + + + + Discovering Parameters + + Any parameter annotations in the function prototype are all forcing (as a unit) if the + Signature Source-Type is set to anything other than + DEFAULT. See the more complete discussion in . + + + If the function prototype is not forced, the decompiler will attempt to discover the parameters + and return value using the calling convention. The prototype model underlying the calling convention + dictates which storage locations can be considered as parameters and their formal ordering. + + +
+