class procedure

A single procedure/function/method.

The procedure class corresponds to the PDG abstraction.

The following are useful for retrieving procedures.

Class Methods
compunit compunit.procedures()
point point.callee(), point.get_procedure()
project project.find_procedure(), project.procedures(), project.procedures_vector()
sfile sfile.procedures_on_line()

procedure Details

class cs.procedure

A single procedure/function/method.

__cmp__(other)

Comparison function for procedure .

Parameters:other (procedure) – The procedure object to compare against.
Return type:int
Returns:An integer N such that:
  • N==0 if the two objects compare equal
  • N<0 if self < other
  • N>0 if self > other
>>> foofn = next(p for p in project.current().procedures() if p.name()=='foo')
>>> foofn
<cs.procedure foo>
>>> barfn = next(p for p in project.current().procedures() if p.name()=='bar')
>>> barfn
<cs.procedure bar>
>>> foofn.__cmp__(barfn)
-1
__eq__(b)

Equality operator for procedure .

Parameters:b (procedure) – The procedure to compare against.
Return type:bool
Returns:True if self and b compare equal, False otherwise.
>>> foofn = next(p for p in project.current().procedures() if p.name()=='foo')
>>> foofn
<cs.procedure foo>
>>> barfn = next(p for p in project.current().procedures() if p.name()=='bar')
>>> barfn
<cs.procedure bar>
>>> foofn == barfn
False
__ge__(b)

Greater-than-or-equal operator for procedure .

Parameters:b (procedure) – The procedure to compare against.
Return type:bool
Returns:True if self >= b , False otherwise.
>>> foofn = next(p for p in project.current().procedures() if p.name()=='foo')
>>> foofn
<cs.procedure foo>
>>> barfn = next(p for p in project.current().procedures() if p.name()=='bar')
>>> barfn
<cs.procedure bar>
>>> foofn >= barfn
False
__gt__(b)

Greater-than operator for procedure .

Parameters:b (procedure) – The procedure to compare against.
Return type:bool
Returns:True if self > b , False otherwise.
>>> foofn = next(p for p in project.current().procedures() if p.name()=='foo')
>>> foofn
<cs.procedure foo>
>>> barfn = next(p for p in project.current().procedures() if p.name()=='bar')
>>> barfn
<cs.procedure bar>
>>> foofn > barfn
False
__hash__()

Get a hash value for a procedure .

Return type:int
>>> foofn = next(p for p in project.current().procedures() if p.name()=='foo')
>>> foofn
<cs.procedure foo>
>>> hash(foofn)
1102019949
__le__(b)

Less-than-or-equal operator for procedure .

Parameters:b (procedure) – The procedure to compare against.
Return type:bool
Returns:True if self <= b , False otherwise.
>>> foofn = next(p for p in project.current().procedures() if p.name()=='foo')
>>> foofn
<cs.procedure foo>
>>> barfn = next(p for p in project.current().procedures() if p.name()=='bar')
>>> barfn
<cs.procedure bar>
>>> foofn <= barfn
True
__lt__(b)

Less-than operator for procedure .

Parameters:b (procedure) – The procedure to compare against.
Return type:bool
Returns:True if self < b , False otherwise.
>>> foofn = next(p for p in project.current().procedures() if p.name()=='foo')
>>> foofn
<cs.procedure foo>
>>> barfn = next(p for p in project.current().procedures() if p.name()=='bar')
>>> barfn
<cs.procedure bar>
>>> foofn < barfn
True
__ne__(b)

Inequality operator for procedure .

Parameters:b (procedure) – The procedure to compare against.
Return type:bool
Returns:False if self and b compare equal, True otherwise.
>>> foofn = next(p for p in project.current().procedures() if p.name()=='foo')
>>> foofn
<cs.procedure foo>
>>> barfn = next(p for p in project.current().procedures() if p.name()=='bar')
>>> barfn
<cs.procedure bar>
>>> foofn != barfn
True
__repr__()

Get a representation of a procedure object that includes information useful for debugging.

