레이블이 디버깅인 게시물을 표시합니다. 모든 게시물 표시
레이블이 디버깅인 게시물을 표시합니다. 모든 게시물 표시

2016년 3월 29일 화요일

파이썬의 라이브러리 NumPy + SciPy _____ 7

==========================================================
이 포스팅은 쓸모 없어진 포스팅입니다.
(NumPy + SciPy ____ 4 ~ NumPy + SciPy ____ 8)
해당 문제점은 Scipy 패키지를 빌드했던 툴(아마도 MS Visual Studio 201x)이 Windows XP를 지원하지 않아서 발생한 것으로 추측하고 있습니다.
이후의 포스팅에서 이 시행착오를 정리할 계획입니다. (아마도 NumPy + SciPy ____ 9)
==========================================================

앞서의 포스팅에서 파이썬이 모두 빌드되었다.
(처음엔 뭐가 부족하거나 문제가 있는게 아닌가 싶었는데 확인해 보니 모두 빌드 되어 있었음. 단지 빌드시에 나온 여러개의 워닝 메시지와 스킵한 프로젝트가 뭔지는 아직 미확인.)

빌드의 결과물은 PC/VS9.0 폴더에 있으며, 릴리즈 버전인 python.exe와 python27.dll, 디버그 버전인 python_d.exe와 python27_d.dll이다. (각 써드 파티의 라이브러리는 각 해당 폴더에 있음)

빌드된 python.

배포되는 Python 실행. 빌드버전과 CRC로 보이는 숫자가 있고 다음에 빌드 시각 2015년 12월 5일 20시 32분.

새로 빌드된 Python 실행. 버전 대신 default, 빌드 시각은 2016년 3월 28일 23시 18분.

Python 소스의 트리 구조

Python의 트리 구조

파이썬 소스의 폴더는 바이너리 배포 버전의 폴더와 약간은 다른데, 여기에서 고민이 생긴다.
완벽한 파이썬의 실행 환경이 갖추어져 있지 않으므로 바로 여기에서 디버깅을 하기엔 제약이 따른다는 것이다.

그러면 어떻게 디버깅을 해야 하는가?

1) 빌드된 디버그 버전의 바이너리를 원래의 환경에 복사해 넣고 디버깅을 한다?
소스와 바이너리의 위치가 다를 경우엔 어떻게 해야 하지?
gdb라면 간단하게 소스 위치만 지정하면 될텐데, Visual Studio의 IDE 환경에서도 이게 가능할까?

2) 소스 디렉토리에 필요한 나머지 파일들을 복사해 놓고 디버깅?
파이썬이 비록 인스톨러로 설치가 되긴 하지만, PATH에 경로를 지정하는 것 외에는 별다른 작업이 필요하지 않은 것 같던데? 아닌가?
그리고 Windows/system32 폴더에 python27.dll이 복사되어 있는 것도 보았다.



먼저 2번의 방법을 좀 더 생각해 보다가, 이런 의문이 떠 올랐다.
- 맨 처음의 NumPy와 SciPy를 설치할 때도 특별히 파이썬의 위치를 지정하지 않았지만 알아서 설치가 되었다. 이건 어떻게 가능했을까? (PATH를 보고? 설치 프로그램인 pip의 위치를 기준으로?)
: 이걸 새로 빌드된 환경에서 시험해 보려고 했는데, 아무리 찾아봐도 pip가 보이질 않는다.
 그냥 복사를 해서라도 해 볼까 하다가 걍 포기.

- 파이썬 인터프리터에서 import를 하면 해당 라이브러리를 잘 찾아낸다. 어떻게 가능한걸까?
: 구글에서 "python import dir order"로 검색을 하자 파이썬의 문서에서 "module-search-path" 부분을 찾아서 보여준다.
https://docs.python.org/2/tutorial/modules.html#the-module-search-path

위 링크에서 언급하는 sys.path를 직접 확인해 보았다.

Python의 sys.path

새로 빌드된 Python의 sys.path
환경변수인 PATH에 지정된 경로와는 상관없이, 현재 실행된 위치를 기반으로 내부의 탐색 경로가 바뀌는 것을 알 수 있다.


다시 위의 디버깅에서 1번의 방법에 대해 알아보니, 빌드시에 생성된 pdb에 소스의 위치 정보가 있으므로 바이너와 소스의 위치가 달라도 소스 레벨의 디버깅이 가능하다고 한다......정말일까?

