Upstream version 9.38.198.0
[platform/framework/web/crosswalk.git] / src / breakpad / src / client / windows / tests / crash_generation_app / crash_generation_app.cc
1 // Copyright (c) 2008, Google Inc.
2 // All rights reserved.
3 //
4 // Redistribution and use in source and binary forms, with or without
5 // modification, are permitted provided that the following conditions are
6 // met:
7 //
8 //     * Redistributions of source code must retain the above copyright
9 // notice, this list of conditions and the following disclaimer.
10 //     * Redistributions in binary form must reproduce the above
11 // copyright notice, this list of conditions and the following disclaimer
12 // in the documentation and/or other materials provided with the
13 // distribution.
14 //     * Neither the name of Google Inc. nor the names of its
15 // contributors may be used to endorse or promote products derived from
16 // this software without specific prior written permission.
17 //
18 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29
30 // crash_generation_app.cpp : Defines the entry point for the application.
31 //
32
33 #include "client/windows/tests/crash_generation_app/crash_generation_app.h"
34
35 #include <windows.h>
36 #include <tchar.h>
37
38 #include "client/windows/crash_generation/client_info.h"
39 #include "client/windows/crash_generation/crash_generation_server.h"
40 #include "client/windows/handler/exception_handler.h"
41 #include "client/windows/common/ipc_protocol.h"
42
43 #include "client/windows/tests/crash_generation_app/abstract_class.h"
44
45 namespace google_breakpad {
46
47 const int kMaxLoadString = 100;
48 const wchar_t kPipeName[] = L"\\\\.\\pipe\\BreakpadCrashServices\\TestServer";
49
50 const DWORD kEditBoxStyles = WS_CHILD |
51                              WS_VISIBLE |
52                              WS_VSCROLL |
53                              ES_LEFT |
54                              ES_MULTILINE |
55                              ES_AUTOVSCROLL |
56                              ES_READONLY;
57
58 // Maximum length of a line in the edit box.
59 const size_t kMaximumLineLength = 256;
60
61 // CS to access edit control in a thread safe way.
62 static CRITICAL_SECTION* cs_edit = NULL;
63
64 // Edit control.
65 static HWND client_status_edit_box;
66
67 HINSTANCE current_instance;             // Current instance.
68 TCHAR title[kMaxLoadString];            // Title bar text.
69 TCHAR window_class[kMaxLoadString];     // Main window class name.
70
71 ATOM MyRegisterClass(HINSTANCE instance);
72 BOOL InitInstance(HINSTANCE, int);
73 LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
74 INT_PTR CALLBACK About(HWND, UINT, WPARAM, LPARAM);
75
76 static int kCustomInfoCount = 2;
77 static CustomInfoEntry kCustomInfoEntries[] = {
78     CustomInfoEntry(L"prod", L"CrashTestApp"),
79     CustomInfoEntry(L"ver", L"1.0"),
80 };
81
82 static ExceptionHandler* handler = NULL;
83 static CrashGenerationServer* crash_server = NULL;
84
85 // Registers the window class.
86 //
87 // This function and its usage are only necessary if you want this code
88 // to be compatible with Win32 systems prior to the 'RegisterClassEx'
89 // function that was added to Windows 95. It is important to call this
90 // function so that the application will get 'well formed' small icons
91 // associated with it.
92 ATOM MyRegisterClass(HINSTANCE instance) {
93   WNDCLASSEX wcex;
94   wcex.cbSize = sizeof(WNDCLASSEX);
95   wcex.style = CS_HREDRAW | CS_VREDRAW;
96   wcex.lpfnWndProc = WndProc;
97   wcex.cbClsExtra = 0;
98   wcex.cbWndExtra = 0;
99   wcex.hInstance = instance;
100   wcex.hIcon = LoadIcon(instance,
101                         MAKEINTRESOURCE(IDI_CRASHGENERATIONAPP));
102   wcex.hCursor = LoadCursor(NULL, IDC_ARROW);
103   wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
104   wcex.lpszMenuName = MAKEINTRESOURCE(IDC_CRASHGENERATIONAPP);
105   wcex.lpszClassName = window_class;
106   wcex.hIconSm = LoadIcon(wcex.hInstance, MAKEINTRESOURCE(IDI_SMALL));
107
108   return RegisterClassEx(&wcex);
109 }
110
111 // Saves instance handle and creates main window
112 //
113 // In this function, we save the instance handle in a global variable and
114 //   create and display the main program window.
115 BOOL InitInstance(HINSTANCE instance, int command_show) {
116   current_instance = instance;
117   HWND wnd = CreateWindow(window_class,
118                           title,
119                           WS_OVERLAPPEDWINDOW,
120                           CW_USEDEFAULT,
121                           0,
122                           CW_USEDEFAULT,
123                           0,
124                           NULL,
125                           NULL,
126                           instance,
127                           NULL);
128
129   if (!wnd) {
130     return FALSE;
131   }
132
133   ShowWindow(wnd, command_show);
134   UpdateWindow(wnd);
135
136   return TRUE;
137 }
138
139 static void AppendTextToEditBox(TCHAR* text) {
140   EnterCriticalSection(cs_edit);
141   SYSTEMTIME current_time;
142   GetLocalTime(&current_time);
143   TCHAR line[kMaximumLineLength];
144   int result = swprintf_s(line,
145                           kMaximumLineLength,
146                           L"[%.2d-%.2d-%.4d %.2d:%.2d:%.2d] %s",
147                           current_time.wMonth,
148                           current_time.wDay,
149                           current_time.wYear,
150                           current_time.wHour,
151                           current_time.wMinute,
152                           current_time.wSecond,
153                           text);
154
155   if (result == -1) {
156     return;
157   }
158
159   int length = GetWindowTextLength(client_status_edit_box);
160   SendMessage(client_status_edit_box,
161               EM_SETSEL,
162               (WPARAM)length,
163               (LPARAM)length);
164   SendMessage(client_status_edit_box,
165               EM_REPLACESEL,
166               (WPARAM)FALSE,
167               (LPARAM)line);
168   LeaveCriticalSection(cs_edit);
169 }
170
171 static DWORD WINAPI AppendTextWorker(void* context) {
172   TCHAR* text = reinterpret_cast<TCHAR*>(context);
173
174   AppendTextToEditBox(text);
175   delete[] text;
176
177   return 0;
178 }
179
180 bool ShowDumpResults(const wchar_t* dump_path,
181                      const wchar_t* minidump_id,
182                      void* context,
183                      EXCEPTION_POINTERS* exinfo,
184                      MDRawAssertionInfo* assertion,
185                      bool succeeded) {
186   TCHAR* text = new TCHAR[kMaximumLineLength];
187   text[0] = _T('\0');
188   int result = swprintf_s(text,
189                           kMaximumLineLength,
190                           TEXT("Dump generation request %s\r\n"),
191                           succeeded ? TEXT("succeeded") : TEXT("failed"));
192   if (result == -1) {
193     delete [] text;
194   }
195
196   QueueUserWorkItem(AppendTextWorker, text, WT_EXECUTEDEFAULT);
197   return succeeded;
198 }
199
200 static void _cdecl ShowClientConnected(void* context,
201                                        const ClientInfo* client_info) {
202   TCHAR* line = new TCHAR[kMaximumLineLength];
203   line[0] = _T('\0');
204   int result = swprintf_s(line,
205                           kMaximumLineLength,
206                           L"Client connected:\t\t%d\r\n",
207                           client_info->pid());
208
209   if (result == -1) {
210     delete[] line;
211     return;
212   }
213
214   QueueUserWorkItem(AppendTextWorker, line, WT_EXECUTEDEFAULT);
215 }
216
217 static void _cdecl ShowClientCrashed(void* context,
218                                      const ClientInfo* client_info,
219                                      const wstring* dump_path) {
220   TCHAR* line = new TCHAR[kMaximumLineLength];
221   line[0] = _T('\0');
222   int result = swprintf_s(line,
223                           kMaximumLineLength,
224                           TEXT("Client requested dump:\t%d\r\n"),
225                           client_info->pid());
226
227   if (result == -1) {
228     delete[] line;
229     return;
230   }
231
232   QueueUserWorkItem(AppendTextWorker, line, WT_EXECUTEDEFAULT);
233
234   CustomClientInfo custom_info = client_info->GetCustomInfo();
235   if (custom_info.count <= 0) {
236     return;
237   }
238
239   wstring str_line;
240   for (size_t i = 0; i < custom_info.count; ++i) {
241     if (i > 0) {
242       str_line += L", ";
243     }
244     str_line += custom_info.entries[i].name;
245     str_line += L": ";
246     str_line += custom_info.entries[i].value;
247   }
248
249   line = new TCHAR[kMaximumLineLength];
250   line[0] = _T('\0');
251   result = swprintf_s(line,
252                       kMaximumLineLength,
253                       L"%s\n",
254                       str_line.c_str());
255   if (result == -1) {
256     delete[] line;
257     return;
258   }
259   QueueUserWorkItem(AppendTextWorker, line, WT_EXECUTEDEFAULT);
260 }
261
262 static void _cdecl ShowClientExited(void* context,
263                                     const ClientInfo* client_info) {
264   TCHAR* line = new TCHAR[kMaximumLineLength];
265   line[0] = _T('\0');
266   int result = swprintf_s(line,
267                           kMaximumLineLength,
268                           TEXT("Client exited:\t\t%d\r\n"),
269                           client_info->pid());
270
271   if (result == -1) {
272     delete[] line;
273     return;
274   }
275
276   QueueUserWorkItem(AppendTextWorker, line, WT_EXECUTEDEFAULT);
277 }
278
279 void CrashServerStart() {
280   // Do not create another instance of the server.
281   if (crash_server) {
282     return;
283   }
284
285   std::wstring dump_path = L"C:\\Dumps\\";
286
287   if (_wmkdir(dump_path.c_str()) && (errno != EEXIST)) {
288     MessageBoxW(NULL, L"Unable to create dump directory", L"Dumper", MB_OK);
289     return;
290   }
291
292   crash_server = new CrashGenerationServer(kPipeName,
293                                            NULL,
294                                            ShowClientConnected,
295                                            NULL,
296                                            ShowClientCrashed,
297                                            NULL,
298                                            ShowClientExited,
299                                            NULL,
300                                            NULL,
301                                            NULL,
302                                            true,
303                                            &dump_path);
304
305   if (!crash_server->Start()) {
306     MessageBoxW(NULL, L"Unable to start server", L"Dumper", MB_OK);
307     delete crash_server;
308     crash_server = NULL;
309   }
310 }
311
312 void CrashServerStop() {
313   delete crash_server;
314   crash_server = NULL;
315 }
316
317 void DerefZeroCrash() {
318   int* x = 0;
319   *x = 1;
320 }
321
322 void InvalidParamCrash() {
323   printf(NULL);
324 }
325
326 void PureCallCrash() {
327   Derived derived;
328 }
329
330 void RequestDump() {
331   if (!handler->WriteMinidump()) {
332     MessageBoxW(NULL, L"Dump request failed", L"Dumper", MB_OK);
333   }
334   kCustomInfoEntries[1].set_value(L"1.1");
335 }
336
337 void CleanUp() {
338   if (cs_edit) {
339     DeleteCriticalSection(cs_edit);
340     delete cs_edit;
341   }
342
343   if (handler) {
344     delete handler;
345   }
346
347   if (crash_server) {
348     delete crash_server;
349   }
350 }
351
352 // Processes messages for the main window.
353 //
354 // WM_COMMAND - process the application menu.
355 // WM_PAINT   - Paint the main window.
356 // WM_DESTROY - post a quit message and return.
357 LRESULT CALLBACK WndProc(HWND wnd,
358                          UINT message,
359                          WPARAM w_param,
360                          LPARAM l_param) {
361   int message_id;
362   int message_event;
363   PAINTSTRUCT ps;
364   HDC hdc;
365
366   HINSTANCE instance = (HINSTANCE)GetWindowLongPtr(wnd, GWLP_HINSTANCE);
367
368   switch (message) {
369     case WM_COMMAND:
370       // Parse the menu selections.
371       message_id = LOWORD(w_param);
372       message_event = HIWORD(w_param);
373       switch (message_id) {
374         case IDM_ABOUT:
375           DialogBox(current_instance,
376                     MAKEINTRESOURCE(IDD_ABOUTBOX),
377                     wnd,
378                     About);
379           break;
380         case IDM_EXIT:
381           DestroyWindow(wnd);
382           break;
383         case ID_SERVER_START:
384           CrashServerStart();
385           break;
386         case ID_SERVER_STOP:
387           CrashServerStop();
388           break;
389         case ID_CLIENT_DEREFZERO:
390           DerefZeroCrash();
391           break;
392         case ID_CLIENT_INVALIDPARAM:
393           InvalidParamCrash();
394           break;
395         case ID_CLIENT_PURECALL:
396           PureCallCrash();
397           break;
398         case ID_CLIENT_REQUESTEXPLICITDUMP:
399           RequestDump();
400           break;
401         default:
402           return DefWindowProc(wnd, message, w_param, l_param);
403       }
404       break;
405     case WM_CREATE:
406       client_status_edit_box = CreateWindow(TEXT("EDIT"),
407                                             NULL,
408                                             kEditBoxStyles,
409                                             0,
410                                             0,
411                                             0,
412                                             0,
413                                             wnd,
414                                             NULL,
415                                             instance,
416                                             NULL);
417       break;
418     case WM_SIZE:
419       // Make the edit control the size of the window's client area.
420       MoveWindow(client_status_edit_box,
421                  0,
422                  0,
423                  LOWORD(l_param),        // width of client area.
424                  HIWORD(l_param),        // height of client area.
425                  TRUE);                  // repaint window.
426       break;
427     case WM_SETFOCUS:
428       SetFocus(client_status_edit_box);
429       break;
430     case WM_PAINT:
431       hdc = BeginPaint(wnd, &ps);
432       EndPaint(wnd, &ps);
433       break;
434     case WM_DESTROY:
435       CleanUp();
436       PostQuitMessage(0);
437       break;
438     default:
439       return DefWindowProc(wnd, message, w_param, l_param);
440   }
441
442   return 0;
443 }
444
445 // Message handler for about box.
446 INT_PTR CALLBACK About(HWND dlg,
447                        UINT message,
448                        WPARAM w_param,
449                        LPARAM l_param) {
450   UNREFERENCED_PARAMETER(l_param);
451   switch (message) {
452     case WM_INITDIALOG:
453       return (INT_PTR)TRUE;
454
455     case WM_COMMAND:
456       if (LOWORD(w_param) == IDOK || LOWORD(w_param) == IDCANCEL) {
457         EndDialog(dlg, LOWORD(w_param));
458         return (INT_PTR)TRUE;
459       }
460       break;
461   }
462
463   return (INT_PTR)FALSE;
464 }
465
466 }  // namespace google_breakpad
467
468 int APIENTRY _tWinMain(HINSTANCE instance,
469                        HINSTANCE previous_instance,
470                        LPTSTR command_line,
471                        int command_show) {
472   using namespace google_breakpad;
473
474   UNREFERENCED_PARAMETER(previous_instance);
475   UNREFERENCED_PARAMETER(command_line);
476
477   cs_edit = new CRITICAL_SECTION();
478   InitializeCriticalSection(cs_edit);
479
480   CustomClientInfo custom_info = {kCustomInfoEntries, kCustomInfoCount};
481
482   CrashServerStart();
483   // This is needed for CRT to not show dialog for invalid param
484   // failures and instead let the code handle it.
485   _CrtSetReportMode(_CRT_ASSERT, 0);
486   handler = new ExceptionHandler(L"C:\\dumps\\",
487                                  NULL,
488                                  google_breakpad::ShowDumpResults,
489                                  NULL,
490                                  ExceptionHandler::HANDLER_ALL,
491                                  MiniDumpNormal,
492                                  kPipeName,
493                                  &custom_info);
494
495   // Initialize global strings.
496   LoadString(instance, IDS_APP_TITLE, title, kMaxLoadString);
497   LoadString(instance,
498              IDC_CRASHGENERATIONAPP,
499              window_class,
500              kMaxLoadString);
501   MyRegisterClass(instance);
502
503   // Perform application initialization.
504   if (!InitInstance(instance, command_show)) {
505     return FALSE;
506   }
507
508   HACCEL accel_table = LoadAccelerators(
509       instance,
510       MAKEINTRESOURCE(IDC_CRASHGENERATIONAPP));
511
512   // Main message loop.
513   MSG msg;
514   while (GetMessage(&msg, NULL, 0, 0)) {
515     if (!TranslateAccelerator(msg.hwnd, accel_table, &msg)) {
516       TranslateMessage(&msg);
517       DispatchMessage(&msg);
518     }
519   }
520
521   return static_cast<int>(msg.wParam);
522 }