Return type:str
Returns:The string representation.
>>> foofn = next(p for p in project.current().procedures() if p.name()=='foo')
>>> foofn
<cs.procedure foo>
>>> repr(foofn)
'<cs.procedure foo>'
__str__()

Get a simple string representation of a procedure object.

Return type:str
Returns:The string representation.
>>> foofn = next(p for p in project.current().procedures() if p.name()=='foo')
>>> foofn
<cs.procedure foo>
>>> str(foofn)
'foo'
adjusted_callers()

Get an iterator over the call sites ( point of kind point_kind.CALL_SITE or point_kind.INDIRECT_CALL) to a procedure, taking into account any translations incurred by csonar_replace_*() calls and the FUNCTION_MAP configuration file variable.

Return type:procedure_adjusted_callers_iterator
Returns:The initialized procedure_adjusted_callers_iterator .

For a fixed project build and procedure , the iteration order is deterministic but does not correspond to the execution order or source file location of the call sites.

Indirect call resolution takes place in the pointer analysis phase, so results for indirect calls will be best if traversal takes place in the bottom-up phase or later. For both direct and indirect calls, traversal will fail if it is attempted before the beginning of the serial depth-first phase.

>>> cu = next(c for c in project.current().compunits()
...              if c.name().endswith('apitest.cpp'))
>>> proc = next(p for p in cu.procedures() if p.name()=='bar')
>>> for pt in proc.adjusted_callers():  # iteration managed by procedure_adjusted_callers_iterator.__iter__()
...                                     # and procedure_adjusted_callers_iterator.__next__()
...      fl = pt.file_line()
...      print(fl[0].normalized_name().split('/')[-1], fl[1], pt.characters())
...
apitest.cpp 35 bar()
apitest.cpp 36 bar()
apitest.cpp 40 bar()
apitest.cpp 14 bar()
basename()

Get the basename of a procedure.

Return type:str
Returns:The procedure’s basename.

The basename of a procedure is defined with respect to the friendly name (as returned by procedure.name()) as follows.

  • If the friendly name contains one or more scope resolution operators “::”, the basename is the method name component (i.e., rightmost token). For example, if the friendly name is ClassName::MethodName, the basename is MethodName.
  • Otherwise, the basename is the same as the friendly name.

When cross-referencing queries ( xr_query ) are executed, the specified tokens are compared against procedure basenames, and query results ( xr_tuple ) from procedure name matches contain a hash of this basename. Therefore, use procedure.basename() to extract any procedure name that you want to use as a xr_query token or compare against query results.

>>> proc = next(p for p in project.current().procedures() if 'who' in p.verbose_name())
>>> proc
<cs.procedure whoknows>
>>> proc.name()
'whoknows'
>>> proc.basename()
'whoknows'
>>> proc.verbose_name()
'whoknows(int)'
call_sites([flags =  procedure_call_sites_flags.DIRECT])

Get an iterator over the call sites in a procedure.

Parameters:flags (procedure_call_sites_flags) – (optional) procedure_call_sites_flags characterizing the kinds of call sites to iterate over.
Return type:procedure_call_sites_iterator
Returns:The initialized iterator over the call sites in the procedure whose kinds are as specified by flags.

For a fixed project build and procedure, the iteration order is deterministic but does not correspond to the execution order or source file location of the call sites.

>>> foofn = next(p for p in project.current().procedures() if p.name()=='foo')
>>> indirect = foofn.call_sites(procedure_call_sites_flags.INDIRECT)
>>> indirect.at_end()
True
>>> cu = next(c for c in project.current().compunits() if c.name().endswith('apitest.cpp'))
>>> proc = next(p for p in cu.procedures() if p.name()=='foo')
>>> for pt in proc.call_sites(): # iteration is managed by procedure_call_sites_iterator.__iter__()
...                              # and  procedure_call_sites_iterator.__next__()
...     print(pt.callee())
...
bar
bar
mymalloc
bar
call_sites_count([flags =  procedure_call_sites_flags.DIRECT])

Get the number of call sites in a procedure.

Parameters:flags (procedure_call_sites_flags) – (optional) procedure_call_sites_flags characterizing the kinds of call sites to count.
Return type:int
Returns:The number of call sites in the procedure whose kinds are as specified by flags.

