iASL: Add new warnings for method LocalX and ArgX variables.

1) Warn if a Local is set but never used
2) Warn if a ArgX is never used (for non-predefined method names)
3) Warn if a ArgX that is used as a local is never used
This commit is contained in:
Robert Moore 2015-06-25 09:56:52 -07:00
parent 03c66d2425
commit eb9f8cb9fd
9 changed files with 428 additions and 156 deletions

View File

@ -191,8 +191,73 @@ LkIsObjectUsed (
{
ACPI_NAMESPACE_NODE *Node = ACPI_CAST_PTR (ACPI_NAMESPACE_NODE, ObjHandle);
ACPI_NAMESPACE_NODE *Next;
ASL_METHOD_LOCAL *MethodLocals;
ASL_METHOD_LOCAL *MethodArgs;
UINT32 i;
if (Node->Type == ACPI_TYPE_METHOD)
{
if (!Node->Op || !Node->MethodLocals)
{
return (AE_OK);
}
MethodLocals = (ASL_METHOD_LOCAL *) Node->MethodLocals;
MethodArgs = (ASL_METHOD_LOCAL *) Node->MethodArgs;
/*
* Analysis of LocalX variables
*/
for (i = 0; i < ACPI_METHOD_NUM_LOCALS; i++)
{
/* Warn for Locals that are set but never referenced */
if ((MethodLocals[i].Flags & ASL_LOCAL_INITIALIZED) &&
(!(MethodLocals[i].Flags & ASL_LOCAL_REFERENCED)))
{
sprintf (MsgBuffer, "Local%u", i);
AslError (ASL_WARNING, ASL_MSG_LOCAL_NOT_USED,
MethodLocals[i].Op, MsgBuffer);
}
}
/*
* Analysis of ArgX variables (standard method arguments,
* and remaining unused ArgX can also be used as locals)
*/
for (i = 0; i < ACPI_METHOD_NUM_ARGS; i++)
{
if (MethodArgs[i].Flags & ASL_ARG_IS_LOCAL)
{
/* Warn if ArgX is being used as a local, but not referenced */
if ((MethodArgs[i].Flags & ASL_ARG_INITIALIZED) &&
(!(MethodArgs[i].Flags & ASL_ARG_REFERENCED)))
{
sprintf (MsgBuffer, "Arg%u", i);
AslError (ASL_WARNING, ASL_MSG_ARG_AS_LOCAL_NOT_USED,
MethodArgs[i].Op, MsgBuffer);
}
}
else
{
/*
* Remark if a normal method ArgX is not referenced.
* We ignore the predefined methods since often, not
* all arguments are needed or used.
*/
if ((Node->Name.Ascii[0] != '_') &&
(!(MethodArgs[i].Flags & ASL_ARG_REFERENCED)))
{
sprintf (MsgBuffer, "Arg%u", i);
AslError (ASL_REMARK, ASL_MSG_ARG_NOT_USED,
MethodArgs[i].Op, MsgBuffer);
}
}
}
}
/* Referenced flag is set during the namespace xref */
if (Node->Flags & ANOBJ_IS_REFERENCED)

View File

@ -307,7 +307,11 @@ const char *AslCompilerMsgs [] =
/* ASL_MSG_BUFFER_ALLOCATION */ "Could not allocate line buffer",
/* ASL_MSG_MISSING_DEPENDENCY */ "Missing dependency",
/* ASL_MSG_ILLEGAL_FORWARD_REF */ "Illegal forward reference within a method",
/* ASL_MSG_ILLEGAL_METHOD_REF */ "Illegal reference across two methods"
/* ASL_MSG_ILLEGAL_METHOD_REF */ "Illegal reference across two methods",
/* ASL_MSG_LOCAL_NOT_USED */ "Method Local is set but never used",
/* ASL_MSG_ARG_AS_LOCAL_NOT_USED */ "Method Argument (as a local) is set but never used",
/* ASL_MSG_ARG_NOT_USED */ "Method Argument is never used"
};
/* Table compiler */

View File

@ -310,6 +310,9 @@ typedef enum
ASL_MSG_MISSING_DEPENDENCY,
ASL_MSG_ILLEGAL_FORWARD_REF,
ASL_MSG_ILLEGAL_METHOD_REF,
ASL_MSG_LOCAL_NOT_USED,
ASL_MSG_ARG_AS_LOCAL_NOT_USED,
ASL_MSG_ARG_NOT_USED,
/* These messages are used by the Data Table compiler only */

View File

@ -327,7 +327,7 @@ MtMethodAnalysisWalkBegin (
return (AE_ERROR);
}
RegisterNumber = (Op->Asl.AmlOpcode & 0x000F);
RegisterNumber = (Op->Asl.AmlOpcode & 0x0007);
/*
* If the local is being used as a target, mark the local

View File

@ -374,5 +374,19 @@ typedef struct acpi_serial_info
} ACPI_SERIAL_INFO;
typedef struct asl_method_local
{
ACPI_PARSE_OBJECT *Op;
UINT8 Flags;
} ASL_METHOD_LOCAL;
/* Values for Flags field above */
#define ASL_LOCAL_INITIALIZED (1)
#define ASL_LOCAL_REFERENCED (1<<1)
#define ASL_ARG_IS_LOCAL (1<<2)
#define ASL_ARG_INITIALIZED (1<<3)
#define ASL_ARG_REFERENCED (1<<4)
#endif /* __ASLTYPES_H */

View File

@ -138,6 +138,10 @@ XfNamespaceLocateEnd (
UINT32 Level,
void *Context);
static ACPI_PARSE_OBJECT *
XfGetParentMethod (
ACPI_PARSE_OBJECT *Op);
static BOOLEAN
XfObjectExists (
char *Name);
@ -352,59 +356,16 @@ XfCheckFieldRange (
}
#ifdef __UNDER_DEVELOPMENT
/*******************************************************************************
*
* FUNCTION: XfIsObjectParental
*
* PARAMETERS: ChildOp - Op to be checked
* PossibleParentOp - Determine if this op is in the family
*
* RETURN: TRUE if ChildOp is a descendent of PossibleParentOp
*
* DESCRIPTION: Determine if an Op is a descendent of another Op. Used to
* detect if a method is declared within another method.
*
******************************************************************************/
static BOOLEAN
XfIsObjectParental (
ACPI_PARSE_OBJECT *ChildOp,
ACPI_PARSE_OBJECT *PossibleParentOp)
{
ACPI_PARSE_OBJECT *ParentOp;
/* Search upwards through the tree for possible parent */
ParentOp = ChildOp;
while (ParentOp)
{
if (ParentOp == PossibleParentOp)
{
return (TRUE);
}
ParentOp = ParentOp->Asl.Parent;
}
return (FALSE);
}
/*******************************************************************************
*
* FUNCTION: XfGetParentMethod
*
* PARAMETERS: Op - Op to be checked
* PARAMETERS: Op - Parse Op to be checked
*
* RETURN: Op for parent method. NULL if object is not within a method.
* RETURN: Control method Op if found. NULL otherwise
*
* DESCRIPTION: Determine if an object is within a control method. Used to
* implement special rules for named references from within a
* control method.
*
* NOTE: It would be better to have the parser set a flag in the Op if possible.
* DESCRIPTION: Find the control method parent of a parse op. Returns NULL if
* the input Op is not within a control method.
*
******************************************************************************/
@ -412,121 +373,23 @@ static ACPI_PARSE_OBJECT *
XfGetParentMethod (
ACPI_PARSE_OBJECT *Op)
{
ACPI_PARSE_OBJECT *ParentOp;
ACPI_PARSE_OBJECT *NextOp;
if (!Op)
NextOp = Op->Asl.Parent;
while (NextOp)
{
return (NULL);
}
if (Op->Asl.ParseOpcode == PARSEOP_METHOD)
{
return (NULL);
}
/* Walk upwards through the parse tree, up to the root if necessary */
ParentOp = Op;
while (ParentOp)
{
if (ParentOp->Asl.ParseOpcode == PARSEOP_METHOD)
if (NextOp->Asl.AmlOpcode == AML_METHOD_OP)
{
return (ParentOp);
return (NextOp);
}
ParentOp = ParentOp->Asl.Parent;
NextOp = NextOp->Asl.Parent;
}
/* Object is not within a method */
return (NULL);
return (NULL); /* No parent method found */
}
/*******************************************************************************
*
* FUNCTION: XfCheckIllegalReference
*
* PARAMETERS: Op - Op referring to the target
* TargetNode - Target of the reference
*
* RETURN: None. Emits error message for an illegal reference
*
* DESCRIPTION: Determine if a named reference is legal. A "named" reference
* is something like: Store(ABCD, ...), where ABCD is an AML
* Nameseg or Namepath.
*
* NOTE: Caller must ensure that the name Op is in fact a reference, and not
* an actual name declaration (creation of a named object).
*
******************************************************************************/
static void
XfCheckIllegalReference (
ACPI_PARSE_OBJECT *Op,
ACPI_NAMESPACE_NODE *TargetNode)
{
ACPI_PARSE_OBJECT *MethodOp1;
ACPI_PARSE_OBJECT *MethodOp2;
ACPI_PARSE_OBJECT *TargetOp;
/*
* Check for an illegal reference to a named object:
*
* 1) References from one control method to another, non-parent
* method are not allowed, they will fail at runtime.
*
* 2) Forward references within a control method are not allowed.
* AML interpreters use a one-pass parse of control methods
* so these forward references will fail at runtime.
*/
TargetOp = TargetNode->Op;
MethodOp1 = XfGetParentMethod (Op);
MethodOp2 = XfGetParentMethod (TargetOp);
/* Are both objects within control method(s)? */
if (!MethodOp1 || !MethodOp2)
{
return;
}
/* Objects not in the same method? */
if (MethodOp1 != MethodOp2)
{
/*
* 1) Cross-method named reference
*
* This is OK if and only if the target reference is within in a
* method that is a parent of current method
*/
if (!XfIsObjectParental (MethodOp1, MethodOp2))
{
AslError (ASL_ERROR, ASL_MSG_ILLEGAL_METHOD_REF, Op,
Op->Asl.ExternalName);
}
}
/*
* 2) Both reference and target are in the same method. Check if this is
* an (illegal) forward reference by examining the exact source code
* location of each (the referenced object and the object declaration).
* This is a bit nasty, yet effective.
*/
else if (Op->Asl.LogicalByteOffset < TargetOp->Asl.LogicalByteOffset)
{
AslError (ASL_ERROR, ASL_MSG_ILLEGAL_FORWARD_REF, Op,
Op->Asl.ExternalName);
}
}
#endif
/*******************************************************************************
*
* FUNCTION: XfNamespaceLocateBegin
@ -568,10 +431,67 @@ XfNamespaceLocateBegin (
UINT8 Message = 0;
const ACPI_OPCODE_INFO *OpInfo;
UINT32 Flags;
ASL_METHOD_LOCAL *MethodLocals = NULL;
ASL_METHOD_LOCAL *MethodArgs = NULL;
int RegisterNumber;
UINT32 i;
ACPI_FUNCTION_TRACE_PTR (XfNamespaceLocateBegin, Op);
if ((Op->Asl.AmlOpcode == AML_METHOD_OP) && Op->Asl.Node)
{
Node = Op->Asl.Node;
/* Support for method LocalX/ArgX analysis */
if (!Node->MethodLocals)
{
/* Create local/arg info blocks */
MethodLocals = UtLocalCalloc (
sizeof (ASL_METHOD_LOCAL) * ACPI_METHOD_NUM_LOCALS);
Node->MethodLocals = MethodLocals;
MethodArgs = UtLocalCalloc (
sizeof (ASL_METHOD_LOCAL) * ACPI_METHOD_NUM_ARGS);
Node->MethodArgs = MethodArgs;
/*
* Get the method argument count
* First, get the name node
*/
NextOp = Op->Asl.Child;
/* Get the NumArguments node */
NextOp = NextOp->Asl.Next;
Node->ArgCount = (UINT8)
(((UINT8) NextOp->Asl.Value.Integer) & 0x07);
/* We will track all posible ArgXs */
for (i = 0; i < ACPI_METHOD_NUM_ARGS; i++)
{
if (i < Node->ArgCount)
{
/* Real Args are always "initialized" */
MethodArgs[i].Flags = ASL_ARG_INITIALIZED;
}
else
{
/* Other ArgXs can be used as locals */
MethodArgs[i].Flags = ASL_ARG_IS_LOCAL;
}
MethodArgs[i].Op = Op;
}
}
}
/*
* If this node is the actual declaration of a name
* [such as the XXXX name in "Method (XXXX)"],
@ -584,10 +504,88 @@ XfNamespaceLocateBegin (
return_ACPI_STATUS (AE_OK);
}
/* We are only interested in opcodes that have an associated name */
OpInfo = AcpiPsGetOpcodeInfo (Op->Asl.AmlOpcode);
/* Check method LocalX variables */
if (OpInfo->Type == AML_TYPE_LOCAL_VARIABLE)
{
/* Find parent method Op */
NextOp = XfGetParentMethod (Op);
if (!NextOp)
{
return_ACPI_STATUS (AE_OK);
}
/* Get method node */
Node = NextOp->Asl.Node;
RegisterNumber = Op->Asl.AmlOpcode & 0x0007; /* 0x60 through 0x67 */
MethodLocals = Node->MethodLocals;
if (Op->Asl.CompileFlags & NODE_IS_TARGET)
{
/* Local is being initialized */
MethodLocals[RegisterNumber].Flags |= ASL_LOCAL_INITIALIZED;
MethodLocals[RegisterNumber].Op = Op;
return_ACPI_STATUS (AE_OK);
}
/* Mark this Local as referenced */
MethodLocals[RegisterNumber].Flags |= ASL_LOCAL_REFERENCED;
MethodLocals[RegisterNumber].Op = Op;
return_ACPI_STATUS (AE_OK);
}
/* Check method ArgX variables */
if (OpInfo->Type == AML_TYPE_METHOD_ARGUMENT)
{
/* Find parent method Op */
NextOp = XfGetParentMethod (Op);
if (!NextOp)
{
return_ACPI_STATUS (AE_OK);
}
/* Get method node */
Node = NextOp->Asl.Node;
/* Get Arg # */
RegisterNumber = Op->Asl.AmlOpcode - AML_ARG0; /* 0x68 through 0x6F */
MethodArgs = Node->MethodArgs;
if (Op->Asl.CompileFlags & NODE_IS_TARGET)
{
/* Arg is being initialized */
MethodArgs[RegisterNumber].Flags |= ASL_ARG_INITIALIZED;
MethodArgs[RegisterNumber].Op = Op;
return_ACPI_STATUS (AE_OK);
}
/* Mark this Arg as referenced */
MethodArgs[RegisterNumber].Flags |= ASL_ARG_REFERENCED;
MethodArgs[RegisterNumber].Op = Op;
return_ACPI_STATUS (AE_OK);
}
/*
* After method ArgX and LocalX, we are only interested in opcodes
* that have an associated name
*/
if ((!(OpInfo->Flags & AML_NAMED)) &&
(!(OpInfo->Flags & AML_CREATE)) &&
(Op->Asl.ParseOpcode != PARSEOP_NAMESTRING) &&
@ -1166,3 +1164,178 @@ XfNamespaceLocateEnd (
return_ACPI_STATUS (AE_OK);
}
#ifdef __UNDER_DEVELOPMENT
/*******************************************************************************
*
* FUNCTION: XfIsObjectParental
*
* PARAMETERS: ChildOp - Op to be checked
* PossibleParentOp - Determine if this op is in the family
*
* RETURN: TRUE if ChildOp is a descendent of PossibleParentOp
*
* DESCRIPTION: Determine if an Op is a descendent of another Op. Used to
* detect if a method is declared within another method.
*
******************************************************************************/
static BOOLEAN
XfIsObjectParental (
ACPI_PARSE_OBJECT *ChildOp,
ACPI_PARSE_OBJECT *PossibleParentOp)
{
ACPI_PARSE_OBJECT *ParentOp;
/* Search upwards through the tree for possible parent */
ParentOp = ChildOp;
while (ParentOp)
{
if (ParentOp == PossibleParentOp)
{
return (TRUE);
}
ParentOp = ParentOp->Asl.Parent;
}
return (FALSE);
}
/*******************************************************************************
*
* FUNCTION: XfGetParentMethod
*
* PARAMETERS: Op - Op to be checked
*
* RETURN: Op for parent method. NULL if object is not within a method.
*
* DESCRIPTION: Determine if an object is within a control method. Used to
* implement special rules for named references from within a
* control method.
*
* NOTE: It would be better to have the parser set a flag in the Op if possible.
*
******************************************************************************/
static ACPI_PARSE_OBJECT *
XfGetParentMethod (
ACPI_PARSE_OBJECT *Op)
{
ACPI_PARSE_OBJECT *ParentOp;
if (!Op)
{
return (NULL);
}
if (Op->Asl.ParseOpcode == PARSEOP_METHOD)
{
return (NULL);
}
/* Walk upwards through the parse tree, up to the root if necessary */
ParentOp = Op;
while (ParentOp)
{
if (ParentOp->Asl.ParseOpcode == PARSEOP_METHOD)
{
return (ParentOp);
}
ParentOp = ParentOp->Asl.Parent;
}
/* Object is not within a method */
return (NULL);
}
/*******************************************************************************
*
* FUNCTION: XfCheckIllegalReference
*
* PARAMETERS: Op - Op referring to the target
* TargetNode - Target of the reference
*
* RETURN: None. Emits error message for an illegal reference
*
* DESCRIPTION: Determine if a named reference is legal. A "named" reference
* is something like: Store(ABCD, ...), where ABCD is an AML
* Nameseg or Namepath.
*
* NOTE: Caller must ensure that the name Op is in fact a reference, and not
* an actual name declaration (creation of a named object).
*
******************************************************************************/
static void
XfCheckIllegalReference (
ACPI_PARSE_OBJECT *Op,
ACPI_NAMESPACE_NODE *TargetNode)
{
ACPI_PARSE_OBJECT *MethodOp1;
ACPI_PARSE_OBJECT *MethodOp2;
ACPI_PARSE_OBJECT *TargetOp;
/*
* Check for an illegal reference to a named object:
*
* 1) References from one control method to another, non-parent
* method are not allowed, they will fail at runtime.
*
* 2) Forward references within a control method are not allowed.
* AML interpreters use a one-pass parse of control methods
* so these forward references will fail at runtime.
*/
TargetOp = TargetNode->Op;
MethodOp1 = XfGetParentMethod (Op);
MethodOp2 = XfGetParentMethod (TargetOp);
/* Are both objects within control method(s)? */
if (!MethodOp1 || !MethodOp2)
{
return;
}
/* Objects not in the same method? */
if (MethodOp1 != MethodOp2)
{
/*
* 1) Cross-method named reference
*
* This is OK if and only if the target reference is within in a
* method that is a parent of current method
*/
if (!XfIsObjectParental (MethodOp1, MethodOp2))
{
AslError (ASL_ERROR, ASL_MSG_ILLEGAL_METHOD_REF, Op,
Op->Asl.ExternalName);
}
}
/*
* 2) Both reference and target are in the same method. Check if this is
* an (illegal) forward reference by examining the exact source code
* location of each (the referenced object and the object declaration).
* This is a bit nasty, yet effective.
*/
else if (Op->Asl.LogicalByteOffset < TargetOp->Asl.LogicalByteOffset)
{
AslError (ASL_ERROR, ASL_MSG_ILLEGAL_FORWARD_REF, Op,
Op->Asl.ExternalName);
}
}
#endif

View File

@ -265,8 +265,12 @@ typedef struct acpi_namespace_node
*/
#ifdef ACPI_LARGE_NAMESPACE_NODE
union acpi_parse_object *Op;
void *MethodLocals;
void *MethodArgs;
UINT32 Value;
UINT32 Length;
UINT8 ArgCount;
#endif
} ACPI_NAMESPACE_NODE;

