레이블이 vim인 게시물을 표시합니다. 모든 게시물 표시
레이블이 vim인 게시물을 표시합니다. 모든 게시물 표시

2014년 11월 5일 수요일

Vim 파일 저장 오류 __ 10

최종 오류의 원인으로 등장한 stat() 함수.
하지만 DOSBox에서는 실패한 이 함수의 결과가 시험용을 작성한 코드에서는 성공했다.
어째서 다른 결과가 나온 걸까?

gdb를 이용해서 어셈블리 코드 레벨의 실행 절차마저 세세하게 따져봐야 할 지경에 이르게 되었다.
하지만 Linux gdb에서의 어셈블리 코드의 표기가 MS-Windows 계열에서 사용하는 표기와 너무 달라서 해독이 난감해 하던 터였다.

일단, 지난 번에 만든 stat() 함수를 사용하는 테스트용 C program의 Assembly code를 생성해 보았다.
실행 결과야 이미 알고 있으니 최대한 단순하게 만들어서 Assembly code도 간단하도록 간략화 시켰다.

stat() 테스트 프로그램

gcc에서 -S 옵션을 사용하면 Assembly Code를 출력한다.
gcc -S 옵션
그렇게 만들어진 Assembly Code는...
테스트 프로그램의 Assembly Code
역시나 뭔가 참 어색하다.
상수값에 $를 쓴다거나 레지스터 이름에 %를 붙인다는 걸 알 수 있지만, 오퍼랜드의 순서가 바뀌어 있고, %gs:20 ?? 156(%esp) ??? 이건 대체 뭘까?

Linux용 Assembly 공부를 해야 하나 하고 관련 서적과 자료들을 인터넷에서 검색을 했다.

헌데... CPU는 동일한 인텔 계열인데 굳이 Assembly 공부를 다시 해야 하나?
OS에 관련된 부분을 제외하면 단순히 표기법만 다른 것 아닌가?

그렇다면 gcc에서 Assembly Code를 출력할 때 이 표기법을 바꿀 수 있지 않을까?
전에 어디에선가 본 기억으로는 Assembly Code의 표기법은 AT&T와 Intel의 방식으로 나뉘어져 있으며, AT&T 표기법은 Unix 계열에서, Intel 표기법은 MS-Windows 계열에서 주로 사용한다고 했던 것 같다.
gcc는 MS-Windows용으로도 porting되어 있으니 양쪽 표기법을 모두 지원할 것이라 생각이 들어 gcc 매뉴얼을 다시 살펴 보았다.

그래서 찾아낸 옵션, -masm=intel로 지정해주면 된다.
-masm 옵션
그렇게 만들어진 Assembly Code,
테스트 프로그램의 Assembly Code. Intel 표기법
이제야 조금 익숙해진 모양새.

그렇다면 gdb에서도 Assembly Code룰 보여줄 때 표기법을 바꿀 수 있지 않을까?
그래서 gdb 매뉴얼을 찾아 본 결과,
gdb의 disassemble 옵션

2014년 10월 25일 토요일

Vim 파일 저장 오류 __ 8

디버그 메시지를 확인하던 중, 메시지의 출력이 되지 않아 확인을 하지 못하고 중단이 되었었다.
SetFileAttr()
하지만 추가적으로 확인해 본 결과, 메시지의 출력은 정상적으로 되었다.
단지, 내가 추가한 부분에 걸리지 않았던 것 뿐.
DOS_SetFileAttr()이 호출되면 중간에는 아무런 문제가 없이 마지막의 GetFileAttr()까지 오는 것이었다.

하지만 소스에서 보듯이 GetFileAttr()은 함수포인터로 호출되므로 정확한 파일 이름을 알 수가 없다.
GetFileAttr() 검색
가상함수인 GetFileAttr()은 드라이브의 종류에 따라 각기 달리 구현되어 있다.
확인해 본 결과 이번 경우에는 drive_local.cpp에 있는 함수가 호출되는 것을 알게 되었다.

그래서 GetFileAttr()에 메시지 추가.
문제가 발생하는 부분은 stat()함수가 실패했기 때문이었다.
GetFileAttr()

