KOEI's Diary 위치로그  |  태그  |  방명록
COBOL call flow 그려보기
개발이야기 | 2008/03/24 02:51
2008/03/24 02:51 2008/03/24 02:51

최근에 COBOL로 된 코드를 잔뜩 볼 일이 생겼습니다. 코볼 소스 라인이 긴게 주석을 합쳐서 2만 라인이 넘는 것들도 있고해서 분석할 엄두가 안 나더군요..
 어떻게 call flow라도 알 방법이 없을까 하고 소프트웨어를 뒤져보니 상용만 있고(과자 구하기가 힘들더군요) 오픈소스쪽도 소스포지를 좀 뒤져봤는데(ㅠ.ㅠ 나중에 얼마 안지나서 이상한 이름으로 존재하는 것이 있더군요..)
 이 답답한 사정을 shining군에게 토로했더니, 30분 정도 브레인스토밍 30분 짝 프로그래밍을 해서 약식의 콜 흐름을 그려봤습니다.

 일단 해야할 일을 정의했습니다. call flow를 그린다는 일은 함수가 함수를 부르는 것을 그래프로 보여주는 작업입니다. 즉 caller와 callee를 모두 구하면 됩니다. 그래프를 그려주는건 리눅스에서 library dependencies를 간단하게 graphviz로 그려주는 쉘스크립트를 보고 참조하기로 했고, 코볼의 문법 자체가 워낙에 영문에 가까워서 파싱 자체가 어렵지 않았습니다.

  • 함수를 나타내는 부분
    • 함수명                                         SECTION.
    • 데이터섹션 예약어는 제외합니다.
  • 함수를 부르는 부분
    • CALL "외부함수"
    • CALL '외부함수'
    • PERFORM 내부함수
    • PERFORM으로 시작하는 것중 문법적인 예외사항 제거

  • 일단 가능한 빠른 시간내에 구현을 제약사항으로 처리했기 때문에 최대한 간단하게 호출하는 3부분만 파싱해서 구현했습니다. 중복제거 및 awk , shell 의존성 제거 먼저 저 3 가지 타입만 가볍게 긁어오는 것을 shining군이 awk로 작성을 했습니다. 정규표현식으로 해당 부분을 긁어서 graphviz용 입력파일을 작성했습니다. 생성된 그래프 파일입니다. (함수 이름은 모두 변경했습니다.)
    사용자 삽입 이미지

    코드는 다음과 같습니다.

    #!/usr/bin/env ruby

    # FILE EXTENSION
    $COBOL_EXTENSION = '.cbl'
    $DOT_EXTENSION = '.dot'
    $PNG_ENTENSION = '.png'

    # DOT SETTING
    if RUBY_PLATFORM.match(/mswin32$/) then # windows
     
    $DOT_EXECUTE=ENV['ProgramFiles'] + '\Graphviz\bin\dot.exe' if ENV['ProgramFiles']
      $FONTNAME="Tahoma"
    else
      $DOT_EXECUTE="dot"
    end
    $FONTSIZE=12

    # perform reserve words
    PERFORM_RESERVES = [ 'AFTER', 'BEFORE', 'BY', 'FROM', 'TEST', 'UNTIL', 'VARYING', 'WITH' ]

    def cobol_call_flow_generate( filename )
      # cobol file extension check
     
    return if File.extname(filename) != $COBOL_EXTENSION 

      # dot tempoary filename
     
    dot_filename = ARGV[0]+$DOT_EXTENSION
     
      # dot output image filename
     
    output_filename = ARGV[0]+$PNG_ENTENSION
     
      # function call related
     
    calls = []

      # current sections name
     
    current_function = "INVALID-SECTION"
     
      # cobol file read & parsing
     
    File.open(ARGV[0], 'r') { |f|
        while input_line = f.gets
          case input_line
            when /^\s*\*/
                next
            when /^\s*([A-Z0-9-]*)\s*SECTION\.\s*\n$/
                current_function = $1
            when /^\s*PERFORM\s*([A-Z0-9-]*)/
                calls << [ current_function, $1, :perfom ] unless PERFORM_RESERVES.include?($1) or calls.include?([ current_function, $1, :perform ])
            when /^\s*CALL\s*['"](.*)['"]/
                calls << [current_function, $1, :call ] unless calls.include?([current_function, $1, :call ])
            end
      end
    }

      # write dot file
     
    File.open(dot_filename, 'w') { |wf|
        wf.puts('digraph DependencyTree {')
        wf.puts("  node [ fontname=\"#$FONTNAME\", fontsize=#$FONTSIZE ]; ");
        wf.puts('  "A-MAIN" [shape=Mdiamond];')
        wf.puts('  "Z-FINISH" [shape=Mdiamond];')
     
       
    calls.each { |i|
          wf.puts(\"#{i[1]}\" [shape=diamond,style=filled,color=lightgray]; ") if i[2] == :call
          wf.puts(\"#{i[0]}\" -> \"#{i[1]}\"")
        }
        wf.puts('}')
      }
     
      # execute dot
     
    dot_command = "\"#{$DOT_EXECUTE}\" -Tpng #{dot_filename} -o #{output_filename}"
      system(dot_command)
     
      # remove tempoary dot file
     
    require 'fileutils'
      FileUtils.rm(dot_filename)
    end

    # main
    if ( ARGV.size < 1 )
      puts "#{File.basename $0} [cobol files]"
      exit 0
    end

    ARGV.each { |cobol_file|
      cobol_call_flow_generate( cobol_file )
    }


    현재 가지고 있는 문제점은 다음과 같습니다.
    1. 하나의 함수에서 여러번 콜을 하는 것을 고려하지 않았습니다.
    2. 외부함수와 내부함수를 구분하지 않습니다.
    3. 다른 파일을 찾아서 연동하는 부분이 빠져있습니다.
    4. C 함수와 COBOL함수를 구분하지 않습니다.

    태그 :
    트랙백0 | 댓글8
    이 글의 관련글(트랙백) 주소 :: http://koei.fiaa.net/trackback/501
    광이랑 2008/03/28 10:42 L R X
    잘하고 있구만!!!
    KOEI 2008/03/30 13:57 L X
    만들어서 보긴 하는데 진도가 잘 안나가서 반성중입니다.
    넘넘 길어요;
    하늘이 2008/04/02 22:33 L R X
    graphviz를 이럴때 쓰는구낭;; 왠지 익숙하다 했는데;;

    그나저나 겁나게 뭔가 많은걸 하고 사는듯하넹 =D
    간만에 또 와보고는.. 화들짝했다네;;
    KOEI 2008/04/03 00:28 L X
    로오오오옹 타이이임 노오오오 씨이이이이
    간만에 글 올린 사람이 머 그렇지 머. ; 들러주어서 감사 감사.
    근 1년만에 쓴 글이네 그래.. 많은걸 하고 살진 않는다오.
    작년 중반이후로 좀 아파서 잠적하고 살았다오;
    얼굴 못본지가 1년이 넘은거 같네 그래. 판이는 잘 지내려나? 보고 싶다.
    nurinamu 2008/05/14 08:49 L R X
    광용싸마~ 간만이에용~ㅋㅋ
    은근슬쩍 들려서
    흔적 남기구 가용~ 보구싶어용 브라더~
    KOEI 2008/08/14 12:41 L X
    냥냥 올만이야 3달만의 리플이라 ㅠ.ㅠ OTL
    seha 2009/05/28 08:04 L R X
    별걸 다 해
    -_-
    KOEI 2009/07/16 11:06 L X
    헙 마님 3개월만에 들어와봤더니 립흘이

    그동안 만수무강하셨사옵니까? 항가

    [로그인][오픈아이디란?]
    아이디 :
    비밀번호 :
    홈페이지 :
      비밀글로 등록
    내용 :
     



    Ruby 그리고 AIX
    개발이야기 | 2007/03/26 02:17
    2007/03/26 02:17 2007/03/26 02:17

    AIX에서 Ruby 돌리기?

    별로 생각하고 싶지 않은 스토리인데.. 상황이 그리 되는 어쩔 수 없으니...

    1차시도 1.8.5을 visual age c compiler로 컴팔하기
     => __ceil, __floor를 못 찾겠다 꾀꼬리
    2차시도 1.8.5를 gcc로 컴팔하기
     => 컴팔이 잘 된다 오예~, 그러나 ext/socket 은 왜 컴파일을 안 하는데. 소켓써야하는데 ㅠ.ㅠ
    3차시도 1.8.6을 gcc로 컴팔하기
     => 오옹 그냥 해봤는데 socket도 들어있네 아싸

    흐웅 그나저나 이 머신 왜이리 접속하는데 오래걸려. 그래도 행복하게 ruby를 쓸 수 있네 ㅋㅋ
    들어가는게 느리니 느리겠거니...

    require 'socket'

    t = TCPSocket.new('www.daum.net',80) # 가는 세월 그누구가~ 막을수가 있나요 ㅠ.ㅠ

    요게 느린 것도 아마 AIX 요 머신이 특이한 걸 것이야..
    얼래 그런데 ftp로 데이터 받아오기나, 그 외의 것들은 빠른데.... -ㅅ-
    알고보니 Ruby에서 ext/socket 모듈로 Socket 생성시 접속이 오라지게 느리게 된다.
    꾸에엑 이를 어쩌나.. 소켓이 필요한 부분이 TCPSocket으로 접속도 해야하고, open-uri를 이용해서 ftp에서 파일도 받아와야하는데..

    고객은 앞에 있고.. 데모 보여줘야하는데... ㄷㄷㄷ
    부랴 부랴 netcat, wget으로 두부분을 스슥 바꿨다.
    UNIX는 저에게 system, popen과 ``를 주셨나이다. ㄳㄳ

    일단 일단락.. 그러나 상황이 조금 바뀌어서 AIX에서 Ruby/Pcap도 써야할 상황.
    컴파일을 하는데 잘 안 되네.. -ㅅ-
    컴파일하고 나니 모듈 로딩이 안 된다.

     구글링하던 도중 AIX에서 Ruby Building할때 1차시도의 해결책을 찾았다.
     알고 보니 망할 Visual Age Compiler 6.0의 버그문제. python을 비롯한 다른 오픈프로젝트에서도 관련 얘기가 나오네. -ㅅ- 그래서 vac로 다시 한번 컴팔해봤다.

     4차시도 잘 된다. 그러나 확장모듈 로딩이 죄다~ 안 된다. 쩝쩝쩝..
      gcc로 다시 회귀 그러면서 아차차 생각난 것...
     5차시도 CC="gcc -maix64" 요리 하니 ext/socket에서 지연되던 문제가 사라졌다. 성능도 조금 좋아진 느낌이다. GOOD!

     그러나 역시 Ruby/pcap은 로딩이 되지 않는다. (해결되면 포스팅 이어짐 안되면 한동안 좀비모드일듯.. C++ Porting 고고싱 T-T)
     libpcap 컴파일시에 CC="gcc -maix64" CFLAGS="-g -O2" ./configure --with-pcap=dlpi --disable-ipv6  로 옵션을 줘서 해결. README.aix문서를 읽어보고 bpf를 사용하지 않고 dlpi를 사용하게 하니 문제없이 작동 - 머 특정 용도 활용이라서 원하는 기능만 돌아가는지 확인. (Fixnum을 Symbol로 사용하짐 랄라는 에러가 3개 뜬다 덜덜덜.. -ㅅ-)

    추가적인 수정 사항 (흑 2006.03.29 새벽3시 퇴근 ㅠ.ㅠ)
    1. Endian 문제가 있어서 (실제 데이터는 리틀엔디안 AIX는 빅엔디안) 2바이트짜리 길이를 나타내는 부분이었는데 len.unpack('s')를 len.reverse.unpack('s')로 수정
    2. 이상하게 tcpdump에서 쓴 패킷 캡쳐시간이 리눅스에서와 AIX에서 14시간 정도 차이가 난다. 그냥 그런가 부다 하고 처리하는 중.

    오랜만에 AIX만지면서 알게된 잼있는거 linux기반의 opensource들과 AIX가 좀 더 친해졌다.
    미리 컴파일된 바이너리를 http://aixpdslib.seas.ucla.edu/ 에서 잘 받아썼는데 IBM에서 rpm으로 공식지원하는 녀석이 생겼다. 이름도 그럴듯하다~
     AIX Toolbox for Linux Applications 엄훠 이젠 rpm으로 설치하세요~
     
     또하나는 netcat, libpcap, tcpdump 그리고 몇몇 소프트웨어를 컴팔하면서 간단하게 에러나는 것을 잡은 부분 정리

     1) extern int h_errno; 를 만나면 가뿐히 지워주세요. (AIX버젼 바이너리가 올리간 사이트의 소스와 원본소스를 비교)
     2) VAC C 컴파일러는 enum { AA,BB, CC,} 와 같은 코드를 용납하지 않아요~ 마지막에 여유로 쉼표를 찍지 말아주세요~

    태그 : , , ,
    트랙백0 | 댓글4
    이 글의 관련글(트랙백) 주소 :: http://koei.fiaa.net/trackback/489
    aqua 2007/03/29 09:30 L R X
    UNIX는 저에게 system, popen과 ``를 주셨나이다. ㄳㄳ <-- 이 부분 욜라 인정 큭큭
    KOEI 2007/03/29 18:46 L X
    그래도 얼마나 덜덜덜이었는지 모를꺼야 ㅠ.ㅠ
    생각도 못 했었지.. TCPSocket 생성이 느릴꺼라고는..
    aqua 2007/03/29 09:31 L R X
    아 그런데 AIX 쓰는 곳도 의외로 많이 보게 되는 구나 -_-;
    KOEI 2007/03/29 19:21 L X
    전에 거기야 또 ㅋㅋ

    [로그인][오픈아이디란?]
    아이디 :
    비밀번호 :
    홈페이지 :
      비밀글로 등록
    내용 :
     



    [PREV] [1][2][3][4][5] ... [6] [NEXT]
    관리자  |   글쓰기
    BLOG main image
    소소한 일상.. 그안의 나..
    전체 (11)
    개발이야기 (7)
    전산쟁이 맹달이 (2)
    사랑하는사람들 (2)
    Reading (0)
    삽질 Feisty COBL call_graph Ubuntu VB.NET tcpdump libpcap 짝프로그래밍 조카 AIX Ruby 나연이 개발 agile 데스크탑 TCP 리눅스
    COBOL call flow 그려보기 (8)
    Ruby 그리고 AIX (4)
    libpcap linux에서 timeout... (2)
    사랑하는 조카 =)
    [리뷰] Ubuntu Feisty - 충분... (6)
    헙 마님 3개월만에 들어와봤...
    2009 - KOEI
    별걸 다 해 -_-
    2009 - seha
    냥냥 올만이야 3달만의 리플...
    2008 - KOEI
    광용싸마~ 간만이에용~ㅋㅋ...
    2008 - nurinamu
    로오오오옹 타이이임 노오오...
    2008 - KOEI
    Active Directory 에 사용자...
    해적의 쉼터
    Total : 27632
    Today : 4
    Yesterday : 3
    태터툴즈 배너
    rss
     
     
     
    위치로그 : 태그 : 방명록 : 관리자
    KOEI’s Blog is powered by Tattertools.com / Designed by plyfly.net