For a fixed procedure P and procedure_call_sites_flags F, P.call_sites_count(F) will match:

  • The iteration count of the iterator returned by P.call_sites(F).
  • The number of items in the list returned by P.call_sites_vector().
>>> foofn = next(p for p in project.current().procedures() if p.name()=='foo')
>>> foofn.call_sites_count(procedure_call_sites_flags.INDIRECT)
0
>>> foofn = next(p for p in project.current().procedures() if p.name()=='foo')
>>> foofn.call_sites_count()
4
call_sites_vector([flags =  procedure_call_sites_flags.DIRECT])

Get a list of the call sites in a procedure.

Parameters:flags (procedure_call_sites_flags) – (optional) procedure_call_sites_flags indicating what kinds of call sites are of interest.
Return type:[point]
Returns:The call sites in the procedure whose kinds are as specified by flags.
Raises:result.PDG_IS_UNDEFINED if the procedure has kind procedure_kind.UNDEFINED.

For a fixed procedure P and procedure_call_sites_flags F, the length of P.call_sites_vector(F) will match the value returned by P.call_sites_count(F).

Use procedure.call_sites() to get an iterator over the call sites.

>>> foofn = next(p for p in project.current().procedures() if p.name()=='foo')
>>> foofn.call_sites_vector(procedure_call_sites_flags.INDIRECT)
()
>>> foofn = next(p for p in project.current().procedures() if p.name()=='foo')
>>> foofn.call_sites_vector()
(<cs.point [call-site] bar(int, void *, int)>, <cs.point [call-site] bar(int, void *, int)>, <cs.point [call-site] mymalloc(int)>, <cs.point [call-site] bar(int, void *, int)>)
callers()

Get an iterator over the direct call sites ( point of kind point_kind.CALL_SITE) whose target is self.

Return type:procedure_callers_iterator
Returns:The initialized iterator.

For a fixed project build and procedure, the iteration order is deterministic but does not correspond to the execution order or source file location of the call sites.

>>> cu = next(c for c in project.current().compunits() if c.name().endswith('apitest.cpp'))
>>> proc = next(p for p in cu.procedures() if p.name()=='bar')
>>> for p in proc.callers(): # iteration is managed by procedure_callers_iterator.__iter__()
...                          # and  procedure_callers_iterator.__next__()
...     print(p.get_procedure())
...
foo
foo
foo
bar
callers_count()

Get the number of direct callers of a procedure.

Return type:int
Returns:The number of direct call sites ( point of kind point_kind.CALL_SITE) whose target is self.

For a procedure P, P.callers_count() will match the iteration count of the iterator returned by P.callers().

>>> barfn = next(p for p in project.current().procedures() if p.name()=='bar')
>>> barfn.callers_count()
4
entry_point()

Get the entry point of a procedure.

Return type:point
Returns:The entry point (whose point_kind is point_kind.ENTRY) for the procedure.
Raises:result.PDG_IS_UNDEFINED if the procedure has kind procedure_kind.UNDEFINED.
>>> barfn = next(p for p in project.current().procedures() if p.name()=='bar')
>>> barfn.entry_point()
<cs.point [entry] bar(int, void *, int)>
exit_point()

Get the exit point of a procedure.

Return type:point
Returns:The exit point (whose point_kind is point_kind.EXIT) for the procedure.
Raises:result.PDG_IS_UNDEFINED if the procedure has kind procedure_kind.UNDEFINED.

The exit point has no incoming or outgoing control dependences or data dependences. It is part of the CFG.

>>> barfn = next(p for p in project.current().procedures() if p.name()=='bar')
>>> barfn.exit_point()
<cs.point [exit] bar(int, void *, int)>
file_line()

Get the file instance and (smallest offset) line of the entry point for a procedure.

Return type:(sfileinst, int)
Returns:A pair encoding the source file instance containing the procedure entry point and the (smallest offset) line on which the entry point occurs in that source file instance.
Raises:result.NO_POSITION if the procedure has kind procedure_kind.UNDEFINED or its entry point does not have a position.
>>> barfn = next(p for p in project.current().procedures() if p.name()=='bar')
>>> barfn.file_line()
(<cs.sfileinst C:\alex\test\apitest.cpp>, 9)
formal_in(rank)

