|
Analysis IssuesAnalyzing Header FilesGenerally, there is no need to include the header files in the list of files you pass to the Imagix 4D analyzer. By specifying the .c and .cpp files and the include directories, the header files are automatically analyzed if they are directly or indirectly included through #include statements. The only reason to list the header files is to cause them to be added to your project even if they're not transitively included by a C or C++ source file.
System vs. Application Include DirectoriesWith the Imagix 4D analyzer, as with a compiler, you specify a list of include directories. When the analyzer encounters a #include preprocessor directive, it searches the include directories, in the order that they are specified, until it finds a file matching the name specified in the #include statement. By default, the Imagix 4D analyzer distinguishes between these two include statements:
#include "fileA.h" #include <fileA.h>in only one way. In the first statement, where the file name is surrounded by quotation marks, the analyzer first searches for fileA.h in the current directory. Then, with either statement, the analyzer continues to look through the specified include directories. This search continues until the first fileA.h is found. You can specify that certain include directories be considered system include directories. This is done by using the -Sdirname rather than the -Idirname option when invoking imagix-csrc. There are two possible effects of using -S rather than -I, and both involve source analyzer options. The first is tied to the -nosys option. When the -nosys option is set, header files located in directories designated as system include directories are still parsed, but no data file is generated, and you can't explore their contents. So it is recommended that you use -S for specifying include directories containing header files, such as stdio.h, that you generally aren't interested in. This avoids cluttering up your project's database with unimportant data. The second difference between -S and -I occurs if the -sysincfirst option is applied. The option -sysincfirst causes all of the -S directories to be searched before any of the -I directories for any header files specified with < >. If you follow the convention of using
#include "appfile.h"for specifying your own application header files and
#include <sysfile.h>for including the system header files, you can use the -sysincfirst option. It may be useful in resolving header file name conflicts, in those cases where some of your application header files and some of your system header files have the same name.
Path NamesWindows supports the use of spaces in path names, and is not case-sensitive. This has certain implications for invoking the Imagix 4D analyzer. Consider the following examples:
(1) imagix-csrc -IC:\Program Files\Include -ox File.c (2) imagix-csrc "-IC:\Program Files\Include" -ox File.c (3) imagix-csrc "-IC:\PROGRAM FILES\INCLUDE" -ox File.cThe include directory C:\Program Files\Include has a space in it. Arguments containing such spaces need to be surrounded with double quotes. Thus, example (1) will generate a analysis error, while example (2) will analyze correctly. Examples (2) and (3) are equivalent because of Windows' case-insensitivity.
Function PointersC and C++ support the use of function pointers, a pointer to a function's entry address in physical memory, to call a function. One of the areas in which Imagix 4D source code analysis transcends standard parsing is the information that the analyzer captures about the static aspects of function pointers.Any variable that gets set with data containing function names is marked as a function pointer. All the functions in its static initializer are recorded as being (potentially) called from this function pointer. If a function makes a call through the function pointer, then the function is shown as calling the function pointer variable. As a result, you can see the potential call tree by following the call relationship from the function to the function pointer variable and then to all the functions potentially being assigned to this variable. The analyzer will also track assignments from one function pointer to another function pointer and it will recognize function pointers or functions passed as parameters. This approach works well for function pointer variables that are statically initialized, or arrays of function pointers, or structs / unions / classes that have function pointer members. The analyzer will also track assignments. However, if the variable gets dynamically updated (i.e. if another function name is assigned in a statement), or if there is a pointer involved in getting to the function pointer variable, or if the function names are passed through parameters, then the graph will generalize and show all possible functions and function pointers that can be called. It will not try to assess the control logic to eliminate functions that would be precluded by certain if-statements. The following examples show what is handled.
// function pointer relationships int foo1(); int foo2(); int foo3(), foo4(), foo5(); typedef int (*fpT)(); fpT x1 = foo1; // handled: direct fptr fpT *x4 = &x1, x2 = x1, x3; // handled: pointer to fptr int *v; fpT a1[] = {foo1, foo2, foo3}; // handled: array of fptrs fpT (*a2)[] = &a1; // handled: pointer to array of fptrs struct s1T { fpT fp; double w; struct sinT { int cnt; fpT fp2; } si[3]; } s1 = {foo3, 2.0}, // handled: struct containing fptrs s2 = {foo2, 3.0, {{2, foo1}}}, // handled: struct containing arrays of fptrs *sp1 = &s1; // handled: pointer to struct containing fptrs struct s1T s3 = {foo1, 0.4, {{3, foo4},{4,foo3}}}; // handled struct s1T tkentries[] = {{foo1, 4.0, {{1, foo2}}}, {foo3, 5.0}}; // handled fpT goo1() { fpT r = &foo4; if (v) return r; // handled: return values else return foo5; // handled: return values } void goo2(fpT &fp) { fp = foo3; // handled: out parameters } int bar1() { fpT locfp; (*x1)(); // handled -> foo1,foo2 goo1()(); // handled -> foo4,foo5 *v = 2; (s1.fp)(); // handled -> foo1,foo2,foo3 x3 = s1.fp; // handled *x4 = foo3; // handled (*a2)[1](); // handled -> foo1,foo2,foo3 goo2(locfp); (*locfp)(); // handled -> foo3 } int bar2(fpT p, fpT q) { if (v) p = foo3; // handled if (*v) p = x1; // handled (*p)(); // handled -> foo1,foo2,foo3 x1 = foo2; // handled x2 = sp1->fp; // handled s1.fp = foo1; // handled x3 = goo1(); // handled q(); // handled -> foo2 } int bar3() { (*a1[*v])(); // handled -> foo1,foo2,foo3 (*sp1->fp)(); // handled -> foo1,foo2,foo3 bar2(foo1,foo2); // handled (*x2)(); // handled -> foo1,foo2,foo3 (*x3)(); // handled -> foo1,foo2,foo3,foo4,foo5 s2.si[0].fp2(); // handled -> foo1,foo2,foo3,foo4,foo5 s3.fp(); // handled -> foo1,foo2,foo3 (*s3.si[1].fp2)();// handled -> foo1,foo2,foo3,foo4,foo5 (**x4)(); // handled -> foo1,foo2,foo3 while (*x4) (*x4++)(); // handled -> foo1,foo2,foo3 (sp1++->fp)(); // handled -> foo1,foo2,foo3 (x2=foo1)(); // handled -> foo1,foo2,foo3 }Note that you can add more knowledge into Imagix 4D's database by indicating which functions are potentially called by a function pointer. One way to do this is to create datafiles containing this information (see `Adding Your Own Data - vdb files'). Another approach is to modify your source code. When you know which functions are called by a function pointer, you can add source lines like the following, and Imagix 4D will then be able to complete the call trees.
#ifdef IMAGIX_ONLY FunctionPointerType fp = {func1, func2, ..., funcN}; #else FunctionPointerType fp; // normal definition for fp #endifAlso note that in the case of structs, the functions are associated with the members. Hence, two struct variables of the same struct type that are completely distinct will be merged together. Same declaration cross-references are not captured (e.g. "FPTR x = foo, y = x;"). The handling of void* as a potential function pointer is controlled through the -voidfptr option (see `Analyzer Syntax and Options'). Cases where memcpy is used to copy function pointers can be tracked by incorporating libc.inc located in the ../imagix/user/cc_lib directory. See the comments in libc.inc itself for instructions.
|