View File

@ -336,6 +336,7 @@ ACPI_TYPED_IDENTIFIER_TABLE AcpiIdentifiers[] = {
{"ACPI_MEM_SPACE_CONTEXT", SRC_TYPE_STRUCT},
{"ACPI_MEMORY_ATTRIBUTE", SRC_TYPE_STRUCT},
{"ACPI_MEMORY_LIST", SRC_TYPE_STRUCT},
{"ACPI_METHOD_LOCAL", SRC_TYPE_STRUCT},
{"ACPI_MTMR_ENTRY", SRC_TYPE_STRUCT},
{"ACPI_MUTEX", SRC_TYPE_SIMPLE},
{"ACPI_MUTEX_HANDLE", SRC_TYPE_SIMPLE},
@ -563,6 +564,7 @@ ACPI_TYPED_IDENTIFIER_TABLE AcpiIdentifiers[] = {
{"ASL_LISTING_NODE", SRC_TYPE_STRUCT},
{"ASL_MAPPING_ENTRY", SRC_TYPE_STRUCT},
{"ASL_METHOD_INFO", SRC_TYPE_STRUCT},
{"ASL_METHOD_LOCAL", SRC_TYPE_STRUCT},
{"ASL_RESERVED_INFO", SRC_TYPE_STRUCT},
{"ASL_RESOURCE_INFO", SRC_TYPE_STRUCT},
{"ASL_RESOURCE_NODE", SRC_TYPE_STRUCT},

View File

@ -396,5 +396,12 @@ DefinitionBlock ("badcode.aml", "DSDT", 1, "Intel", "Example", 0x00000001)
CreateField (RSC3, \DWI1._MIF, 5, MIF)
CreateField (RSC3, \DWI1._RNG, 3, RNG2)
}
Method (L100)
{
/* Method Local is set but never used */
Store (40, Local0)
}
}