Get the point corresponding to the formal-in with the specified rank.

Parameters:

rank (int) – The rank of the desired parameter.

Return type:

point

Returns:

The point corresponding to the formal-in parameter whose rank is rank.

Raises:

Rank starts at 1, with globals coming first, followed by non-globals. Note that only non-globals can be retrieved by this function.

>>> barfn = next(p for p in project.current().procedures() if p.name()=='bar')
>>> barfn.formal_in(2)
<cs.point [formal-in] >
formal_ins()

Get the formal-in and global-formal-in points of a procedure.

Return type:point_set
Returns:The procedure’s formal-ins ( point of kind point_kind.FORMAL_IN) and global-formal-ins ( point of kind point_kind.GLOBAL_FORMAL_IN), as a point_set .
Raises:result.PDG_IS_UNDEFINED if the procedure has kind procedure_kind.UNDEFINED.

Methods procedure.formal_ins() and procedure.formal_ins_vector() retrieve different sets:

>>> barfn = next(p for p in project.current().procedures() if p.name()=='bar')
>>> barfn.formal_ins()
<cs.point_set {<cs.point [formal-in] >, <cs.point [formal-in] >, <cs.point [formal-in] >}>
formal_ins_vector()

Get a list containing the formal-in points of a procedure.

Return type:[point]
Returns:A list containing the procedure’s formal-ins ( point of kind point_kind.FORMAL_IN), in the order in which they occur in the code.
Raises:result.PDG_IS_UNDEFINED if the procedure has kind procedure_kind.UNDEFINED.

Methods procedure.formal_ins() and procedure.formal_ins_vector() retrieve different sets:

>>> barfn = next(p for p in project.current().procedures() if p.name()=='bar')
>>> barfn.formal_ins_vector()
(<cs.point [formal-in] >, <cs.point [formal-in] >, <cs.point [formal-in] >)
formal_outs()

Get the formal-out and global-formal-out points of a procedure.

Return type:point_set
Returns:The procedure’s formal-outs ( point of kind point_kind.FORMAL_OUT) and global-formal-outs ( point of kind point_kind.GLOBAL_FORMAL_OUT), as a point_set .
Raises:result.PDG_IS_UNDEFINED if the procedure has kind procedure_kind.UNDEFINED.

Methods procedure.formal_outs() and procedure.formal_outs_vector() retrieve different sets:

>>> barfn = next(p for p in project.current().procedures() if p.name()=='bar')
>>> barfn.formal_outs()
<cs.point_set {<cs.point [formal-out] >}>
formal_outs_vector()

Get the formal-out points of a procedure.

Return type:[point]
Returns:A list of listing the formal-out parameters ( point of kind point_kind.FORMAL_OUT), in the order in which they occur in the code.
Raises:result.PDG_IS_UNDEFINED if the procedure has kind procedure_kind.UNDEFINED.

Methods procedure.formal_outs() and procedure.formal_outs_vector() retrieve different sets:

>>> barfn = next(p for p in project.current().procedures() if p.name()=='bar')
>>> barfn.formal_outs()
<cs.point_set {<cs.point [formal-out] >}>
get_ast([family =  ast_family.DEFAULT])

Retrieve the AST for a procedure.

Parameters:

family (ast_family) – (optional) Procedures may be associated with multiple ASTs. This specifies which one to get.

Return type:

ast

Returns:

The ast of ast_family family that is associated with the procedure.

Raises:
>>> v0 = project.current()
>>> v1 = v0.procedures_vector()
>>> v1[3].get_ast(ast_family.C_UNNORMALIZED)
<cs.ast [cc:routine] malloc>
>>> v0 = project.current()
>>> v1 = v0.procedures_vector()
>>> v1[4].get_ast()
<cs.ast [x64:proc-statement] foo proc near>
get_compunit()

Get the compilation unit containing a procedure.