stat() 도움말

stat() 도움말 (계속)

stat() 도움말 (계속)

다시 빌드하고 디버그 메시지 확인...

메시지를 봐도 특별히 이상한 점은 찾을 수가 없다.

위의 stat()에 대한 도움말을 읽어 보니, 실패했을 경우에는 errno에 에러 코드를 설정한다고 한다.
그래서 메시지에 errno의 값을 함께 출력하도록 수정.
GetFileAttr()에 메시지 추가

디버그 메시지로 출력된 errno의 값은 2.
debug 출력

errno = 2는 "No such file or directory"...
파일이 없다니....
errno 값의 의미

완전히 막혀버린 상황.
stat() 함수는 기본적인 C 함수이기 때문에, 더 이상의 디버깅을 해도 소용이 없게 된다.
이 문제는 vim의 문제도 아니고 DOSBox의 문제도 아닌 Ubuntu의 문제가 되기 때문이다.

지금으로썬 Ubuntu(혹은 Linux)에서의 DOSBox는 문제가 있다는 것으로 결론을 내릴 수 밖에 없다.

2014년 10월 24일 금요일

Vim 파일 저장 오류 __ 7

예전에 만들어 두었던 debug 버전의 DOSBox를 실행해 보았다.


디버그 터미널에는 여러가지 정보가 표시된다.
DOSBox 화면에서 Alt-Pause를 누르면 디버그 모드를 진입하게 된다.

지금은 디버그 모드로 진입하지 않고 단지 디버그 터미널에 출력되는 내용만 확인해 보았다.

먼저, 기존에 존재하던 "NEWFILE"이라는 파일을 vim으로 열었을 때 디버그 터미널에는 다음과 같은 내용이 출력된다.
"vim NEWFILE"을 실행

파일을 수정하고 ":w"를 입력하여 저장을 시도했다.
역시나 저장되지 않았고, 디버그 터미널에는 다음과 같은 내용이 출력되었다.
수정 후 저장 시도
[Set File Attribute]는 not supported라는 메시지를 출력한다.
아무래도 이 부분이 의심스럽다.

그렇다면 vim이 아닌 다른 에디터는 대체 어째서 문제가 없다는 것일까?
edit를 이용해서 같은 파일을 열어 보았다.
"edit NEWFILE"을 실행

수정을 하고 저장을 해 보았다.
수정 후 저장
Attribute 따위는 아무것도 없다.
file open command의 파라미터가 0인지 1인지에 따라 load/save를 수행하는 듯 하다.
그냥 저장만 하고 끝.

DOSBox의 디버그 메시지에 대해서 자세히 확인하기 위해서는 DOSBox의 소스에서 해당 메시지를 찾아 봐야 하겠다.

DOSBox 소스 검색
"file open command"는 dos_files.cpp의 DOS_OpenFile()에서 출력하는 메시지로, 다음에 오는 숫자는 다음과 같은 의미를 가지고 있다.
0 : read
1 : write
2 : read & write

"file create attributes"는 dos_files.cpp의 DOS_CreateFile()에서 출력하는 메시지로, 다음에 오는 숫자가 attribute를 나타낸다.

"Set File Attributes"는 dos.cpp의 DOS_21Handler()에서 출력하는 메시지이다.
MS-DOS Interrupt Handler를 에뮬레이션 하는 부분인데, 해당 메시지가 출력되는 Interrupt는
AH = 0x43, AL = 0x01, Set File Attribute라고 명시되어 있는 부분이다.

MS-DOS Interrupt, Set File Attributes

그런데 해당 소스를 보면 좀 이상하다.
Interrup Handler가 구현이 안 된것도 아닌데, 아래쪽의 처리를 하기도 전에 "not supported"라는 메시지를 출력하고 있다는 것이다.

일단, MS-DOS Interrupt 21h, ah = 0x43, al = 0x01에 대한 설명을 찾아보면,
디음과 같은 상세한 설명을 볼 수 있다.
MS-DOS Interrupt 21h, ah=0x43, al=0x01

