sync with latest
[sdk/emulator/qemu.git] / tizen / src / maru_err_table.c
1 /*
2  * Error message
3  *
4  * Copyright (C) 2011, 2012 Samsung Electronics Co., Ltd. All rights reserved.
5  *
6  * Contact:
7  * SeokYeon Hwang <syeon.hwang@samsung.com>
8  * GiWoong Kim <giwoong.kim@samsung.com>
9  * YeongKyoon Lee <yeongkyoon.lee@samsung.com>
10  *
11  * This program is free software; you can redistribute it and/or
12  * modify it under the terms of the GNU General Public License
13  * as published by the Free Software Foundation; either version 2
14  * of the License, or (at your option) any later version.
15  *
16  * This program is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19  * GNU General Public License for more details.
20  *
21  * You should have received a copy of the GNU General Public License
22  * along with this program; if not, write to the Free Software
23  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
24  * MA 02110-1301, USA.
25  *
26  * Contributors:
27  * - S-Core Co., Ltd
28  *
29  */
30
31
32 #include "qemu-common.h"
33 #include "maru_err_table.h"
34 #include <stdio.h>
35 #include <stdlib.h>
36 #include <string.h>
37 #include <glib.h>
38
39 #ifdef _WIN32
40 #include <windows.h>
41 #else
42 #include <execinfo.h>
43 #endif
44
45 /* This table must match the enum definition */
46 static char _maru_string_table[][JAVA_MAX_COMMAND_LENGTH] = {
47     /* 0 */ "",
48     /* 1 */ "Failed to allocate memory in qemu.",
49     /* 2 */ "Failed to load a kernel file the following path.\
50 Check if the file is corrupted or missing.\n\n",
51     /* 3 */ "Failed to load a bios file the following path.\
52 Check if the file is corrupted or missing.\n\n",
53     /* 4 */ "Skin process cannot be initialized. Skin server is not ready.",
54     /* 5 */ "Emulator has stopped working.\n\
55 A problem caused the program to stop working correctly.",
56     /* add here.. */
57     ""
58 };
59
60
61 static int maru_exit_status = MARU_EXIT_NORMAL;
62 static char maru_exit_msg[JAVA_MAX_COMMAND_LENGTH] = { 0, };
63
64 void maru_register_exit_msg(int maru_exit_index, char const *const additional_msg)
65 {
66     int len = 0;
67
68     if (maru_exit_index >= MARU_EXIT_NORMAL) {
69         fprintf(stderr, "Invalid error message index = %d\n", maru_exit_index);
70         return;
71     }
72     if (maru_exit_status != MARU_EXIT_NORMAL) {
73         fprintf(stderr, "The error message is already registered = %d\n", maru_exit_status);
74         return;
75     }
76
77     maru_exit_status = maru_exit_index;
78
79     if (maru_exit_status != MARU_EXIT_UNKNOWN) {
80         if (maru_exit_status == MARU_EXIT_HB_TIME_EXPIRED) {
81             fprintf(stderr, "Skin client could not connect to Skin server.\
82 The time of internal heartbeat has expired.\n");
83         }
84
85         if (additional_msg != NULL) {
86             len = strlen(_maru_string_table[maru_exit_status])
87                     + strlen(additional_msg) + 1;
88             if (len > JAVA_MAX_COMMAND_LENGTH) {
89                 len = JAVA_MAX_COMMAND_LENGTH;
90             }
91
92             snprintf(maru_exit_msg, len, "%s%s",
93                     _maru_string_table[maru_exit_status], additional_msg);
94         } else {
95             len = strlen(_maru_string_table[maru_exit_status]) + 1;
96             if (len > JAVA_MAX_COMMAND_LENGTH) {
97                 len = JAVA_MAX_COMMAND_LENGTH;
98             }
99
100             snprintf(maru_exit_msg, len,
101                     "%s", _maru_string_table[maru_exit_status]);
102         }
103     } else if (additional_msg != NULL) { /* MARU_EXIT_UNKNOWN */
104         len = strlen(additional_msg);
105         if (len >= JAVA_MAX_COMMAND_LENGTH) {
106             len = JAVA_MAX_COMMAND_LENGTH - 1;
107         }
108
109         pstrcpy(maru_exit_msg, len + 1, additional_msg);
110         maru_exit_msg[len] = '\0';
111     }
112
113     fprintf(stdout, "The error message is registered = %d : %s\n",
114         maru_exit_status, maru_exit_msg);
115 }
116
117 void maru_atexit(void)
118 {
119     if (maru_exit_status != MARU_EXIT_NORMAL || strlen(maru_exit_msg) != 0) {
120         maru_dump_backtrace(NULL, 0);
121         start_simple_client(maru_exit_msg);
122     }
123 }
124
125 char *maru_convert_path(char *msg, const char *path)
126 {
127     char *current_path = NULL;
128     char *err_msg = NULL;
129 #ifdef _WIN32
130     char *dos_err_msg = NULL;
131 #endif
132     int total_len = 0;
133     int msg_len = 0;
134     int cur_path_len = 0;
135     int path_len = 0;
136     int res = -1;
137
138     res = (int)g_path_is_absolute(path);
139     path_len = (strlen(path) + 1);
140     if (msg) {
141         msg_len = strlen(msg) + 1;
142     }
143
144     if (!res) {
145         current_path = (char *)g_get_current_dir();
146         cur_path_len = strlen(current_path) + strlen("/") + 1;
147         total_len += cur_path_len;
148     }
149     total_len += (path_len + msg_len);
150
151     err_msg = g_malloc0(total_len * sizeof(char));
152
153     if (msg) {
154         snprintf(err_msg, msg_len, "%s", msg);
155         total_len = msg_len - 1;
156     } else {
157         total_len = 0;
158     }
159
160     if (!res) {
161         snprintf(err_msg + total_len, cur_path_len, "%s%s", current_path, "/");
162         total_len += (cur_path_len - 1);
163     }
164     snprintf(err_msg + total_len, path_len, "%s", path);
165
166 #ifdef _WIN32
167     {
168         int i;
169
170         dos_err_msg = g_strdup(err_msg);
171         if (!dos_err_msg) {
172             fprintf(stderr,
173                 "failed to duplicate an error message from %p\n", err_msg);
174             if (current_path) {
175                 g_free(current_path);
176             }
177             g_free(err_msg);
178             return NULL;
179         }
180
181         for (i = (total_len - 1); dos_err_msg[i]; i++) {
182             if (dos_err_msg[i] == '/') {
183                 dos_err_msg[i] = '\\';
184             }
185         }
186         pstrcpy(err_msg, strlen(dos_err_msg) + 1, dos_err_msg);
187         g_free(dos_err_msg);
188     }
189 #endif
190     if (current_path) {
191         g_free(current_path);
192     }
193
194     return err_msg;
195 }
196
197 /* Print 'backtrace' */
198 #ifdef _WIN32
199 struct frame_layout {
200     void *pNext;
201     void *pReturnAddr;
202 };
203
204 static char *aqua_get_filename_from_path(char *path_buf)
205 {
206     char *ret_slash;
207     char *ret_rslash;
208
209     ret_slash = strrchr(path_buf, '/');
210     ret_rslash = strrchr(path_buf, '\\');
211
212     if (ret_slash || ret_rslash) {
213         if (ret_slash > ret_rslash) {
214             return ret_slash + 1;
215         } else{
216             return ret_rslash + 1;
217         }
218     }
219
220     return path_buf;
221 }
222
223
224 static HMODULE aqua_get_module_handle(DWORD dwAddress)
225 {
226     MEMORY_BASIC_INFORMATION Buffer;
227     return VirtualQuery((LPCVOID) dwAddress, &Buffer, sizeof(Buffer))
228             ? (HMODULE) Buffer.AllocationBase : (HMODULE) 0;
229 }
230 #endif
231
232 void maru_dump_backtrace(void *ptr, int depth)
233 {
234 #ifdef _WIN32
235     int nCount;
236     void *pTopFrame;
237     struct frame_layout currentFrame;
238     struct frame_layout *pCurrentFrame;
239
240     char module_buf[1024];
241     HMODULE hModule;
242
243     PCONTEXT pContext = ptr;
244     if (!pContext) {
245         __asm__ __volatile__ ("movl   %%ebp, %0" : "=m" (pTopFrame));
246     } else {
247         pTopFrame = (void *)((PCONTEXT)pContext)->Ebp;
248     }
249
250     nCount = 0;
251     currentFrame.pNext = ((struct frame_layout *)pTopFrame)->pNext;
252     currentFrame.pReturnAddr = ((struct frame_layout *)pTopFrame)->pReturnAddr;
253     pCurrentFrame = (struct frame_layout *)pTopFrame;
254
255     fprintf(stderr, "\nBacktrace Dump Start :\n");
256     if (pContext) {
257         fprintf(stderr, "[%02d]Addr = 0x%p", nCount, ((PCONTEXT)pContext)->Eip);
258         memset(module_buf, 0, sizeof(module_buf));
259         hModule = aqua_get_module_handle((DWORD)((PCONTEXT)pContext)->Eip);
260         if (hModule) {
261             if (!GetModuleFileNameA(hModule, module_buf, sizeof(module_buf))) {
262                 memset(module_buf, 0, sizeof(module_buf));
263             }
264         }
265         fprintf(stderr, " : %s\n", aqua_get_filename_from_path(module_buf));
266         nCount++;
267     }
268
269     while (1) {
270         if (((void *)pCurrentFrame < pTopFrame)
271             || ((void *)pCurrentFrame >= (void *)0xC0000000)) {
272             break;
273         }
274
275         fprintf(stderr, "[%02d]Addr = 0x%p", nCount, currentFrame.pReturnAddr);
276         memset(module_buf, 0, sizeof(module_buf));
277         hModule = aqua_get_module_handle((DWORD)currentFrame.pReturnAddr);
278         if (hModule) {
279             if (!GetModuleFileNameA(hModule, module_buf, sizeof(module_buf))) {
280                 memset(module_buf, 0, sizeof(module_buf));
281             }
282         }
283         fprintf(stderr, " : %s\n", aqua_get_filename_from_path(module_buf));
284
285     if (!ReadProcessMemory(GetCurrentProcess(), currentFrame.pNext,
286             (void *)&currentFrame, sizeof(struct frame_layout), NULL)) {
287             break;
288         }
289         pCurrentFrame = (struct frame_layout *)pCurrentFrame->pNext;
290
291         if (depth) {
292             if (!--depth) {
293                 break;
294             }
295         }
296         nCount++;
297     }
298 #else
299     int i, ndepth;
300     void *trace[1024];
301     char **symbols;
302
303     fprintf(stderr, "\n Backtrace Dump Start :\n");
304
305     ndepth = backtrace(trace, 1024);
306     fprintf(stderr, "Backtrace depth is %d.\n", ndepth);
307
308     symbols = backtrace_symbols(trace, ndepth);
309     if (symbols == NULL) {
310         fprintf(stderr, "'backtrace_symbols()' return error");
311         return;
312     }
313
314     for (i = 0; i < ndepth; i++) {
315         fprintf(stderr, "%s\n", symbols[i]);
316     }
317     free(symbols);
318 #endif
319 }
320