Home | Info | Community | Development | myReactOS | Contact Us
ReactOS Development > Doxygendbgchnl.c
Go to the documentation of this file.
00001 /* 00002 * ReactOS Task Manager 00003 * 00004 * dbgchnl.c 00005 * 00006 * Copyright (C) 2003 - 2004 Eric Pouech 00007 * 00008 * This library is free software; you can redistribute it and/or 00009 * modify it under the terms of the GNU Lesser General Public 00010 * License as published by the Free Software Foundation; either 00011 * version 2.1 of the License, or (at your option) any later version. 00012 * 00013 * This library is distributed in the hope that it will be useful, 00014 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00015 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00016 * Lesser General Public License for more details. 00017 * 00018 * You should have received a copy of the GNU Lesser General Public 00019 * License along with this library; if not, write to the Free Software 00020 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 00021 */ 00022 00023 #include <precomp.h> 00024 00025 /* TODO: 00026 * - the dialog box could be non modal 00027 * - in that case, 00028 * + could refresh channels from time to time 00029 * - get a better UI (replace the 'x' by real tick boxes in list view) 00030 * - implement a real solution around the get_symbol hack 00031 * - enhance visual feedback: the list is large, and it's hard to get the 00032 * right line when clicking on rightmost column (trace for example) 00033 * - get rid of printfs (error reporting) and use real message boxes 00034 * - include the column width settings in the full column management scheme 00035 */ 00036 00037 BOOL DebugChannelsAreSupported(void) 00038 { 00039 #ifdef WINE 00040 return TRUE; 00041 #endif 00042 return FALSE; 00043 } 00044 00045 static int list_channel_CB(HANDLE hProcess, void* addr, WCHAR* buffer, void* user) 00046 { 00047 int j; 00048 WCHAR val[2]; 00049 LVITEM lvi; 00050 int index; 00051 HWND hChannelLV = (HWND)user; 00052 00053 memset(&lvi, 0, sizeof(lvi)); 00054 00055 lvi.mask = LVIF_TEXT; 00056 lvi.pszText = buffer + 1; 00057 00058 index = ListView_InsertItem(hChannelLV, &lvi); 00059 if (index == -1) return 0; 00060 00061 val[1] = L'\0'; 00062 for (j = 0; j < 4; j++) 00063 { 00064 val[0] = (buffer[0] & (1 << j)) ? L'x' : L' '; 00065 ListView_SetItemText(hChannelLV, index, j + 1, val); 00066 } 00067 return 1; 00068 } 00069 00070 struct cce_user 00071 { 00072 LPCWSTR name; /* channel to look for */ 00073 unsigned value, mask; /* how to change channel */ 00074 unsigned done; /* number of successful changes */ 00075 unsigned notdone; /* number of unsuccessful changes */ 00076 }; 00077 00078 /****************************************************************** 00079 * change_channel_CB 00080 * 00081 * Callback used for changing a given channel attributes 00082 */ 00083 static int change_channel_CB(HANDLE hProcess, void* addr, WCHAR* buffer, void* pmt) 00084 { 00085 struct cce_user* user = (struct cce_user*)pmt; 00086 00087 if (!user->name || !wcscmp(buffer + 1, user->name)) 00088 { 00089 buffer[0] = (buffer[0] & ~user->mask) | (user->value & user->mask); 00090 if (WriteProcessMemory(hProcess, addr, buffer, 1, NULL)) 00091 user->done++; 00092 else 00093 user->notdone++; 00094 } 00095 return 1; 00096 } 00097 00098 #ifdef WINE 00099 /****************************************************************** 00100 * get_symbol 00101 * 00102 * Here it gets ugly :-( 00103 * This is quick hack to get the address of first_dll in a running process 00104 * We make the following assumptions: 00105 * - libwine (lib) is loaded in all processes at the same address (or 00106 * at least at the same address at this process) 00107 * - we load the same libwine.so version in this process and in the 00108 * examined process 00109 * Final address is gotten by: 1/ querying the address of a known exported 00110 * symbol out of libwine.so with dlsym, 2/ then querying nm on libwine.so to 00111 * get the offset from the data segment of this known symbol and of first_dll, 00112 * 3/ computing the actual address of first_dll by adding the result of 1/ and 00113 * the delta of 2/. 00114 * Ugly, yes, but it somehow works. We should replace that with debughlp 00115 * library, that'd be way better. Exporting first_dll from libwine.so would make 00116 * this code simpler, but still ugly. 00117 */ 00118 /* FIXME: we only need those includes for the next function */ 00119 #include <dlfcn.h> /* for RTLD_LAZY */ 00120 #include <sys/types.h> 00121 #include <sys/stat.h> 00122 #include <unistd.h> 00123 #include <stdio.h> 00124 #include "wine/library.h" 00125 00126 void* get_symbol(HANDLE hProcess, const char* name, const char* lib) 00127 { 00128 char buffer[1024]; 00129 void* h; 00130 DWORD addr = 0, tmp = 0; 00131 FILE* f; 00132 char* env; 00133 00134 if (!(h = wine_dlopen(lib, RTLD_LAZY, buffer, sizeof(buffer)))) 00135 { 00136 printf("Couldn't load %s (%s)\n", lib, buffer); 00137 return NULL; 00138 } 00139 00140 env = getenv("LD_LIBRARY_PATH"); 00141 if (env) 00142 { 00143 char *next, *ptr; 00144 struct stat s; 00145 00146 for (ptr = env = strdup(env); ptr; ptr = next) 00147 { 00148 next = strchr(ptr, ':'); 00149 if (next) *next++ = '\0'; 00150 sprintf(buffer, "nm %s", ptr); 00151 if (buffer[strlen(buffer) - 1] != '/') strcat(buffer, "/"); 00152 strcat(buffer, lib); 00153 if (stat(buffer + 3, &s) == 0) break; 00154 } 00155 free(env); 00156 if (!ptr) 00157 { 00158 printf("Couldn't find %s in LD_LIBRARY_PATH\n", lib); 00159 return NULL; 00160 } 00161 } 00162 if (!(f = popen(buffer, "r"))) 00163 { 00164 printf("Cannot execute '%s'\n", buffer); 00165 return NULL; 00166 } 00167 00168 while (fgets(buffer, sizeof(buffer), f)) 00169 { 00170 char *p = buffer + strlen(buffer) - 1; 00171 if (p < buffer) continue; 00172 if (*p == '\n') *p-- = 0; 00173 if (p - buffer < 11) continue; 00174 buffer[8] = '\0'; 00175 if (!strcmp(&buffer[11], name)) addr += strtol(buffer, NULL, 16); 00176 if (buffer[9] == 'D' && !tmp && (tmp = (DWORD)wine_dlsym(h, &buffer[11], NULL, 0)) != 0) 00177 addr += tmp - strtol(buffer, NULL, 16); 00178 } 00179 pclose(f); 00180 return (char*)addr; 00181 } 00182 #else 00183 void* get_symbol(HANDLE hProcess, const char* name, const char* lib) 00184 { 00185 printf("get_symbol: not implemented on this platform\n"); 00186 return NULL; 00187 } 00188 #endif 00189 00190 struct dll_option_layout 00191 { 00192 void* next; 00193 void* prev; 00194 char* const* channels; 00195 unsigned int nb_channels; 00196 }; 00197 00198 typedef int (*EnumChannelCB)(HANDLE, void*, WCHAR*, void*); 00199 00200 /****************************************************************** 00201 * enum_channel 00202 * 00203 * Enumerates all known channels on process hProcess through callback 00204 * ce. 00205 */ 00206 static int enum_channel(HANDLE hProcess, EnumChannelCB ce, void* user, unsigned unique) 00207 { 00208 struct dll_option_layout dol; 00209 int ret = 1; 00210 void* buf_addr; 00211 WCHAR buffer[32]; 00212 void* addr; 00213 WCHAR** cache = NULL; 00214 unsigned i, j, num_cache, used_cache; 00215 00216 addr = get_symbol(hProcess, "first_dll", "libwine.so"); 00217 if (!addr) return -1; 00218 if (unique) 00219 cache = HeapAlloc(GetProcessHeap(), 0, (num_cache = 32) * sizeof(WCHAR*)); 00220 else 00221 num_cache = 0; 00222 used_cache = 0; 00223 00224 for (; 00225 ret && addr && ReadProcessMemory(hProcess, addr, &dol, sizeof(dol), NULL); 00226 addr = dol.next) 00227 { 00228 for (i = 0; i < dol.nb_channels; i++) 00229 { 00230 if (ReadProcessMemory(hProcess, (void*)(dol.channels + i), &buf_addr, sizeof(buf_addr), NULL) && 00231 ReadProcessMemory(hProcess, buf_addr, buffer, sizeof(buffer), NULL)) 00232 { 00233 if (unique) 00234 { 00235 /* since some channels are defined in multiple compilation units, 00236 * they will appear several times... 00237 * so cache the channel's names we already reported and don't report 00238 * them again 00239 */ 00240 for (j = 0; j < used_cache; j++) 00241 if (!wcscmp(cache[j], buffer + 1)) break; 00242 if (j != used_cache) continue; 00243 if (used_cache == num_cache) 00244 cache = HeapReAlloc(GetProcessHeap(), 0, cache, (num_cache *= 2) * sizeof(WCHAR*)); 00245 cache[used_cache++] = wcscpy(HeapAlloc(GetProcessHeap(), 0, (wcslen(buffer + 1) + 1) * sizeof(WCHAR)), 00246 buffer + 1); 00247 } 00248 ret = ce(hProcess, buf_addr, buffer, user); 00249 } 00250 } 00251 } 00252 if (unique) 00253 { 00254 for (j = 0; j < used_cache; j++) HeapFree(GetProcessHeap(), 0, (WCHAR*)cache[j]); 00255 HeapFree(GetProcessHeap(), 0, cache); 00256 } 00257 return 0; 00258 } 00259 00260 static void DebugChannels_FillList(HWND hChannelLV) 00261 { 00262 HANDLE hProcess; 00263 00264 (void)ListView_DeleteAllItems(hChannelLV); 00265 00266 hProcess = OpenProcess(PROCESS_VM_OPERATION | PROCESS_VM_READ, FALSE, GetSelectedProcessId()); 00267 if (!hProcess) return; /* FIXME messagebox */ 00268 SendMessageW(hChannelLV, WM_SETREDRAW, FALSE, 0); 00269 enum_channel(hProcess, list_channel_CB, (void*)hChannelLV, TRUE); 00270 SendMessageW(hChannelLV, WM_SETREDRAW, TRUE, 0); 00271 CloseHandle(hProcess); 00272 } 00273 00274 static void DebugChannels_OnCreate(HWND hwndDlg) 00275 { 00276 HWND hLV = GetDlgItem(hwndDlg, IDC_DEBUG_CHANNELS_LIST); 00277 LVCOLUMN lvc; 00278 00279 lvc.mask = LVCF_FMT | LVCF_TEXT | LVCF_WIDTH; 00280 lvc.fmt = LVCFMT_LEFT; 00281 lvc.pszText = L"Debug Channel"; 00282 lvc.cx = 100; 00283 (void)ListView_InsertColumn(hLV, 0, &lvc); 00284 00285 lvc.mask = LVCF_FMT | LVCF_TEXT | LVCF_WIDTH; 00286 lvc.fmt = LVCFMT_CENTER; 00287 lvc.pszText = L"Fixme"; 00288 lvc.cx = 55; 00289 (void)ListView_InsertColumn(hLV, 1, &lvc); 00290 00291 lvc.mask = LVCF_FMT | LVCF_TEXT | LVCF_WIDTH; 00292 lvc.fmt = LVCFMT_CENTER; 00293 lvc.pszText = L"Err"; 00294 lvc.cx = 55; 00295 (void)ListView_InsertColumn(hLV, 2, &lvc); 00296 00297 lvc.mask = LVCF_FMT | LVCF_TEXT | LVCF_WIDTH; 00298 lvc.fmt = LVCFMT_CENTER; 00299 lvc.pszText = L"Warn"; 00300 lvc.cx = 55; 00301 (void)ListView_InsertColumn(hLV, 3, &lvc); 00302 00303 lvc.mask = LVCF_FMT | LVCF_TEXT | LVCF_WIDTH; 00304 lvc.fmt = LVCFMT_CENTER; 00305 lvc.pszText = L"Trace"; 00306 lvc.cx = 55; 00307 (void)ListView_InsertColumn(hLV, 4, &lvc); 00308 00309 DebugChannels_FillList(hLV); 00310 } 00311 00312 static void DebugChannels_OnNotify(HWND hDlg, LPARAM lParam) 00313 { 00314 NMHDR* nmh = (NMHDR*)lParam; 00315 00316 switch (nmh->code) 00317 { 00318 case NM_CLICK: 00319 if (nmh->idFrom == IDC_DEBUG_CHANNELS_LIST) 00320 { 00321 LVHITTESTINFO lhti; 00322 HWND hChannelLV; 00323 HANDLE hProcess; 00324 NMITEMACTIVATE* nmia = (NMITEMACTIVATE*)lParam; 00325 00326 hProcess = OpenProcess(PROCESS_VM_OPERATION | PROCESS_VM_READ | PROCESS_VM_WRITE, FALSE, GetSelectedProcessId()); 00327 if (!hProcess) return; /* FIXME message box */ 00328 lhti.pt = nmia->ptAction; 00329 hChannelLV = GetDlgItem(hDlg, IDC_DEBUG_CHANNELS_LIST); 00330 SendMessageW(hChannelLV, LVM_SUBITEMHITTEST, 0, (LPARAM)&lhti); 00331 if (nmia->iSubItem >= 1 && nmia->iSubItem <= 4) 00332 { 00333 WCHAR val[2]; 00334 WCHAR name[32]; 00335 unsigned bitmask = 1 << (lhti.iSubItem - 1); 00336 struct cce_user user; 00337 00338 ListView_GetItemText(hChannelLV, lhti.iItem, 0, name, sizeof(name) / sizeof(name[0])); 00339 ListView_GetItemText(hChannelLV, lhti.iItem, lhti.iSubItem, val, sizeof(val) / sizeof(val[0])); 00340 user.name = name; 00341 user.value = (val[0] == L'x') ? 0 : bitmask; 00342 user.mask = bitmask; 00343 user.done = user.notdone = 0; 00344 enum_channel(hProcess, change_channel_CB, &user, FALSE); 00345 if (user.done) 00346 { 00347 val[0] ^= (L'x' ^ L' '); 00348 ListView_SetItemText(hChannelLV, lhti.iItem, lhti.iSubItem, val); 00349 } 00350 if (user.notdone) 00351 printf("Some channel instance weren't correctly set\n"); 00352 } 00353 CloseHandle(hProcess); 00354 } 00355 break; 00356 } 00357 } 00358 00359 static INT_PTR CALLBACK DebugChannelsDlgProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) 00360 { 00361 switch (message) 00362 { 00363 case WM_INITDIALOG: 00364 DebugChannels_OnCreate(hDlg); 00365 return TRUE; 00366 case WM_COMMAND: 00367 if (LOWORD(wParam) == IDOK || LOWORD(wParam) == IDCANCEL) { 00368 EndDialog(hDlg, LOWORD(wParam)); 00369 return TRUE; 00370 } 00371 break; 00372 case WM_NOTIFY: 00373 DebugChannels_OnNotify(hDlg, lParam); 00374 break; 00375 } 00376 return FALSE; 00377 } 00378 00379 void ProcessPage_OnDebugChannels(void) 00380 { 00381 DialogBoxW(hInst, (LPCWSTR)IDD_DEBUG_CHANNELS_DIALOG, hMainWnd, DebugChannelsDlgProc); 00382 } Generated on Fri May 25 2012 04:15:51 for ReactOS by
1.7.6.1
|