1 #include <stdio.h>
2 #include <string.h>
3 #include <stdint.h>
4 #include <stdlib.h>
5 #include <math.h>
6 #include <cutils/log.h>
7 
8 #include "crash_analyzer_defs.h"
9 #include "crash_analyzer.h"
10 
11 #define MAX_PATTERN_SIZE 1024
12 #define MAX_CSTRING_SIZE 8000
13 #define SEPARATOR " | "
14 
find_rightmost_setbit_position(uint32_t number)15 int find_rightmost_setbit_position(uint32_t number)
16 {
17     if (number)
18         return log2(number ^ (number & (number - 1)));
19 
20     return -1;
21 }
22 
find_exception_in_hmd_dmx(unsigned char * buf,int buf_len,const char * core,char * outbuf,int outbuf_max_size)23 char* find_exception_in_hmd_dmx(unsigned char *buf, int buf_len,
24                                 const char *core, char *outbuf,
25                                 int outbuf_max_size)
26 {
27     char exccause[64] = {0};
28     char epc1[32] = {0};
29     uint32_t *wordBuf = (uint32_t*)buf;
30 
31     if (buf == NULL || buf_len < HMD_DMX_INDEX_MAX * BYTES_PER_WORD ||
32         core == NULL || outbuf == NULL || outbuf_max_size <= 0 ||
33         wordBuf[START_HMD_DMX_INDEX] == 0 ||
34         strlen(outbuf) >= outbuf_max_size)
35         return outbuf;
36 
37     int excepIndex = wordBuf[EXCEPTION_INDEX];
38 
39     if (excepIndex >= HMD_DMXEXCEPTIONCAUSELIST_SIZE) {
40         strncpy(exccause, "Reserved", sizeof(exccause));
41     }
42     else {
43         strncpy(exccause, Hmd_DmxExceptionCauseList[excepIndex],
44                 sizeof(exccause));
45     }
46 
47     snprintf(epc1, sizeof(epc1), "0x%08x", wordBuf[EPC1_INDEX]);
48 
49     if (strlen(outbuf) > 0) {
50         strncat(outbuf, SEPARATOR,
51                 outbuf_max_size - strlen(outbuf) - 1);
52     }
53 
54     strncat(outbuf, core,
55             outbuf_max_size - strlen(outbuf) - 1);
56     strncat(outbuf, " crash ",
57             outbuf_max_size - strlen(outbuf) - 1);
58     strncat(outbuf, exccause,
59             outbuf_max_size - strlen(outbuf) - 1);
60     strncat(outbuf, "/",
61             outbuf_max_size - strlen(outbuf) - 1);
62     strncat(outbuf, epc1,
63             outbuf_max_size - strlen(outbuf) - 1);
64 
65     return outbuf;
66 }
67 
find_exceptionin_cm4(unsigned char * buf,int buf_len,const char * core,char * outbuf,int outbuf_max_size)68 char* find_exceptionin_cm4(unsigned char *buf, int buf_len, const char *core,
69                            char *outbuf, int outbuf_max_size)
70 {
71 
72     char cause[64] = {0};
73     uint32_t *wordBuf = (uint32_t*)buf;
74 
75     if (buf == NULL || buf_len < CM4_INDEX_MAX * BYTES_PER_WORD ||
76         core == NULL || outbuf == NULL || outbuf_max_size <= 0 ||
77         wordBuf[START_CM4_INDEX] == 0 ||
78         strlen(outbuf) >= outbuf_max_size)
79         return outbuf;
80 
81     int faultStatusRegister = wordBuf[FAULT_STATUS_INDEX];
82 
83     int exceptionBitSet = find_rightmost_setbit_position(faultStatusRegister);
84 
85     if (exceptionBitSet == -1) {
86         return outbuf;
87     }
88 
89     if (exceptionBitSet >= CM4EXCEPTIONCAUSELIST_SIZE) {
90         strncpy(cause, "Reserved", sizeof(cause));
91     }
92     else {
93         strncpy(cause, Cm4ExceptionCauseList[exceptionBitSet],
94                 sizeof(cause));
95     }
96 
97     if(strlen(outbuf) > 0){
98         strncat(outbuf, SEPARATOR,
99                 outbuf_max_size - strlen(outbuf) - 1);
100     }
101 
102     strncat(outbuf, core,
103             outbuf_max_size - strlen(outbuf) - 1);
104     strncat(outbuf, " crash ",
105             outbuf_max_size - strlen(outbuf) - 1);
106     strncat(outbuf, cause,
107             outbuf_max_size - strlen(outbuf) - 1);
108 
109     return outbuf;
110 }
111 
112 
find_fatal_assert(unsigned char * buf,int buf_len,int size,const char * core,char * outbuf,int outbuf_max_size)113 char* find_fatal_assert(unsigned char *buf, int buf_len, int size,
114                         const char *core, char *outbuf,
115                         int outbuf_max_size)
116 {
117 
118     char cause[64] = {0};
119     char lineNumStr[10] = {0};
120     uint32_t *wordBuf = (uint32_t*)buf;
121     uint32_t wordSize = size / 4;
122     /*
123      *|Time Stamp|Event Label,Debug Level,Line No|Opaque Data 1|Opaque Data 2|Opaque Data 3|Opaque Data 4|
124      *|(64 bits) | (12 bits), (4 bits), (16 bits)|  (32 bits)  |  (32 bits)  |  (32 bits)  |  (32 bits)  |
125      */
126     int info_size = 7;
127     /* Index of event label word in 64 bit timestamp */
128     int curEvtIndex = 2;
129 
130     if (buf == NULL || size <= 0 || buf_len < size || core == NULL ||
131         outbuf == NULL || outbuf_max_size <= 0 ||
132         strlen(outbuf) >= outbuf_max_size)
133         return outbuf;
134 
135     /* This 32-bit word containing this info
136      * is in Little-Endian format to read
137      * the value of this fields.
138      *
139      *  |0...11|  -> Module Id
140      *  |12...15| -> Log level
141      *  |16...31| -> Line no
142      */
143     while (curEvtIndex < wordSize) {
144         int evt = wordBuf[curEvtIndex];
145         int logLevel = (evt >> 12) & 0xF;
146 
147         if (logLevel != DBG_LOG_LVL_FATAL) {
148             curEvtIndex += info_size;
149             continue;
150         }
151 
152         int module_id = evt & 0xFFF;
153         int lineNo = (evt >> 16) & 0xFFFF;
154 
155         if (module_id >= ASSERTDEBUGMODLIST_SIZE) {
156             /* Invalid module id */
157             curEvtIndex += info_size;
158             continue;
159         }
160         else {
161             snprintf(cause, sizeof(cause), "%s",
162                      AssertDebugModList[module_id]);
163         }
164 
165         strncat(cause , "+",
166                 sizeof(cause) - strlen(cause) - 1);
167 
168         snprintf(lineNumStr, sizeof(lineNumStr), "%d", lineNo);
169 
170         strncat(cause, lineNumStr,
171                 sizeof(cause) - strlen(cause) - 1);
172 
173         if(strlen(outbuf) > 0) {
174             strncat(outbuf, SEPARATOR,
175                     outbuf_max_size - strlen(outbuf) - 1);
176         }
177 
178         strncat(outbuf, "ASSERT LOG in ",
179                 outbuf_max_size - strlen(outbuf) - 1);
180         strncat(outbuf, core,
181                 outbuf_max_size - strlen(outbuf) - 1);
182         strncat(outbuf, " ",
183                 outbuf_max_size - strlen(outbuf) - 1);
184         strncat(outbuf, cause,
185                 outbuf_max_size - strlen(outbuf) - 1);
186 
187         return outbuf;
188     }
189 
190     return outbuf;
191 }
192 
analyse_crash_info(const unsigned char * buf,const int buf_len,char * out_crash_analyzer_str,int max_out_crash_analyzer_str_size)193 int analyse_crash_info(const unsigned char *buf, const int buf_len,
194                        char *out_crash_analyzer_str,
195                        int max_out_crash_analyzer_str_size)
196 {
197     unsigned int file_index = 0, size = 0, tot_len = 0;
198     int fcount = 0;
199     unsigned char *ptr = NULL;
200 
201     if (buf == NULL || out_crash_analyzer_str == NULL ||
202         buf_len <= 0 || max_out_crash_analyzer_str_size <= 0) {
203         ALOGE("%s: Bad parameters", __func__);
204         return -1;
205     }
206 
207     out_crash_analyzer_str[0] = '\0';
208 
209     while ((tot_len + STEP_LENGTH - 1 < buf_len) && (fcount++ < FILE_MAX)) {
210         file_index = buf[tot_len];
211 
212         size = buf[tot_len + 8] |
213             buf[tot_len + 9] << 8 |
214             buf[tot_len + 10] << 16 |
215             buf[tot_len + 11] << 24;
216 
217         tot_len += STEP_LENGTH;
218         ptr = (unsigned char*)buf + tot_len;
219 
220         if (file_index == CM4_DUMP_DEBUG) {
221             find_fatal_assert(ptr, buf_len - tot_len, size, "CM4",
222                               out_crash_analyzer_str,
223                               max_out_crash_analyzer_str_size);
224         } else if(file_index == HMD_DUMP_DEBUG) {
225             find_fatal_assert(ptr, buf_len - tot_len, size, "HMD",
226                               out_crash_analyzer_str,
227                               max_out_crash_analyzer_str_size);
228         } else if(file_index == DMX_DUMP_DEBUG) {
229             find_fatal_assert(ptr, buf_len - tot_len, size, "DMX",
230                               out_crash_analyzer_str,
231                               max_out_crash_analyzer_str_size);
232         } else if(file_index == CM4_DUMP_CRASH) {
233             find_exceptionin_cm4(ptr, buf_len - tot_len, "CM4",
234                                  out_crash_analyzer_str,
235                                  max_out_crash_analyzer_str_size);
236         } else if(file_index == HMD_DUMP_CRASH) {
237             find_exception_in_hmd_dmx(ptr, buf_len - tot_len, "HMD",
238                                       out_crash_analyzer_str,
239                                       max_out_crash_analyzer_str_size);
240         } else if(file_index == DMX_DUMP_CRASH) {
241             find_exception_in_hmd_dmx(ptr, buf_len - tot_len, "DMX",
242                                       out_crash_analyzer_str,
243                                       max_out_crash_analyzer_str_size);
244         } else {
245             ALOGE("%s: unknown index number: %u", __func__ , file_index);
246         }
247 
248         tot_len += size;
249     }
250 
251     return strlen(out_crash_analyzer_str);
252 }
253