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)
    삽질 Ruby libpcap 개발 데스크탑 TCP AIX agile Feisty 조카 VB.NET tcpdump 나연이 짝프로그래밍 Ubuntu 리눅스 COBL call_graph
    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 : 27630
    Today : 2
    Yesterday : 3
    태터툴즈 배너
    rss
     
     
     
    위치로그 : 태그 : 방명록 : 관리자
    KOEI’s Blog is powered by Tattertools.com / Designed by plyfly.net