| /* |
| static char RCSId[] = "$Id: relay.c,v 1.2 1993/07/04 04:04:21 root Exp root $"; |
| static char Copyright[] = "Copyright Robert J. Amstadt, 1993"; |
| */ |
| |
| #include <stdio.h> |
| #include <stdlib.h> |
| #include <string.h> |
| #include <sys/types.h> |
| #include <sys/stat.h> |
| #include <fcntl.h> |
| #include <unistd.h> |
| #include <errno.h> |
| #ifdef linux |
| #include <linux/unistd.h> |
| #include <linux/head.h> |
| #include <linux/ldt.h> |
| #endif |
| |
| #include "ldt.h" |
| |
| #include "neexe.h" |
| #include "prototypes.h" |
| #include "dlls.h" |
| #include "options.h" |
| #include "selectors.h" |
| #include "stackframe.h" |
| #include "wine.h" |
| #include "stddebug.h" |
| /* #define DEBUG_RELAY */ |
| #include "debug.h" |
| |
| #if 0 |
| /* Make make_debug think these were really used */ |
| dprintf_relay |
| #endif |
| |
| #ifdef WINELIB |
| #define WineLibSkip(x) 0 |
| #else |
| #define WineLibSkip(x) x |
| #endif |
| |
| struct dll_name_table_entry_s dll_builtin_table[N_BUILTINS] = |
| { |
| { "KERNEL", WineLibSkip(&KERNEL_table), 1 }, |
| { "USER", WineLibSkip(&USER_table), 1 }, |
| { "GDI", WineLibSkip(&GDI_table), 1 }, |
| { "WIN87EM", WineLibSkip(&WIN87EM_table), 1 }, |
| { "SHELL", WineLibSkip(&SHELL_table), 1 }, |
| { "SOUND", WineLibSkip(&SOUND_table), 1 }, |
| { "KEYBOARD", WineLibSkip(&KEYBOARD_table), 1 }, |
| { "WINSOCK", WineLibSkip(&WINSOCK_table), 1 }, |
| { "STRESS", WineLibSkip(&STRESS_table), 1 }, |
| { "MMSYSTEM", WineLibSkip(&MMSYSTEM_table), 1 }, |
| { "SYSTEM", WineLibSkip(&SYSTEM_table), 1 }, |
| { "TOOLHELP", WineLibSkip(&TOOLHELP_table), 1 }, |
| { "MOUSE", WineLibSkip(&MOUSE_table), 1 }, |
| { "COMMDLG", WineLibSkip(&COMMDLG_table), 1 }, |
| { "OLE2", WineLibSkip(&OLE2_table), 1 }, |
| { "OLE2CONV", WineLibSkip(&OLE2CONV_table), 1 }, |
| { "OLE2DISP", WineLibSkip(&OLE2DISP_table), 1 }, |
| { "OLE2NLS", WineLibSkip(&OLE2NLS_table), 1 }, |
| { "OLE2PROX", WineLibSkip(&OLE2PROX_table), 1 }, |
| { "OLECLI", WineLibSkip(&OLECLI_table), 1 }, |
| { "OLESVR", WineLibSkip(&OLESVR_table), 1 }, |
| { "COMPOBJ", WineLibSkip(&COMPOBJ_table), 1 }, |
| { "STORAGE", WineLibSkip(&STORAGE_table), 1 }, |
| { "WINPROCS", WineLibSkip(&WINPROCS_table), 1 }, |
| }; |
| /* don't forget to increase N_BUILTINS in dlls.h if you add a dll */ |
| |
| /* Saved 16-bit stack */ |
| WORD IF1632_Saved16_ss = 0; |
| WORD IF1632_Saved16_sp = 0; |
| WORD IF1632_Saved16_bp = 0; |
| |
| /* Saved 32-bit stack */ |
| DWORD IF1632_Saved32_esp = 0; |
| DWORD IF1632_Saved32_ebp = 0; |
| |
| /*********************************************************************** |
| * RELAY_Init |
| */ |
| BOOL RELAY_Init(void) |
| { |
| WORD codesel, datasel; |
| struct dll_table_s *table; |
| struct dll_table_entry_s *entry; |
| int i, j; |
| |
| /* Allocate the code selector for CallTo16 routines */ |
| |
| extern void CALL16_Start(), CALL16_End(); |
| extern void CALL16_Ret_word(), CALL16_Ret_long(); |
| extern DWORD CALL16_RetAddr_word, CALL16_RetAddr_long; |
| |
| codesel = SELECTOR_AllocBlock( (void *)CALL16_Start, |
| (int)CALL16_End - (int)CALL16_Start, |
| SEGMENT_CODE, TRUE, FALSE ); |
| if (!codesel) return FALSE; |
| |
| /* Patch the return addresses for CallTo16 routines */ |
| |
| CALL16_RetAddr_word = MAKELONG( (int)CALL16_Ret_word - (int)CALL16_Start, |
| codesel ); |
| CALL16_RetAddr_long = MAKELONG( (int)CALL16_Ret_long - (int)CALL16_Start, |
| codesel ); |
| |
| /* Allocate the selectors for built-in dlls */ |
| |
| for (i = 0; i < N_BUILTINS; i++) |
| { |
| table = dll_builtin_table[i].table; |
| codesel = SELECTOR_AllocBlock( table->code_start, |
| (int)table->code_end-(int)table->code_start, |
| SEGMENT_CODE, TRUE, FALSE ); |
| if (!codesel) return FALSE; |
| if (table->data_start != table->data_end) |
| datasel = SELECTOR_AllocBlock( table->data_start, |
| (int)table->data_end-(int)table->data_start, |
| SEGMENT_DATA, TRUE, FALSE ); |
| else datasel = 0; |
| entry = table->dll_table; |
| for (j = 0; j < table->dll_table_length; j++, entry++) |
| { |
| if (entry->selector == 1) /* code selector */ |
| entry->selector = codesel; |
| else if (entry->selector == 2) /* data selector */ |
| entry->selector = datasel; |
| else entry->selector = 0; /* constant selector */ |
| } |
| } |
| |
| return TRUE; |
| } |
| |
| |
| #ifndef WINELIB |
| |
| void RELAY_DebugCall32( char *args ) |
| { |
| STACK16FRAME *frame; |
| char *args16; |
| int i; |
| |
| if (!debugging_relay) return; |
| |
| frame = CURRENT_STACK16; |
| printf( "Call %s.%d: %s(", |
| dll_builtin_table[frame->dll_id-1].dll_name, |
| frame->ordinal_number, |
| dll_builtin_table[frame->dll_id-1].table->dll_table[frame->ordinal_number].export_name ); |
| args16 = (char *)frame->args; |
| for (i = 0; i < strlen(args); i++) |
| { |
| switch(args[i]) |
| { |
| case 'w': |
| case 's': |
| args16 += 2; |
| break; |
| case 'l': |
| case 'p': |
| args16 += 4; |
| break; |
| } |
| } |
| |
| while (*args) |
| { |
| switch(*args) |
| { |
| case 'w': |
| case 's': |
| args16 -= 2; |
| printf( "0x%04x", *(WORD *)args16 ); |
| break; |
| case 'l': |
| args16 -= 4; |
| printf( "0x%08x", *(int *)args16 ); |
| break; |
| case 'p': |
| args16 -= 4; |
| printf( "%04x:%04x", *(WORD *)(args16+2), *(WORD *)args16 ); |
| break; |
| } |
| args++; |
| if (*args) printf( "," ); |
| } |
| printf( ") ret=%04x:%04x ds=%04x\n", frame->cs, frame->ip, frame->ds ); |
| } |
| |
| |
| void RELAY_DebugReturn( int short_ret, int ret_val ) |
| { |
| STACK16FRAME *frame; |
| |
| if (!debugging_relay) return; |
| |
| frame = CURRENT_STACK16; |
| printf( "Ret %s.%d: %s() ", |
| dll_builtin_table[frame->dll_id-1].dll_name, |
| frame->ordinal_number, |
| dll_builtin_table[frame->dll_id-1].table->dll_table[frame->ordinal_number].export_name ); |
| if (short_ret) printf( "retval=0x%04x\n", ret_val & 0xffff ); |
| else printf( "retval=0x%08x\n", ret_val ); |
| } |
| |
| |
| void RELAY_Unimplemented(void) |
| { |
| STACK16FRAME *frame = CURRENT_STACK16; |
| |
| fprintf( stderr, "No handler for routine %s.%d\n", |
| dll_builtin_table[frame->dll_id-1].dll_name, |
| frame->ordinal_number ); |
| exit(1); |
| } |
| |
| |
| /*********************************************************************** |
| * RELAY_DebugCall16 |
| * |
| * 'stack' points to the called function address on the 32-bit stack. |
| * Stack layout: |
| * ... ... |
| * (stack+12) arg2 |
| * (stack+8) arg1 |
| * (stack+4) 16-bit ds |
| * (stack) func to call |
| */ |
| void RELAY_DebugCall16( int* stack, int nbargs ) |
| { |
| if (!debugging_relay) return; |
| |
| printf( "CallTo16(func=%04x:%04x,ds=%04x", |
| HIWORD(stack[0]), LOWORD(stack[0]), LOWORD(stack[1]) ); |
| stack += 2; |
| while (nbargs--) printf( ",0x%x", *stack++ ); |
| printf( ")\n" ); |
| } |
| |
| #endif /* WINELIB */ |
| |
| /********************************************************************** |
| * FindDLLTable |
| */ |
| struct dll_table_s * |
| FindDLLTable(char *dll_name) |
| { |
| int i; |
| |
| for (i = 0; i < N_BUILTINS; i++) |
| if (strcasecmp(dll_builtin_table[i].dll_name, dll_name) == 0 |
| && dll_builtin_table[i].dll_is_used) |
| return dll_builtin_table[i].table; |
| return NULL; |
| } |
| |
| /********************************************************************** |
| * FindOrdinalFromName |
| */ |
| int |
| FindOrdinalFromName(struct dll_table_entry_s *dll_table, char *func_name) |
| { |
| int i, limit; |
| |
| for (i = 0; i < N_BUILTINS; i++) |
| if (dll_table == dll_builtin_table[i].table->dll_table) |
| break; |
| |
| if (i == N_BUILTINS) |
| return 0; |
| |
| limit = dll_builtin_table[i].table->dll_table_length; |
| for (i = 0; i < limit; i++) |
| if (strcasecmp(dll_table[i].export_name, func_name) == 0) |
| return i; |
| |
| return 0; |
| } |
| |
| #ifndef WINELIB |
| #ifdef WINESTAT |
| void winestat(){ |
| int i, j; |
| double perc; |
| int used, implemented; |
| int tused, timplemented; |
| struct dll_table_entry_s *table; |
| |
| tused = 0; |
| timplemented = 0; |
| for (i = 0; i < N_BUILTINS; i++) { |
| table = dll_builtin_table[i].table->dll_table; |
| used = 0; |
| implemented = 0; |
| for(j=0; j < dll_builtin_table[i].table->dll_table_length; j++) { |
| if(table[j].used){ |
| used++; |
| if (table[j].export_name[0]) implemented++; |
| else |
| printf("%s.%d not implemented\n", |
| dll_builtin_table[i].dll_name, |
| j); |
| }; |
| }; |
| tused += used; |
| timplemented += implemented; |
| if(used) |
| perc = implemented * 100.00 / used; |
| else |
| perc = 0.0; |
| if (used) |
| printf("%s: %d of %d (%3.1f %%)\n", dll_builtin_table[i].dll_name, implemented, used, perc); |
| }; |
| perc = timplemented * 100.00 / tused; |
| printf("TOTAL: %d of %d winapi functions implemented (%3.1f %%)\n",timplemented, tused, perc); |
| } |
| #endif /* WINESTAT */ |
| #endif /* !WINELIB */ |