전체 화면 모드로 PL/I 프로그램 디버깅

PL/I에 대한 기본 디버깅 태스크에 대한 설명은 다음 PL/I 프로그램을 참조하십시오.

예제: 디버깅을 위한 샘플 PL/I 프로그램

이 절에서 설명하는 자료와 연관된 자세한 정보에 대해서는 다음 주제를 참조하십시오.

예제: 디버깅을 위한 샘플 PL/I 프로그램

아래 프로그램은 디버깅 태스크를 보여 주기 위해 다양한 주제에서 사용됩니다.

이 프로그램은 문자 버퍼에서 입력을 읽는 단순한 계산기입니다. 정수를 읽은 경우에는 스택에 밀어넣어집니다. 연산자(+ - * /) 중 하나를 읽은 경우에는 맨 위에 있는 두 요소가 스택에서 나가고, 해당 연산자에 대해 연산이 수행된 다음 그 결과가 스택에 밀어넣어집니다. = 연산자는 스택의 맨 위에 있는 요소의 값을 버퍼에 씁니다.

PLICALC를 실행하기 전에 다음 명령을 입력하여 터미널에 SYSPRINT를 할당해야 합니다.

ALLOC FI(SYSPRINT) DA(*) REUSE

Main program PLICALC

 plicalc: proc options(main);
 /*------------------------------------------------------------------*/
 /*                                                                  */
 /* A simple calculator that does operations on integers that        */
 /* are pushed and popped on a stack                                 */
 /*                                                                  */
 /*------------------------------------------------------------------*/
 dcl index  builtin;
 dcl length builtin;
 dcl substr builtin;
 /*                                                                  */
 dcl 1 stack,
       2 stkptr fixed bin(15,0) init(0),
       2 stknum(50) fixed bin(31,0);
 dcl 1 bufin,
       2 bufptr fixed bin(15,0) init(0),
       2 bufchr char (100) varying;
 dcl 1 tok char (100) varying;
 dcl 1 tstop char(1) init ('s');
 dcl 1 ndx fixed bin(15,0);
 dcl num      fixed bin(31,0);
 dcl i        fixed bin(31,0);
 dcl push entry external;
 dcl pop  entry returns (fixed bin(31,0)) external;
 dcl readtok entry returns (char (100) varying) external;
 /*------------------------------------------------------------------*/
 /* input  action:                                                   */
 /*    2      push 2 on stack                                        */
 /*    18     push 18                                                */
 /*    +      pop 2, pop 18, add, push result (20)                   */
 /*    =      output value on the top of the stack (20)              */
 /*    5      push 5                                                 */
 /*    /      pop 5, pop 20, divide, push result (4)                 */
 /*    =      output value on the top of the stack (4)               */
 /*------------------------------------------------------------------*/
 bufchr = '2 18 + = 5 / =';
 do while (tok ^= tstop);
   tok = readtok(bufin);          /* get next 'token' */
   select (tok);
     when (tstop)
       leave;
     when ('+') do;
       num = pop(stack);
       call push(stack,num);      /*   CALC1   statement */
     end;
     when ('-') do;
       num = pop(stack);
       call push(stack,pop(stack)-num);
     end;
     when ('*')
       call push(stack,pop(stack)*pop(stack));
     when ('/') do;
       num = pop(stack);
       call push(stack,pop(stack)/num); /*   CALC2   statement */
     end;
     when ('=') do;
       num = pop(stack);
       put list ('PLICALC: ', num) skip;
       call push(stack,num);
     end;
     otherwise do;/* must be an integer */
       num = atoi(tok);
       call push(stack,num);
 end;
 end;
 end;
 return;

TOK function

 atoi: procedure(tok) returns (fixed bin(31,0));
 /*------------------------------------------------------------------*/
 /*                                                                  */
 /* convert character string to number                               */
 /* (note: string validated by readtok)                              */
 /*                                                                  */
 /*------------------------------------------------------------------*/
   dcl 1 tok char (100) varying;
   dcl 1 num fixed bin (31,0);
   dcl 1 j fixed bin(15,0);
   num = 0;
   do j = 1 to length(tok);
     num = (10 * num) + (index('0123456789',substr(tok,j,1))-1);
   end;
   return (num);
 end atoi;
 end plicalc;

PUSH function

 push: procedure(stack,num);
 /*------------------------------------------------------------------*/
 /*                                                                  */
 /* a simple push function for a stack of integers                   */
 /*                                                                  */
 /*------------------------------------------------------------------*/
 dcl 1 stack connected,
       2 stkptr fixed bin(15,0),
       2 stknum(50) fixed bin(31,0);
 dcl num      fixed bin(31,0);
 stkptr = stkptr + 1;
 stknum(stkptr) = num; /*   PUSH1   statement */
 return;
 end push;

