summaryrefslogtreecommitdiff
path: root/sim/arc/sim-if.c
blob: 4c5433daddc8c858b13fa5c6dbe83f1d79aba18e (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
/* Main simulator entry points specific to the ARC.
   Copyright (C) 1996, 1997, 1998, 1999, 2003, 2004, 2005, 2006, 2007, 2008,
   2009 Free Software Foundation, Inc.

   This file is part of GDB, the GNU debugger.

   This program is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
   the Free Software Foundation; either version 2, or (at your option)
   any later version.

   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU General Public License for more details.

   You should have received a copy of the GNU General Public License along
   with this program; if not, write to the Free Software Foundation, Inc.,
   59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */


/******************************************************************************/
/*                                                                            */
/* Outline:                                                                   */
/*     This module provides operations to:                                    */
/*                                                                            */
/*        1) create an "instance" of the ARC simulator                        */
/*        2) destroy an "instance" of the ARC simulator                       */
/*        3) create an "inferior" to run on the simulator                     */
/*        4) execute a simulator-related command                              */
/*                                                                            */
/*     N.B. there can be only one simulator instance at a time because of the */
/*          use of the current_state global variable.                         */
/*                                                                            */
/*     This module is also responsible for setting up the "command line"      */
/*     arguments and environment (name/value pairs) to be passed to the       */
/*     program that is to be debugged. This data is passed on the stack above */
/*     the top of stack as it is known to the program.                        */
/*                                                                            */
/*     E.g. if we are passing 4 arguments to main, we must place the data on  */
/*          the stack as:                                                     */
/*                                                                            */
/*             .                                                              */
/*             .                                                              */
/*          stack[top + A3] <== <arg_3>                                       */
/*             .                                                              */
/*             .                                                              */
/*          stack[top + A2] <== <arg_2>                                       */
/*             .                                                              */
/*             .                                                              */
/*          stack[top + A1] <== <arg_1>                                       */
/*             .                                                              */
/*             .                                                              */
/*          stack[top + A0] <== <arg_0>                                       */
/*          stack[top + 28] <== 0x0           # ? NULL terminator             */
/*          stack[top + 24] <== 0x0           # envp NULL terminator          */
/*          stack[top + 20] <== 0x0           # argv NULL terminator          */
/*          stack[top + 16] <== TOP + A3      # argv[3]                       */
/*          stack[top + 12] <== TOP + A2      # argv[2]                       */
/*          stack[top +  8] <== TOP + A1      # argv[1]                       */
/*          stack[top +  4] <== TOP + A0      # argv[0]                       */
/*          stack[top     ] <== 0x4           # argc                          */
/*                                                                            */
/*     where TOP = &stack[top]                                                */
/*       and A0 .. A3 are the offsets of the stored arguments from the stack  */
/*       top.                                                                 */
/*                                                                            */
/*                                                                            */
/* Notes:                                                                     */
/*     The interface to this module is somewhat muddled: both sim_open and    */
/*     sim_create_inferior have a BFD parameter which denotes the executable  */
/*     file which is to be run; but for sim_open this parameter may be NULL.  */
/*                                                                            */
/*     Also, both sim_open and sim_create_inferior have an argv parameter,    */
/*     but for sim_open *some* of the strings in this array parameter may be  */
/*     command-line arguments to be passed to the program to be executed,     */
/*     whilst the others are arguments for the simulator itself; but for      */
/*     sim_create_inferior, *all* of the strings (if any) in this parameter   */
/*     are such command-line arguments.                                       */
/*                                                                            */
/*     Finally, sim_create_inferior has an envp parameter which holds a set   */
/*     of name/value pairs to be passed as the environment of the executed    */
/*     program, whereas sim_open does not; but this is not (currently) done.  */
/*                                                                            */
/*                                                                            */
/*     This complexity arises from the variety of ways in which a simulator   */
/*     instance may be created and used:                                      */
/*                                                                            */
/*       a) the instance may be created by gdb before the executable file is  */
/*          known; e.g. the user may issue the commands                       */
/*                                                                            */
/*              set endian big | little                                       */           
/*              target sim                                                    */
/*              file <executable>                                             */
/*              load                                                          */
/*              run                                                           */
/*                                                                            */
/*          and in this case the BFD parameter to sim_open is NULL, and its   */
/*          argv parameter does not hold the executable's arguments;          */
/*                                                                            */
/*       b) the instance may be created by gdb after the executable file is   */
/*          known; e.g. the user may issue the commands                       */
/*                                                                            */
/*              file <executable>                                             */
/*              target sim                                                    */
/*              load                                                          */
/*              run                                                           */
/*                                                                            */
/*          and in this case the BFD parameter to sim_open is non-NULL, and   */
/*          its argv parameter does not hold the executable's arguments;      */
/*                                                                            */
/*       c) the instance may be created by a standalone executable; e.g.      */
/*          known; e.g. the user may issue the command                        */
/*                                                                            */
/*              run <executable> [ <arg1> .. <argN> ]                         */
/*                                                                            */
/*          and in this case the BFD parameter to sim_open is non-NULL, and   */
/*          its argv parameter does hold the executable's arguments.          */
/*                                                                            */
/*     Note that in each case, the argv parameter to sim_create_inferior      */
/*     holds the command-line arguments for the executable (so, there is      */
/*     apparently no need for them to be passed in the sim_open argv also!).  */
/*                                                                            */
/*     The arguments to the executed program may also be specified in several */
/*     ways; e.g by use of the gdb 'set args' command, or as arguments to the */
/*     gdb 'run' command; or, in the case of a standalone executable, on the  */
/*     command line.                                                          */
/*                                                                            */
/*     Note that the executable program can be run (by gdb) repeatedly with   */
/*     different argument lists, i.e. there may be multiple calls of          */
/*     sim_create_inferior after a call of sim_open; and each of these lists  */
/*     may require a different amount of memory to hold them on the stack.    */
/*                                                                            */
/*                                                                            */
/*     It is necessary to define a memory region with a particular start      */
/*     address and size in the simulator memory (all accesses outside this    */
/*     address range by the executed program are erroneous, thus allowing     */
/*     invalid accesses to be detected); this region must include the program */
/*     text, (un)initialized data, heap and stack.  This must also include    */
/*     the argument/environment data which is passed above the top of the     */
/*     stack.                                                                 */
/*                                                                            */
/*     If the executable file is known (i.e. we have a non-NULL BFD),         */
/*     the bounds of the memory region required for the program may be        */
/*     extracted from the section header information in the file; if the      */
/*     arguments/environment are known, the space required to hold them on    */
/*     the stack may be computed. This allows the total space to be computed, */
/*     and so a memory region holding it may be defined.                      */
/*                                                                            */
/*     However, if a subsequent execution of the program should require a     */
/*     greater total space (because its arguments have changed) it is then    */
/*     necessary to define an additional memory region to provide the extra   */
/*     space; it is not possible to redefine the existing region, or a new    */
/*     region of the new size (as memory regions may not overlap).            */
/*                                                                            */
/******************************************************************************/

/* system header files */

#ifdef HAVE_STRING_H
#include <string.h>
#else
#ifdef HAVE_STRINGS_H
#include <strings.h>
#endif
#endif
#ifdef HAVE_STDLIB_H
#include <stdlib.h>
#endif

/* simulator / binutils header files */

#include "sim-main.h"
#include "sim-options.h"
#include "libiberty.h"
#include "bfd.h"


/* -------------------------------------------------------------------------- */
/*                         conditional compilation flags                      */
/* -------------------------------------------------------------------------- */

//#define LOGGING
//#define PUSH_ENVIRONMENT_ONTO_STACK


/* -------------------------------------------------------------------------- */
/*                               externally visible data                      */
/* -------------------------------------------------------------------------- */

/* Records simulator descriptor so utilities like arc_dump_regs can be called
   from gdb.  */
SIM_DESC current_state;


/* -------------------------------------------------------------------------- */
/*                               local data                                   */
/* -------------------------------------------------------------------------- */

#define DEFAULT_ENVIRONMENT_SPACE     2048

#define TARGET_POINTER_SIZE    4
#define TARGET_INT_SIZE        4


/* -------------------------------------------------------------------------- */
/*                               local macros                                 */
/* -------------------------------------------------------------------------- */

#define IS_LITTLE_ENDIAN(abfd)   (abfd) ? bfd_little_endian (abfd) \
                                        : (CURRENT_TARGET_BYTE_ORDER == LITTLE_ENDIAN)


/* -------------------------------------------------------------------------- */
/*                               local functions                              */
/* -------------------------------------------------------------------------- */

/* Cover function of sim_state_free to free the cpu buffers as well.  */

static void
free_state (SIM_DESC sd)
{
  if (STATE_MODULES (sd) != NULL)
    sim_module_uninstall (sd);
  sim_cpu_free_all (sd);
  sim_state_free (sd);
}


/* PROFILE_CPU_CALLBACK */

static void
print_arc_misc_cpu (SIM_CPU *cpu, int verbose)
{
  if (CPU_PROFILE_FLAGS (cpu) [PROFILE_INSN_IDX])
    {
      SIM_DESC sd = CPU_STATE (cpu);
      char     buf[20];

      sim_io_printf (sd, "Miscellaneous Statistics\n\n");
      sim_io_printf (sd, "  %-*s %s\n\n",
		     PROFILE_LABEL_WIDTH, "Fill nops:",
		     sim_add_commas (buf, sizeof (buf),
				     CPU_ARC_MISC_PROFILE (cpu)->fillnop_count));
    }
}


#ifdef LOGGING
static void
dump (SIM_DESC sd, char** argv, char** envp)
{
  char **cpp, **rpp;
  char* tag;
  int   cnt;

  for (cpp = argv, tag = "argv", cnt = 2; cnt--; cpp = envp, tag = "env")
    {
      if (cpp)
        {
           int i = 0;

           for (rpp = cpp; *rpp; rpp++, i++)
               sim_io_eprintf(sd, "%s[%d] = %s\n", tag, i, *rpp);
        }
    }
}
#endif

/* Setup copy arguments / environment to the stack area of SD according
   to argv and envp.  Either or both of argv and envp may be NULL.
   Return 0 on failure, nonzero on success.  */

static int
setup_stack (SIM_DESC sd, int little_endian_p, char** argv, char** envp)
{
  SIM_CPU* cpu = STATE_CPU (sd, 0);
  int      wpp = sd->memory.stack_top + TARGET_INT_SIZE;
  int      cp  = sd->memory.argument_data_start;
  int      count;
  char**   cpp;

#ifdef LOGGING
  sim_io_eprintf(sd, "setup stack (%c/E) %d args\n",
                     (little_endian_p) ? 'L' : 'B',
                     sd->memory.num_arguments);
  dump(sd, argv, envp);
#endif

  if (sd->memory.stack_top <= sd->memory.stack_start)
    {
      host_callback *callback = STATE_CALLBACK (sd);

      (*callback->printf_filtered) (callback, "stack overflow\n");
      return 0;
    }

  /* Can't use sim_core_write_unaligned_4 without everything
     initialized when tracing, and then these writes would get into
     the trace.  */
#define write_dword(addr, data)                                              \
 do                                                                          \
   {                                                                         \
     bfd_byte buf[4];                                                        \
     USI data_ = data;                                                       \
     USI addr_ = addr;                                                       \
     if (little_endian_p)                                                    \
       bfd_putl32 (data_, buf);                                              \
     else                                                                    \
       bfd_putb32 (data_, buf);                                              \
     if (sim_core_write_buffer (sd, cpu, 0, buf, addr_, 4) != 4)             \
        {                                                                    \
          sim_io_eprintf(sd, "failed to write word to address 0x%x\n", addr);\
          return 0;                                                          \
        }                                                                    \
   }                                                                         \
 while (0)


 /* Push the arguments and environment onto the stack.  */

  write_dword (sd->memory.stack_top, sd->memory.num_arguments);
  for (cpp = argv, count = 2; count--; cpp = envp)
    {
      if (cpp)
        {
          char*  argument;
          char** rpp;

          for (rpp = cpp; (argument = *cpp); cpp++)
            {
              size_t len = strlen(argument) + 1;

#ifdef LOGGING
              sim_io_eprintf(sd, "pushing argument '%s' onto program stack at address 0x%x\n", argument, cp);
#endif

              if (sim_core_write_buffer (sd, cpu, 0, argument, cp, len) != len)
                {
                  sim_io_eprintf(sd, "could not push argument '%s' onto program stack at address 0x%x\n", argument, cp);
                  return 0;
                }
              write_dword (wpp, cp);
              cp += len;
              wpp += TARGET_POINTER_SIZE;
            }
        }

      write_dword (wpp, 0);         // NULL array terminator
      wpp += TARGET_POINTER_SIZE;

    }
  write_dword (wpp, 0); /* uClibc aux_dat NULL terminator.  */

  /* success */
  return 1;
}


/* Find out heap and stack end boundaries, and calculate required memory size;
   if this cannot be done, use the default memory size.
   ABFD, ARGV and/or ENVP may be NULL.
   If this calculation fails, return 0.  */

static int
determine_memory_requirements (SIM_DESC sd, struct bfd *abfd, char **argv,
			       char **envp, struct sim_memory* memory)
{
  USI    stack_start           = 0, stack_top = 0, heap_start = 0, heap_end = 0;
  USI    program_end           = 0;
  USI    memory_size;
  USI    data_start;
  int    argc                  = 0;
  size_t total_argument_length = 0;
  int    num_pointers          = 0;

  /* N.B. the *_end variables actually denote the next byte after the end of
   the sections to which they refer; however, they are used consistently
   in this way, so that is not a problem!  */

  /* If we have an executable file to look at.  */
  if (abfd)
    {
      asection* section;

      /* Look at each section in the file.  */
      for (section = abfd->sections; section; section = section->next)
        {
          if (strcmp (bfd_get_section_name (abfd, section), ".stack") == 0)
            {
              stack_start = bfd_get_section_vma (abfd, section);
              stack_top   = stack_start + bfd_section_size (abfd, section);
              stack_top  &= -TARGET_POINTER_SIZE;

              /* N.B. this assumes that the target memory region to be
		 created has the range 0 .. stack_top - 1, i.e. that there
		 is nothing in the program that has to be loaded at
		 addresses above the stack top.  */
              memory_size = stack_top;
            }
          else if (strcmp (bfd_get_section_name (abfd, section), ".heap") == 0)
            {
              heap_start = bfd_get_section_vma (abfd, section);
              heap_end   = heap_start + bfd_section_size (abfd, section);
            }
          else if (bfd_get_section_flags(abfd, section) & SEC_LOAD)
            {
              USI section_end = bfd_get_section_vma (abfd, section) +
                                bfd_section_size    (abfd, section);

              /* Keep track of the end address of whatever else is to be
		 loaded.  */
              if (program_end < section_end)
                program_end = section_end;
            }
        }

       /* If we know the start of the stack, check for an overlap.  */ 
      if (stack_start > 0 && program_end > stack_start)
	{
	  sim_io_eprintf(sd,
			 "program data overlaps program stack at 0x%x (0x%x)\n",
			 stack_start, program_end);
	  return 0;
	}

       /* No heap section found?  */
      if (heap_end == 0)
        {
          /* Assume the heap lies between the program data and the stack.  */
          heap_start = program_end;
          heap_end   = stack_start;
        }
    }


  /* If we have arguments or environment variables to pass to the program.  */

  if (argv)
    {
      char **rpp;

      for (rpp = argv; *rpp; rpp++, num_pointers++)
         total_argument_length += strlen (*rpp) + 1; 

       argc = num_pointers;
    }
  num_pointers++; /* For NULL terminator.  */

  if (envp)
    {
      char** rpp;

      for (rpp = envp; *rpp; rpp++, num_pointers++)
         total_argument_length += strlen (*rpp) + 1;   
    }
  num_pointers++;   /* For NULL terminator.  */

  num_pointers++;   /* For uclibc aux_dat.  */

  /* If we could not get the stack bounds from the executable file (and hence
     do not know the memory size), use the default memory size and take the
     top of the stack as being at the end of that memory range (aligned to
     the size of a target pointer).  */
  if (!stack_top)
    stack_top = (USI) ((ARC_DEFAULT_MEM_SIZE + 3) & -TARGET_POINTER_SIZE);

  data_start = (USI) (stack_top                          +
                      TARGET_INT_SIZE                    +  /* For argc.  */
                      num_pointers * TARGET_POINTER_SIZE);

  /* We need enough memory to hold the program stack, plus the data to be passed
     above the top of the stack.  */
  memory_size = (USI) (data_start + total_argument_length);

#ifdef PUSH_ENVIRONMENT_ONTO_STACK
  if (!envp)
     memory_size += DEFAULT_ENVIRONMENT_SPACE;
#endif

  /* Round up to multiple of 32: strlen expects memory to come in chunks
     that are at least cache-line (32 bytes) sized.
     FIXME: is that true?  */
  memory_size += 31;
  memory_size &= -32;

  memory->heap_start          = heap_start;
  memory->heap_end            = heap_end;
  memory->stack_top           = stack_top;
  memory->stack_start         = stack_start;
  memory->total_size          = memory_size;
  memory->argument_data_start = data_start;
  memory->num_arguments       = (USI) argc;

#ifdef LOGGING
  sim_io_eprintf(sd, "heap  start   : 0x%x\n", heap_start);
  sim_io_eprintf(sd, "heap  end     : 0x%x\n", heap_end);
  sim_io_eprintf(sd, "stack start   : 0x%x\n", stack_start);
  sim_io_eprintf(sd, "stack top     : 0x%x\n", stack_top);
  sim_io_eprintf(sd, "memory size   : 0x%x\n", memory_size);
  sim_io_eprintf(sd, "arg data start: 0x%x\n", data_start);
  sim_io_eprintf(sd, "%d args\n", argc);
#endif

  /* Success.  */
  return 1;
}


static void
define_memory_region (SIM_DESC sd, USI start, USI size)
{ 
  /* Allocate core managed memory if none specified by user.  */
  if (!sd->memory_regions_defined_by_user)
    {
#ifdef LOGGING
      sim_io_printf   (sd, "memory region 0x%x,0x%x\n", start, size);
#endif
      sim_do_commandf (sd, "memory region 0x%x,0x%x",   start, size);
    }
}


/* -------------------------------------------------------------------------- */
/*                               externally visible functions                 */
/* -------------------------------------------------------------------------- */

/* Create an instance of the simulator.  */

SIM_DESC
sim_open (SIM_OPEN_KIND  kind,
          host_callback *callback,
          struct bfd    *abfd,      /* May be NULL.  */
          char         **argv)
{
  SIM_DESC sd = sim_state_alloc (kind, callback);
  int      little_endian_p;
  char**   prog_argv;
  char     c;

  SIM_ASSERT (STATE_MAGIC (sd) == SIM_MAGIC_NUMBER);

#ifdef LOGGING
  sim_io_eprintf (sd, "sim_open: %p\n", abfd);
  dump(sd, argv, NULL);
#endif

  /* The cpu data is kept in a separately-allocated chunk of memory.  */
  if (sim_cpu_alloc_all (sd, 1, cgen_cpu_max_extra_bytes ()) != SIM_RC_OK)
    {
      free_state (sd);
      return 0;
    }

#if 0 /* FIXME: pc is in mach-specific struct.  */
  /* FIXME: watchpoints code shouldn't need this.  */
  {
    SIM_CPU *current_cpu = STATE_CPU (sd, 0);
    STATE_WATCHPOINTS (sd)->pc = &(PC);
    STATE_WATCHPOINTS (sd)->sizeof_pc = sizeof (PC);
  }
#endif

  if (sim_pre_argv_init (sd, argv[0]) != SIM_RC_OK)
    {
      free_state (sd);
      return 0;
    }

#ifdef HAVE_DV_SOCKSER /* FIXME: was done differently before.  */
  if (dv_sockser_install (sd) != SIM_RC_OK)
    {
      free_state (sd);
      return 0;
    }
#endif

#if 0 /* FIXME: 'twould be nice if we could do this.  */
  /* These options override any module options.
     Obviously ambiguity should be avoided, however the caller may wish to
     augment the meaning of an option.  */
  if (extra_options != NULL)
    sim_add_option_table (sd, extra_options);
#endif

  /* getopt will print the error message so we just have to exit if this fails.
     FIXME: Hmmm...  in the case of gdb we need getopt to call
     print_filtered.  */
  if (sim_parse_args (sd, argv) != SIM_RC_OK)
    {
      free_state (sd);
      return 0;
    }

#ifdef LOGGING
  /* sim_parse_args may set up STATE_PROG_ARGV(sd), in the case that kind == SIM_OPEN_STANDALONE.  */
  dump(sd, STATE_PROG_ARGV (sd), NULL);
#endif

  /* Check for/establish the reference program image, and set arch info.  */
  if (sim_analyze_program (sd,
			   (STATE_PROG_ARGV (sd) != NULL
			    ? *STATE_PROG_ARGV (sd)
			    : NULL),
			   abfd) != SIM_RC_OK)
    {
      free_state (sd);
      return 0;
    }

  prog_argv = STATE_PROG_ARGV (sd);

  /* If we have not been given an executable file.  */
  if (!abfd)
    {
      /* If the test below fails, we will use ARC_DEFAULT_MEM_SIZE. */
      if (prog_argv != NULL && *prog_argv != NULL)
	{
	  char* name = *prog_argv;

	  abfd = bfd_openr (name, 0);

	  if (abfd == NULL || !bfd_check_format (abfd, bfd_object))
	    {
	      free_state (sd);
	      return 0;
	    }
	}
    }

  /* Establish any remaining configuration options.  */
  if (sim_config (sd) != SIM_RC_OK)
    {
      free_state (sd);
      return 0;
    }

  little_endian_p = IS_LITTLE_ENDIAN(abfd);

  /* Check whether core managed memory has been specified by user.
     Use address 4 here in case the user wanted address 0 unmapped.
     N.B. this is really not a very good check - we want to know whether the
     user has explicitly specified the target's memory regions, so that we
     don't define a region ourself (which might overlap), and we try to
     find that out by seeing if we can read the memory at address 0x4 !!!!  */
  sd->memory_regions_defined_by_user = 
    sim_core_read_buffer (sd, NULL, read_map, &c, 4, 1) != 0;

  /* Calculate the memory size required without actually initializing the stack.  */
  if (!determine_memory_requirements(sd, abfd, prog_argv, NULL, &sd->memory))
    {
      free_state (sd);
      return 0;
    }

  define_memory_region (sd, 0, sd->memory.total_size);

  /* If the simulator is being used stand-alone, we know that the program 
     arguments we have been given here are not going to change later on (when
     sim_create_inferior is called) - so we can go ahead and set up the stack
     with those arguments right now.  */
  if (STATE_OPEN_KIND (sd) == SIM_OPEN_STANDALONE)
    {
      /* Now that we do know the memory size, initialize the stack.  */
      if (!setup_stack (sd, little_endian_p, prog_argv, NULL))
        {
          free_state (sd);
          return 0;
        }
    }

  if (sim_post_argv_init (sd) != SIM_RC_OK)
    {
      free_state (sd);
      return 0;
    }

  /* Open a copy of the cpu descriptor table.  */
  {
    CGEN_CPU_DESC cd = arc_cgen_cpu_open_1
                          (STATE_ARCHITECTURE (sd)->printable_name,
			   (little_endian_p ? CGEN_ENDIAN_LITTLE : CGEN_ENDIAN_BIG));
    int i;

    for (i = 0; i < MAX_NR_PROCESSORS; ++i)
      {
	SIM_CPU *cpu = STATE_CPU (sd, i);
	CPU_CPU_DESC (cpu) = cd;
	CPU_DISASSEMBLER (cpu) = sim_cgen_disassemble_insn;
      }

    arc_cgen_init_dis (cd);
  }

  /* Initialize various cgen things not done by common framework.
     Must be done after arc_cgen_cpu_open.  */
  cgen_init (sd);

  for (c = 0; c < MAX_NR_PROCESSORS; c++)
    {
      /* Only needed for profiling, but the structure member is small.  */
      memset (CPU_ARC_MISC_PROFILE (STATE_CPU (sd, i)), 0,
	      sizeof (* CPU_ARC_MISC_PROFILE (STATE_CPU (sd, i))));

      /* Hook in callback for reporting these stats.  */
      PROFILE_INFO_CPU_CALLBACK (CPU_PROFILE_DATA (STATE_CPU (sd, i))) =
         print_arc_misc_cpu;
    }

  /* Store in a global so things like arc32_dump_regs can be invoked
     from the gdb command line.  */
  current_state = sd;

  return sd;
}


void
sim_close (SIM_DESC sd, int quitting)
{
  arc_cgen_cpu_close (CPU_CPU_DESC (STATE_CPU (sd, 0)));
  sim_module_uninstall (sd);
}


SIM_RC
sim_create_inferior (SIM_DESC sd, struct bfd *abfd, char **argv, char **envp)
{
  SIM_CPU *current_cpu = STATE_CPU (sd, 0);
  SIM_ADDR addr;

#ifndef PUSH_ENVIRONMENT_ONTO_STACK
  envp = NULL;
#endif
#ifdef LOGGING
  sim_io_eprintf (sd, "sim_create_inferior: %p\n", abfd);
  dump (sd, argv, envp);
#endif

  if (abfd != NULL)
    {
      int little_endian_p = bfd_little_endian (abfd);

      if (little_endian_p)
        {
          if (CURRENT_TARGET_BYTE_ORDER == BIG_ENDIAN)
            {
              sim_io_eprintf (sd, "Target is big-endian but executable file %s is little-endian.\n",
			      bfd_get_filename (abfd));
              return SIM_RC_FAIL;
            }
        }
      else
        {
          if (CURRENT_TARGET_BYTE_ORDER == LITTLE_ENDIAN)
            {
              sim_io_eprintf (sd, "Target is little-endian but executable file %s is big-endian.\n",
			      bfd_get_filename(abfd));
              return SIM_RC_FAIL;
            }
        }

      addr = bfd_get_start_address (abfd);
    }
  else
    addr = 0;

  sim_pc_set (current_cpu, addr);

  /* If the simulator is being used stand-alone, we have already set up the
     stack (when sim_open was called); but if the simulator is being used by
     gdb we must set up the stack each time that sim_create_inferior is
     called, in case the program arguments have changed since last time.  */
  if (STATE_OPEN_KIND(sd) == SIM_OPEN_DEBUG)
    {
      struct sim_memory memory;

      if (determine_memory_requirements (sd, abfd, argv, envp, &memory))
        {
          USI current_size = sd->memory.total_size;

          if (memory.total_size > current_size)
            {
#ifdef LOGGING
              sim_io_eprintf (sd, "program requires memory size 0x%x bytes"
                                  " but simulator currently has memory size 0x%x bytes\n",
                                   memory.total_size, current_size);
#endif

              /* Define another memory region to provide the extra memory
		 required.  */
              define_memory_region (sd, current_size,
				    memory.total_size - current_size);

              /* Update all the memory details.  */
              sd->memory = memory;
            }
          else
            {
              /* Update all the memory details *except* the current size.  */
              sd->memory = memory;
              sd->memory.total_size = current_size;
            }

	  if (!setup_stack (sd, IS_LITTLE_ENDIAN (abfd), argv, envp))
	    return SIM_RC_FAIL;
	}
      else
	return SIM_RC_FAIL;
    }

  current_cpu->endbrk = sd->memory.heap_start;

  /* Set r28 (SP) to the stack top, and set r0/r1 to argc/argv. */
  a5f_h_cr_set (current_cpu, 0,  sd->memory.num_arguments);
  a5f_h_cr_set (current_cpu, 1,  sd->memory.stack_top + 4);
  a5f_h_cr_set (current_cpu, 28, sd->memory.stack_top);

#ifdef LOGGING
  sim_io_eprintf (sd, "R0 = 0x%08X\n", sd->memory.num_arguments);
  sim_io_eprintf (sd, "R1 = 0x%08X\n", sd->memory.stack_top + 4);
  sim_io_eprintf (sd, "SP = 0x%08X\n", sd->memory.stack_top);
#endif

#if 0
  STATE_ARGV (sd) = sim_copy_argv (argv);
  STATE_ENVP (sd) = sim_copy_argv (envp);
#endif

  return SIM_RC_OK;
}


void
sim_do_command (SIM_DESC sd, char* cmd)
{
  char **argv;

  if (cmd == NULL)
    return;

  argv = buildargv (cmd);

  /* Is the command 'info reg[ister] <name>' ?  */

  if (argv[0] != NULL
      && strcasecmp (argv[0], "info") == 0
      && argv[1] != NULL
      && strncasecmp (argv[1], "reg", 3) == 0)
    {
      SI val;

      if (argv[2] == NULL)
        sim_io_eprintf (sd, "Missing register in `%s'\n", cmd);
      else if (argv[3] != NULL)
        sim_io_eprintf (sd, "Too many arguments in `%s'\n", cmd);

      /* Should we recognize some/all of the ARC register names here?  */

      else
	sim_io_eprintf (sd, "Printing of register `%s' not supported with `sim info'\n",
			argv[2]);
    }
  else
    {
      if (sim_args_command (sd, cmd) != SIM_RC_OK)
	sim_io_eprintf (sd, "Unknown sim command `%s'\n", cmd);
    }

  freeargv (argv);
}

/******************************************************************************/