1 /*
2  * Copyright (C) 2015-2018 Alibaba Group Holding Limited
3  */
4 #include "k_api.h"
5 #include "debug_api.h"
6 
7 /* convert int to ascii(HEX)
8    while using format % in libc, malloc/free is involved.
9    this function avoid using malloc/free. so it works when heap corrupt. */
k_int2str(int num,char * str)10 char *k_int2str(int num, char *str)
11 {
12     char         index[] = "0123456789ABCDEF";
13     unsigned int usnum   = (unsigned int)num;
14 
15     str[7] = index[usnum % 16];
16     usnum /= 16;
17     str[6] = index[usnum % 16];
18     usnum /= 16;
19     str[5] = index[usnum % 16];
20     usnum /= 16;
21     str[4] = index[usnum % 16];
22     usnum /= 16;
23     str[3] = index[usnum % 16];
24     usnum /= 16;
25     str[2] = index[usnum % 16];
26     usnum /= 16;
27     str[1] = index[usnum % 16];
28     usnum /= 16;
29     str[0] = index[usnum % 16];
30     usnum /= 16;
31 
32     return str;
33 }
34 
35 #if (K_MM_STATISTIC > 0)
debug_mm_overview(int (* print_func)(const char * fmt,...))36 void debug_mm_overview(int (*print_func)(const char *fmt, ...))
37 {
38 #if (RHINO_CONFIG_MM_BLK > 0)
39     mblk_info_t pool_info;
40 #endif
41 
42     size_t max_free_blk_size = 0;
43 #if (RHINO_CONFIG_MM_TLF > 0)
44     max_free_blk_size = krhino_mm_max_free_size_get();
45 #endif
46 
47     char s_heap_overview[] =
48                 "      | 0x         | 0x         | 0x         | 0x         | 0x            |\r\n";
49 
50     print_func(
51                 "---------------------------------------------------------------------------\r\n");
52     print_func(
53                 "[HEAP]| TotalSz    | FreeSz     | UsedSz     | MinFreeSz  | MaxFreeBlkSz  |\r\n");
54 
55     k_int2str((int)(g_kmm_head->free_size + g_kmm_head->used_size),
56               &s_heap_overview[10]);
57     k_int2str((int)g_kmm_head->free_size, &s_heap_overview[23]);
58     k_int2str((int)g_kmm_head->used_size, &s_heap_overview[36]);
59     k_int2str((int)(g_kmm_head->free_size + g_kmm_head->used_size -
60                     g_kmm_head->maxused_size),
61               &s_heap_overview[49]);
62     k_int2str((int)max_free_blk_size, &s_heap_overview[62]);
63     print_func(s_heap_overview);
64 
65     print_func(
66                 "---------------------------------------------------------------------------\r\n");
67 
68 #if (RHINO_CONFIG_MM_BLK > 0)
69     (void)krhino_mblk_info_nolock((mblk_pool_t *)g_kmm_head->fix_pool, &pool_info);
70     print_func(
71                 "[POOL]| PoolSz     | FreeSz     | UsedSz     | MinFreeSz  | MaxFreeBlkSz  |\r\n");
72 
73     k_int2str((int)pool_info.pool_size, &s_heap_overview[10]);
74     k_int2str((int)(pool_info.pool_size - pool_info.used_size), &s_heap_overview[23]);
75     k_int2str((int)pool_info.used_size, &s_heap_overview[36]);
76     k_int2str((int)(pool_info.pool_size - pool_info.max_used_size), &s_heap_overview[49]);
77     k_int2str((int)pool_info.max_blk_size, &s_heap_overview[62]);
78     print_func(s_heap_overview);
79 
80     print_func(
81                 "---------------------------------------------------------------------------\r\n");
82 #endif
83 }
84 #else
debug_mm_overview(int (* print_func)(const char * fmt,...))85 void debug_mm_overview(int (*print_func)(const char *fmt, ...))
86 {
87     print_func("K_MM_STATISTIC in k_config.h is closed!\r\n");
88 }
89 #endif
90 
91 #if (RHINO_CONFIG_KOBJ_LIST > 0)
debug_task_show(int (* print_func)(const char * fmt,...),ktask_t * task)92 static void debug_task_show(int (*print_func)(const char *fmt, ...), ktask_t *task)
93 {
94     size_t        free_size;
95     int           stat_idx;
96     int           i;
97     int           cpu_idx;
98     char         *cpu_stat[] = { "UNK",      "RDY", "PEND",    "SUS",
99                                  "PEND_SUS", "SLP", "SLP_SUS", "DEL"
100                                };
101     const name_t *task_name;
102 
103     char s_task_overview[] = "                              0x         0x      "
104                              "   0x        (0x        )\r\n";
105 
106     if (krhino_task_stack_min_free(task, &free_size) != RHINO_SUCCESS) {
107         free_size = 0;
108     }
109     free_size *= sizeof(cpu_stack_t);
110 
111     /* set name */
112     task_name = task->task_name == NULL ? "anonym" : task->task_name;
113     for (i = 0; i < 20; i++) {
114         s_task_overview[i] = ' ';
115     }
116     for (i = 0; i < strlen(task_name); i++) {
117         s_task_overview[i] = task_name[i];
118     }
119 
120     /* set state */
121     stat_idx = task->task_state >= sizeof(cpu_stat) / sizeof(char *)
122                ? 0
123                : task->task_state;
124     for (i = 21; i < 29; i++) {
125         s_task_overview[i] = ' ';
126     }
127     for (i = 21; i < 29; i++) {
128         if (cpu_stat[stat_idx][i - 21] == '\0') {
129             break;
130         }
131         s_task_overview[i] = cpu_stat[stat_idx][i - 21];
132     }
133 
134     /* set stack priority */
135     k_int2str(task->prio, &s_task_overview[32]);
136 
137     /* set stack info */
138     k_int2str((int)task->task_stack_base, &s_task_overview[43]);
139     k_int2str((int)task->stack_size * sizeof(cpu_stack_t),
140               &s_task_overview[54]);
141     k_int2str((int)free_size, &s_task_overview[65]);
142     cpu_idx = 65 + 17;
143 
144     (void)cpu_idx;
145 #if (RHINO_CONFIG_CPU_NUM > 1)
146     s_task_overview[cpu_idx] = (uint8_t)('0' + task->cpu_binded);
147     s_task_overview[cpu_idx + 10] = (uint8_t)('0' + task->cpu_num);
148     s_task_overview[cpu_idx + 20] = (uint8_t)('0' + task->cur_exc);
149 #endif
150 
151     /* print */
152     if (print_func == NULL) {
153         print_func = printf;
154     }
155     print_func(s_task_overview);
156 
157 }
debug_task_overview(int (* print_func)(const char * fmt,...))158 void debug_task_overview(int (*print_func)(const char *fmt, ...))
159 {
160     klist_t      *listnode;
161     ktask_t      *task;
162 
163     print_func("---------------------------------------------------------------"
164                "-----------\r\n");
165 #if (RHINO_CONFIG_CPU_NUM > 1)
166     print_func("TaskName             State    Prio       Stack      StackSize "
167                "(MinFree)      cpu_binded    cpu_num    cur_exc\r\n");
168 #else
169     print_func("TaskName             State    Prio       Stack      StackSize "
170                "(MinFree)\r\n");
171 #endif
172     print_func("---------------------------------------------------------------"
173                "-----------\r\n");
174 
175     for (listnode = g_kobj_list.task_head.next;
176          listnode != &g_kobj_list.task_head; listnode = listnode->next) {
177         task = krhino_list_entry(listnode, ktask_t, task_stats_item);
178         debug_task_show(print_func, task);
179     }
180 }
181 #else
debug_task_overview(int (* print_func)(const char * fmt,...))182 void debug_task_overview(int (*print_func)(const char *fmt, ...))
183 {
184     print_func("RHINO_CONFIG_KOBJ_LIST in k_config.h is closed!\r\n");
185 }
186 #endif /* #if (RHINO_CONFIG_KOBJ_LIST > 0) */
187 
188 #if (RHINO_CONFIG_BUF_QUEUE > 0)
189 #if (RHINO_CONFIG_KOBJ_LIST > 0)
debug_buf_queue_overview(int (* print_func)(const char * fmt,...))190 void debug_buf_queue_overview(int (*print_func)(const char *fmt, ...))
191 {
192     int           i;
193     klist_t      *listnode;
194     klist_t      *blk_list_head;
195     ktask_t      *task;
196     kbuf_queue_t *buf_queue;
197     const name_t *task_name;
198     char s_buf_queue_overview[] = "0x         0x         0x         0x         "
199                                   "0x                             \r\n";
200 
201     print_func(
202                 "------------------------------------------------------------------\r\n");
203     print_func(
204                 "BufQueAddr TotalSize  PeakNum    CurrNum    MinFreeSz  TaskWaiting\r\n");
205     print_func(
206                 "------------------------------------------------------------------\r\n");
207     for (listnode = g_kobj_list.buf_queue_head.next;
208          listnode != &g_kobj_list.buf_queue_head; listnode = listnode->next) {
209 
210         buf_queue = krhino_list_entry(listnode, kbuf_queue_t, buf_queue_item);
211         if (buf_queue->blk_obj.obj_type != RHINO_BUF_QUEUE_OBJ_TYPE) {
212             print_func("BufQueue Type error!\r\n");
213             break;
214         }
215 
216         /* set buf_queue information */
217         k_int2str((int)buf_queue, &s_buf_queue_overview[2]);
218         k_int2str((int)(buf_queue->ringbuf.end - buf_queue->ringbuf.buf),
219                   &s_buf_queue_overview[13]);
220         k_int2str((int)buf_queue->peak_num, &s_buf_queue_overview[24]);
221         k_int2str((int)buf_queue->cur_num, &s_buf_queue_overview[35]);
222         k_int2str((int)buf_queue->min_free_buf_size, &s_buf_queue_overview[46]);
223 
224         /* set pending task name */
225         blk_list_head = &buf_queue->blk_obj.blk_list;
226         if (is_klist_empty(blk_list_head)) {
227             task_name = " ";
228         } else {
229             task = krhino_list_entry(blk_list_head->next, ktask_t, task_list);
230             task_name = task->task_name == NULL ? "anonym" : task->task_name;
231         }
232 
233         for (i = 0; i < 20; i++) {
234             s_buf_queue_overview[55 + i] = ' ';
235         }
236         for (i = 0; i < 20; i++) {
237             if (task_name[i] == '\0') {
238                 break;
239             }
240             s_buf_queue_overview[55 + i] = task_name[i];
241         }
242 
243         /* print */
244         print_func(s_buf_queue_overview);
245     }
246 }
247 #else
debug_buf_queue_overview(int (* print_func)(const char * fmt,...))248 void debug_buf_queue_overview(int (*print_func)(const char *fmt, ...))
249 {
250     print_func("RHINO_CONFIG_KOBJ_LIST in k_config.h is closed!\r\n");
251 }
252 #endif
253 #endif
254 
255 #if (RHINO_CONFIG_QUEUE > 0)
256 #if (RHINO_CONFIG_KOBJ_LIST > 0)
debug_queue_overview(int (* print_func)(const char * fmt,...))257 void debug_queue_overview(int (*print_func)(const char *fmt, ...))
258 {
259     int           i;
260     klist_t      *listnode;
261     klist_t      *blk_list_head;
262     ktask_t      *task;
263     kqueue_t     *queue;
264     const name_t *task_name;
265     char          s_queue_overview[] =
266                 "0x         0x         0x         0x                             \r\n";
267 
268     print_func("-------------------------------------------------------\r\n");
269     print_func("QueAddr    TotalSize  PeakNum    CurrNum    TaskWaiting\r\n");
270     print_func("-------------------------------------------------------\r\n");
271 
272     for (listnode = g_kobj_list.queue_head.next;
273          listnode != &g_kobj_list.queue_head; listnode = listnode->next) {
274 
275         queue = krhino_list_entry(listnode, kqueue_t, queue_item);
276         if (queue->blk_obj.obj_type != RHINO_QUEUE_OBJ_TYPE) {
277             print_func("Queue Type error!\r\n");
278             break;
279         }
280 
281         /* set queue information */
282         k_int2str((int)queue->msg_q.queue_start, &s_queue_overview[2]);
283         k_int2str((int)queue->msg_q.size, &s_queue_overview[13]);
284         k_int2str((int)queue->msg_q.peak_num, &s_queue_overview[24]);
285         k_int2str((int)queue->msg_q.cur_num, &s_queue_overview[35]);
286 
287         /* set pending task name */
288         blk_list_head = &queue->blk_obj.blk_list;
289         if (is_klist_empty(blk_list_head)) {
290             task_name = " ";
291         } else {
292             task = krhino_list_entry(blk_list_head->next, ktask_t, task_list);
293             task_name = task->task_name == NULL ? "anonym" : task->task_name;
294         }
295 
296         for (i = 0; i < 20; i++) {
297             s_queue_overview[44 + i] = ' ';
298         }
299         for (i = 0; i < 20; i++) {
300             if (task_name[i] == '\0') {
301                 break;
302             }
303             s_queue_overview[44 + i] = task_name[i];
304         }
305 
306         /* print */
307         print_func(s_queue_overview);
308     }
309 }
310 #else
debug_queue_overview(int (* print_func)(const char * fmt,...))311 void debug_queue_overview(int (*print_func)(const char *fmt, ...))
312 {
313     print_func("RHINO_CONFIG_KOBJ_LIST in k_config.h is closed!\r\n");
314 }
315 #endif
316 #endif
317 
318 #if (RHINO_CONFIG_SEM > 0)
319 #if (RHINO_CONFIG_KOBJ_LIST > 0)
debug_sem_overview(int (* print_func)(const char * fmt,...))320 void debug_sem_overview(int (*print_func)(const char *fmt, ...))
321 {
322     int           i, cnt = 0;
323     ksem_t       *sem;
324     ktask_t      *task;
325     klist_t      *listnode;
326     klist_t      *blk_list_head;
327     const name_t *task_name;
328     char          s_sem_overview[] =
329                 "0x         0x         0x                             \r\n";
330     char          s_sem_total[] =
331                 "Total: 0x         \r\n";
332 
333     print_func("--------------------------------------------\r\n");
334     print_func("SemAddr    Count      PeakCount  TaskWaiting\r\n");
335     print_func("--------------------------------------------\r\n");
336 
337     for (listnode = g_kobj_list.sem_head.next;
338          listnode != &g_kobj_list.sem_head; listnode = listnode->next) {
339 
340         cnt++;
341 
342         sem = krhino_list_entry(listnode, ksem_t, sem_item);
343         if (sem->blk_obj.obj_type != RHINO_SEM_OBJ_TYPE) {
344             print_func("Sem Type error sem addr %p!\r\n", sem);
345             break;
346         }
347 
348         /* only show sem waited by task */
349         blk_list_head = &sem->blk_obj.blk_list;
350         if (is_klist_empty(blk_list_head)) {
351             continue;
352         }
353 
354         /* set sem information */
355         k_int2str((int)sem, &s_sem_overview[2]);
356         k_int2str((int)sem->count, &s_sem_overview[13]);
357         k_int2str((int)sem->peak_count, &s_sem_overview[24]);
358 
359         /* set pending task name */
360         blk_list_head = &sem->blk_obj.blk_list;
361         if (is_klist_empty(blk_list_head)) {
362             task_name = " ";
363         } else {
364             task = krhino_list_entry(blk_list_head->next, ktask_t, task_list);
365             task_name = task->task_name == NULL ? "anonym" : task->task_name;
366         }
367 
368         for (i = 0; i < 20; i++) {
369             s_sem_overview[33 + i] = ' ';
370         }
371         for (i = 0; (i < 20) && i < strlen(task_name); i++) {
372             s_sem_overview[33 + i] = task_name[i];
373         }
374 
375         /* print */
376         print_func(s_sem_overview);
377     }
378     k_int2str(cnt, &s_sem_total[9]);
379     print_func(s_sem_total);
380 }
381 #else
debug_sem_overview(int (* print_func)(const char * fmt,...))382 void debug_sem_overview(int (*print_func)(const char *fmt, ...))
383 {
384     print_func("RHINO_CONFIG_KOBJ_LIST in k_config.h is closed!\r\n");
385 }
386 #endif
387 #endif /* RHINO_CONFIG_SEM */
388 
389 #if (RHINO_CONFIG_KOBJ_LIST > 0)
debug_mutex_overview(int (* print_func)(const char * fmt,...))390 void debug_mutex_overview(int (*print_func)(const char *fmt, ...))
391 {
392     int           i, cnt = 0;
393     kmutex_t     *mutex;
394     ktask_t      *task;
395     klist_t      *listnode;
396     klist_t      *blk_list_head;
397     const name_t *task_name;
398     char          s_mutex_overview[] =
399                 "0x                              0x                              \r\n";
400     char          s_mutex_total[] =
401                 "Total: 0x         \r\n";
402 
403     print_func("--------------------------------------------\r\n");
404     print_func("MutexAddr  TaskOwner            NestCnt    TaskWaiting\r\n");
405     print_func("--------------------------------------------\r\n");
406 
407     for (listnode = g_kobj_list.mutex_head.next;
408          listnode != &g_kobj_list.mutex_head; listnode = listnode->next) {
409 
410         cnt++;
411 
412         mutex = krhino_list_entry(listnode, kmutex_t, mutex_item);
413         if (mutex->blk_obj.obj_type != RHINO_MUTEX_OBJ_TYPE) {
414             print_func("Mutex Type error!\r\n");
415             break;
416         }
417 
418         /* only show mutex waited by task */
419         task = mutex->mutex_task;
420         if (task == NULL) {
421             continue;
422         }
423 
424         /* set mutex information */
425         k_int2str((int)mutex, &s_mutex_overview[2]);
426         k_int2str((int)mutex->owner_nested, &s_mutex_overview[34]);
427 
428         /* set owner task name */
429         task_name = task->task_name == NULL ? "anonym" : task->task_name;
430         for (i = 0; i < 20; i++) {
431             s_mutex_overview[11 + i] = ' ';
432         }
433         for (i = 0; i <= strlen(task_name); i++) {
434             s_mutex_overview[11 + i] = task_name[i];
435         }
436 
437         /* set pending task name */
438         blk_list_head = &mutex->blk_obj.blk_list;
439         if (!is_klist_empty(blk_list_head)) {
440             task = krhino_list_entry(blk_list_head->next, ktask_t, task_list);
441             task_name = task->task_name == NULL ? "anonym" : task->task_name;
442             for (i = 0; i < 20; i++) {
443                 s_mutex_overview[43 + i] = ' ';
444             }
445             for (i = 0; (i < 20) && (i < strlen(task_name)); i++) {
446                 s_mutex_overview[43 + i] = task_name[i];
447             }
448         }
449 
450         /* print */
451         print_func(s_mutex_overview);
452     }
453 
454     k_int2str(cnt, &s_mutex_total[9]);
455     print_func(s_mutex_total);
456 }
457 #else
debug_mutex_overview(int (* print_func)(const char * fmt,...))458 void debug_mutex_overview(int (*print_func)(const char *fmt, ...))
459 {
460     print_func("RHINO_CONFIG_KOBJ_LIST in k_config.h is closed!\r\n");
461 }
462 #endif
463 
debug_overview(int (* print_func)(const char * fmt,...))464 void debug_overview(int (*print_func)(const char *fmt, ...))
465 {
466 #if (RHINO_CONFIG_MM_TLF > 0)
467     print_func("========== Heap Info  ==========\r\n");
468     debug_mm_overview(print_func);
469 #endif
470     print_func("========== Task Info  ==========\r\n");
471     debug_task_overview(print_func);
472 #if (RHINO_CONFIG_QUEUE > 0)
473     print_func("========== Queue Info ==========\r\n");
474     debug_queue_overview(print_func);
475 #endif
476 #if (RHINO_CONFIG_BUF_QUEUE > 0)
477     print_func("======== Buf Queue Info ========\r\n");
478     debug_buf_queue_overview(print_func);
479 #endif
480 #if (RHINO_CONFIG_SEM > 0)
481     print_func("========== Sem Waiting ==========\r\n");
482     debug_sem_overview(print_func);
483 #endif
484     print_func("========= Mutex Waiting =========\r\n");
485     debug_mutex_overview(print_func);
486 }
487 
488 #if (K_MM_STATISTIC > 0)
489 #if (RHINO_CONFIG_MM_TLF > 0)
debug_heap_info_get(debug_mm_info_t * mm_info)490 void debug_heap_info_get(debug_mm_info_t *mm_info)
491 {
492     mm_info->total_size   = g_kmm_head->free_size + g_kmm_head->used_size;
493     mm_info->free_size    = g_kmm_head->free_size;
494     mm_info->used_size    = g_kmm_head->used_size;
495     mm_info->maxused_size = g_kmm_head->maxused_size;
496     mm_info->maxblk_size  = -1; /* not support current, will be replaced by krhino_mm_max_free_size_get() */
497     return;
498 }
499 #endif
500 
501 #if (RHINO_CONFIG_MM_BLK > 0)
debug_pool_info_get(debug_mm_info_t * mm_info)502 void debug_pool_info_get(debug_mm_info_t *mm_info)
503 {
504     mblk_info_t pool_info;
505     (void)krhino_mblk_info_nolock((mblk_pool_t *)g_kmm_head->fix_pool, &pool_info);
506     mm_info->total_size   = pool_info.pool_size;
507     mm_info->free_size    = pool_info.pool_size - pool_info.used_size;
508     mm_info->used_size    = pool_info.used_size;
509     mm_info->maxused_size = pool_info.max_used_size;
510     mm_info->maxblk_size  = pool_info.max_blk_size;
511     return;
512 }
513 #endif
514 #endif
515 
516