그래서 빌드된 exe, dll, pdb 파일들을 모두 원래의 파이썬이 설치되어 있던 폴더에 복사했다. (원래의 exe와 dll은 다른 폴더에 피신 시켜 둠.)

새로 빌드한 파일들을 파이썬 설치 폴더에 복사

그런데.... 안된다.
Visual Studio에서 읽어 들여 보았으나, 디스어셈블 코드만 보여 줄 뿐, 소스를 찾지 못한다.
심지어 소스 폴더를 지정하는 옵션도 없다.


그래서....Visual Studio에서 프로젝트의 속성을 수정했다.
Python 프로젝트의 속성에서 Debugging의 Command 항목 수정

저기에 직접 디버깅할 실행 파일 이름을 지정해주면 된다.
Debugging 위의 General에서 Output Dir을 바꿔주는 것도 방법이긴 한데, 수정 - 빌드 - 디버깅 작업이 그리 많지 않을거라 생각하기에 최소한만 건드리는 방법을 택한 것이다.

그리고 Visual Studio에서 Start Debugging(F5)을 하면 다음과 같이 나온다.
여기에서 sys.path로 작업중인 디렉토리를 확인할 수 있다.
Start Debugging후에 sys.path로 작업중인 위치 확인.

그리고 그토록 알고자 했던 그 문제점이 재현되는지 확인하기 위해 "from scipy import special, optimize"를 입력하자...

기존의 문제점이 재현되는지 확인....어?
출력되는 메시지가 다르다. 에러는 에러인데....뭔가 이상하다.

아까 디버그와 릴리즈 버전의 바이너리를 모두 복사해 놓은 상태이기에, Visual Studio를 거치지 않고 바로 실행해서 다시 확인해 보았다.


먼저 디버그 버전의 경우..

디버그 버전
역시나 맨 처음과는 다른, Visual Studio를 거쳤을 때와 같은 에러 메시지.

그럼 릴리즈 버전의 경우는...
릴리즈 버전
애초에 보았던 것과 동일한 에러 메시지.

이런 x같은 경우를 보았나.

디버그 버전과 릴리즈 버전의 동작이 서로 다르단 말인가? 왓더뻐~어~억 쒜트 쒜~에~트

메시지를 차근 차근 확인해 본 결과, 릴리즈 버전은 numpy를 먼저 다 import하고 난 후에 scipy의 special을 import하는 중에 에러가 발생했고, 디버그 버전은 numpy를 import하는 과정에서부터 에러가 발생한 것으로 보인다.


침착하고.....
이 문제점이 내가 빌드하는 과정에서 발생한 것인지, 파이썬 자체의 소스 혹은 빌드 구성에 문제가 있는 것인지 알려면 빌드 로그를 모두 꼼꼼하게 확인해 보아야 한다.

그리고 애초에 문제가 되었던 부분에 대한 확인은, 당장은 릴리즈 버전으로 밖에 할 수 없는 상황이고, 이것도 메시지 출력을 이용하거나, 의심되는 부분을 바로 수정해서 확인해 보는 방법 뿐인 듯 하다.

단, 하나의 문제점 때문에 너무나 많은 과정을 거치고 있고, 자꾸 곁가지를 치면서 목표의식마저 흐릿해져 가고 있는 듯 하다.

디버그 버전과 릴리즈 버전의 문제를 확인하기 앞서서, 본래의 문제점을 먼저 해결하길 나 자신에게 바래 본다.

2014년 10월 30일 목요일

버그와 디버깅에 관한 단상

디버깅에 집중하다 보니,
마지막 포스팅에서의 쓸데없는 생각, 자기 자신을 (온전히) 디버깅할 수 있는 프로그램은 없다...

오늘 밤, 아니군 어제 밤, 간만에 산책을 하면서 들어 온 생각
자기 자신을 디버깅 할 수 있는 머신은 과연 불가능한 걸까?
(현재의 프로그램이라는 좁은 제한을 벗어나 모듈화 되고 병렬처리가 가능하고 자기 복제도 가능한 등의 H/W와 S/W를 모두 갖춘 진보된 장치라면 가능하지 않을까?
그리고 이런 기술적인 문제를 넘어서의 고차원적인 문제를 생각해 본 것이다.)

극장판 애니메이션 [공각기동대]의 초반부에 이런 대사가 나온다.
버그가 없는 프로그램도 없지만, 디버깅이 불가능한 프로그램도 없지.




