Analyzing the ABAP Call Stack - Who Is Calling Me?
Analyzing the ABAP Call Stack - Who Is Calling Me?

Analyzing the ABAP Call Stack - Who Is Calling Me?

Published at December 9, 2019by Jörg Brandeis

The following texts were partially or completely generated with the help of generative AI models.

"In software engineering and computer science, a call stack (also known as procedure stack) is a specially used stack that holds the state of the subroutines currently being called during the runtime of a program." (Wikipedia)

Sometimes it is important to know the context from which a method call originated. As long as you make the method call yourself, you can of course pack this information into the appropriate parameters. But when the methods are called by the system, as is the case with BAdIs, for example, you have no influence over that. In my specific example, the goal is to distinguish whether a customer exit for a BW Bex variable is called

  1. During the normal execution of a report, or
  2. During simulation for another user (transaction RSUDO/RSECADMIN), or
  3. In the background during the generation of authorizations.

I cannot get the necessary information into the interface of the exit. A simple workaround to obtain this information is the function module SYSTEM_CALLSTACK. It returns the complete call stack. The following listing shows a simple test of this function:

    REPORT zjb_test.

    CLASS lcl_outer DEFINITION.
      PUBLIC SECTION.
        CLASS-METHODS test_outer.
    ENDCLASS.

    CLASS lcl_inner DEFINITION.
      PUBLIC SECTION.
        CLASS-METHODS test_inner.
    ENDCLASS.

    lcl_outer=>test_outer( ).

    CLASS lcl_inner IMPLEMENTATION.

      METHOD test_inner.
        DATA lt_callstack1  TYPE abap_callstack  .

        CALL FUNCTION 'SYSTEM_CALLSTACK'
          EXPORTING
            max_level    = 0
          IMPORTING
            callstack    = lt_callstack1.
        BREAK-POINT.
      ENDMETHOD.

    ENDCLASS.

    CLASS lcl_outer IMPLEMENTATION.

      METHOD test_outer.
        lcl_inner=>test_inner( ).
      ENDMETHOD.

    ENDCLASS.

Result of the Report

Row  MAINPROGRAM  INCLUDE   LINE  BLOCKTYPE  BLOCKNAME           FLAG_SYSTEM<br>    ============================================================================
1    ZJB_TEST     ZJB_TEST  26    METHOD     TEST_INNER          
2    ZJB_TEST     ZJB_TEST  41    METHOD     TEST_OUTER          
3    ZJB_TEST     ZJB_TEST  18    EVENT      START-OF-SELECTION  

You can see that the three levels are listed in the table here.

For the actual problem, all I now need to do is search the call stack to see whether one of the classes appears in it. In my example, searching for the class CL_RS2HANA_AUTH_MANAGER, method RUN_REPLICATION would be suitable for detecting situation 3. The following call stack belongs to it:

