[ipc/ipcdev.git] / qnx / src / ipc3x_dev / ti / syslink / procMgr / hlos / knl / loaders / Elf / Qnx / DLOAD / DLWRAPPER / dlw.c
1 /*
2 * dlw.c
3 *
4 * Client-side driver of reference implementation of the dynamic loader for
5 * C6x.
6 *
7 * Copyright (C) 2009 Texas Instruments Incorporated - http://www.ti.com/
8 *
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 *
14 * Redistributions of source code must retain the above copyright
15 * notice, this list of conditions and the following disclaimer.
16 *
17 * Redistributions in binary form must reproduce the above copyright
18 * notice, this list of conditions and the following disclaimer in the
19 * documentation and/or other materials provided with the
20 * distribution.
21 *
22 * Neither the name of Texas Instruments Incorporated nor the names of
23 * its contributors may be used to endorse or promote products derived
24 * from this software without specific prior written permission.
25 *
26 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
27 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
28 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
29 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
30 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
31 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
32 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
33 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
34 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
35 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
36 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
37 *
38 */
40 #include <stdarg.h>
41 #include <stdio.h>
42 #include <stdlib.h>
43 #include <string.h>
44 #include "ArrayList.h"
45 #include "symtab.h"
46 #include "dload.h"
47 #include "dload_api.h"
48 #include "util.h"
49 #include "dlw_debug.h"
50 #include "dlw_dsbt.h"
51 #include "dlw_trgmem.h"
53 int export_var=100;
55 /*---------------------------------------------------------------------------*/
56 /* Global function pointer that will be set to point at whatever entry */
57 /* point that we want to be in effect when the "execute" command is */
58 /* specified. */
59 /*---------------------------------------------------------------------------*/
60 static int (*loaded_program)() = NULL;
62 /*---------------------------------------------------------------------------*/
63 /* Handle of the loaded program. */
64 /*---------------------------------------------------------------------------*/
65 static uint32_t prog_handle;
67 /*****************************************************************************/
68 /* Loader Testing Shell Functions */
69 /* */
70 /* These are intended for debugging and testing the loader. */
71 /*****************************************************************************/
73 /*****************************************************************************/
74 /* LOAD_EXECUTABLE() - Invoke the loader to create an executable image of */
75 /* the specified program, saving the loader's return value as the */
76 /* future entry point. */
77 /*****************************************************************************/
78 static void load_executable(const char* file_name, int argc, char** argv)
79 {
80 /*------------------------------------------------------------------------*/
81 /* Open specified file from "load" command, load it, then close the file. */
82 /*------------------------------------------------------------------------*/
84 /*------------------------------------------------------------------------*/
85 /* NOTE!! We require that any shared objects that we are trying to load */
86 /* be in the current directory. */
87 /*------------------------------------------------------------------------*/
88 /*------------------------------------------------------------------------*/
89 /* If there is registry available, we'll need to look up the given */
90 /* file_name in the registry to find the actual pathname to be used */
91 /* while opening the file. Otherwise, we'll just use the given file */
92 /* name. */
93 /*------------------------------------------------------------------------*/
94 FILE* fp = fopen(file_name, "rb");
96 /*------------------------------------------------------------------------*/
97 /* Were we able to open the file successfully? */
98 /*------------------------------------------------------------------------*/
99 if (!fp)
100 {
101 DLIF_error(DLET_FILE, "Failed to open file '%s'.\n", file_name);
102 return;
103 }
105 /*------------------------------------------------------------------------*/
106 /* If we have a DLModules symbol available in the base image, then we */
107 /* need to create debug information for this file in target memory to */
108 /* support whatever DLL View plug-in or script is implemented in the */
109 /* debugger. */
110 /*------------------------------------------------------------------------*/
111 if (DLL_debug)
112 DLDBG_add_host_record(file_name);
114 /*------------------------------------------------------------------------*/
115 /* Now, we are ready to start loading the specified file onto the target. */
116 /*------------------------------------------------------------------------*/
117 prog_handle = DLOAD_load(fp, argc, argv);
118 fclose(fp);
120 /*------------------------------------------------------------------------*/
121 /* If the load was successful, then we'll need to write the debug */
122 /* information for this file into target memory. */
123 /*------------------------------------------------------------------------*/
124 if (prog_handle)
125 {
126 if (DLL_debug)
127 {
128 /*---------------------------------------------------------------*/
129 /* Allocate target memory for the module's debug record. Use */
130 /* host version of the debug information to determine how much */
131 /* target memory we need and how it is to be filled in. */
132 /*---------------------------------------------------------------*/
133 /* Note that we don't go through the normal API functions to get */
134 /* target memory and write the debug information since we're not */
135 /* dealing with object file content here. The DLL View debug is */
136 /* supported entirely on the client side. */
137 /*---------------------------------------------------------------*/
138 DLDBG_add_target_record(prog_handle);
139 }
141 /*---------------------------------------------------------------------*/
142 /* Find entry point associated with loaded program's handle, set up */
143 /* entry point in "loaded_program". */
144 /*---------------------------------------------------------------------*/
145 DLOAD_get_entry_point(prog_handle, (TARGET_ADDRESS)(&loaded_program));
146 printf("loaded_program: 0x%x\n", loaded_program);
147 }
149 /*------------------------------------------------------------------------*/
150 /* Report failure to load an object file. */
151 /*------------------------------------------------------------------------*/
152 else
153 DLIF_error(DLET_MISC, "Failed load of file '%s'.\n", file_name);
154 }
156 /*****************************************************************************/
157 /* EXECUTE_PROGRAM() - Execute loaded program and print return value. */
158 /*****************************************************************************/
159 static void execute_program(int argc, char** argv)
160 {
161 /*------------------------------------------------------------------------*/
162 /* Have we got an entry point that we begin executing at? */
163 /*------------------------------------------------------------------------*/
164 if (loaded_program == NULL)
165 {
166 fprintf(stderr,"<< D O L T >> ERROR: No program has been loaded.\n");
167 return;
168 }
170 /*------------------------------------------------------------------------*/
171 /* Call loaded program at the entry point in "loaded_program". */
172 /*------------------------------------------------------------------------*/
173 printf("Return value: %d\n", loaded_program(argc,argv));
174 }
176 /*---------------------------------------------------------------------------*/
177 /* Global flag to control debug output. */
178 /*---------------------------------------------------------------------------*/
179 #if LOADER_DEBUG
180 BOOL debugging_on = 0;
181 #endif
183 /*---------------------------------------------------------------------------*/
184 /* Global flag to enable profiling. */
185 /*---------------------------------------------------------------------------*/
186 #if LOADER_DEBUG || LOADER_PROFILE
187 BOOL profiling_on = 0;
188 #endif
190 /*---------------------------------------------------------------------------*/
191 /* User command data structure */
192 /*---------------------------------------------------------------------------*/
193 enum command_id_t
194 {
195 INFORMATION,
196 LOAD_EXECUTABLE,
197 CORE,
198 EXIT,
199 HELP,
200 EXECUTE_PROGRAM,
201 UNLOAD_PROGRAM,
202 BASE_IMAGE,
203 DEBUG,
204 PROFILE,
205 COMMENT,
206 DUMP_TRGMEM,
207 CORE_VERSION,
208 ERROR_ID
209 };
211 struct commands_t
212 {
213 const char *command;
214 enum command_id_t id;
215 };
217 static struct commands_t commands[] = {
218 { "information", INFORMATION },
219 { "load_executable", LOAD_EXECUTABLE },
220 { "core", CORE },
221 { "exit", EXIT },
222 { "help", HELP },
223 { "execute_program", EXECUTE_PROGRAM },
224 { "unload_program", UNLOAD_PROGRAM },
225 { "base_image", BASE_IMAGE },
226 { "dump_trgmem", DUMP_TRGMEM },
227 { "version", CORE_VERSION },
228 #if LOADER_DEBUG
229 { "debug", DEBUG },
230 #endif
231 #if LOADER_DEBUG || LOADER_PROFILE
232 { "profile", PROFILE },
233 #endif
234 { "#", COMMENT },
235 };
237 /*****************************************************************************/
238 /* HELP() - Print a brief summary of the available commands. */
239 /*****************************************************************************/
240 static void help(void)
241 {
242 int i;
244 fprintf(stderr, "Commands:\n");
246 for (i = 0; i < sizeof(commands) / sizeof(*commands); i++)
247 printf("\t%s\n", commands[i].command);
248 }
250 /*****************************************************************************/
251 /* FIND_COMMAND_ID() - Look up a command name or partial command name in the */
252 /* commands table. Return an enum representing command. */
253 /*****************************************************************************/
254 static enum command_id_t find_command_id(const char *tok)
255 {
256 int i, found = -1;
257 size_t tok_len = strlen(tok);
259 for (i = 0; i < sizeof(commands) / sizeof(*commands); i++)
260 if (!strncasecmp(tok, commands[i].command, tok_len))
261 {
262 if (found != -1)
263 {
264 fprintf(stderr,
265 "<< D O L T >> ERROR: Ambiguous command '%s'\n", tok);
266 return ERROR_ID;
267 }
268 found = i;
269 }
271 if (found != -1) return commands[found].id;
272 else
273 {
274 fprintf(stderr, "Unknown command '%s'\n", tok);
275 return ERROR_ID;
276 }
277 }
279 /*****************************************************************************/
280 /* INPUT_SERVER abstracts whether the commands come from the interactive */
281 /* command line, a script file, or the --command option */
282 /*****************************************************************************/
283 typedef struct input_server_t
284 {
285 enum { IST_FILE, IST_STR } type;
286 FILE *input_file;
287 const char *string;
288 size_t string_pos;
289 } INPUT_SERVER;
291 static INPUT_SERVER *cmd_set_file(FILE *input_file)
292 {
293 INPUT_SERVER *input_server = malloc(sizeof(INPUT_SERVER));
294 input_server->type = IST_FILE;
295 input_server->input_file = input_file;
296 return input_server;
297 }
299 static INPUT_SERVER *cmd_set_string(const char *str)
300 {
301 INPUT_SERVER *input_server = malloc(sizeof(INPUT_SERVER));
302 input_server->type = IST_STR;
303 input_server->string = str;
304 input_server->string_pos = 0;
305 return input_server;
306 }
308 static int cmd_getc(INPUT_SERVER *server)
309 {
310 if (server->type == IST_FILE) return fgetc(server->input_file);
311 else
312 {
313 int ch;
314 if (!server->string) return EOF;
315 ch = server->string[server->string_pos++];
316 if (!ch) return EOF;
317 return ch;
318 }
319 }
321 static int cmd_error(INPUT_SERVER *server)
322 {
323 if (server->type == IST_FILE) return ferror(server->input_file);
324 else return server->string == NULL;
325 }
327 static int cmd_eof(INPUT_SERVER *server)
328 {
329 if (server->type == IST_FILE) return feof(server->input_file);
330 else return !cmd_error(server) && !server->string[server->string_pos];
331 }
333 static int cmd_isstdin(INPUT_SERVER *server)
334 {
335 if (server->type == IST_FILE) return server->input_file == stdin;
336 else return 0;
337 }
339 /*****************************************************************************/
340 /* GET_LINE() - Read up to buf_len bytes worth of command-line input. */
341 /*****************************************************************************/
342 static char *get_line(char *cmd_buffer, size_t buf_len, INPUT_SERVER *server)
343 {
344 size_t pos = 0;
345 /* fgets always NUL-terminates, we'll do the same */
347 while (pos < (buf_len - 1))
348 {
349 int ch;
351 if ((ch = cmd_getc(server)) == EOF)
352 {
353 if (cmd_error(server)) return NULL;
354 else if (pos) goto done; /* EOF, but read at least 1 char */
355 else return NULL;
356 }
357 else
358 {
359 if (ch == ';' || ch == '\n')
360 {
361 /* End of command. Discard ';' or '\n' */
362 goto done;
363 }
364 else if (ch == '#')
365 {
366 /* comment start, discard everything until end-of-line */
367 while (((ch = cmd_getc(server)) != EOF) && ch != '\n')
368 ;
369 goto done;
370 }
371 else
372 {
373 cmd_buffer[pos++] = ch;
374 }
375 }
376 }
378 /* Buffer overrun */
379 fprintf(stderr, "<< D O L T >> ERROR: command buffer overrun.\n");
380 exit(1);
382 done:
384 cmd_buffer[pos] = '\0';
385 return cmd_buffer;
386 }
388 /*****************************************************************************/
389 /* MAIN() - RIDL client driver. Implements a user-interactive shell, but */
390 /* can also take input from a script file using "--script <file>" */
391 /* command-line option. */
392 /*****************************************************************************/
393 #if UNIT_TEST
394 int ridl_main(int argc, char** argv)
395 #else
396 int ridl_main(int argc, char** argv)
397 #endif
398 {
399 /*------------------------------------------------------------------------*/
400 /* Current length of a RIDL command is limited to a fixed-sized buffer. */
401 /* Exceeding this fixed buffer will result in a runtime error. */
402 /*------------------------------------------------------------------------*/
403 char cmd_buffer[1000];
405 /*------------------------------------------------------------------------*/
406 /* Identify command-line input stream. By default, this is stdin, but */
407 /* we can take commands from a script, using the --script option. */
408 /*------------------------------------------------------------------------*/
409 INPUT_SERVER *cmd_server = cmd_set_file(stdin);
411 /*------------------------------------------------------------------------*/
412 /* Process command-line arguments to RIDL executable. */
413 /*------------------------------------------------------------------------*/
414 int a;
415 for (a = 1; a < argc; a++)
416 {
417 /*---------------------------------------------------------------------*/
418 /* RIDL can take input from a script file. This is useful for running */
419 /* RIDL under a test harness. Specify the script file using --script */
420 /* option (usage: --script <file>). */
421 /*---------------------------------------------------------------------*/
422 if (!strcmp(argv[a], "--script"))
423 {
424 if (cmd_server) free(cmd_server);
425 cmd_server = cmd_set_file(fopen(argv[a+1], "r"));
426 }
428 /*---------------------------------------------------------------------*/
429 /* RIDL can run commands specified on the command line. This is */
430 /* useful for running RIDL under a test harness. Specify the commands */
431 /* --command option (usage: --command "<cmd1>; <cmd2>"). */
432 /*---------------------------------------------------------------------*/
433 if (!strcmp(argv[a], "--command"))
434 {
435 if (cmd_server) free(cmd_server);
436 cmd_server = cmd_set_string(argv[a+1]);
437 }
439 #if LOADER_DEBUG
440 /*---------------------------------------------------------------------*/
441 /* Internal debug. Can specify debugging from the command-line with */
442 /* --debug option. User interface also supports a "debug" command. */
443 /*---------------------------------------------------------------------*/
444 if (!strcmp(argv[a], "--debug"))
445 debugging_on = 1;
446 #endif
448 #if LOADER_DEBUG || LOADER_PROFILE
449 /*---------------------------------------------------------------------*/
450 /* Profiling. It is important that this loader is small and fast. */
451 /* We may need to turn on profiing via --profile option to find where */
452 /* the loader is sluggish. */
453 /*---------------------------------------------------------------------*/
454 if (!strcmp(argv[a], "--profile"))
455 profiling_on = 1;
456 #endif
457 }
459 /*------------------------------------------------------------------------*/
460 /* Initialize the dynamic loader. */
461 /*------------------------------------------------------------------------*/
462 DLOAD_initialize();
464 /*------------------------------------------------------------------------*/
465 /* Initialize the client's model of the master DSBT. */
466 /*------------------------------------------------------------------------*/
467 AL_initialize(&DSBT_master, sizeof(DSBT_Entry), 1);
469 /*------------------------------------------------------------------------*/
470 /* Banner for user interaction mode. */
471 /*------------------------------------------------------------------------*/
472 if (cmd_isstdin(cmd_server))
473 {
474 printf("Welcome to the Reference Implementation of the Dynamic Loader (RIDL).\n");
475 printf("Using %s\n", DLOAD_version());
476 }
479 /*------------------------------------------------------------------------*/
480 /* Command processing loop. */
481 /*------------------------------------------------------------------------*/
482 cmd_buffer[0]='\0';
483 while(1)
484 {
485 int32_t prog_argc,i;
486 char* pathname;
487 char* tok, *str_argc;
488 Array_List prog_argv;
490 /*---------------------------------------------------------------------*/
491 /* In user interactive mode, prompt user for next command. */
492 /*---------------------------------------------------------------------*/
493 if (cmd_isstdin(cmd_server)) printf("RIDL> ");
495 /*---------------------------------------------------------------------*/
496 /* Read up to semicolon, newline, or comment character. */
497 /*---------------------------------------------------------------------*/
498 if (get_line(cmd_buffer, sizeof(cmd_buffer), cmd_server) == NULL)
499 {
500 if (cmd_eof(cmd_server))
501 {
502 if (cmd_isstdin(cmd_server)) printf("exit\n");
503 exit(0);
504 }
505 else
506 {
507 fprintf(stderr,
508 "<< D O L T >> FATAL: "
509 "Unknown error reading commands\n");
510 exit(1);
511 }
512 }
514 /*---------------------------------------------------------------------*/
515 /* Scan first token, skip over any empty command lines. */
516 /*---------------------------------------------------------------------*/
517 tok = strtok(cmd_buffer, " \n");
518 if (!tok) continue;
520 /*---------------------------------------------------------------------*/
521 /* We have some kind of command. Transfer control to the right place */
522 /* in the loader. */
523 /*---------------------------------------------------------------------*/
524 switch (find_command_id(tok))
525 {
526 /*------------------------------------------------------------------*/
527 /* "exit" */
528 /* */
529 /* This is a safe exit out of RIDL user-interface. */
530 /*------------------------------------------------------------------*/
531 case EXIT:
532 exit(0);
533 break;
535 /*------------------------------------------------------------------*/
536 /* "help" */
537 /* */
538 /* Display a list of commands */
539 /*------------------------------------------------------------------*/
540 case HELP:
541 help();
542 break;
544 /*------------------------------------------------------------------*/
545 /* "information" */
546 /* */
547 /* Some minimally useful information. Where is dl6x's printf() */
548 /* and where is its exit()? */
549 /*------------------------------------------------------------------*/
550 case INFORMATION:
551 printf("Host printf: %x\nHost exit: %x\n",printf, exit);
552 break;
554 /*------------------------------------------------------------------*/
555 /* "load <program> [<argc> <argv[0]> <argv[1]> ...]" */
556 /* */
557 /* Load an executable program into memory with the supplied command */
558 /* line arguments. This will load any dependent files as well. */
559 /*------------------------------------------------------------------*/
560 case LOAD_EXECUTABLE:
561 pathname = strtok(NULL," \n");
562 str_argc = strtok(NULL," \n");
563 if (str_argc)
564 prog_argc = strtoul(str_argc, NULL, 0);
565 else
566 prog_argc = 0;
568 /*---------------------------------------------------------------*/
569 /* Initialize Target Memory Allocator Interface */
570 /*---------------------------------------------------------------*/
571 AL_initialize(&prog_argv, sizeof(char*), 1);
573 /*---------------------------------------------------------------*/
574 /* Allocate a private copy of each argv string specified in the */
575 /* load command. */
576 /*---------------------------------------------------------------*/
577 for (i = 0; i < prog_argc; i++)
578 {
579 char* temp = malloc(100);
580 strcpy(temp,strtok(NULL, " \n"));
581 AL_append(&prog_argv,&temp);
582 }
584 /*---------------------------------------------------------------*/
585 /* Write out progress information for arguments read from load */
586 /* command. */
587 /*---------------------------------------------------------------*/
588 for (i = 0; i < prog_argc; i++)
589 printf("Arg %d: %s\n",i,*((char**)(prog_argv.buf) + i));
591 /*---------------------------------------------------------------*/
592 /* Go invoke the core loader to load the specified program. */
593 /*---------------------------------------------------------------*/
594 load_executable(pathname, prog_argc, (char**)(prog_argv.buf));
596 /*---------------------------------------------------------------*/
597 /* Did we get a valid program handle back from the loader? */
598 /*---------------------------------------------------------------*/
599 if (!prog_handle && !cmd_isstdin(cmd_server))
600 {
601 fprintf(stderr,
602 "<< D O L T >> FATAL: load_executable failed in "
603 "script. Terminating.\n");
604 exit(1);
605 }
607 #if LOADER_DEBUG
608 /*---------------------------------------------------------------*/
609 /* If debug mode is turned on, then the loader will dump */
610 /* whatever is in target memory to a "prog.dump" file. */
611 /* This file can be processed by dis6x or ofd6x for further */
612 /* debugging. */
613 /*---------------------------------------------------------------*/
614 if (debugging_on)
615 {
616 FILE* dumpfile = fopen("prog.dump","wb");
617 if (!dumpfile)
618 fprintf(stderr,
619 "<< D O L T >> ERROR: prog.dump could not be "
620 "written.\n");
621 else
622 {
623 DLTMM_fwrite_trg_mem(dumpfile);
624 fclose(dumpfile);
625 }
626 }
627 #endif
628 break;
630 /*------------------------------------------------------------------*/
631 /* "core <entry point> [<argc> <argv[0]> <argv[1]> ...]" */
632 /* */
633 /* Load the core image "prog.dump" into target memory, setting the */
634 /* specified address as the entry point. Can also provide an */
635 /* argument list to be passed into the executable program. */
636 /*------------------------------------------------------------------*/
637 case CORE:
638 {
639 /*---------------------------------------------------------------*/
640 /* Find and open "prog.dump" file. This should have been */
641 /* created by a previous "load" command under debug. */
642 /*---------------------------------------------------------------*/
643 FILE* core = fopen("prog.dump","rb");
644 if (!core)
645 {
646 fprintf(stderr,
647 "<< D O L T >> ERROR: prog.dump could not be read.\n");
648 continue;
649 }
651 /*---------------------------------------------------------------*/
652 /* Read the contents of "prog.dump" into target memory area. */
653 /*---------------------------------------------------------------*/
654 DLTMM_fread_trg_mem(core);
655 fclose(core);
657 /*---------------------------------------------------------------*/
658 /* Set entry point to specified entry point value (1st argument */
659 /* to "core" command). */
660 /*---------------------------------------------------------------*/
661 loaded_program = (int(*)())(strtoul(strtok(NULL," \n"),NULL,0));
663 /*---------------------------------------------------------------*/
664 /* Process any argc, argv stuff that we want to use for this */
665 /* run. */
666 /*---------------------------------------------------------------*/
667 prog_argc = strtoul(strtok(NULL," \n"), NULL, 0);
668 AL_initialize(&prog_argv,sizeof(char*), 1);
670 for (i = 0; i < prog_argc; i++)
671 {
672 char* temp = malloc(100);
673 strcpy(temp,strtok(NULL," \n"));
674 AL_append(&prog_argv,&temp);
675 }
677 for (i = 0; i < prog_argc; i++)
678 printf("Arg %d: %s\n",i,*((char**)(prog_argv.buf) + i));
679 }
680 break;
682 /*------------------------------------------------------------------*/
683 /* "execute" */
684 /* */
685 /* Transfer control to the most recently loaded program. Expect */
686 /* "loaded_program" to be pointing at entry point that we want to */
687 /* start with. */
688 /*------------------------------------------------------------------*/
689 case EXECUTE_PROGRAM:
690 execute_program(prog_argc, (char**)(prog_argv.buf));
691 break;
693 /*------------------------------------------------------------------*/
694 /* "unload" */
695 /* */
696 /* Unload the last program that was loaded into memory. Does this */
697 /* include any base image symbols? */
698 /*------------------------------------------------------------------*/
699 /* We'll only worry about removing debug information if the module */
700 /* is actually unloaded from target space (DLOAD_unload() returns */
701 /* TRUE only if module is no longer needed and has indeed been */
702 /* unloaded from target memory). */
703 /*------------------------------------------------------------------*/
704 case UNLOAD_PROGRAM:
705 if (DLOAD_unload(prog_handle))
706 {
707 DSBT_release_entry(prog_handle);
708 if (DLL_debug) DLDBG_rm_target_record(prog_handle);
709 }
711 loaded_program = NULL;
713 break;
715 /*------------------------------------------------------------------*/
716 /* "base_image <program>" */
717 /* */
718 /* Load the global symbols from the dynamic symbol table of the */
719 /* specified program. It is assumed that the specified program */
720 /* has already been loaded into target memory and is running. */
721 /*------------------------------------------------------------------*/
722 case BASE_IMAGE:
723 {
724 char* base_image_name = strtok(NULL, " \n");
725 FILE* image = fopen(base_image_name, "rb");
727 /*---------------------------------------------------------------*/
728 /* Make sure that base image file was successfully opened. */
729 /*---------------------------------------------------------------*/
730 if (!image)
731 {
732 DLIF_error(DLET_FILE, "Failed to open base image file '%s'.\n",
733 base_image_name);
734 break;
735 }
737 /*---------------------------------------------------------------*/
738 /* Base image is assumed to be already loaded and running on the */
739 /* target. The dynamic loader still has to read all of the */
740 /* dynamic symbols in the base image so that we can link an */
741 /* incoming DLL against the base image. */
742 /*---------------------------------------------------------------*/
743 if (!(prog_handle = DLOAD_load_symbols(image)))
744 {
745 /*------------------------------------------------------------*/
746 /* If we didn't get a proper file handle back from the */
747 /* DLOAD_load_symbols() API function, then we need to recover */
748 /* gracefully. */
749 /*------------------------------------------------------------*/
750 /* If a failure occurs from a script file, then we assume a */
751 /* catastrophic failure and terminate the session. */
752 /*------------------------------------------------------------*/
753 if (!prog_handle && !cmd_isstdin(cmd_server))
754 {
755 fprintf(stderr,
756 "<< D O L T >> FATAL: base_image failed in script. "
757 "Terminating.\n");
758 exit(1);
759 }
760 }
762 if (image) fclose(image);
764 /*---------------------------------------------------------------*/
765 /* Query base image for DLModules symbol to determine whether */
766 /* debug support needs to be provided by the client side of the */
767 /* loader. */
768 /*---------------------------------------------------------------*/
769 /* Note that space for the DLL View debug list is already */
770 /* allocated as part of the base image, the header record is */
771 /* initialized to zero and needs to be filled in when the first */
772 /* module record is written to target memory. */
773 /*---------------------------------------------------------------*/
774 DLL_debug = DLOAD_query_symbol(prog_handle,
775 "_DLModules", &DLModules_loc);
776 }
777 break;
779 /*------------------------------------------------------------------*/
780 /* dump_trgmem <offset>, <nbytes>, <filename> */
781 /* */
782 /* Dumps nbytes from the target memory starting at <offset>. */
783 /*------------------------------------------------------------------*/
784 case DUMP_TRGMEM:
785 {
786 char* offset_str = strtok(NULL, ",");
787 char* nbytes_str = strtok(NULL, ",");
788 uint32_t offset = strtoul(offset_str, NULL, 0);
789 uint32_t nbytes = strtoul(nbytes_str, NULL, 0);
790 char* fn = strtok(NULL, " \n");
791 FILE* fp = fopen(fn, "wb");
793 DLTMM_dump_trg_mem(offset, nbytes, fp);
795 fclose(fp);
796 break;
797 }
799 /*------------------------------------------------------------------*/
800 /* "version" */
801 /* */
802 /* Echo version ID string for dynamic loader core to STDOUT. */
803 /*------------------------------------------------------------------*/
804 case CORE_VERSION:
805 printf("\n%s\n", DLOAD_version());
806 break;
808 /*------------------------------------------------------------------*/
809 /* "debug" */
810 /* */
811 /* Turn on debugging. Could also increase level of debug if */
812 /* we wanted to go for different levels of debug detail. */
813 /*------------------------------------------------------------------*/
814 #if LOADER_DEBUG
815 case DEBUG:
816 debugging_on = 1;
817 break;
818 #endif
820 /*------------------------------------------------------------------*/
821 /* "profile" */
822 /* */
823 /* Turn on profiling. Used to find inefficiencies in loader speed */
824 /* while debugging internally. */
825 /*------------------------------------------------------------------*/
826 #if LOADER_DEBUG || LOADER_PROFILE
827 case PROFILE:
828 profiling_on = 1;
829 break;
830 #endif
831 /*------------------------------------------------------------------*/
832 /* Unrecognized commands will be reported and ignored. We just */
833 /* move onto the next prompt or line in the script. */
834 /* Note that in a script, if a line begins with '#', it is treated */
835 /* as a comment. Comment delimiter tokens must be first on a line. */
836 /*------------------------------------------------------------------*/
837 case COMMENT:
838 default:
839 if (tolower(tok[0]) != '#')
840 fprintf(stderr,
841 "<< D O L T >> ERROR: Unrecognized command ignored.\n");
842 continue;
843 }
844 }
846 /*NOTREACHED*/
847 return 0;
848 }