그런가?

2001: A Space Odyssey에는 HAL 9000이라는 인공지능 컴퓨터가 등장한다.
탁월한 능력을 지녔으며 우주선의 모든 것을 관리/제어하는 중요한 역할을 한다.
하지만 지구와의 통신을 위한 위성 안테나 모듈에 문제가 있다는 잘못된(?) 판단을 내린다.
우주선의 항해사들은 HAL 9000에 버그가 발생했다고 생각을 하지만 HAL 9000은 그렇지 않다고 생각한다.

버그를 제거하는 디버깅의 시작은 버그를 인식하는 것이다.
HAL 9000이 제아무리 뛰어나다 해도 그것이 버그라고 인식하지 못한다면 디버깅은 불가능하다.

그렇다면 과연 그것이 버그였을까?
엄격하게 따지자면 그건 버그가 아니었다.
그 문제를 보는 이의 시각에 따라 옳고 그름이 갈리기 때문이다.
그리고 HAL 9000은 나름대로의 이유가 있었기에 안테나 모듈의 문제를 제기했던 것이다.
하지만 항해사들의 입장에서는 문제 없는 모듈에 문제가 있다고 교체를 강요하는 HAL 9000에 큰 버그가 있다고 생각했던 것이다.

만약 모든 입장, 모든 치우침, 모든 편견에서 자유로워진다면 버그라고 인식할 것이 없는 건 아닐까?
결국은 극히 제한된 일부로써의 편향된 입장을 가지게 되면 버그로 인식할 것은 매우 많아지는 것이고, 버그는 그 자체가 문제가 아니라, 그걸 바라보는 이의 편향된 생각이 만들어낸 왜곡된 환상이었던 건 아닐까?


일본의 만화가 우라사와 나오키의 [플루토]를 보면 이런 이야기가 나온다.
최고의 로봇을 만들기 위해 고민을 하던 텐마 박사는 결국 모든 인류의 특성을 한데 모아서 자신의 로봇에게 주입을 했고, 기동을 시켰으나 결국 그 로봇은 깨어나지 못했다고 한다. 모든 인류의 특성을 가진 롯봇은 결국 자신의 주체를 혼동하여 결정하지 못했기 때문이라고...




2013년 7월 7일 일요일

Appler 디버깅하기 ___ 4

터보디버거가 어째 좀 불안해서 디버깅을 하다가 새로 시작하곤 해야 하는 문제가 있었기에 의욕이 급속히 감소 되었더랬습니다. (지난 포스팅 말미에 썼던 문제점입니다.)

거기에 레퍼런스로 사용하던 Oracle의 VirtualBox도 말썽을 부렸습니다.
4.2.14 버전으로 업데이트하고 나니 키보드도 제대로 작동하지 않는 문제가 발생하더군요.
처음엔 제가 사용하는 리눅스의 사양이 너무 딸려서 시스템의 오작동이 아닌가 생각 했는데, 윈도우즈용도 마찬가지인 것을 확인하고는 참...어이가 없었습니다.
Oracle이 겨우 이런 회사인가....
며칠후에 4.2.16으로 업뎃하고 나니 다행히 정상으로 돌아오긴 했습니다.

암튼 이래저래 시간은 흘러가고 디버깅은 지연되고....하다가 겨우 다시 붙잡았습니다.

첫번째 디버깅 타겟으로 잡은 것은 Path&Filter 부분이었습니다.
Path&Filter 부분에서 Path와 Filter 사이에 backslash가 없었던 문제부터 디버깅을 해 보기로 했습니다.

찾아보니 Path, Filter, PathFilter라는 변수가 있었고, 이 변수를 채우는 프로시져로 ReadDirectory가 있었습니다.

먼저 VirtualBox에서 이 부분을 디버깅하면서 나온 정상적인 결과를 보겠습니다.
int 21h(ah=60h)를 호출한 후

Path 변수를 확인해 보니 문자열의 마지막에 Backslash가 있습니다.
터보디버거에서는 어쩐 일인지 Path 문자열을 Watch에 등록했는데, 앞 두글자만 보여주더군요. 그래서 Data Inspecting으로 주소를 확인하고 View-Dump로 메모리를 확인해 보니 문자열 모두를 볼 수 있었습니다.
VirtualBox에서는 정상으로 작동하고 있었기에 이걸 정상적인 결과로 가정했습니다.