Return type:compunit
Returns:The compilation unit ( compunit ).
>>> barfn = next(p for p in project.current().procedures() if p.name()=='bar')
>>> barfn.get_compunit()
<cs.compunit C:\alex\test\apitest.cpp>
get_id()

Get the unique identifier of a procedure.

Return type:int
Returns:The unique identifier.
  • In an incremental analysis, a procedure will have the same identifier that it did in the incremental parent if and only if the containing compilation unit is not recompiled. If the containing compilation unit is recompiled, the procedure will have a new unique identifier not previously used for any procedure in any incremental ancestor analysis.
  • In all other cases identifiers do not persist between different analyses of the same project (or the same code in a different project).

To get a procedure given its ID, use project.find_procedure().

>>> barfn = next(p for p in project.current().procedures() if p.name()=='bar')
>>> barfn.get_id()
-6
get_kind()

Retrieve the procedure_kind of a procedure.

Return type:procedure_kind
Returns:The procedure’s procedure_kind .
>>> barfn = next(p for p in project.current().procedures() if p.name()=='bar')
>>> barfn.get_kind()
<cs.procedure_kind user-defined>
get_symbol()

Get the symbol for a procedure.

Return type:symbol
Returns:The symbol .
>>> barfn = next(p for p in project.current().procedures() if p.name()=='bar')
>>> barfn.get_symbol()
<cs.symbol bar(int, void *, int)>
handle()

Get a handle for this procedure .

Return type:str
Returns:The procedure’s handle.

Use this function to retrieve a handle to the procedure which can be stored externally and used with project.lookup_procedure_handle() to retrieve the procedure when needed. This handle is valid only for the analysis it was generated from. If you rebuild the project, the handle will no longer be valid.

A handle is a string consisting of letters (upper and lower case) and numbers, and could also include the following characters: “+”, “=”, and “_”.

>>> barfn = next(p for p in project.current().procedures() if p.name()=='bar')
>>> barfn.handle()
'goCAgAIL'
has_vararg()

Check: does a procedure have a formal vararg parameter?

Return type:bool
Returns:True if the procedure has a formal vararg parameter; False otherwise.
>>> barfn = next(p for p in project.current().procedures() if p.name()=='bar')
>>> barfn.has_vararg()
False
local_symbols()

Get an iterator over the local variables ( symbol ) that are declared in a procedure.

Return type:procedure_locals_iterator
Returns:The initialized iterator.

To iterate over nonlocal variables for a compilation unit, use the iterator returned by compunit.global_symbols(). Note that neither a compilation unit globals iterator nor a procedure locals iterator will access symbols of kind symbol_kind.PARAM. To iterate over these, call project.param_symbol() with increasing num argument until you get a result.ELEMENT_NOT_PRESENT error.

>>> cu = next(c for c in project.current().compunits() if c.name().endswith('apitest.cpp'))
>>> proc = next(p for p in cu.procedures() if p.name()=='foo')
>>> for s in proc.local_symbols():   # iteration managed by procedure_locals_iterator.__iter__()
...                                  # and procedure_locals_iterator.__next__()
...     if s.get_kind() == symbol_kind.USER:
...         print(s)
...
s
j
p
b
a
name()

Get the user-friendly name of a procedure.

Return type:str
Returns:The procedure’s user-friendly name.

For C++ methods, the returned user-friendly name will be of the form ClassName::MethodName.

  • Namespace::ClassName::MethodName if the class is a member of a namespace.
  • Class1Name::ClassName::MethodName if the class is nested inside another class.
  • (etc)

Use this method only to retrieve user-friendly procedure names for display.

>>> proc = next(p for p in project.current().procedures() if 'who' in p.verbose_name())
>>> proc
<cs.procedure whoknows>
>>> proc.name()
'whoknows'
>>> proc.basename()
'whoknows'
>>> proc.verbose_name()
'whoknows(int)'
points()

Get all the points in a procedure.

Return type:point_set
Returns:A point_set containing all the points ( point ) in the procedure.
Raises:result.PDG_IS_UNDEFINED if the procedure has kind procedure_kind.UNDEFINED.
>>> barfn = next(p for p in project.current().procedures() if p.name()=='bar')
>>> barfn.points()
<cs.point_set {<cs.point [entry] bar(int, void *, int)>, <cs.point [formal-in] >, <cs.point [formal-in] >, 37 more...}>
preexit_point()

