1 /*
2 * Copyright (c) 2006-2024 RT-Thread Development Team
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 *
6 * Change Logs:
7 * Date Author Notes
8 * 2018/08/29 Bernard first version
9 */
10
11 #include <rthw.h>
12
13 #include "dlfcn.h"
14 #include "dlmodule.h"
15 #include "dlelf.h"
16
17 #ifdef RT_USING_POSIX_FS
18 #include <stdio.h>
19 #include <fcntl.h>
20 #include <unistd.h>
21 #include <sys/stat.h>
22 #include <sys/statfs.h>
23 #endif
24
25 #define DBG_TAG "DLMD"
26 #define DBG_LVL DBG_INFO
27 #include <rtdbg.h> /* must after of DEBUG_ENABLE or some other options*/
28
29 static struct rt_module_symtab *_rt_module_symtab_begin = RT_NULL;
30 static struct rt_module_symtab *_rt_module_symtab_end = RT_NULL;
31
32 #if defined(__IAR_SYSTEMS_ICC__) /* for IAR compiler */
33 #pragma section="RTMSymTab"
34 #endif
35
36 /* set the name of module */
_dlmodule_set_name(struct rt_dlmodule * module,const char * path)37 static void _dlmodule_set_name(struct rt_dlmodule *module, const char *path)
38 {
39 int size;
40 struct rt_object *object;
41 const char *first, *end, *ptr;
42
43 object = &(module->parent);
44 ptr = first = (char *)path;
45 end = path + rt_strlen(path);
46
47 while (*ptr != '\0')
48 {
49 if (*ptr == '/')
50 first = ptr + 1;
51 if (*ptr == '.')
52 end = ptr - 1;
53
54 ptr ++;
55 }
56
57 size = end - first + 1;
58 if (size >= RT_NAME_MAX) size = RT_NAME_MAX - 1;
59
60 rt_strncpy(object->name, first, size);
61 object->name[size] = '\0';
62 }
63
64 #define RT_MODULE_ARG_MAX 8
_rt_module_split_arg(char * cmd,rt_size_t length,char * argv[])65 static int _rt_module_split_arg(char *cmd, rt_size_t length, char *argv[])
66 {
67 int argc = 0;
68 char *ptr = cmd;
69
70 while ((ptr - cmd) < length)
71 {
72 /* strip bank and tab */
73 while ((*ptr == ' ' || *ptr == '\t') && (ptr - cmd) < length)
74 *ptr++ = '\0';
75 /* check whether it's the end of line */
76 if ((ptr - cmd) >= length) break;
77
78 /* handle string with quote */
79 if (*ptr == '"')
80 {
81 argv[argc++] = ++ptr;
82
83 /* skip this string */
84 while (*ptr != '"' && (ptr - cmd) < length)
85 if (*ptr ++ == '\\') ptr ++;
86 if ((ptr - cmd) >= length) break;
87
88 /* skip '"' */
89 *ptr ++ = '\0';
90 }
91 else
92 {
93 argv[argc++] = ptr;
94 while ((*ptr != ' ' && *ptr != '\t') && (ptr - cmd) < length)
95 ptr ++;
96 }
97
98 if (argc >= RT_MODULE_ARG_MAX) break;
99 }
100
101 return argc;
102 }
103
104 /* invoked by main thread for exit */
_dlmodule_exit(void)105 static void _dlmodule_exit(void)
106 {
107 struct rt_dlmodule *module;
108
109 module = dlmodule_self();
110 if (!module) return; /* not a module thread */
111
112 rt_enter_critical();
113 if (module->stat == RT_DLMODULE_STAT_RUNNING)
114 {
115 struct rt_object *object = RT_NULL;
116 struct rt_list_node *node = RT_NULL;
117
118 /* set stat to closing */
119 module->stat = RT_DLMODULE_STAT_CLOSING;
120
121 /* suspend all threads in this module */
122 for (node = module->object_list.next; node != &(module->object_list); node = node->next)
123 {
124 object = rt_list_entry(node, struct rt_object, list);
125
126 if ((object->type & ~RT_Object_Class_Static) == RT_Object_Class_Thread)
127 {
128 rt_thread_t thread = (rt_thread_t)object;
129
130 /* stop timer and suspend thread*/
131 if ((RT_SCHED_CTX(thread).stat & RT_THREAD_STAT_MASK) != RT_THREAD_CLOSE &&
132 (RT_SCHED_CTX(thread).stat & RT_THREAD_STAT_MASK) != RT_THREAD_INIT)
133 {
134 rt_timer_stop(&(thread->thread_timer));
135 rt_thread_suspend(thread);
136 }
137 }
138 }
139 }
140 rt_exit_critical();
141
142 return;
143 }
144
_dlmodule_thread_entry(void * parameter)145 static void _dlmodule_thread_entry(void* parameter)
146 {
147 int argc = 0;
148 char *argv[RT_MODULE_ARG_MAX];
149
150 struct rt_dlmodule *module = (struct rt_dlmodule*)parameter;
151
152 if (module == RT_NULL || module->cmd_line == RT_NULL)
153 /* malloc for module_cmd_line failed. */
154 return;
155
156 if (module->cmd_line)
157 {
158 rt_memset(argv, 0x00, sizeof(argv));
159 argc = _rt_module_split_arg((char *)module->cmd_line, rt_strlen(module->cmd_line), argv);
160 if (argc == 0) goto __exit;
161 }
162
163 /* set status of module */
164 module->stat = RT_DLMODULE_STAT_RUNNING;
165
166 LOG_D("run main entry: 0x%p with %s",
167 module->entry_addr,
168 module->cmd_line);
169
170 if (module->entry_addr)
171 module->entry_addr(argc, argv);
172
173 __exit:
174 _dlmodule_exit();
175
176 return ;
177 }
178
179 /**
180 * @brief create a dynamic module object and initialize it.
181 *
182 * @return struct rt_dlmodule* If module create successfully, return the pointer to its rt_dlmodule structure.
183 */
dlmodule_create(void)184 struct rt_dlmodule *dlmodule_create(void)
185 {
186 struct rt_dlmodule *module = RT_NULL;
187
188 module = (struct rt_dlmodule*) rt_object_allocate(RT_Object_Class_Module, "module");
189 if (module)
190 {
191 module->stat = RT_DLMODULE_STAT_INIT;
192
193 /* set initial priority and stack size */
194 module->priority = RT_THREAD_PRIORITY_MAX - 1;
195 module->stack_size = 2048;
196
197 rt_list_init(&(module->object_list));
198 }
199
200 return module;
201 }
202
dlmodule_destroy_subthread(struct rt_dlmodule * module,rt_thread_t thread)203 void dlmodule_destroy_subthread(struct rt_dlmodule *module, rt_thread_t thread)
204 {
205 RT_ASSERT(thread->parent.module_id== module);
206
207 /* lock scheduler to prevent scheduling in cleanup function. */
208 rt_enter_critical();
209
210 rt_thread_close(thread);
211
212 /* remove thread from thread_list (defunct thread list) */
213 rt_list_remove(&RT_THREAD_LIST_NODE(thread));
214
215 /* invoke thread cleanup */
216 if (thread->cleanup != RT_NULL)
217 thread->cleanup(thread);
218
219 rt_exit_critical();
220
221 #ifdef RT_USING_SIGNALS
222 rt_thread_free_sig(thread);
223 #endif
224
225 if (thread->parent.type & RT_Object_Class_Static)
226 {
227 /* detach object */
228 rt_object_detach((rt_object_t)thread);
229 }
230 #ifdef RT_USING_HEAP
231 else
232 {
233 /* release thread's stack */
234 RT_KERNEL_FREE(thread->stack_addr);
235 /* delete thread object */
236 rt_object_delete((rt_object_t)thread);
237 }
238 #endif
239 }
240
241 /**
242 * @brief destroy dynamic module and cleanup all kernel objects inside it.
243 *
244 * @param module Pointer to the module to be destroyed.
245 * @return rt_err_t On success, it returns RT_EOK. Otherwise, it returns the error code.
246 */
dlmodule_destroy(struct rt_dlmodule * module)247 rt_err_t dlmodule_destroy(struct rt_dlmodule* module)
248 {
249 int i;
250
251 RT_DEBUG_NOT_IN_INTERRUPT;
252
253 /* check parameter */
254 if (module == RT_NULL)
255 return -RT_ERROR;
256
257 /* can not destroy a running module */
258 if (module->stat == RT_DLMODULE_STAT_RUNNING)
259 return -RT_EBUSY;
260
261 /* do module cleanup */
262 if (module->cleanup_func)
263 {
264 rt_enter_critical();
265 module->cleanup_func(module);
266 rt_exit_critical();
267 }
268
269 /* list_object(&(module->object_list));*/
270
271 /* cleanup for all kernel objects inside module*/
272 {
273 struct rt_object *object = RT_NULL;
274 struct rt_list_node *node = RT_NULL;
275
276 /* detach/delete all threads in this module */
277 for (node = module->object_list.next; node != &(module->object_list); )
278 {
279 int object_type;
280
281 object = rt_list_entry(node, struct rt_object, list);
282 object_type = object->type & ~RT_Object_Class_Static;
283
284 /* to next node */
285 node = node->next;
286
287 if (object->type & RT_Object_Class_Static)
288 {
289 switch (object_type)
290 {
291 case RT_Object_Class_Thread:
292 dlmodule_destroy_subthread(module, (rt_thread_t)object);
293 break;
294 #ifdef RT_USING_SEMAPHORE
295 case RT_Object_Class_Semaphore:
296 rt_sem_detach((rt_sem_t)object);
297 break;
298 #endif
299 #ifdef RT_USING_MUTEX
300 case RT_Object_Class_Mutex:
301 rt_mutex_detach((rt_mutex_t)object);
302 break;
303 #endif
304 #ifdef RT_USING_EVENT
305 case RT_Object_Class_Event:
306 rt_event_detach((rt_event_t)object);
307 break;
308 #endif
309 #ifdef RT_USING_MAILBOX
310 case RT_Object_Class_MailBox:
311 rt_mb_detach((rt_mailbox_t)object);
312 break;
313 #endif
314 #ifdef RT_USING_MESSAGEQUEUE
315 case RT_Object_Class_MessageQueue:
316 rt_mq_detach((rt_mq_t)object);
317 break;
318 #endif
319 #ifdef RT_USING_MEMHEAP
320 case RT_Object_Class_MemHeap:
321 rt_memheap_detach((struct rt_memheap*)object);
322 break;
323 #endif
324 #ifdef RT_USING_MEMPOOL
325 case RT_Object_Class_MemPool:
326 rt_mp_detach((struct rt_mempool*)object);
327 break;
328 #endif
329 case RT_Object_Class_Timer:
330 rt_timer_detach((rt_timer_t)object);
331 break;
332 default:
333 LOG_E("Unsupported oject type in module.");
334 break;
335 }
336 }
337 else
338 {
339 switch (object_type)
340 {
341 case RT_Object_Class_Thread:
342 dlmodule_destroy_subthread(module, (rt_thread_t)object);
343 break;
344 #ifdef RT_USING_SEMAPHORE
345 case RT_Object_Class_Semaphore:
346 rt_sem_delete((rt_sem_t)object);
347 break;
348 #endif
349 #ifdef RT_USING_MUTEX
350 case RT_Object_Class_Mutex:
351 rt_mutex_delete((rt_mutex_t)object);
352 break;
353 #endif
354 #ifdef RT_USING_EVENT
355 case RT_Object_Class_Event:
356 rt_event_delete((rt_event_t)object);
357 break;
358 #endif
359 #ifdef RT_USING_MAILBOX
360 case RT_Object_Class_MailBox:
361 rt_mb_delete((rt_mailbox_t)object);
362 break;
363 #endif
364 #ifdef RT_USING_MESSAGEQUEUE
365 case RT_Object_Class_MessageQueue:
366 rt_mq_delete((rt_mq_t)object);
367 break;
368 #endif
369 #ifdef RT_USING_MEMHEAP
370 /* no delete operation */
371 #endif
372 #ifdef RT_USING_MEMPOOL
373 case RT_Object_Class_MemPool:
374 rt_mp_delete((struct rt_mempool*)object);
375 break;
376 #endif
377 case RT_Object_Class_Timer:
378 rt_timer_delete((rt_timer_t)object);
379 break;
380 default:
381 LOG_E("Unsupported oject type in module.");
382 break;
383 }
384 }
385 }
386 }
387
388 if (module->cmd_line) rt_free(module->cmd_line);
389 /* release module symbol table */
390 for (i = 0; i < module->nsym; i ++)
391 {
392 rt_free((void *)module->symtab[i].name);
393 }
394 if (module->symtab != RT_NULL)
395 {
396 rt_free(module->symtab);
397 }
398
399 /* destory module */
400 rt_free(module->mem_space);
401 /* delete module object */
402 rt_object_delete((rt_object_t)module);
403
404 return RT_EOK;
405 }
406
407 /**
408 * @brief retrieve the dynamically loaded module that the current thread belongs to.
409 *
410 * @return struct rt_dlmodule* On success, it returns a pointer to the module. otherwise, it returns RT_NULL.
411 */
dlmodule_self(void)412 struct rt_dlmodule *dlmodule_self(void)
413 {
414 rt_thread_t tid;
415 struct rt_dlmodule *ret = RT_NULL;
416
417 tid = rt_thread_self();
418 if (tid)
419 {
420 ret = (struct rt_dlmodule*) tid->parent.module_id;
421 }
422
423 return ret;
424 }
425
426 /*
427 * Compatible with old API
428 */
rt_module_self(void)429 struct rt_dlmodule *rt_module_self(void)
430 {
431 return dlmodule_self();
432 }
433
434 /**
435 * @brief load an ELF module to memory.
436 *
437 * @param filename the path to the module to load.
438 * @return struct rt_dlmodule* On success, it returns a pointer to the module object. otherwise, RT_NULL is returned.
439 *
440 * @note the function is used to load an ELF (Executable and Linkable Format) module from a file, validate it,
441 * and initialize it as a dynamically loaded module. what it implements are as follows:
442 * 1. Load and Validate ELF: It loads an ELF file, checks its validity, and identifies it as either a relocatable or shared object.
443 * 2. Memory Allocation and Cleanup: Uses rt_malloc and rt_free to allocate and free memory for module data.
444 * Error handling ensures all resources are released if an error occurs.
445 * 3. Symbol Resolution and Initialization: Sets up init function and cleanup function, and calls the module_init function if it is present.
446 * 4. Cache Management: Optionally (when RT_USING_CACHE defined) flushes data and invalidates instruction caches to ensure the module is correctly loaded into memory.
447 */
dlmodule_load(const char * filename)448 struct rt_dlmodule* dlmodule_load(const char* filename)
449 {
450 #ifdef RT_USING_POSIX_FS
451 int fd = -1, length = 0;
452 #endif
453 rt_err_t ret = RT_EOK;
454 rt_uint8_t *module_ptr = RT_NULL;
455 struct rt_dlmodule *module = RT_NULL;
456
457 #ifdef RT_USING_POSIX_FS
458 fd = open(filename, O_RDONLY, 0);
459 if (fd >= 0)
460 {
461 length = lseek(fd, 0, SEEK_END);
462 lseek(fd, 0, SEEK_SET);
463
464 if (length == 0) goto __exit;
465
466 module_ptr = (uint8_t*) rt_malloc (length);
467 if (!module_ptr) goto __exit;
468
469 if (read(fd, module_ptr, length) != length)
470 goto __exit;
471
472 /* close file and release fd */
473 close(fd);
474 fd = -1;
475 }
476 else
477 {
478 goto __exit;
479 }
480 #endif
481
482 if (!module_ptr) goto __exit;
483
484 /* check ELF header */
485 if (rt_memcmp(elf_module->e_ident, RTMMAG, SELFMAG) != 0 &&
486 rt_memcmp(elf_module->e_ident, ELFMAG, SELFMAG) != 0)
487 {
488 rt_kprintf("Module: magic error\n");
489 goto __exit;
490 }
491
492 /* check ELF class */
493 if ((elf_module->e_ident[EI_CLASS] != ELFCLASS32)&&(elf_module->e_ident[EI_CLASS] != ELFCLASS64))
494 {
495 rt_kprintf("Module: ELF class error\n");
496 goto __exit;
497 }
498
499 module = dlmodule_create();
500 if (!module) goto __exit;
501
502 /* set the name of module */
503 _dlmodule_set_name(module, filename);
504
505 LOG_D("rt_module_load: %.*s", RT_NAME_MAX, module->parent.name);
506
507 if (elf_module->e_type == ET_REL)
508 {
509 ret = dlmodule_load_relocated_object(module, module_ptr);
510 }
511 else if (elf_module->e_type == ET_DYN)
512 {
513 ret = dlmodule_load_shared_object(module, module_ptr);
514 }
515 else
516 {
517 rt_kprintf("Module: unsupported elf type\n");
518 goto __exit;
519 }
520
521 /* check return value */
522 if (ret != RT_EOK) goto __exit;
523
524 /* release module data */
525 rt_free(module_ptr);
526
527 /* increase module reference count */
528 module->nref ++;
529
530 /* deal with cache */
531 #ifdef RT_USING_CACHE
532 rt_hw_cpu_dcache_ops(RT_HW_CACHE_FLUSH, module->mem_space, module->mem_size);
533 rt_hw_cpu_icache_ops(RT_HW_CACHE_INVALIDATE, module->mem_space, module->mem_size);
534 #endif
535
536 /* set module initialization and cleanup function */
537 module->init_func = dlsym(module, "module_init");
538 module->cleanup_func = dlsym(module, "module_cleanup");
539 module->stat = RT_DLMODULE_STAT_INIT;
540 /* do module initialization */
541 if (module->init_func)
542 {
543 module->init_func(module);
544 }
545
546 return module;
547
548 __exit:
549 #ifdef RT_USING_POSIX_FS
550 if (fd >= 0) close(fd);
551 #endif
552 if (module_ptr) rt_free(module_ptr);
553 if (module) dlmodule_destroy(module);
554
555 return RT_NULL;
556 }
557
558 /**
559 * @brief load a dynamic module, and create a thread to excute the module main function.
560 *
561 * @param pgname path of the module to be loaded.
562 * @param cmd the command string (with commandline options) for startup module.
563 * @param cmd_size the command's length.
564 * @return struct rt_dlmodule* On success, it returns a pointer to the module object. otherwise, RT_NULL is returned.
565 */
dlmodule_exec(const char * pgname,const char * cmd,int cmd_size)566 struct rt_dlmodule* dlmodule_exec(const char* pgname, const char* cmd, int cmd_size)
567 {
568 struct rt_dlmodule *module = RT_NULL;
569
570 module = dlmodule_load(pgname);
571 if (module)
572 {
573 if (module->entry_addr)
574 {
575 /* exec this module */
576 rt_thread_t tid;
577
578 module->cmd_line = rt_strdup(cmd);
579
580 /* check stack size and priority */
581 if (module->priority > RT_THREAD_PRIORITY_MAX) module->priority = RT_THREAD_PRIORITY_MAX - 1;
582 if (module->stack_size < 2048 || module->stack_size > (1024 * 32)) module->stack_size = 2048;
583
584 tid = rt_thread_create(module->parent.name, _dlmodule_thread_entry, (void*)module,
585 module->stack_size, module->priority, 10);
586 if (tid)
587 {
588 tid->parent.module_id= module;
589 module->main_thread = tid;
590
591 rt_thread_startup(tid);
592 }
593 else
594 {
595 /* destory dl module */
596 dlmodule_destroy(module);
597 module = RT_NULL;
598 }
599 }
600 }
601
602 return module;
603 }
604
605 #if defined(RT_USING_CUSTOM_DLMODULE)
dlmodule_load_custom(const char * filename,struct rt_dlmodule_ops * ops)606 struct rt_dlmodule* dlmodule_load_custom(const char* filename, struct rt_dlmodule_ops* ops)
607 {
608 #ifdef RT_USING_POSIX_FS
609 int fd = -1, length = 0;
610 #endif
611 rt_err_t ret = RT_EOK;
612 rt_uint8_t *module_ptr = RT_NULL;
613 struct rt_dlmodule *module = RT_NULL;
614
615 if (ops)
616 {
617 RT_ASSERT(ops->load);
618 RT_ASSERT(ops->unload);
619 module_ptr = ops->load(filename);
620 }
621 #ifdef RT_USING_POSIX_FS
622 else
623 {
624 fd = open(filename, O_RDONLY, 0);
625 if (fd >= 0)
626 {
627 length = lseek(fd, 0, SEEK_END);
628 lseek(fd, 0, SEEK_SET);
629
630 if (length == 0) goto __exit;
631
632 module_ptr = (uint8_t*) rt_malloc (length);
633 if (!module_ptr) goto __exit;
634
635 if (read(fd, module_ptr, length) != length)
636 goto __exit;
637
638 /* close file and release fd */
639 close(fd);
640 fd = -1;
641 }
642 else
643 {
644 goto __exit;
645 }
646 }
647 #endif
648
649 if (!module_ptr) goto __exit;
650
651 /* check ELF header */
652 if (rt_memcmp(elf_module->e_ident, RTMMAG, SELFMAG) != 0 &&
653 rt_memcmp(elf_module->e_ident, ELFMAG, SELFMAG) != 0)
654 {
655 rt_kprintf("Module: magic error\n");
656 goto __exit;
657 }
658
659 /* check ELF class */
660 if (elf_module->e_ident[EI_CLASS] != ELFCLASS32)
661 {
662 rt_kprintf("Module: ELF class error\n");
663 goto __exit;
664 }
665
666 module = dlmodule_create();
667 if (!module) goto __exit;
668
669 /* set the name of module */
670 _dlmodule_set_name(module, filename);
671
672 LOG_D("rt_module_load: %.*s", RT_NAME_MAX, module->parent.name);
673
674 if (elf_module->e_type == ET_REL)
675 {
676 ret = dlmodule_load_relocated_object(module, module_ptr);
677 }
678 else if (elf_module->e_type == ET_DYN)
679 {
680 ret = dlmodule_load_shared_object(module, module_ptr);
681 }
682 else
683 {
684 rt_kprintf("Module: unsupported elf type\n");
685 goto __exit;
686 }
687
688 /* check return value */
689 if (ret != RT_EOK) goto __exit;
690
691 /* release module data */
692 if (ops)
693 {
694 ops->unload(module_ptr);
695 }
696 else
697 {
698 rt_free(module_ptr);
699 }
700
701 /* increase module reference count */
702 module->nref ++;
703
704 /* deal with cache */
705 #ifdef RT_USING_CACHE
706 rt_hw_cpu_dcache_ops(RT_HW_CACHE_FLUSH, module->mem_space, module->mem_size);
707 rt_hw_cpu_icache_ops(RT_HW_CACHE_INVALIDATE, module->mem_space, module->mem_size);
708 #endif
709
710 /* set module initialization and cleanup function */
711 module->init_func = dlsym(module, "module_init");
712 module->cleanup_func = dlsym(module, "module_cleanup");
713 module->stat = RT_DLMODULE_STAT_INIT;
714 /* do module initialization */
715 if (module->init_func)
716 {
717 module->init_func(module);
718 }
719
720 return module;
721
722 __exit:
723 #ifdef RT_USING_POSIX_FS
724 if (fd >= 0) close(fd);
725 #endif
726 if (module_ptr)
727 {
728 if (ops)
729 {
730 ops->unload(module_ptr);
731 }
732 else
733 {
734 rt_free(module_ptr);
735 }
736 }
737
738 if (module) dlmodule_destroy(module);
739
740 return RT_NULL;
741 }
742
dlmodule_exec_custom(const char * pgname,const char * cmd,int cmd_size,struct rt_dlmodule_ops * ops)743 struct rt_dlmodule* dlmodule_exec_custom(const char* pgname, const char* cmd, int cmd_size, struct rt_dlmodule_ops* ops)
744 {
745 struct rt_dlmodule *module = RT_NULL;
746
747 module = dlmodule_load_custom(pgname, ops);
748 if (module)
749 {
750 if (module->entry_addr)
751 {
752 /* exec this module */
753 rt_thread_t tid;
754
755 module->cmd_line = rt_strdup(cmd);
756
757 /* check stack size and priority */
758 if (module->priority > RT_THREAD_PRIORITY_MAX) module->priority = RT_THREAD_PRIORITY_MAX - 1;
759 if (module->stack_size < 2048 || module->stack_size > (1024 * 32)) module->stack_size = 2048;
760
761 tid = rt_thread_create(module->parent.name, _dlmodule_thread_entry, (void*)module,
762 module->stack_size, module->priority, 10);
763 if (tid)
764 {
765 tid->parent.module_id= module;
766 module->main_thread = tid;
767
768 rt_thread_startup(tid);
769 }
770 else
771 {
772 /* destory dl module */
773 dlmodule_destroy(module);
774 module = RT_NULL;
775 }
776 }
777 }
778
779 return module;
780 }
781 #endif
782
783 /**
784 * @brief exit a dynamically loaded module.
785 *
786 * @param ret_code the return code for module exit.
787 *
788 * @note this function is responsible for gracefully exiting a dynamically loaded module, releasing resources associated with the module,
789 * and handling cleanup operations. what it implements are as follows:
790 * 1. Thread and Resource Cleanup: The function safely exits a module by deleting its main thread and freeing resources associated with it.
791 * 2. Status Management: Checks and updates the module's state, setting a return code and calling _dlmodule_exit() to transition to a closing state.
792 * 3. Critical Sections: Critical sections ensure that the exit process is atomic and free from race conditions.
793 */
dlmodule_exit(int ret_code)794 void dlmodule_exit(int ret_code)
795 {
796 rt_thread_t thread;
797 struct rt_dlmodule *module;
798
799 module = dlmodule_self();
800 if (!module) return;
801
802 /* disable scheduling */
803 rt_enter_critical();
804
805 /* module is not running */
806 if (module->stat != RT_DLMODULE_STAT_RUNNING)
807 {
808 /* restore scheduling */
809 rt_exit_critical();
810
811 return;
812 }
813
814 /* set return code */
815 module->ret_code = ret_code;
816
817 /* do exit for this module */
818 _dlmodule_exit();
819 /* the stat of module was changed to CLOSING in _dlmodule_exit */
820
821 thread = module->main_thread;
822 if ((RT_SCHED_CTX(thread).stat & RT_THREAD_STAT_MASK) == RT_THREAD_CLOSE)
823 {
824 /* main thread already closed */
825 rt_exit_critical();
826
827 return ;
828 }
829
830 /* delete thread: insert to defunct thread list */
831 rt_thread_delete(thread);
832 /* enable scheduling */
833 rt_exit_critical();
834 }
835
836 /**
837 * @brief search for a symbol by its name in the kernel symbol table.
838 *
839 * @param sym_str the symbol name string.
840 * @return rt_ubase_t On success, it returns the address of the symbol.
841 * Otherwise, it returns 0 (indicating the symbol was not found).
842 */
dlmodule_symbol_find(const char * sym_str)843 rt_ubase_t dlmodule_symbol_find(const char *sym_str)
844 {
845 /* find in kernel symbol table */
846 struct rt_module_symtab *index;
847
848 for (index = _rt_module_symtab_begin; index != _rt_module_symtab_end; index ++)
849 {
850 if (rt_strcmp(index->name, sym_str) == 0)
851 return (rt_ubase_t)index->addr;
852 }
853
854 return 0;
855 }
856
rt_system_dlmodule_init(void)857 int rt_system_dlmodule_init(void)
858 {
859 #if defined(__GNUC__) && !defined(__CC_ARM)
860 extern int __rtmsymtab_start;
861 extern int __rtmsymtab_end;
862
863 _rt_module_symtab_begin = (struct rt_module_symtab *)&__rtmsymtab_start;
864 _rt_module_symtab_end = (struct rt_module_symtab *)&__rtmsymtab_end;
865 #elif defined (__CC_ARM)
866 extern int RTMSymTab$$Base;
867 extern int RTMSymTab$$Limit;
868
869 _rt_module_symtab_begin = (struct rt_module_symtab *)&RTMSymTab$$Base;
870 _rt_module_symtab_end = (struct rt_module_symtab *)&RTMSymTab$$Limit;
871 #elif defined (__IAR_SYSTEMS_ICC__)
872 _rt_module_symtab_begin = __section_begin("RTMSymTab");
873 _rt_module_symtab_end = __section_end("RTMSymTab");
874 #endif
875
876 return 0;
877 }
878 INIT_COMPONENT_EXPORT(rt_system_dlmodule_init);
879
880 /**
881 * This function will find the specified module.
882 *
883 * @param name the name of module finding
884 *
885 * @return the module
886 */
dlmodule_find(const char * name)887 struct rt_dlmodule *dlmodule_find(const char *name)
888 {
889 rt_object_t object;
890 struct rt_dlmodule *ret = RT_NULL;
891
892 object = rt_object_find(name, RT_Object_Class_Module);
893 if (object)
894 {
895 ret = (struct rt_dlmodule*) object;
896 }
897
898 return ret;
899 }
900 RTM_EXPORT(dlmodule_find);
901
list_symbols(void)902 int list_symbols(void)
903 {
904 extern int __rtmsymtab_start;
905 extern int __rtmsymtab_end;
906
907 /* find in kernel symbol table */
908 struct rt_module_symtab *index;
909
910 for (index = _rt_module_symtab_begin;
911 index != _rt_module_symtab_end;
912 index ++)
913 {
914 rt_kprintf("%s => 0x%08x\n", index->name, index->addr);
915 }
916
917 return 0;
918 }
919 MSH_CMD_EXPORT(list_symbols, list symbols information);
920
list_module(void)921 int list_module(void)
922 {
923 struct rt_dlmodule *module;
924 struct rt_list_node *list, *node;
925 struct rt_object_information *info;
926
927 info = rt_object_get_information(RT_Object_Class_Module);
928 list = &info->object_list;
929
930 rt_kprintf("module ref address \n");
931 rt_kprintf("-------- -------- ------------\n");
932 for (node = list->next; node != list; node = node->next)
933 {
934 module = (struct rt_dlmodule *)(rt_list_entry(node, struct rt_object, list));
935 rt_kprintf("%-*.*s %-04d 0x%08x\n",
936 RT_NAME_MAX, RT_NAME_MAX, module->parent.name, module->nref, module->mem_space);
937 }
938
939 return 0;
940 }
941 MSH_CMD_EXPORT(list_module, list modules in system);
942