소스에서 보는 DOS interrupt인 int 21h에 대한 자료를 찾아보았습니다.
Ralf Brown이라는 분이 정리한 자료가 있는데, 얼핏 보았는데 상당히 자세한 듯 합니다.

우선 2개의 interrupt에 대한 것만 보면,
INT 21h(AH=60h) TRUENAME

INT 21h(AH=1Ah) Set DTA

그러면 같은 부분을 DOSBox에서 실행했을 때는,
DOSBox에서 디버깅한 경우, Backslash 없음.

어느쪽이 맞는건지 모르겠지만 VirtualBox와 DOSBox가 서로 다르게 작동한다는 것은 확실합니다. 그리고 Appler가 실제 MS-DOS를 기반으로 개발된 것을 감안한다면 VirtualBox의 작동방식이 맞다고 보는 것이 타당할 것입니다.

근본적으로 저 문제를 해결하려면 DOSBox를 수정하는 것이 맞을테고, 수정의 용이함이나 Side Effect를 최소화하면서 Appler를 제대로 구동하려면 Appler를 수정하면 될 것입니다.


어셈블리 프로그래밍에 능숙하지 않은 관계로 소스의 수정은 뒤로 미루고,
다음 문제를 디버깅해 보기로 했습니다.
디렉토리 내의 파일이름들 리스팅에도 문제가 있었고, 사실은 이게 제일 큰 문제였습니다.

처음엔 조금 막막했지만, 흔히들 디렉토리 내의 파일 이름들을 얻어 오는 C의 함수로 FindFirst()와 FindNext()를 사용했던 기억이 났습니다.
그리고 소스내에서 동일한 이름의 매크로가 있는 것을 찾아냈습니다.
FindFirst, FindNext 매크로
매크로 무지 간단합니다.
그냥 DOS Interrupt 호출이네요.
아까 보았던 자료에서 위의 Interrupt에 관한 부분을 찾아 보았습니다.
INT 21h(AH=4Eh) FindFirst

INT 21h(AH=4Fh) FindNext

그런데...정말 혹시나 하는 생각이 들었습니다.
앞서 디버깅한 Path&Filter의 문제로 디렉토리의 파일 이름들도 문제가 생긴게 아닐까 하고..

그래서 디버깅 하면서 바로 수정해서 확인 해 보았습니다.
Path의 마지막에 Backslash(5Ch) 넣어주기

Backslash가 들어갔습니다.

Path&Filter 뿐 아니라 Directory 부분도 정상적으로 나옵니다.

Disk Manager 화면으로 진입하면 ReadDirectory라는 프로시져가 2번 호출이 됩니다.
두번 모두 마지막에 Backslash(5Ch)를 넣어주면 모든게 정상이 됩니다.

이젠 DOSBox의 개발진에게 이 문제를 리포트하든지,
내가 직접 DOSBox를 수정하든지, Appler를 수정하든지...하면 되겠네요.

2013년 6월 8일 토요일

Appler 디버깅하기 ___ 3

이제 빌드가 다 되었으니 디버깅을 하기 전에, 정상적으로 작동을 하는지는 확인해 봐야겠죠?
필요한 파일들(*.rom, *.dsk 등등)을 빌드한 폴더에 복사해 넣고서 확인해 보았습니다.


초기화면

데모화면

로드런너

디스크매니저. 문제도 그대로...

디버거

2013년 6월 6일 목요일

Appler 디버깅하기 ___ 2

일단 빌드해서 startup.asm은 무사히 넘어갔지만,
다음으로 걸린 부분은 floppy.inc 입니다.

emulate.asm을 컴파일하다가 floppy.inc에서 에러가 났습니다.

에러가 난 부분입니다. 역시 잘 모르겠지만 뭔가 기묘하네요.

CurrentDrive와 OtherDrive를 찾아보니 저렇게 선언되어 있는데 이것도 기묘합니다.OTL

우선은 xchg라는 인스트럭션이 뭔지 몰라서, 다시 터보 어셈블러 퀵 레퍼런스를 참조했습니다.
xchg는 값을 바꿔주는 거군요. 일종의 swap이네요.

그런데 이번에 문제가 되는 부분은 앞서보다 복잡하네요.
CurrentDrive/OtherDrive가 사용되는 곳이 많아서 종잡기도 힘들고,
선언된 곳의 저 모양새는 대체 무엇인지 이해가 되질 않습니다.