DOS_SetFileAttr()의 소스는 다음과 같다.
소스를 보니, 주석에 설명한 바와 같이 실제로는 파일의 속성을 바꾸지는 않고 파일의 속성을 읽어 올 뿐이었다.
DOS_SetFIleAttr()

그러면 과연 어떤 부분에서 문제가 되어서 에러가 발생하는 것인지 확인하기 위해, 디버그 메시지를 추가해 보기로 했다.
dos.cpp에 메시지 추가

dos_files.cpp, DOS_SetFileAttr()에 메시지 추가

이제 DOSBox를 다시 빌드해야 하는데, 예전에 어떤 설정으로 빌드했는지 모르니 처음부터 다시해야 한다.
디버그 모드로 빌드하기 위해 "./configure --enable_debug=heavy"
DOSBox 빌드, configure

그리고 make
DOSBox, make

이제 DOSBox를 실행하고 아까와 동일하게 "vim NEWFILE" 실행한 경우의 디버그 메시지들을 확인해 보자.
"vim NEWFILE"의 디버그 메시지

그리고 저장했을 때의 디버그 메시지는...
":w"로 저장했을 때의 디버그 메시지
지정한 파일의 속성은 archive(0x20)이고, 에러 코드(2)의 의미는 "file not found"라고 한다.

그런데, 더 구체적인 오류 메시지인 DOS_SetFileAttr()의 메시지는 전혀 출력이 안되었다.
무슨....?
로그 메시지 출력에 어떤 제한이 있는지 다시 확인해 봐야 하겠다.
어차피 실제 속성을 바꾸지 않는 함수인만큼, 오류의 원인을 확인해 보고 별 문제가 아니라면 그냥 성공한 것으로 리턴하게 만들어야 하지 않을까?

나머지는 다음에...

2014년 10월 21일 화요일

Vim 파일 저장 오류 __ 5

Borland C++의 매뉴얼은 워낙에 구석기 유물인지 찾기가 곤란...
그래서 BC++ IDE의 Help를 활용하기로 했다.

Borland C++ IDE help

_chmod()의 도움말 화면
_chmod의 help

두번째 인자 func가 0이면 get, 1이면 set 기능을 하게 된다.
_chmod의 help (계속)

세번째 인자인 DOS file-attribute는 다음과 같다.
file attribute
실제 값을 확인하기 위해서 DOS.H를 확인해 보았다.
DOS.H
여기서 지난번에 추가한 디버그 메시지를 다시 확인해 보자.
추가했던 디버그 메시지
위의 메시지에서 p=32(0x20)은 mch_open()에서 세번째 인자로 사용될 perm이라는 변수에 할당된 값이며, _chmod() 함수를 이용해 얻은 값이다.
즉, 변수의 이름은 UNIX 파일 시스템의 권한(permission)을 의미하는 듯이 보이지만, MS-DOS 파일 시스템에서는 권한이라는 것이 없기에 파일의 속성만을 나타내고 있는 것이다.

다시 한번 에러가 발생한 부분의 code를 살펴보자.
FILEIO.C
위의 mch_open()이 실패한 것이 문제였고, mch_open()의 세번째 인자로 perm 변수를 사용하고 있음을 볼 수 있다.
하지만 이 소스만 보아도 문제의 소지가 있음을 알 수 있는 것이, 0666, 0777은 UNIX 파일 시스템에서만 유효한 권한(permission)이기 때문이다.
DOS의 파일 속성(읽기,쓰기,숨김,시스템,디렉토리)과 UNIX의 권한(소유자,그룹,관리자의 읽기,쓰기,실행 권리)를 서로 같은 것으로 간주해서 다루고 있다는 것이다.

그러면 정말로 이렇게 온동하여 처리한 것이 문제가 되는 것일까?
앞서 디버그 메시지에서는 perm이 0x20이었음을 확인했다.
8진수인 0777은 0x1FF, AND 연산을 한다해도 여전히 0x20이 되므로 결과적으로는 문제가 되지 않을 것으로 보인다.
그러면 뭘까?

