]> Gitweb @ Texas Instruments - Open Source Git Repositories - git.TI.com/gitweb - ipc/ipcdev.git/blob - qnx/src/ipc3x_dev/ti/syslink/procMgr/hlos/knl/loaders/Elf/Qnx/DLOAD/DLWRAPPER/dlw.c
Moved files from the ipc3x_dev branch in syslink_qnx repository into direct
[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);
156 /*****************************************************************************/
157 /* EXECUTE_PROGRAM() - Execute loaded program and print return value.        */
158 /*****************************************************************************/
159 static void execute_program(int argc, char** argv)
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));
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
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
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)
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);
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)
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     }
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
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)
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;
299 static INPUT_SERVER *cmd_set_string(const char *str)
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;
308 static int cmd_getc(INPUT_SERVER *server)
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     }
321 static int cmd_error(INPUT_SERVER *server)
323     if (server->type == IST_FILE) return ferror(server->input_file);
324     else return server->string == NULL;
327 static int cmd_eof(INPUT_SERVER *server)
329     if (server->type == IST_FILE) return feof(server->input_file);
330     else return !cmd_error(server) && !server->string[server->string_pos];
333 static int cmd_isstdin(INPUT_SERVER *server)
335     if (server->type == IST_FILE) return server->input_file == stdin;
336     else return 0;
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)
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;
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
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;