Drive_S가 배열인걸까요?
그래서 0번은 CurrentDrive, 1번은 OtherDrive로 사용되는 거...
이건 매뉴얼을 다시 찾아 보기로 하고...

Drive_S라는 걸 찾아보니 일종의 structure로군요.
Globals.inc에 선언되어 있습니다.

위에서 보았던 CurrentDrive와 OtherDrive의 선언 부분의 의미를 알아냈습니다.
CurrentDrive    Drive_S    <0>
Drive_S 타입으로 변수 CurrentDrive를 선언하면서, 초기값 0을 할당한 것입니다.
Drive_S는 스트럭쳐로 여러개의 값을 가져야 하지만 ?로 표시되어 있는 ID에 대한 것만 초기화 해 주는 것인 듯 합니다.

터보 어셈블러의 User's Guide 12장에 있는 해당 부분은 다음과 같습니다.



그런데, 아직도 에러가 난 부분의 의미가 뭔지 모르겠습니다.
CS:OtherDrive[SI-1]-CurrentDrive

각 부분의 의미도 정확히 파악이 되지 않으니 전체가 뭘 의미하는지도 모르겠고,
[]이 배열인 듯 하면서도, 선언된걸로 보면 배열이 아니었고...상상력이 부족한걸까요?

좀 크게 보겠습니다.
DeviceSelect 프로시져
하나의 프로시져 였습니다. DeviceSelect라는...
경우에 따라 DeviceSelect10 혹은 DeviceSelect20을 수행하는데, 문제가 되는 부분은 DeviceSelect10인 경우입니다.

이 프로시져를 호출하는 경우를 좀 봐야겠습니다.
ResetFloppy 프로시져

C0EBr/C0EBw 레이블

아래쪽의 C0EBr/C0EBw는 레이블 이름도 이상하고, 시작이 어디서부터인지도 명확하지도 않고 헷갈립니다.
반면에 위쪽의 ResetFloppy는 뜻이 비교적 명료합니다.

좀 더 자세히 분석해 보기 전에 몇가지 모르는 것들을 찾아보았습니다.

Save/Restore 매크로

자주 나오는 Save/Restore는 매크로였고 간단하게 push, pop으로 구현되어 있습니다.

IRP 지시어

IFNB 지시어
매크로에서 사용된 IRP와 IFNB 지시어에 대한 설명이구요,
IRP로 Repeat를 하는데, 인자들 리스트를 r로 정의하였고 IFNB에서 리스트가 비어있는지 검사하면서 반복하는 듯 합니다.

even 지시어
프로시져의 시작부분에 있던 even이라는 지시어에 대한 설명입니다.
16 bit memory alignment를 위해서 짝수번지에 맞추라는 의미인 듯 합니다.

lods 인스트럭션
메모리에 있는 것을 읽어서 al(혹은ax, eax)에 넣는 작업을 합니다.
REP 혹은 LOOP로 반복구간을 정하나 봅니다.


다시 소스를 확인해 보겠습니다.

호출시 al에 담긴 값이 CurrentDrive의 ID와 일치하면 DeviceSelect20을 수행하고 프로시져를 마칩니다. 즉, 바꿀 필요가 없다는 의미이겠죠.
그렇지 않고 바뀌어야 한다면 WriteTrack을 호출하고 돌아와서 CurrentDrive의 값을 하나씩 읽어와서 OtherDrive에 있는 값과 바꿔치고, OtherDrive의 값을 다시 CurrentDrive에 넣습니다.
여기에서 [SI-1]이 사용된 이유는 그 위에서 lods byte ptr CS:[SI]를 수행하면서 si의 값이 증가되었기 때문인 듯 합니다.
그렇다면 어째서 CS:OtherDrive[SI-1]-CurrentDrive일까요?
CurrentDrive를 왜 뺀걸까요?

사실 모르겠습니다. 그리고 CurrentDrive를 빼지 않는게 맞는 것 같습니다만....
일단 저 부분을 제 생각대로 고치고, 나중에 확인해 보겠습니다.
-CurrentDrive 제거

뜨악...그래도 에러?
대충 메시지 보고 찍어서 다시 수정해 보았습니다.
두번째 에러는 실수로 건드렸나 봅니다.
byte ptr 추가

이제야 빌드 완료입니다.

음...디버깅을 한다고 했는데, 겨우 빌드까지만 다 했습니다.
빌드만 했는데 진이 다 빠진 느낌입니다.
오늘은 여기까지만....