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