POP function

 pop: procedure(stack) returns (fixed bin(31,0));
 /*------------------------------------------------------------------*/
 /*                                                                  */
 /* a simple pop function for a stack of integers                    */
 /*                                                                  */
 /*------------------------------------------------------------------*/
 dcl 1 stack connected,
       2 stkptr fixed bin(15,0),
       2 stknum(50) fixed bin(31,0);
 stkptr = stkptr - 1;
 return (stknum(stkptr+1));
 end pop;

READTOK function

 readtok: procedure(bufin) returns (char (100) varying);
 /*------------------------------------------------------------------*/
 /*                                                                  */
 /* a function to read input and tokenize it for a simple calculator */
 /*                                                                  */
 /* action: get next input char, update index for next call          */
 /* return: next input char(s)                                       */
 /*------------------------------------------------------------------*/
 dcl length builtin;
 dcl substr builtin;
 dcl verify builtin;
 dcl 1 bufin connected,
       2 bufptr fixed bin(15,0),
       2 bufchr char (100) varying;
 dcl 1 tok char (100) varying;
 dcl 1 tstop char(1) init ('s');
 dcl 1 j fixed bin(15,0);
                                  /* start of processing */
 if bufptr > length(bufchr) then do;
   tok = tstop;
   return ( tok );
 end;
 bufptr = bufptr + 1;
 do while (substr(bufchr,bufptr,1) = ' ');
   bufptr = bufptr + 1;
   if bufptr > length(bufchr) then do;
     tok = tstop;
     return ( tok );
 end;
 end;
 tok = substr(bufchr,bufptr,1); /* get ready to return single char */
 select (tok);
   when ('+','-','/','*','=')
     bufptr = bufptr;
   otherwise do;                /* possibly an integer */
     tok = '';
     do j = bufptr to length(bufchr);
       if verify(substr(bufchr,j,1),'0123456789') ^= 0 then
         leave;
     end;
     if j > bufptr then do;
         j = j - 1;
       tok = substr(bufchr,bufptr,(j-bufptr+1));
       bufptr = j;
     end;
     else
       tok = tstop;
 end;
 end;
 return (tok);
 end readtok;

이 절에서 설명하는 자료와 연관된 자세한 정보에 대해서는 다음 주제를 참조하십시오.

특정 PL/I 함수가 호출될 때 정지

이 주제에서는 AT CALLAT ENTRY 명령을 사용하여 루틴을 호출한 직후에 정지하는 방법을 설명합니다. 예제: 디버깅을 위한 샘플 PL/I 프로그램은 이 명령을 설명하는 데 사용됩니다.

AT CALL 명령을 사용하려면 TEST 컴파일러 옵션과 함께 호출 프로그램을 컴파일해야 합니다.

READTOK가 호출되기 직전에 정지하려면 다음 명령을 입력하십시오.

AT CALL READTOK ;

AT ENTRY 명령을 사용하려면 TEST 컴파일러 옵션과 함께 호출된 프로그램을 컴파일해야 합니다.

READTOK가 호출된 직후에 정지하려면 다음 명령을 입력하십시오.

AT ENTRY READTOK ;

TOK가 호출된 직후 tok 매개변수가 2인 경우에만 정지하려면 다음 명령을 입력하십시오.

AT ENTRY TOK WHEN tok='2';

PL/I 프로그램이 중지한 명령문 식별

프로그램에 중단점을 여러 개 설정한 경우 다음 명령을 입력하여 프로그램이 중지된 위치를 Debug Tool이 식별하도록 할 수 있습니다.

QUERY LOCATION

Debug Tool 로그 창에는 다음 예제와 비슷한 메시지가 표시됩니다.

QUERY LOCATION ;
ENTRY READTOK 중단점에서 명령을 실행 중입니다.
프로그램이 현재 블록 READTOK를 입력 중입니다.

PL/I 변수 값 수정

단일 변수의 컨텐츠를 나열하려면 소스 창에서 변수명이 있는 곳으로 커서를 이동하고 PF4(LIST)를 누르십시오. 로그 창에 값이 표시됩니다. 이는 명령행에 LIST TITLED variable을 입력하는 것과 같습니다. 예를 들어, Debug Tool 명령행에 AT 22 ; GO ;를 입력하여  CALC1  명령문까지 PLICALC 프로그램을 실행하십시오. NUM 위로 커서를 이동하고 PF4(LIST)를 누르십시오. 로그 창에 다음이 표시됩니다.

 LIST NUM ;
NUM =             18

NUM 값을 22로 수정하려면 NUM = 18 행 위에 NUM = 22을 입력하고 Enter를 눌러 명령행에 놓은 다음 다시 Enter를 눌러 명령을 실행하십시오.

명령행에 대부분의 PL/I 표현식을 입력할 수 있습니다.

