1 /* 2 * Copyright (c) 2006-2018, 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 #include <dfs_posix.h> 18 19 #define DBG_SECTION_NAME "DLMD" 20 #define DBG_ENABLE // enable debug macro 21 #define DBG_LEVEL DBG_INFO 22 #define DBG_COLOR 23 #include <rtdbg.h> // must after of DEBUG_ENABLE or some other options 24 25 static struct rt_module_symtab *_rt_module_symtab_begin = RT_NULL; 26 static struct rt_module_symtab *_rt_module_symtab_end = RT_NULL; 27 28 #if defined(__IAR_SYSTEMS_ICC__) /* for IAR compiler */ 29 #pragma section="RTMSymTab" 30 #endif 31 32 /* set the name of module */ 33 static void _dlmodule_set_name(struct rt_dlmodule *module, const char *path) 34 { 35 int size; 36 struct rt_object *object; 37 const char *first, *end, *ptr; 38 39 object = &(module->parent); 40 ptr = first = (char *)path; 41 end = path + rt_strlen(path); 42 43 while (*ptr != '\0') 44 { 45 if (*ptr == '/') 46 first = ptr + 1; 47 if (*ptr == '.') 48 end = ptr - 1; 49 50 ptr ++; 51 } 52 53 size = end - first + 1; 54 if (size > RT_NAME_MAX) size = RT_NAME_MAX; 55 56 rt_strncpy(object->name, first, size); 57 object->name[size] = '\0'; 58 } 59 60 #define RT_MODULE_ARG_MAX 8 61 static int _rt_module_split_arg(char *cmd, rt_size_t length, char *argv[]) 62 { 63 int argc = 0; 64 char *ptr = cmd; 65 66 while ((ptr - cmd) < length) 67 { 68 /* strip bank and tab */ 69 while ((*ptr == ' ' || *ptr == '\t') && (ptr - cmd) < length) 70 *ptr++ = '\0'; 71 /* check whether it's the end of line */ 72 if ((ptr - cmd) >= length) break; 73 74 /* handle string with quote */ 75 if (*ptr == '"') 76 { 77 argv[argc++] = ++ptr; 78 79 /* skip this string */ 80 while (*ptr != '"' && (ptr - cmd) < length) 81 if (*ptr ++ == '\\') ptr ++; 82 if ((ptr - cmd) >= length) break; 83 84 /* skip '"' */ 85 *ptr ++ = '\0'; 86 } 87 else 88 { 89 argv[argc++] = ptr; 90 while ((*ptr != ' ' && *ptr != '\t') && (ptr - cmd) < length) 91 ptr ++; 92 } 93 94 if (argc >= RT_MODULE_ARG_MAX) break; 95 } 96 97 return argc; 98 } 99 100 /* invoked by main thread for exit */ 101 static void _dlmodule_exit(void) 102 { 103 struct rt_dlmodule *module; 104 105 module = dlmodule_self(); 106 if (!module) return; /* not a module thread */ 107 108 rt_enter_critical(); 109 if (module->stat == RT_DLMODULE_STAT_RUNNING) 110 { 111 struct rt_object *object = RT_NULL; 112 struct rt_list_node *node = RT_NULL; 113 114 /* set stat to closing */ 115 module->stat = RT_DLMODULE_STAT_CLOSING; 116 117 /* suspend all threads in this module */ 118 for (node = module->object_list.next; node != &(module->object_list); node = node->next) 119 { 120 object = rt_list_entry(node, struct rt_object, list); 121 122 if ((object->type & ~RT_Object_Class_Static) == RT_Object_Class_Thread) 123 { 124 rt_thread_t thread = (rt_thread_t)object; 125 126 /* stop timer and suspend thread*/ 127 if ((thread->stat & RT_THREAD_STAT_MASK) != RT_THREAD_CLOSE || 128 (thread->stat & RT_THREAD_STAT_MASK) != RT_THREAD_INIT) 129 { 130 rt_timer_stop(&(thread->thread_timer)); 131 rt_thread_suspend(thread); 132 } 133 } 134 } 135 } 136 rt_exit_critical(); 137 138 return; 139 } 140 141 static void _dlmodule_thread_entry(void* parameter) 142 { 143 int argc = 0; 144 char *argv[RT_MODULE_ARG_MAX]; 145 146 struct rt_dlmodule *module = (struct rt_dlmodule*)parameter; 147 148 if (module == RT_NULL || module->cmd_line == RT_NULL) 149 /* malloc for module_cmd_line failed. */ 150 return; 151 152 if (module->cmd_line) 153 { 154 rt_memset(argv, 0x00, sizeof(argv)); 155 argc = _rt_module_split_arg((char *)module->cmd_line, rt_strlen(module->cmd_line), argv); 156 if (argc == 0) goto __exit; 157 } 158 159 /* set status of module */ 160 module->stat = RT_DLMODULE_STAT_RUNNING; 161 162 LOG_D("run main entry: 0x%p with %s", 163 module->entry_addr, 164 module->cmd_line); 165 166 if (module->entry_addr) 167 module->entry_addr(argc, argv); 168 169 __exit: 170 _dlmodule_exit(); 171 172 return ; 173 } 174 175 struct rt_dlmodule *dlmodule_create(void) 176 { 177 struct rt_dlmodule *module = RT_NULL; 178 179 module = (struct rt_dlmodule*) rt_object_allocate(RT_Object_Class_Module, "module"); 180 if (module) 181 { 182 module->stat = RT_DLMODULE_STAT_INIT; 183 184 /* set initial priority and stack size */ 185 module->priority = RT_THREAD_PRIORITY_MAX - 1; 186 module->stack_size = 2048; 187 188 rt_list_init(&(module->object_list)); 189 } 190 191 return module; 192 } 193 194 void dlmodule_destroy_subthread(struct rt_dlmodule *module, rt_thread_t thread) 195 { 196 RT_ASSERT(thread->module_id == module); 197 198 /* lock scheduler to prevent scheduling in cleanup function. */ 199 rt_enter_critical(); 200 201 /* remove thread from thread_list (ready or defunct thread list) */ 202 rt_list_remove(&(thread->tlist)); 203 204 if ((thread->stat & RT_THREAD_STAT_MASK) != RT_THREAD_CLOSE && 205 (thread->thread_timer.parent.type == (RT_Object_Class_Static | RT_Object_Class_Timer))) 206 { 207 /* release thread timer */ 208 rt_timer_detach(&(thread->thread_timer)); 209 } 210 211 /* change stat */ 212 thread->stat = RT_THREAD_CLOSE; 213 214 /* invoke thread cleanup */ 215 if (thread->cleanup != RT_NULL) 216 thread->cleanup(thread); 217 218 rt_exit_critical(); 219 220 #ifdef RT_USING_SIGNALS 221 rt_thread_free_sig(thread); 222 #endif 223 224 if (thread->type & RT_Object_Class_Static) 225 { 226 /* detach object */ 227 rt_object_detach((rt_object_t)thread); 228 } 229 #ifdef RT_USING_HEAP 230 else 231 { 232 /* release thread's stack */ 233 RT_KERNEL_FREE(thread->stack_addr); 234 /* delete thread object */ 235 rt_object_delete((rt_object_t)thread); 236 } 237 #endif 238 } 239 240 rt_err_t dlmodule_destroy(struct rt_dlmodule* module) 241 { 242 int i; 243 244 RT_DEBUG_NOT_IN_INTERRUPT; 245 246 /* check parameter */ 247 if (module == RT_NULL) 248 return -RT_ERROR; 249 250 /* can not destroy a running module */ 251 if (module->stat == RT_DLMODULE_STAT_RUNNING) 252 return -RT_EBUSY; 253 254 /* do module cleanup */ 255 if (module->cleanup_func) 256 { 257 rt_enter_critical(); 258 module->cleanup_func(module); 259 rt_exit_critical(); 260 } 261 262 // list_object(&(module->object_list)); 263 264 /* cleanup for all kernel objects inside module*/ 265 { 266 struct rt_object *object = RT_NULL; 267 struct rt_list_node *node = RT_NULL; 268 269 /* detach/delete all threads in this module */ 270 for (node = module->object_list.next; node != &(module->object_list); ) 271 { 272 int object_type; 273 274 object = rt_list_entry(node, struct rt_object, list); 275 object_type = object->type & ~RT_Object_Class_Static; 276 277 /* to next node */ 278 node = node->next; 279 280 if (object->type & RT_Object_Class_Static) 281 { 282 switch (object_type) 283 { 284 case RT_Object_Class_Thread: 285 dlmodule_destroy_subthread(module, (rt_thread_t)object); 286 break; 287 #ifdef RT_USING_SEMAPHORE 288 case RT_Object_Class_Semaphore: 289 rt_sem_detach((rt_sem_t)object); 290 break; 291 #endif 292 #ifdef RT_USING_MUTEX 293 case RT_Object_Class_Mutex: 294 rt_mutex_detach((rt_mutex_t)object); 295 break; 296 #endif 297 #ifdef RT_USING_EVENT 298 case RT_Object_Class_Event: 299 rt_event_detach((rt_event_t)object); 300 break; 301 #endif 302 #ifdef RT_USING_MAILBOX 303 case RT_Object_Class_MailBox: 304 rt_mb_detach((rt_mailbox_t)object); 305 break; 306 #endif 307 #ifdef RT_USING_MESSAGEQUEUE 308 case RT_Object_Class_MessageQueue: 309 rt_mq_detach((rt_mq_t)object); 310 break; 311 #endif 312 #ifdef RT_USING_MEMHEAP 313 case RT_Object_Class_MemHeap: 314 rt_memheap_detach((struct rt_memheap*)object); 315 break; 316 #endif 317 #ifdef RT_USING_MEMPOOL 318 case RT_Object_Class_MemPool: 319 rt_mp_detach((struct rt_mempool*)object); 320 break; 321 #endif 322 case RT_Object_Class_Timer: 323 rt_timer_detach((rt_timer_t)object); 324 break; 325 default: 326 LOG_E("Unsupported oject type in module."); 327 break; 328 } 329 } 330 else 331 { 332 switch (object_type) 333 { 334 case RT_Object_Class_Thread: 335 dlmodule_destroy_subthread(module, (rt_thread_t)object); 336 break; 337 #ifdef RT_USING_SEMAPHORE 338 case RT_Object_Class_Semaphore: 339 rt_sem_delete((rt_sem_t)object); 340 break; 341 #endif 342 #ifdef RT_USING_MUTEX 343 case RT_Object_Class_Mutex: 344 rt_mutex_delete((rt_mutex_t)object); 345 break; 346 #endif 347 #ifdef RT_USING_EVENT 348 case RT_Object_Class_Event: 349 rt_event_delete((rt_event_t)object); 350 break; 351 #endif 352 #ifdef RT_USING_MAILBOX 353 case RT_Object_Class_MailBox: 354 rt_mb_delete((rt_mailbox_t)object); 355 break; 356 #endif 357 #ifdef RT_USING_MESSAGEQUEUE 358 case RT_Object_Class_MessageQueue: 359 rt_mq_delete((rt_mq_t)object); 360 break; 361 #endif 362 #ifdef RT_USING_MEMHEAP 363 /* no delete operation */ 364 #endif 365 #ifdef RT_USING_MEMPOOL 366 case RT_Object_Class_MemPool: 367 rt_mp_delete((struct rt_mempool*)object); 368 break; 369 #endif 370 case RT_Object_Class_Timer: 371 rt_timer_delete((rt_timer_t)object); 372 break; 373 default: 374 LOG_E("Unsupported oject type in module."); 375 break; 376 } 377 } 378 } 379 } 380 381 if (module->cmd_line) rt_free(module->cmd_line); 382 /* release module symbol table */ 383 for (i = 0; i < module->nsym; i ++) 384 { 385 rt_free((void *)module->symtab[i].name); 386 } 387 if (module->symtab != RT_NULL) 388 { 389 rt_free(module->symtab); 390 } 391 392 /* destory module */ 393 rt_free(module->mem_space); 394 /* delete module object */ 395 rt_object_delete((rt_object_t)module); 396 397 return RT_EOK; 398 } 399 400 struct rt_dlmodule *dlmodule_self(void) 401 { 402 rt_thread_t tid; 403 struct rt_dlmodule *ret = RT_NULL; 404 405 tid = rt_thread_self(); 406 if (tid) 407 { 408 ret = (struct rt_dlmodule*) tid->module_id; 409 } 410 411 return ret; 412 } 413 414 /* 415 * Compatible with old API 416 */ 417 struct rt_dlmodule *rt_module_self(void) 418 { 419 return dlmodule_self(); 420 } 421 422 struct rt_dlmodule* dlmodule_load(const char* filename) 423 { 424 int fd, length = 0; 425 rt_err_t ret = RT_EOK; 426 rt_uint8_t *module_ptr = RT_NULL; 427 struct rt_dlmodule *module = RT_NULL; 428 429 fd = open(filename, O_RDONLY, 0); 430 if (fd >= 0) 431 { 432 length = lseek(fd, 0, SEEK_END); 433 lseek(fd, 0, SEEK_SET); 434 435 if (length == 0) goto __exit; 436 437 module_ptr = (uint8_t*) rt_malloc (length); 438 if (!module_ptr) goto __exit; 439 440 if (read(fd, module_ptr, length) != length) 441 goto __exit; 442 443 /* close file and release fd */ 444 close(fd); 445 fd = -1; 446 } 447 448 /* check ELF header */ 449 if (rt_memcmp(elf_module->e_ident, RTMMAG, SELFMAG) != 0 && 450 rt_memcmp(elf_module->e_ident, ELFMAG, SELFMAG) != 0) 451 { 452 rt_kprintf("Module: magic error\n"); 453 goto __exit; 454 } 455 456 /* check ELF class */ 457 if (elf_module->e_ident[EI_CLASS] != ELFCLASS32) 458 { 459 rt_kprintf("Module: ELF class error\n"); 460 goto __exit; 461 } 462 463 module = dlmodule_create(); 464 if (!module) goto __exit; 465 466 /* set the name of module */ 467 _dlmodule_set_name(module, filename); 468 469 LOG_D("rt_module_load: %.*s", RT_NAME_MAX, module->parent.name); 470 471 if (elf_module->e_type == ET_REL) 472 { 473 ret = dlmodule_load_relocated_object(module, module_ptr); 474 } 475 else if (elf_module->e_type == ET_DYN) 476 { 477 ret = dlmodule_load_shared_object(module, module_ptr); 478 } 479 else 480 { 481 rt_kprintf("Module: unsupported elf type\n"); 482 goto __exit; 483 } 484 485 /* check return value */ 486 if (ret != RT_EOK) goto __exit; 487 488 /* release module data */ 489 rt_free(module_ptr); 490 491 /* increase module reference count */ 492 module->nref ++; 493 494 /* deal with cache */ 495 #ifdef RT_USING_CACHE 496 rt_hw_cpu_dcache_ops(RT_HW_CACHE_FLUSH, module->mem_space, module->mem_size); 497 rt_hw_cpu_icache_ops(RT_HW_CACHE_INVALIDATE, module->mem_space, module->mem_size); 498 #endif 499 500 /* set module initialization and cleanup function */ 501 module->init_func = dlsym(module, "module_init"); 502 module->cleanup_func = dlsym(module, "module_cleanup"); 503 module->stat = RT_DLMODULE_STAT_INIT; 504 /* do module initialization */ 505 if (module->init_func) 506 { 507 module->init_func(module); 508 } 509 510 return module; 511 512 __exit: 513 if (fd >= 0) close(fd); 514 if (module_ptr) rt_free(module_ptr); 515 if (module) dlmodule_destroy(module); 516 517 return RT_NULL; 518 } 519 520 struct rt_dlmodule* dlmodule_exec(const char* pgname, const char* cmd, int cmd_size) 521 { 522 struct rt_dlmodule *module = RT_NULL; 523 524 module = dlmodule_load(pgname); 525 if (module) 526 { 527 if (module->entry_addr) 528 { 529 /* exec this module */ 530 rt_thread_t tid; 531 532 module->cmd_line = rt_strdup(cmd); 533 534 /* check stack size and priority */ 535 if (module->priority > RT_THREAD_PRIORITY_MAX) module->priority = RT_THREAD_PRIORITY_MAX - 1; 536 if (module->stack_size < 2048 || module->stack_size > (1024 * 32)) module->stack_size = 2048; 537 538 tid = rt_thread_create(module->parent.name, _dlmodule_thread_entry, (void*)module, 539 module->stack_size, module->priority, 10); 540 if (tid) 541 { 542 tid->module_id = module; 543 module->main_thread = tid; 544 545 rt_thread_startup(tid); 546 } 547 else 548 { 549 /* destory dl module */ 550 dlmodule_destroy(module); 551 module = RT_NULL; 552 } 553 } 554 } 555 556 return module; 557 } 558 559 void dlmodule_exit(int ret_code) 560 { 561 rt_thread_t thread; 562 struct rt_dlmodule *module; 563 564 module = dlmodule_self(); 565 if (!module) return; 566 567 /* disable scheduling */ 568 rt_enter_critical(); 569 570 /* module is not running */ 571 if (module->stat != RT_DLMODULE_STAT_RUNNING) 572 { 573 /* restore scheduling */ 574 rt_exit_critical(); 575 576 return; 577 } 578 579 /* set return code */ 580 module->ret_code = ret_code; 581 582 /* do exit for this module */ 583 _dlmodule_exit(); 584 /* the stat of module was changed to CLOSING in _dlmodule_exit */ 585 586 thread = module->main_thread; 587 if ((thread->stat & RT_THREAD_STAT_MASK) == RT_THREAD_CLOSE) 588 { 589 /* main thread already closed */ 590 rt_exit_critical(); 591 592 return ; 593 } 594 595 /* delete thread: insert to defunct thread list */ 596 rt_thread_delete(thread); 597 /* enable scheduling */ 598 rt_exit_critical(); 599 } 600 601 rt_uint32_t dlmodule_symbol_find(const char *sym_str) 602 { 603 /* find in kernel symbol table */ 604 struct rt_module_symtab *index; 605 606 for (index = _rt_module_symtab_begin; index != _rt_module_symtab_end; index ++) 607 { 608 if (rt_strcmp(index->name, sym_str) == 0) 609 return (rt_uint32_t)index->addr; 610 } 611 612 return 0; 613 } 614 615 int rt_system_dlmodule_init(void) 616 { 617 #if defined(__GNUC__) && !defined(__CC_ARM) 618 extern int __rtmsymtab_start; 619 extern int __rtmsymtab_end; 620 621 _rt_module_symtab_begin = (struct rt_module_symtab *)&__rtmsymtab_start; 622 _rt_module_symtab_end = (struct rt_module_symtab *)&__rtmsymtab_end; 623 #elif defined (__CC_ARM) 624 extern int RTMSymTab$$Base; 625 extern int RTMSymTab$$Limit; 626 627 _rt_module_symtab_begin = (struct rt_module_symtab *)&RTMSymTab$$Base; 628 _rt_module_symtab_end = (struct rt_module_symtab *)&RTMSymTab$$Limit; 629 #elif defined (__IAR_SYSTEMS_ICC__) 630 _rt_module_symtab_begin = __section_begin("RTMSymTab"); 631 _rt_module_symtab_end = __section_end("RTMSymTab"); 632 #endif 633 634 return 0; 635 } 636 INIT_COMPONENT_EXPORT(rt_system_dlmodule_init); 637 638 /** 639 * This function will find the specified module. 640 * 641 * @param name the name of module finding 642 * 643 * @return the module 644 */ 645 struct rt_dlmodule *dlmodule_find(const char *name) 646 { 647 rt_object_t object; 648 struct rt_dlmodule *ret = RT_NULL; 649 650 object = rt_object_find(name, RT_Object_Class_Module); 651 if (object) 652 { 653 ret = (struct rt_dlmodule*) object; 654 } 655 656 return ret; 657 } 658 RTM_EXPORT(dlmodule_find); 659 660 int list_symbols(void) 661 { 662 extern int __rtmsymtab_start; 663 extern int __rtmsymtab_end; 664 665 /* find in kernel symbol table */ 666 struct rt_module_symtab *index; 667 668 for (index = _rt_module_symtab_begin; 669 index != _rt_module_symtab_end; 670 index ++) 671 { 672 rt_kprintf("%s => 0x%08x\n", index->name, index->addr); 673 } 674 675 return 0; 676 } 677 MSH_CMD_EXPORT(list_symbols, list symbols information); 678 679 int list_module(void) 680 { 681 struct rt_dlmodule *module; 682 struct rt_list_node *list, *node; 683 struct rt_object_information *info; 684 685 info = rt_object_get_information(RT_Object_Class_Module); 686 list = &info->object_list; 687 688 rt_kprintf("module ref address \n"); 689 rt_kprintf("-------- -------- ------------\n"); 690 for (node = list->next; node != list; node = node->next) 691 { 692 module = (struct rt_dlmodule *)(rt_list_entry(node, struct rt_object, list)); 693 rt_kprintf("%-*.*s %-04d 0x%08x\n", 694 RT_NAME_MAX, RT_NAME_MAX, module->parent.name, module->nref, module->mem_space); 695 } 696 697 return 0; 698 } 699 MSH_CMD_EXPORT(list_module, list modules in system); 700