Row  MAINPROGRAM                       INCLUDE                              LINE  BLOCKTYPE     BLOCKNAME                                    FLAG_SYSTEM
========================================================================================================================================================
1    ZCL_BI_CALLSTACK==============CP  ZCL_BI_CALLSTACK==============CM001  5     METHOD        CHECK_CONTAINS_CLASSNAME                     
2    ZCL_BI_VARIABLE_AUTH==========CP  ZCL_BI_VARIABLE_AUTH==========CM001  9     METHOD        GET_RANGE_FOR_VARNAME                        
3    ZCL_BI_VAR_BI_MGMTID==========CP  ZCL_BI_VAR_BI_MGMTID==========CM001  10    METHOD        GET_RANGE_FOR_VNAM                           
4    ZCL_BI_VAR_ROOT===============CP  ZCL_BI_VAR_ROOT===============CM002  18    METHOD        IF_RSROA_VARIABLES_EXIT_BADI~PROCESS         
5    SAPLRRS0                          LRRS0U01                             42    FUNCTION      RRS_VAR_EXIT                                 
6    SAPLRSEC_CHECKS                   LRSEC_CHECKSF02                      107   FORM          GET_VALUE_FROM_CUST_EXIT                     
7    SAPLRSEC_CHECKS                   LRSEC_CHECKSF03                      1936  FORM          GET_LEAVES_AUTHORIZED                        
8    SAPLRSEC_CHECKS                   LRSEC_CHECKSF03                      1782  FORM          GET_VALUES_OF_LEAVES                         
9    SAPLRSEC_UTILS                    LRSEC_UTILSU02                       341   FUNCTION      RSEC_GET_AUTHS_FILTERED                      
10   CL_RS2HANA_AUTH_AUTHORIZATION=CP  CL_RS2HANA_AUTH_AUTHORIZATION=CCIMP  1224  METHOD        READ_AUTH_INFOPROVIDER                       
11   CL_RS2HANA_AUTH_AUTHORIZATION=CP  CL_RS2HANA_AUTH_AUTHORIZATION=CCIMP  744   METHOD        CONSTRUCTOR                                  
12   CL_RS2HANA_AUTH_AUTHORIZATION=CP  CL_RS2HANA_AUTH_AUTHORIZATION=CCIMP  1333  METHOD        GET                                          
13   CL_RS2HANA_AUTH_AUTHORIZATION=CP  CL_RS2HANA_AUTH_AUTHORIZATION=CM00A  20    METHOD        IF_RS2HANA_AUTH_AUTHORIZATION~IS_AUTHORIZED  
14   CL_RS2HANA_AUTH_MANAGER=======CP  CL_RS2HANA_AUTH_MANAGER=======CM02G  22    METHOD        _STEP_01C_CHECK_AUTHORIZATIONS               
15   CL_RS2HANA_AUTH_MANAGER=======CP  CL_RS2HANA_AUTH_MANAGER=======CM023  20    METHOD        RUN_STEP_01_PREPARE                          
16   CL_RS2HANA_AUTH_MANAGER=======CP  CL_RS2HANA_AUTH_MANAGER=======CM02D  27    METHOD        _RUN_REPLICATION                             
17   CL_RS2HANA_AUTH_MANAGER=======CP  CL_RS2HANA_AUTH_MANAGER=======CM022  125   METHOD        RUN_REPLICATION                              
18   RS2HANA_AUTH_RUN                  RS2HANA_AUTH_RUN_CL                  453   METHOD        RUN                                          
19   RS2HANA_AUTH_RUN                  RS2HANA_AUTH_RUN                     252   FORM          %_SEL_SCREEN                                 
20   RS2HANA_AUTH_RUN                  RS2HANA_AUTH_RUN                     483   MODULE (PAI)  %_END_OF_SCREEN                              X
21   RS2HANA_AUTH_RUN                  <SYSINI>                             18    EVENT         SYSTEM-EXIT                                  X

For this situation I wrote a class that checks whether a combination of class and method appears in the call stack. If that is not the case, an exception is raised. The caller can then catch it and act accordingly.

CLASS zcl_callstack DEFINITION
  PUBLIC FINAL CREATE PUBLIC .

  PUBLIC SECTION.
    CLASS-METHODS check_contains IMPORTING iv_classname  TYPE seoclsname
                                          iv_methodname TYPE seocmpname
                                RAISING   zcx_not_found.

ENDCLASS.

CLASS zcl_callstack IMPLEMENTATION.
  METHOD check_contains.
    DATA lt_callstack  TYPE abap_callstack  .
    DATA lv_mainprogram_pattern TYPE progname VALUE '==============================CP'.
    DATA(lv_classlength) =  strlen( iv_classname ).

    lv_mainprogram_pattern(lv_classlength) = iv_classname.

    CALL FUNCTION 'SYSTEM_CALLSTACK'
      EXPORTING
        max_level    = 0
      IMPORTING
        et_callstack = lt_callstack.

    READ TABLE lt_callstack TRANSPORTING NO FIELDS
                            WITH KEY  mainprogram = lv_mainprogram_pattern
                                      blockname = iv_methodname.
    IF sy-subrc NE 0.
      RAISE EXCEPTION TYPE zcx_not_found.
    ENDIF.
    BREAK-POINT.
  ENDMETHOD.

ENDCLASS.

The approach shown works well. However, it should only be used when passing the information by other means, e.g. via a parameter, is not possible. The reason for this is that a specific call sequence in the call stack does not represent a defined interface. Internally, SAP can change everything, as long as the exit is called with the same parameters.

More articles

New!
New!