PF2(STEP)를 눌러 PUSH에 대한 호출로 step into한 다음  PUSH1  명령문에 도달할 때까지 step하십시오. STKNUM 변수의 속성을 보려면 다음 Debug Tool 명령을 입력하십시오.

DESCRIBE ATTRIBUTES STKNUM;

로그 창에 다음과 같은 결과가 표시됩니다.

 속성: STKNUM
   주소: 0003944C, 길이: 200
     PUSH : STACK.STKNUM(50)  FIXED BINARY(31,0) REAL PARAMETER
         주소: 0003944C, 길이: 4

다음 명령을 실행하여 STACK이 가리키는 구조의 모든 멤버 값을 나열할 수 있습니다.

LIST STACK;

로그 창에 다음과 같은 결과가 표시됩니다.

 LIST STACK ;
STACK.STKPTR =                 2
STACK.STKNUM(1) =              2
STACK.STKNUM(2) =             18
STACK.STKNUM(3) =         233864

  ·
  ·
  ·
STACK.STKNUM(50) = 121604

다음 예제에서와 같이 명령으로 대입을 실행하여 구조의 멤버 값을 변경할 수 있습니다.

STKNUM(STKPTR) = 33;

조건이 true인 경우에만 PL/I 행에서 정지

대개 프로그램의 특정 부분이 처음에는 잘 작동하지만 특정 조건에서는 실패하는 경우가 많습니다. 이때 단순히 행 중단점만 설정하면 계속해서 GO를 입력해야 하므로 이 방법은 효율적이지 않습니다.

예제: 디버깅을 위한 샘플 PL/I 프로그램

예를 들어, PLICALC에서 제수가 0인 경우에만(예외가 발생하기 전에) 나눗셈을 중지하려고 합니다. 다음과 같이 중단점을 설정하십시오.

AT 31 DO; IF NUM ^= 0 THEN GO; END;

31행은  CALC2  명령문입니다. 이 명령을 실행하면 Debug Tool이 31행에서 중지합니다. NUM 값이 0이 아니면 프로그램이 계속 실행됩니다. NUM 값이 0일 경우에만 이 명령을 실행하면 Debug Tool이 31행에서 중지합니다.

일부분만 TEST를 사용하여 컴파일된 PL/I 디버깅

예제: 디버깅을 위한 샘플 PL/I 프로그램

PUSH 서브루틴에 대한 시작점에 중단점을 설정하려 한다고 가정해 보십시오. PUSHTEST를 사용하여 컴파일되었지만 다른 파일은 그렇지 않습니다. Debug Tool에 빈 소스 창이 표시됩니다. 컴파일 단위를 표시하려면 다음 명령을 입력하십시오.

LIST NAMES CUS

LIST NAMES CUS 명령은 Debug Tool에 알려진 모든 컴파일 단위 목록을 표시합니다. PUSH가 애플리케이션에 의해 나중에 페치된 경우에는 이 컴파일 단위가 Debug Tool에 알려지지 않았을 수 있습니다. 표시되는 경우 다음 명령을 입력하십시오.

SET QUALIFY CU PUSH
AT ENTRY PUSH;
GO ;

표시되지 않는 경우 다음과 같이 appearance 중단점을 설정하십시오.

AT APPEARANCE PUSH ;
GO ;

다음과 같이 중단점을 결합할 수도 있습니다.

AT APPEARANCE PUSH AT ENTRY PUSH; GO;

이 appearance 중단점은 PUSH 컴파일 단위의 함수가 처음 실행될 때 제어를 가져오기 위해 필요합니다. 제어를 가져오면, 다음과 같이 PUSH에 대한 시작점에 중단점을 설정할 수 있습니다.

AT ENTRY PUSH;

PL/I에 원시 스토리지 표시

LIST STORAGE 명령을 사용하여 변수의 스토리지를 표시할 수 있습니다. 예를 들어, STACK의 처음 30자에 대한 스토리지를 표시하려면 다음 명령을 입력하십시오.

LIST STORAGE(STACK,30)

이 절에서 설명하는 자료와 연관된 자세한 정보에 대해서는 다음 주제를 참조하십시오.

PL/I 함수 역추적 보기

대개 프로그래밍 오류가 발생하면 프로그래밍 오류를 야기한 것이 무엇인지, 특히 호출 함수의 역추적이 무엇인지 파악하려고 합니다. 이 정보를 보려면 다음 명령을 실행하십시오.

LIST CALLS ;

예제: 디버깅을 위한 샘플 PL/I 프로그램

예를 들어, 다음 명령과 함께 PLICALC 예제를 실행하십시오.

AT ENTRY READTOK ;
GO ;
LIST CALLS ;

그러면 로그 창에 다음과 같은 내용이 표시됩니다.

At ENTRY IN PL/I subroutine READTOK.
From LINE 17.1 IN PL/I subroutine PLICALC.