mch_open()을 다시 확인해 보자.
mch_open()은 open()로 연결되어 있다.
mch_open() 매크로
open()의 help를 확인해 보자.
open()의 help
세번째 인자인 mode는 생략이 가능한 것으로 나와있다.
open()의 help (계속)
mode를 더 확인해 보니,
mode의 help
_chmod()의 file-attribute와는 다른 상수들이다.
실제 값은 어떨까?
sys/stat.h의 mode
이렇게 보니 _chmod()와 open()은 전혀 다른 계통의 함수들로 연계하여 사용하기에는 문제가 있어보인다.
open()은 기존의 UNIX 파일 시스템과의 호환성을 염두에 두고 MS-DOS에 포팅이 되었다고 한다면 _chmod()는 MS-DOS의 파일시스템에서만 사용할 수 있게 독자적으로 만들어진 것으로 보인다.


그렇다면, mch_open()의 세번째 인자의 값을 바꾸어주면 문제가 없을까?
하지만 정말 이 부분이 문제였다면, Windows에서 DOSBox를 구동하여 vim을 사용했을 때에도 동일한 문제가 발생해야 한다.
암튼 일단은 세번째 인자를 고쳐서 해 보기로 하자.

vim의 소스들을 살펴보니 대부분 세번째 인자로 0을 사용하고 있으며, 위의 stat.h에서도 일반적인 파일은 0을 사용한다고 되어 있기에 무조건 0을 사용하도록 수정해 보았다.
FILEIO.C
DOSBox에서 다시 make
make
그리고 기존의 파일을 열어서 수정하고 다시 저장해보니...
save
역시 예상과 같이 이것이 문제가 아니였던듯....

2014년 10월 18일 토요일

Vim 파일 저장 오류 __ 4

일단 터보 디버거는 미뤄두고, 간단히 메시지로 디버깅...

메시지 출력에 원하는 정보를 넣어서 출력하게 하려면 소스를 조금 수정해야 한다.

일단 메시지용 변수를 추가하고, 출력할 메시지를 만드는 부분을 추가해야 한다.

메시지 출력용 변수 추가 (#2781)

출력할 메시지 만들기 (#3970,#3971)

소스의 수정은 Ubuntu 상에서 했으므로, DOSBox에서는 파일이 변경된 것으로 인식할지 아닐지 몰라서 touch 한번 해주고 make를 해 보았다.
빌드 성공

우선 newfile 이라는 이름으로 새 파일을 만들어 본다.
새 파일 만들기

새 파일 만들기는 이전에 그랬듯이 성공.
저장 성공

이번에는 수정하기.
수정 실패, 메시지 확인.
역시나 실패. 메시지는 원했던 대로 출력되었다.
변수 값은 append = 0, forceit = 0, perm = 32

이 값들의 의미를 확인하기 위해 다시 소스를 보자.

append가 0인 것은 약간 의외....이지만 큰 영향은 아닌 듯 보임.
forceit은 당연히 0일 것이다.(":w!"가 아닌 ":w"였으니까..)
그런데 perm은 32? 8진수로 바꾸면 040?
UNIX 파일시스템이라면 소유자의 권한은 없고, 그룹은 쓰기 권한만 있는 셈?
하지만, 이건 MS-DOS의 FAT 파일시스템이므로 무슨 의미인지 정확하지가 않다.
그런데도 소스에서는 0666, 0777과 같이 UNIX 파일 시스템에서의 권한과 동일하게 다루고 있는 모습은 의문이다.

우선 perm의 값이 어떻게 32가 나온것인지 확인해 보기 위해 소스를 따라가 보자.
위의 mch_open() 이전에 perm 값을 구해 오는 부분은 다음의 mch_getperm() 부분이다.

perm을 구하는 부분
 mch_getperm()은 다시 vim_chmod()를 호출한다.
mch_getperm()
 vim_chmo()에서는 _chmod() 함수를 호출한다.
vim_chmod()
_chmod()는 UNIX의 chmod() 함수와는 다른 것으로 보인다.(인자의 갯수도 다름)

Borland C 매뉴얼을 찾아 봐야할 듯...