#include <stdio.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <windows.h>
#define DR_NUM 10 // 출력할 Register 개수
#define MAX_PROGRAM_SIZE 0x10000 // 적재할 프로그램의 최대 크기
#define SECTION_SIZE 512
#define DEFAULT_DISPLAY_LINE 16 // 메모리 출력 시 기본 출력 행 수
#define ROW_LINE 16 // 메모리 출력 행 수
// 입력할 수 있는 명령 목록
#define CommandDisplay 0x00 // Command Display when wrong Command
#define MemoryDisplay 0x01 // Memory Display Command
#define MemoryModify 0x02 // Memory Modify Command
#define RegisterDisplay 0x03 // Register Display Command
#define ProgramLoad 0x04 // Executable Program Load
#define ProgramRun 0x05 // Loaded Program Execute
#define MemoryClear 0x06 // Memory Clear Command
#define CodeDisplay 0x07 // Code Area Display Command
#define DataDisplay 0x08 // Data Area Display Command
#define StackDisplay 0x09 // Stack Area Display Command
#define MemoryStatusDisplay 0xFD // Memory Status Display Command
#define NoInput 0xFE // 입력이 없을 경우
#define ExitProgram 0xFF // Exit Command
char *R_NAME[] = // 레지스터 상태를 출력할 때 사용되는 배열
{
"EFL", "EIP", "EDI", "ESI", "EBP",
"ESP", "EBX", "EDX", "ECX", "EAX"
};
typedef struct // 레지스터 정보가 저장되는 구조체
{
int efl;
int eip;
int edi;
int esi;
int ebp;
int esp;
int ebx;
int edx;
int ecx;
int eax;
} context;
struct // 명령어와 숫자를 대응시키기 위해 사용
{ // 미리 Define된 값과 대응
unsigned char *name;
unsigned char f_num;
} GROUP[] =
{
"Q\n" , ExitProgram,
"QUIT\n", ExitProgram,
"MC\n", MemoryClear,
"MD\n", MemoryDisplay,
"MM\n", MemoryModify,
"R\n" , RegisterDisplay,
"P\n" , MemoryStatusDisplay,
"LOAD\n", ProgramLoad,
"GO\n", ProgramRun,
"\n" , NoInput,
"CODE\n", CodeDisplay,
"DATA\n", DataDisplay,
"STACK\n", StackDisplay,
"HELP\n", CommandDisplay,
0 , 0,
};
//enum으로 수정할 것!!!
unsigned char File_Name[255]; // 읽어올 파일 이름의 임시 저장소
static unsigned char *mem; // 동적할당의 시작 위치
static unsigned char *mem_end; // 동적할당의 끝 위치
static unsigned char *code; // 프로그램 저장공간의 시작 위치 -code
static unsigned char *data; // 프로그램 저장공간의 시작 위치 -data
unsigned char Load_Flag; // 프로그램이 로드 유무 표시
unsigned char Display_Flag; // 메모리 값 출력시 계속해서 출력하는
// 경우를 위해
int File_DS; // 저수준 파일의 데스크립터
static context stat_old; // 기존의 레지스터 값 저장
// 어셈블리로 구현한 함수
extern unsigned char md(int); // Memory Display Function By Assembly
extern void mm(int, char); // Memory Modify Function By Assembly
extern void STST(context *); // STore STatus
extern void LDST(context *); // LoaD STatus
// C로 구현한 함수
void AddressDisplay(); // 함수, 변수 등의 주소 값 출력
void MDFunction(unsigned int *); // 주소를 입력 받아 그 곳의 값 출력
void MMFunction(unsigned int *); // 주소를 입력 받아 그 곳의 값 수정
void RFunction(); // 레지스터 상태 출력
void PRFunction(); // Program Run Function
void CDFunction(); // Command Display Function
void go(); // Program Run Function
void load(); // Program Load Function
void Clear_mem(); // Dynamic Memory Clear Function
unsigned char StringToNum(char *); // Command String to Number Function
void MSDFunction(unsigned int *, unsigned int); // 주소의 값 출력
void Address_Check(unsigned int *); // Address Check Function
void main ()
{
unsigned char out = 0; // 명령의 Define된 변환 값 저장
unsigned char Command[255]; // 사용자가 사용하는 명령어를 저장
unsigned int addr = 0; // 메모리 주소값을 입력 받아 저장
context stat_new; // 레지스터 값의 임시 저장
mem = (unsigned char *)malloc(MAX_PROGRAM_SIZE * 2); // 128Kbyte 동적 할당
if (NULL == mem)
{
printf("메모리 동적 할당에 실패하였습니다.\n");
printf("모니터 프로그램을 종료합니다.\n");
return;
}
else
{
mem_end = (unsigned char *)(mem + (MAX_PROGRAM_SIZE * 2) - 1);
code = (unsigned char *)
(((unsigned int)mem & 0xFFFF0000) + MAX_PROGRAM_SIZE);
data = code + 0x2000;
Clear_mem();
}
STST(&stat_old); // 초기 레지스터 상태를 저장
printf("\n\nMonitor Program is Starting....\n");
AddressDisplay();
RFunction();
printf("stat_old's Address = [0x%08X]\n", &stat_old);
while (1)
{
fflush(stdin);
putchar('>'); // 프롬프트 출력
putchar(' '); // 프롬프트 출력
fgets(Command, 255, stdin);
out = StringToNum(Command);
switch (out)
{
case MemoryClear: // 동적 할당 메모리의 초기화
Clear_mem();
continue;
case CommandDisplay: // 명령 목록을 보여줌
CDFunction();
continue;
case MemoryDisplay: // Memory Display
MDFunction(&addr);
continue;
case MemoryModify: // Memory Modify
MMFunction(&addr);
continue;
case RegisterDisplay: // Register status Display
RFunction();
continue;
case MemoryStatusDisplay: // 프로그램 주소 정보를 출력
AddressDisplay();
continue;
case ProgramLoad: // 실행할 프로그램을 적재
load();
continue;
case ProgramRun: // 적재된 프로그램을 실행
PRFunction();
continue;
case CodeDisplay: // 코드 영역 출력
addr = (unsigned int)(code);
MSDFunction(&addr, DEFAULT_DISPLAY_LINE);
continue;
case DataDisplay: // 데이터 영역 출력
addr = (unsigned int)(code + 0x2000);
MSDFunction(&addr, DEFAULT_DISPLAY_LINE);
continue;
case StackDisplay: // 스택 영역 출력
addr = (unsigned int)(mem_end - 0x00000100 + 0x00000001);
MSDFunction(&addr, DEFAULT_DISPLAY_LINE);
Display_Flag = 0;
continue;
case NoInput: // 입력 없이 엔터만 입력할 경우
if (1 == Display_Flag)
{
MSDFunction(&addr, DEFAULT_DISPLAY_LINE);
}
else
{
}
continue;
case ExitProgram: // 종료 문자를 사용하였을 경우
default:
break;
}
break;
}
free(mem); // 동적 할당 제거
mem = 0; // 재사용 금지
mem_end = 0; // 재사용 금지
code = 0; // 재사용 금지
return;
}
void AddressDisplay() // Address Display Function
/*******************************************************************************
기능 : 현재 프로그램의 주소 정보를 출력
인수 : void
반환값 : void
*******************************************************************************/
{
Display_Flag = 0;
printf("\nCode Start Address : 0x%08X\n", main);
printf( "Data Start Address : 0x%08X\n", R_NAME);
printf( "Program Load Address : 0x%08X\n", code);
printf( "Dynamic Memory area : 0x%08X to 0x%08X (%dKBytes)\n"
, mem, mem_end, (mem_end - mem + 1)/1024);
return;
}
unsigned char StringToNum(char *name) // String To Number Function
/*******************************************************************************
기능 : 명령을 입력하였을 때 대응하는 Define 숫자로 변환
인수 : 문자열형의 명령어
반환값 : 명령어에 대응하는 hex형 값
*******************************************************************************/
{
int loop_temp = strlen(name);
while (1)
{
if (0 >= loop_temp)
{
break;
}
else
{
--loop_temp;
*(name + loop_temp) = toupper(*(name + loop_temp));
}
}
loop_temp = 0;
while (1) // 구조체의 끝에 도달하면 종료
{
if (0 == strcmp(name, (*(GROUP + loop_temp)).name))
// 일치하는 단어가 검색되었을 경우
{
break;
}
else if(0 == (*(GROUP + loop_temp)).f_num)
{
break;
}
else
{
++loop_temp;
}
}
return (*(GROUP + loop_temp)).f_num;
// 일치하는 단어와 대응되는 숫자를 반환
// 일치하는 단어가 없으면 0반환
}
void MDFunction(unsigned int *addr) // Memory Display Function
/*******************************************************************************
기능 : 주소값을 입력 받아서 그 주소에 있는 값을 출력
인수 : 입력받은 값을 저장할 장소
반환값 : void
*******************************************************************************/
{
printf("메모리 주소를 입력하세요(0x%08X~0x%08X) : ", mem, mem_end);
scanf("%x", addr);
MSDFunction(addr, DEFAULT_DISPLAY_LINE); // 출력 디폴트 라인 수로 출력
}
void MSDFunction(unsigned int *addr, unsigned int print_line)
// Memory Status Display Function
/*******************************************************************************
기능 : 인수로 넘겨받은 주소로부터 ROW_LINE개 단위를 1줄로 print_line의 숫자 만큼
화면에 출력
인수 : 출력할 대상이 있는 곳의 주소값, 메모리 출력시 출력 라인 수
반환값 : void
*******************************************************************************/
{
unsigned int loop_temp = 0; // 반복문을 위한 임시 변수 선언
unsigned char memory_dump[ROW_LINE]; // 반환된 메모리값을 임시로 저장
Address_Check(addr);
if (0 == Display_Flag)
{
return;
}
else
{
printf(" Address "); // 화면 상단 자리 표시를 위한 출력
}
while (loop_temp < ROW_LINE) // Hex 부분 출력
{
printf("%02X ", loop_temp++);
}
putchar(' ');
loop_temp = 0;
while (loop_temp < ROW_LINE) // ASCII 부분 출력
{
printf("%X", loop_temp++);
}
putchar('\n');
while (0 < print_line) // Data 부분 출력 루프 시작
{
Address_Check(addr);
if (0 == Display_Flag)
{
return;
}
else
{
loop_temp = 0;
printf("0x%08X ", *addr); // 메모리 주소 출력
}
while (1) // 메모리 읽어 오기 및 hex 출력 시작
{
// 메모리 주소에 위치한 값을 배열에 저장
*(memory_dump + loop_temp) = md(*addr);
// 배열에 저장된 값 출력
printf("%02X ", *(memory_dump + loop_temp));
++loop_temp;
++(*addr);
if (0 == (loop_temp % ROW_LINE)) // ROW_LINE개를 출력하였으면 loop 종료
{
break;
}
else
{
}
} // 메모리 읽어 오기 및 hex 출력 끝
putchar(' ');
loop_temp = 0;
while (1) // ASCII 부분 출력 루프 시작
{
if (0 == *(memory_dump + loop_temp))
{
putchar('.'); // 널 문자 대치
}
else if (32 > *(memory_dump + loop_temp))
{
putchar('*'); // 제어 문자 대치
}
else if (127 <= *(memory_dump + loop_temp))
{
putchar('*'); // 그래픽 문자 대치
}
else
{
putchar(*(memory_dump + loop_temp));
}
++loop_temp;
if (0 == (loop_temp % ROW_LINE)) // ROW_LINE개를 출력하였으면 loop 종료
{
break;
}
else
{
}
} // ASCII 부분 출력 루프 끝
putchar('\n');
--print_line;
} // Data 출력 루프 끝
putchar('\n');
}
void MMFunction(unsigned int *addr) // Memory Modify Function
/*******************************************************************************
기능 : 수정할 대상이 잇는 곳의 주소를 인수로 받아서 그 곳의 값을 변경하고
변경한 내용을 출력
인수 : 수정할 대상이 있는 곳의 주소값
반환값 : void
*******************************************************************************/
{
unsigned char out = 0;
MDFunction(addr);
*addr = *addr - (DEFAULT_DISPLAY_LINE * ROW_LINE);
printf("변경하고 싶은 값(16진수)을 입력하세요 : ");
scanf("%x", &out);
mm(*addr, out);
out = md(*addr);
MSDFunction(addr, 1);
return;
}
void RFunction() // Register status display Function
/*******************************************************************************
기능 : 레지스터의 상태를 화면으로 출력
인수 : void
반환값 : void
*******************************************************************************/
{
unsigned int i = DR_NUM;
unsigned int *temp = (unsigned int *)&stat_old;
context stat_new;
Display_Flag = 0;
printf("-------------- 프로그램 실행 초기의 레지스터 상태 -------------\n");
while(1)
{
if (i == 0)
{
break;
}
else
{
--i;
printf("%s ADDRESS VALUE : 0x%08X ", *(R_NAME + i), *(temp + i));
}
if (0 == i % 2)
{
putchar('\n');
}
else
{
}
}
STST(&stat_new);
temp = (unsigned int *)&stat_new;
i = DR_NUM;
printf("----------------- 현재 레지스터 상태 -------------------\n");
while(1)
{
if (i == 0)
{
break;
}
else
{
--i;
printf("%s ADDRESS VALUE : 0x%08X ", *(R_NAME + i),*(temp + i));
}
if (0 == i % 2)
{
putchar('\n');
}
else
{
}
}
printf("---------------------------------------------------------------\n");
return;
}
void CDFunction() // Command Display Function
/*******************************************************************************
기능 : 이 프로그램의 사용법을 출력
인수 : void
반환값 : void
*******************************************************************************/
{
Display_Flag = 0;
printf("메모리 디버거 명령어\n");
printf("R : Register Value Display\n");
printf("P : Memory Status Display\n");
printf("MC : Memory Clear\n");
printf("MM : Memory Modify\n");
printf("MD : Memory Display\n");
printf("LOAD : Program Load\n");
printf("GO : Loaded Program Execute\n");
printf("CODE : Code Area Display\n");
printf("DATA : Data Area Display\n");
printf("STACK : Stack Area Display\n");
printf("HELP : Help Message Display\n");
printf("QUIT(Q) : Exit Program\n");
return;
}
void PRFunction() // Program Run Function
/*******************************************************************************
기능 : 프로그램이 메모리에 적재되었는지 검사하고 적재되어 있으면 실행
인수 : void
반환값 : void
*******************************************************************************/
{
Display_Flag = 0;
if (1 == Load_Flag) // 프로그램 적재 유무 판별
{
go();
}
else
{
printf("외부 프로그램이 적재되어 있지 않습니다.\n");
printf("load 명령을 사용하여 프로그램을 적재하시길 바랍니다.\n");
}
return;
}
void load() // Program Load Function
/*******************************************************************************
기능 : 프로그램의 이름을 입력받아 그 프로그램을 64K만큼 할당한 임의의 주소
공간에 적재
인수 : void
반환값 : void
*******************************************************************************/
{
int Read_Num ;
int Header_Size;
IMAGE_DOS_HEADER *dhp;
IMAGE_NT_HEADERS32 *php;
IMAGE_FILE_HEADER *fhp;
IMAGE_OPTIONAL_HEADER32 *ohp;
Clear_mem();
printf("\n읽어 들일 파일 이름을 입력하세요 : ");
scanf("%s", File_Name);
File_DS = open(File_Name, O_RDONLY | O_BINARY);
if (0 > File_DS)
{
printf("파일을 찾을 수 없거나 읽을 수 없습니다.\n");
printf("파일이 존재하는지 확인해 주세요.\n");
printf("(경로명 사이에 '\'를 '\\'로 바꾸어 보십시오)\n");
return;
}
else
{
Read_Num = read(File_DS, code, MAX_PROGRAM_SIZE);
}
if(0 > Read_Num)
{
printf("파일이 존재하지만 읽을 수 없습니다.\n");
close(File_DS);
return;
}
else
{
dhp = (IMAGE_DOS_HEADER *) code;
php = (IMAGE_NT_HEADERS *) (code+(dhp->e_lfanew));
fhp = (IMAGE_FILE_HEADER *) ((char *)php+sizeof(php->Signature));
ohp = (IMAGE_OPTIONAL_HEADER32 *)((char *)fhp+sizeof(IMAGE_FILE_HEADER));
Header_Size = ohp->SizeOfHeaders;
Clear_mem();
}
if (0 > lseek(File_DS, Header_Size, SEEK_SET))
{
printf("파일의 헤더정보 Skip 실패!!\n");
printf("파일을 적재할 수 없습니다..\n");
close(File_DS);
return;
}
else
{
Read_Num = read(File_DS, code, SECTION_SIZE);
}
if(0 > Read_Num)
{
printf("파일이 존재하지만 읽을 수 없습니다.\n");
close(File_DS);
return;
}
else
{
Read_Num = read(File_DS, data, SECTION_SIZE);
}
close(File_DS);
if(0 > Read_Num)
{
printf("파일이 존재하지만 읽을 수 없습니다.\n");
return;
}
else
{
File_DS = 0;
Load_Flag = 1;
printf("파일을 성공적으로 메모리에 적재하였습니다.\n");
printf("읽어 들인 파일의 크기는 [%d]Bytes입니다.\n\n", Read_Num);
}
return;
}
void go() // Program Runing Function
/*******************************************************************************
기능 : 동적할당 영역에 저장된 프로그램을 실행
인수 : void
반환값 : void
*******************************************************************************/
{
context stat_new;
stat_new.eax = (int)(&stat_old);
stat_new.ebx = 0;
stat_new.ecx = 0;
stat_new.edx = 0;
stat_new.esi = 0;
stat_new.edi = 0;
stat_new.esp = (int)(mem_end + 1);
stat_new.ebp = 0;
stat_new.eip = (int)(code);
stat_new.efl = 0;
printf("적재된 프로그램을 실행합니다...\n");
LDST(&stat_new);
printf("SYSTEM PANIC!!\n");
}
void Clear_mem() // Dynamic Memory Clear Function
/*******************************************************************************
기능 : 동적할당 영역에 저장된 값들을 초기화
인수 : void
반환값 : void
*******************************************************************************/
{
unsigned char *temp = mem;
Load_Flag = 0; // 로드된 프로그램을 제거하므로 0으로 설정
Display_Flag = 0;
while (1)
{
*temp = 0;
if (mem_end == temp)
{
break;
}
else
{
++temp;
}
}
}
void Address_Check(unsigned int *addr) // Address Check Function
/*******************************************************************************
기능 : 파라미터가 출력할 수 있는 범위의 주소 값인지 검사
인수 : 검사할 주소
반환값 : void
*******************************************************************************/
{
if ((unsigned int)mem > *addr)
{
printf("출력할 수 없는 주소 공간입니다.\n");
}
else if ((unsigned int)mem_end < *addr)
{
printf("출력할 수 없는 주소 공간입니다.\n");
Display_Flag = 0;
}
else
{
Display_Flag = 1;
return;
}
Display_Flag = 0;
return;
}