Get the preexit point of a procedure.

Return type:point
Returns:The preexit point (whose point_kind is point_kind.PREEXIT) for the procedure.
Raises:result.PDG_IS_UNDEFINED if the procedure has kind procedure_kind.UNDEFINED.

The preexit point has no incoming or outgoing control dependences or data dependences. It is part of the CFG.

>>> cu = next(c for c in project.current().compunits() if c.name().endswith('test.cpp'))
>>> proc = next(p for p in cu.procedures() if p.name()=='foo')
>>> prex = proc.preexit_point()
>>> prex
<cs.point [preexit] foo>
>>> prex.solitary_cfg_target()
<cs.point [exit] foo>
reachable()

Check: is a procedure reachable from the reachability roots specified with configuration file parameter REACHABILITY_ROOTS?

Return type:

bool

Returns:

True if the procedure is reachable from the reachability roots, False if it is not reachable.

Raises:
>>> v0 = project.current()
>>> v1 = v0.procedures_vector()
>>> v1[1].reachable()
True
retrieve_point(_id)

Get a point from a procedure by ID.

Parameters:

_id (int) – The identifier of the desired point .

Return type:

point

Returns:

The point whose ID is _id.

Raises:

To get a point’s ID, use point.get_id().

>>> barfn = next(p for p in project.current().procedures() if p.name()=='bar')
>>> barfn.retrieve_point(12)
<cs.point [control-point] i == 0>
stable_cmp(other)

Compare with another procedure , with stable results across sufficiently-similar analyses.

Parameters:other (procedure) – The procedure to compare against.
Return type:int
Returns:An integer N, such that:
  • N<0 if self considered less than other
  • N==0 if self and other are the same object
  • N>0 if self considered greater than other

The comparison is stable in the following sense. Suppose there are two analyses A1 and A2 generated with exactly the same inputs (including identical analyzed code, underlying build commands and ordering, command line and configuration settings, increment order and contents). Let a1 and b1 be two procedure objects in A1, and a2 and b2 be the point objects in A2 that correspond to a1 and b1 respectively. Then a1.stable_cmp(b1)==a2.stable_cmp(b2).

If you don’t need comparison relationships to be stable across analyses, use procedure.__cmp__(): it has better performance.

>>> barfn = next(p for p in project.current().procedures() if p.name()=='bar')
>>> foofn = next(p for p in project.current().procedures() if p.name()=='foo')
>>> barfn.stable_cmp(foofn)
-1
stable_hash()

Get a hash value for a procedure , with stable results across sufficiently-similar analyses.

Return type:int
Returns:The computed hash value.

This hash value is stable in the following sense. Suppose there are two analyses A1 and A2 generated with exactly the same inputs (including identical analyzed code, underlying build commands and ordering, command line and configuration settings, increment order and contents). Let v1 be a procedure object in A1, and v2 be the procedure object in A2 that corresponds to v1. Then v1.stable_hash()==v2.stable_hash().

If you don’t need hash values to be stable across analyses, use procedure.__hash__(): it has better performance.

>>> barfn = next(p for p in project.current().procedures() if p.name()=='bar')
>>> barfn.stable_hash()
2632000026
verbose_name()

Get the name of a procedure.

Return type:str
Returns:The procedure name.

See also procedure.name(), procedure.basename().

In some cases, a single procedure P will have markedly different values for P.name() and P.verbose_name(). For example, consider the following program. Let F be the procedure for function foo(), then F.name() is “foo”, but F.verbose_name() is “bar”.

void foo() asm("bar");

void foo() {
  printf("1234");
}

int main() {
  foo();
}
>>> proc = next(p for p in project.current().procedures() if 'who' in p.verbose_name())
>>> proc
<cs.procedure whoknows>
>>> proc.name()
'whoknows'
>>> proc.basename()
'whoknows'
>>> proc.verbose_name()
'whoknows(int)'