ReactOS Fundraising Campaign 2012
 
€ 4,410 / € 30,000

Information | Donate

Home | Info | Community | Development | myReactOS | Contact Us

  1. Home
  2. Community
  3. Development
  4. myReactOS
  5. Fundraiser 2012

  1. Main Page
  2. Alphabetical List
  3. Data Structures
  4. Directories
  5. File List
  6. Data Fields
  7. Globals
  8. Related Pages

ReactOS Development > Doxygen

dbgchnl.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 doxygen 1.7.6.1

ReactOS is a registered trademark or a trademark of ReactOS Foundation in the United States and other countries.