이는 호출자의 역추적을 표시합니다.

TEST를 사용하여 컴파일된 PL/I 코드의 런타임 경로 추적

프로그램을 변경하지 않고 시작점과 종료점을 표시하여 프로그램을 추적하려면 명령 파일을 사용하거나 명령을 개별적으로 입력하여 2단계에 설명된 명령을 입력할 수 있습니다. 명령 파일을 사용하려면 다음 단계를 수행하십시오.

  1. 다음과 비슷한 이름의 PDS 멤버를 작성하십시오. userid.DT.COMMANDS(PLICALL)
  2. 파일이나 데이터셋을 편집하여 다음 Debug Tool 명령을 추가하십시오.
    SET PROGRAMMING LANGUAGE PLI ;
    DCL LVLSTR CHARACTER (50);
    DCL LVL FIXED BINARY (15);
    LVL = 0;
    AT ENTRY *
    DO;
    LVLSTR = ' ' ;
    LVL = LVL + 1 ;
    LVLSTR = 'ENTERING >' || %BLOCK;
    LIST UNTITLED ( LVLSTR ) ;
    GO ;
    END;
    AT EXIT *
    DO;
    LVLSTR = 'EXITING < ' || %BLOCK;
    LIST UNTITLED ( LVLSTR ) ;
    LVL = LVL - 1 ;
    GO ;
    END;
  3. Debug Tool을 시작하십시오.
  4. 다음 명령을 입력하십시오.
    USE DT.COMMANDS(PLICALL)
  5. 프로그램 순서를 실행하십시오. Debug Tool 로그 창에 추적이 표시됩니다.

예를 들어, USE 명령을 입력한 후 다음 프로그램 순서를 실행하십시오.

*PROCESS MACRO,OPT(TIME); 
 *PROCESS S STMT TEST(ALL); 

 PLICALL: PROC OPTIONS (MAIN); 

 DCL PLIXOPT CHAR(60) VAR STATIC EXTERNAL 

 INIT('STACK(20K,20K),TEST'); 

 CALL PLISUB; 

 PUT SKIP LIST('DONE WITH PLICALL'); 

 PLISUB: PROC; 

 DCL PLISUB1 ENTRY ; 

 CALL PLISUB1; 

 PUT SKIP LIST('DONE WITH PLISUB '); 

 END PLISUB; 

 PLISUB1: PROC; 

 DCL PLISUB2 ENTRY ; 

 CALL PLISUB2; 

 PUT SKIP LIST('DONE WITH PLISUB1'); 

 END PLISUB1; 

 PLISUB2: PROC; 

 PUT SKIP LIST('DONE WITH PLISUB2'); 
 END PLISUB2; 
 END PLICALL; 

Debug Tool 로그 창에 다음 추적과 비슷한 추적이 표시됩니다.

'ENTERING >PLICALL                                 '
'ENTERING >PLISUB                                  '
'ENTERING >PLISUB1                                 '
'ENTERING >PLISUB2                                 '
'EXITING < PLISUB2                                 '
'EXITING < PLISUB1                                 '
'EXITING < PLISUB                                  '
'EXITING < PLICALL                                 '

PL/I의 예기치 않은 스토리지 겹쳐쓰기 오류 찾기

프로그램이 실행되는 중에 일부 스토리지의 값이 예기치 않게 변경되어 이 값이 언제 어디서 변경되었는지 알아야 할 때가 있습니다. 다음 예제를 참조하십시오. 다음 예제에서는 호출자가 예상하는 것보다 프로그램이 더 많이 변경됩니다.

2 FIELD1(2) CHAR(8);
2 FIELD2 CHAR(8);
 CTR = 3;         /* an invalid index value is set */
 FIELD1(CTR) = 'TOO MUCH';

다음 명령을 사용하여 FIELD2의 주소를 찾으십시오.

DESCRIBE ATTRIBUTES FIELD2

결과가 X'00521D42'라고 가정해 보십시오. 이 주소에서 시작하여 다음 8바이트에서 스토리지 값이 변경되었는지 감시하는 중단점을 설정하려면 다음 명령을 실행하십시오.

AT CHANGE %STORAGE('00521D42'px,8)

이 스토리지의 값이 변경된 경우, 프로그램이 실행될 때 Debug Tool이 정지됩니다.

PL/I에서 정의되지 않은 프로그램을 호출하기 전에 정지

정의되지 않은 프로그램 또는 함수 호출은 심각한 오류를 발생할 수 있습니다. 이러한 호출이 실행되기 직전에 정지하려면 다음과 같이 중단점을 설정하십시오.

AT CALL 0

이 중단점에서 Debug Tool이 중지하면 GO BYPASS 명령을 입력하여 이 호출을 생략할 수 있습니다. 이렇게 하면 오류 조건을 발생시키지 않고 디버그 세션을 계속할 수 있습니다.