]> git.proxmox.com Git - mirror_ubuntu-zesty-kernel.git/blame - drivers/staging/tidspbridge/dynload/cload.c
Fix common misspellings
[mirror_ubuntu-zesty-kernel.git] / drivers / staging / tidspbridge / dynload / cload.c
CommitLineData
26f8db7d
ORL
1/*
2 * cload.c
3 *
4 * DSP-BIOS Bridge driver support functions for TI OMAP processors.
5 *
6 * Copyright (C) 2005-2006 Texas Instruments, Inc.
7 *
8 * This package is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License version 2 as
10 * published by the Free Software Foundation.
11 *
12 * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
13 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
14 * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
15 */
16
17#include "header.h"
18
19#include "module_list.h"
20#define LINKER_MODULES_HEADER ("_" MODULES_HEADER)
21
26f8db7d
ORL
22/*
23 * forward references
24 */
25static void dload_symbols(struct dload_state *dlthis);
26static void dload_data(struct dload_state *dlthis);
27static void allocate_sections(struct dload_state *dlthis);
28static void string_table_free(struct dload_state *dlthis);
29static void symbol_table_free(struct dload_state *dlthis);
30static void section_table_free(struct dload_state *dlthis);
31static void init_module_handle(struct dload_state *dlthis);
32#if BITS_PER_AU > BITS_PER_BYTE
33static char *unpack_name(struct dload_state *dlthis, u32 soffset);
34#endif
35
36static const char cinitname[] = { ".cinit" };
37static const char loader_dllview_root[] = { "?DLModules?" };
38
39/*
40 * Error strings
41 */
42static const char readstrm[] = { "Error reading %s from input stream" };
43static const char err_alloc[] = { "Syms->dload_allocate( %d ) failed" };
44static const char tgtalloc[] = {
45 "Target memory allocate failed, section %s size " FMT_UI32 };
46static const char initfail[] = { "%s to target address " FMT_UI32 " failed" };
47static const char dlvwrite[] = { "Write to DLLview list failed" };
48static const char iconnect[] = { "Connect call to init interface failed" };
49static const char err_checksum[] = { "Checksum failed on %s" };
50
51/*************************************************************************
52 * Procedure dload_error
53 *
54 * Parameters:
55 * errtxt description of the error, printf style
56 * ... additional information
57 *
58 * Effect:
59 * Reports or records the error as appropriate.
60 *********************************************************************** */
61void dload_error(struct dload_state *dlthis, const char *errtxt, ...)
62{
63 va_list args;
64
65 va_start(args, errtxt);
66 dlthis->mysym->error_report(dlthis->mysym, errtxt, args);
67 va_end(args);
68 dlthis->dload_errcount += 1;
69
70} /* dload_error */
71
72#define DL_ERROR(zza, zzb) dload_error(dlthis, zza, zzb)
73
74/*************************************************************************
75 * Procedure dload_syms_error
76 *
77 * Parameters:
78 * errtxt description of the error, printf style
79 * ... additional information
80 *
81 * Effect:
82 * Reports or records the error as appropriate.
83 *********************************************************************** */
84void dload_syms_error(struct dynamic_loader_sym *syms, const char *errtxt, ...)
85{
86 va_list args;
87
88 va_start(args, errtxt);
89 syms->error_report(syms, errtxt, args);
90 va_end(args);
91}
92
93/*************************************************************************
94 * Procedure dynamic_load_module
95 *
96 * Parameters:
97 * module The input stream that supplies the module image
98 * syms Host-side symbol table and malloc/free functions
99 * alloc Target-side memory allocation
100 * init Target-side memory initialization
101 * options Option flags DLOAD_*
102 * mhandle A module handle for use with Dynamic_Unload
103 *
104 * Effect:
105 * The module image is read using *module. Target storage for the new
106 * image is
107 * obtained from *alloc. Symbols defined and referenced by the module are
108 * managed using *syms. The image is then relocated and references
109 * resolved as necessary, and the resulting executable bits are placed
110 * into target memory using *init.
111 *
112 * Returns:
113 * On a successful load, a module handle is placed in *mhandle,
114 * and zero is returned. On error, the number of errors detected is
115 * returned. Individual errors are reported during the load process
116 * using syms->error_report().
117 ********************************************************************** */
118int dynamic_load_module(struct dynamic_loader_stream *module,
119 struct dynamic_loader_sym *syms,
120 struct dynamic_loader_allocate *alloc,
121 struct dynamic_loader_initialize *init,
122 unsigned options, void **mhandle)
123{
124 register unsigned *dp, sz;
125 struct dload_state dl_state; /* internal state for this call */
126
127 /* blast our internal state */
128 dp = (unsigned *)&dl_state;
129 for (sz = sizeof(dl_state) / sizeof(unsigned); sz > 0; sz -= 1)
130 *dp++ = 0;
131
132 /* Enable _only_ BSS initialization if enabled by user */
133 if ((options & DLOAD_INITBSS) == DLOAD_INITBSS)
134 dl_state.myoptions = DLOAD_INITBSS;
135
136 /* Check that mandatory arguments are present */
137 if (!module || !syms) {
138 dload_error(&dl_state, "Required parameter is NULL");
139 } else {
140 dl_state.strm = module;
141 dl_state.mysym = syms;
142 dload_headers(&dl_state);
143 if (!dl_state.dload_errcount)
144 dload_strings(&dl_state, false);
145 if (!dl_state.dload_errcount)
146 dload_sections(&dl_state);
147
148 if (init && !dl_state.dload_errcount) {
149 if (init->connect(init)) {
150 dl_state.myio = init;
151 dl_state.myalloc = alloc;
152 /* do now, before reducing symbols */
153 allocate_sections(&dl_state);
154 } else
155 dload_error(&dl_state, iconnect);
156 }
157
158 if (!dl_state.dload_errcount) {
159 /* fix up entry point address */
160 unsigned sref = dl_state.dfile_hdr.df_entry_secn - 1;
161 if (sref < dl_state.allocated_secn_count)
162 dl_state.dfile_hdr.df_entrypt +=
163 dl_state.ldr_sections[sref].run_addr;
164
165 dload_symbols(&dl_state);
166 }
167
168 if (init && !dl_state.dload_errcount)
169 dload_data(&dl_state);
170
171 init_module_handle(&dl_state);
172
173 /* dl_state.myio is init or 0 at this point. */
174 if (dl_state.myio) {
175 if ((!dl_state.dload_errcount) &&
176 (dl_state.dfile_hdr.df_entry_secn != DN_UNDEF) &&
177 (!init->execute(init,
178 dl_state.dfile_hdr.df_entrypt)))
179 dload_error(&dl_state, "Init->Execute Failed");
180 init->release(init);
181 }
182
183 symbol_table_free(&dl_state);
184 section_table_free(&dl_state);
185 string_table_free(&dl_state);
186 dload_tramp_cleanup(&dl_state);
187
188 if (dl_state.dload_errcount) {
189 dynamic_unload_module(dl_state.myhandle, syms, alloc,
190 init);
191 dl_state.myhandle = NULL;
192 }
193 }
194
195 if (mhandle)
196 *mhandle = dl_state.myhandle; /* give back the handle */
197
198 return dl_state.dload_errcount;
199} /* DLOAD_File */
200
201/*************************************************************************
202 * Procedure dynamic_open_module
203 *
204 * Parameters:
205 * module The input stream that supplies the module image
206 * syms Host-side symbol table and malloc/free functions
207 * alloc Target-side memory allocation
208 * init Target-side memory initialization
209 * options Option flags DLOAD_*
210 * mhandle A module handle for use with Dynamic_Unload
211 *
212 * Effect:
213 * The module image is read using *module. Target storage for the new
214 * image is
215 * obtained from *alloc. Symbols defined and referenced by the module are
216 * managed using *syms. The image is then relocated and references
217 * resolved as necessary, and the resulting executable bits are placed
218 * into target memory using *init.
219 *
220 * Returns:
221 * On a successful load, a module handle is placed in *mhandle,
222 * and zero is returned. On error, the number of errors detected is
223 * returned. Individual errors are reported during the load process
224 * using syms->error_report().
225 ********************************************************************** */
226int
227dynamic_open_module(struct dynamic_loader_stream *module,
228 struct dynamic_loader_sym *syms,
229 struct dynamic_loader_allocate *alloc,
230 struct dynamic_loader_initialize *init,
231 unsigned options, void **mhandle)
232{
233 register unsigned *dp, sz;
234 struct dload_state dl_state; /* internal state for this call */
235
236 /* blast our internal state */
237 dp = (unsigned *)&dl_state;
238 for (sz = sizeof(dl_state) / sizeof(unsigned); sz > 0; sz -= 1)
239 *dp++ = 0;
240
241 /* Enable _only_ BSS initialization if enabled by user */
242 if ((options & DLOAD_INITBSS) == DLOAD_INITBSS)
243 dl_state.myoptions = DLOAD_INITBSS;
244
245 /* Check that mandatory arguments are present */
246 if (!module || !syms) {
247 dload_error(&dl_state, "Required parameter is NULL");
248 } else {
249 dl_state.strm = module;
250 dl_state.mysym = syms;
251 dload_headers(&dl_state);
252 if (!dl_state.dload_errcount)
253 dload_strings(&dl_state, false);
254 if (!dl_state.dload_errcount)
255 dload_sections(&dl_state);
256
257 if (init && !dl_state.dload_errcount) {
258 if (init->connect(init)) {
259 dl_state.myio = init;
260 dl_state.myalloc = alloc;
261 /* do now, before reducing symbols */
262 allocate_sections(&dl_state);
263 } else
264 dload_error(&dl_state, iconnect);
265 }
266
267 if (!dl_state.dload_errcount) {
268 /* fix up entry point address */
269 unsigned sref = dl_state.dfile_hdr.df_entry_secn - 1;
270 if (sref < dl_state.allocated_secn_count)
271 dl_state.dfile_hdr.df_entrypt +=
272 dl_state.ldr_sections[sref].run_addr;
273
274 dload_symbols(&dl_state);
275 }
276
277 init_module_handle(&dl_state);
278
279 /* dl_state.myio is either 0 or init at this point. */
280 if (dl_state.myio) {
281 if ((!dl_state.dload_errcount) &&
282 (dl_state.dfile_hdr.df_entry_secn != DN_UNDEF) &&
283 (!init->execute(init,
284 dl_state.dfile_hdr.df_entrypt)))
285 dload_error(&dl_state, "Init->Execute Failed");
286 init->release(init);
287 }
288
289 symbol_table_free(&dl_state);
290 section_table_free(&dl_state);
291 string_table_free(&dl_state);
292
293 if (dl_state.dload_errcount) {
294 dynamic_unload_module(dl_state.myhandle, syms, alloc,
295 init);
296 dl_state.myhandle = NULL;
297 }
298 }
299
300 if (mhandle)
301 *mhandle = dl_state.myhandle; /* give back the handle */
302
303 return dl_state.dload_errcount;
304} /* DLOAD_File */
305
306/*************************************************************************
307 * Procedure dload_headers
308 *
309 * Parameters:
310 * none
311 *
312 * Effect:
313 * Loads the DOFF header and verify record. Deals with any byte-order
314 * issues and checks them for validity.
315 *********************************************************************** */
316#define COMBINED_HEADER_SIZE (sizeof(struct doff_filehdr_t)+ \
317 sizeof(struct doff_verify_rec_t))
318
319void dload_headers(struct dload_state *dlthis)
320{
321 u32 map;
322
323 /* Read the header and the verify record as one. If we don't get it
324 all, we're done */
325 if (dlthis->strm->read_buffer(dlthis->strm, &dlthis->dfile_hdr,
326 COMBINED_HEADER_SIZE) !=
327 COMBINED_HEADER_SIZE) {
328 DL_ERROR(readstrm, "File Headers");
329 return;
330 }
331 /*
332 * Verify that we have the byte order of the file correct.
333 * If not, must fix it before we can continue
334 */
335 map = REORDER_MAP(dlthis->dfile_hdr.df_byte_reshuffle);
336 if (map != REORDER_MAP(BYTE_RESHUFFLE_VALUE)) {
337 /* input is either byte-shuffled or bad */
338 if ((map & 0xFCFCFCFC) == 0) { /* no obviously bogus bits */
339 dload_reorder(&dlthis->dfile_hdr, COMBINED_HEADER_SIZE,
340 map);
341 }
342 if (dlthis->dfile_hdr.df_byte_reshuffle !=
343 BYTE_RESHUFFLE_VALUE) {
344 /* didn't fix the problem, the byte swap map is bad */
345 dload_error(dlthis,
346 "Bad byte swap map " FMT_UI32 " in header",
347 dlthis->dfile_hdr.df_byte_reshuffle);
348 return;
349 }
350 dlthis->reorder_map = map; /* keep map for future use */
351 }
352
353 /*
354 * Verify checksum of header and verify record
355 */
356 if (~dload_checksum(&dlthis->dfile_hdr,
357 sizeof(struct doff_filehdr_t)) ||
358 ~dload_checksum(&dlthis->verify,
359 sizeof(struct doff_verify_rec_t))) {
360 DL_ERROR(err_checksum, "header or verify record");
361 return;
362 }
363#if HOST_ENDIANNESS
364 dlthis->dfile_hdr.df_byte_reshuffle = map; /* put back for later */
365#endif
366
367 /* Check for valid target ID */
368 if ((dlthis->dfile_hdr.df_target_id != TARGET_ID) &&
369 -(dlthis->dfile_hdr.df_target_id != TMS470_ID)) {
370 dload_error(dlthis, "Bad target ID 0x%x and TARGET_ID 0x%x",
371 dlthis->dfile_hdr.df_target_id, TARGET_ID);
372 return;
373 }
374 /* Check for valid file format */
375 if ((dlthis->dfile_hdr.df_doff_version != DOFF0)) {
376 dload_error(dlthis, "Bad DOFF version 0x%x",
377 dlthis->dfile_hdr.df_doff_version);
378 return;
379 }
380
381 /*
382 * Apply reasonableness checks to count fields
383 */
384 if (dlthis->dfile_hdr.df_strtab_size > MAX_REASONABLE_STRINGTAB) {
385 dload_error(dlthis, "Excessive string table size " FMT_UI32,
386 dlthis->dfile_hdr.df_strtab_size);
387 return;
388 }
389 if (dlthis->dfile_hdr.df_no_scns > MAX_REASONABLE_SECTIONS) {
390 dload_error(dlthis, "Excessive section count 0x%x",
391 dlthis->dfile_hdr.df_no_scns);
392 return;
393 }
394#ifndef TARGET_ENDIANNESS
395 /*
396 * Check that endianness does not disagree with explicit specification
397 */
398 if ((dlthis->dfile_hdr.df_flags >> ALIGN_COFF_ENDIANNESS) &
399 dlthis->myoptions & ENDIANNESS_MASK) {
400 dload_error(dlthis,
401 "Input endianness disagrees with specified option");
402 return;
403 }
404 dlthis->big_e_target = dlthis->dfile_hdr.df_flags & DF_BIG;
405#endif
406
407} /* dload_headers */
408
409/* COFF Section Processing
410 *
411 * COFF sections are read in and retained intact. Each record is embedded
412 * in a new structure that records the updated load and
413 * run addresses of the section */
414
415static const char secn_errid[] = { "section" };
416
417/*************************************************************************
418 * Procedure dload_sections
419 *
420 * Parameters:
421 * none
422 *
423 * Effect:
424 * Loads the section records into an internal table.
425 *********************************************************************** */
426void dload_sections(struct dload_state *dlthis)
427{
428 s16 siz;
429 struct doff_scnhdr_t *shp;
430 unsigned nsecs = dlthis->dfile_hdr.df_no_scns;
431
432 /* allocate space for the DOFF section records */
433 siz = nsecs * sizeof(struct doff_scnhdr_t);
434 shp =
435 (struct doff_scnhdr_t *)dlthis->mysym->dload_allocate(dlthis->mysym,
436 siz);
437 if (!shp) { /* not enough storage */
438 DL_ERROR(err_alloc, siz);
439 return;
440 }
441 dlthis->sect_hdrs = shp;
442
443 /* read in the section records */
444 if (dlthis->strm->read_buffer(dlthis->strm, shp, siz) != siz) {
445 DL_ERROR(readstrm, secn_errid);
446 return;
447 }
448
449 /* if we need to fix up byte order, do it now */
450 if (dlthis->reorder_map)
451 dload_reorder(shp, siz, dlthis->reorder_map);
452
453 /* check for validity */
454 if (~dload_checksum(dlthis->sect_hdrs, siz) !=
455 dlthis->verify.dv_scn_rec_checksum) {
456 DL_ERROR(err_checksum, secn_errid);
457 return;
458 }
459
460} /* dload_sections */
461
462/*****************************************************************************
463 * Procedure allocate_sections
464 *
465 * Parameters:
466 * alloc target memory allocator class
467 *
468 * Effect:
469 * Assigns new (target) addresses for sections
470 **************************************************************************** */
471static void allocate_sections(struct dload_state *dlthis)
472{
473 u16 curr_sect, nsecs, siz;
474 struct doff_scnhdr_t *shp;
475 struct ldr_section_info *asecs;
476 struct my_handle *hndl;
477 nsecs = dlthis->dfile_hdr.df_no_scns;
478 if (!nsecs)
479 return;
480 if ((dlthis->myalloc == NULL) &&
481 (dlthis->dfile_hdr.df_target_scns > 0)) {
482 DL_ERROR("Arg 3 (alloc) required but NULL", 0);
483 return;
484 }
485 /*
486 * allocate space for the module handle, which we will keep for unload
487 * purposes include an additional section store for an auto-generated
488 * trampoline section in case we need it.
489 */
490 siz = (dlthis->dfile_hdr.df_target_scns + 1) *
491 sizeof(struct ldr_section_info) + MY_HANDLE_SIZE;
492
493 hndl =
494 (struct my_handle *)dlthis->mysym->dload_allocate(dlthis->mysym,
495 siz);
496 if (!hndl) { /* not enough storage */
497 DL_ERROR(err_alloc, siz);
498 return;
499 }
500 /* initialize the handle header */
ee4317f7
RS
501 hndl->dm.next = hndl->dm.prev = hndl; /* circular list */
502 hndl->dm.root = NULL;
26f8db7d
ORL
503 hndl->dm.dbthis = 0;
504 dlthis->myhandle = hndl; /* save away for return */
505 /* pointer to the section list of allocated sections */
506 dlthis->ldr_sections = asecs = hndl->secns;
507 /* * Insert names into all sections, make copies of
508 the sections we allocate */
509 shp = dlthis->sect_hdrs;
510 for (curr_sect = 0; curr_sect < nsecs; curr_sect++) {
511 u32 soffset = shp->ds_offset;
512#if BITS_PER_AU <= BITS_PER_BYTE
513 /* attempt to insert the name of this section */
514 if (soffset < dlthis->dfile_hdr.df_strtab_size)
803cd75e
AU
515 ((struct ldr_section_info *)shp)->name =
516 dlthis->str_head + soffset;
26f8db7d
ORL
517 else {
518 dload_error(dlthis, "Bad name offset in section %d",
519 curr_sect);
803cd75e 520 ((struct ldr_section_info *)shp)->name = NULL;
26f8db7d
ORL
521 }
522#endif
523 /* allocate target storage for sections that require it */
a563510f 524 if (ds_needs_allocation(shp)) {
803cd75e 525 *asecs = *(struct ldr_section_info *)shp;
26f8db7d
ORL
526 asecs->context = 0; /* zero the context field */
527#if BITS_PER_AU > BITS_PER_BYTE
528 asecs->name = unpack_name(dlthis, soffset);
529 dlthis->debug_string_size = soffset + dlthis->temp_len;
530#else
531 dlthis->debug_string_size = soffset;
532#endif
533 if (dlthis->myalloc != NULL) {
534 if (!dlthis->myalloc->
535 dload_allocate(dlthis->myalloc, asecs,
a563510f 536 ds_alignment(asecs->type))) {
26f8db7d
ORL
537 dload_error(dlthis, tgtalloc,
538 asecs->name, asecs->size);
539 return;
540 }
541 }
542 /* keep address deltas in original section table */
543 shp->ds_vaddr = asecs->load_addr - shp->ds_vaddr;
544 shp->ds_paddr = asecs->run_addr - shp->ds_paddr;
545 dlthis->allocated_secn_count += 1;
546 } /* allocate target storage */
547 shp += 1;
548 asecs += 1;
549 }
550#if BITS_PER_AU <= BITS_PER_BYTE
551 dlthis->debug_string_size +=
552 strlen(dlthis->str_head + dlthis->debug_string_size) + 1;
553#endif
554} /* allocate sections */
555
556/*************************************************************************
557 * Procedure section_table_free
558 *
559 * Parameters:
560 * none
561 *
562 * Effect:
563 * Frees any state used by the symbol table.
564 *
565 * WARNING:
566 * This routine is not allowed to declare errors!
567 *********************************************************************** */
568static void section_table_free(struct dload_state *dlthis)
569{
570 struct doff_scnhdr_t *shp;
571
572 shp = dlthis->sect_hdrs;
573 if (shp)
574 dlthis->mysym->dload_deallocate(dlthis->mysym, shp);
575
576} /* section_table_free */
577
578/*************************************************************************
579 * Procedure dload_strings
580 *
581 * Parameters:
582 * sec_names_only If true only read in the "section names"
583 * portion of the string table
584 *
585 * Effect:
586 * Loads the DOFF string table into memory. DOFF keeps all strings in a
587 * big unsorted array. We just read that array into memory in bulk.
588 *********************************************************************** */
589static const char stringtbl[] = { "string table" };
590
591void dload_strings(struct dload_state *dlthis, bool sec_names_only)
592{
593 u32 ssiz;
594 char *strbuf;
595
596 if (sec_names_only) {
597 ssiz = BYTE_TO_HOST(DOFF_ALIGN
598 (dlthis->dfile_hdr.df_scn_name_size));
599 } else {
600 ssiz = BYTE_TO_HOST(DOFF_ALIGN
601 (dlthis->dfile_hdr.df_strtab_size));
602 }
603 if (ssiz == 0)
604 return;
605
606 /* get some memory for the string table */
607#if BITS_PER_AU > BITS_PER_BYTE
608 strbuf = (char *)dlthis->mysym->dload_allocate(dlthis->mysym, ssiz +
609 dlthis->dfile_hdr.
610 df_max_str_len);
611#else
612 strbuf = (char *)dlthis->mysym->dload_allocate(dlthis->mysym, ssiz);
613#endif
614 if (strbuf == NULL) {
615 DL_ERROR(err_alloc, ssiz);
616 return;
617 }
618 dlthis->str_head = strbuf;
619#if BITS_PER_AU > BITS_PER_BYTE
620 dlthis->str_temp = strbuf + ssiz;
621#endif
622 /* read in the strings and verify them */
623 if ((unsigned)(dlthis->strm->read_buffer(dlthis->strm, strbuf,
624 ssiz)) != ssiz) {
625 DL_ERROR(readstrm, stringtbl);
626 }
627 /* if we need to fix up byte order, do it now */
628#ifndef _BIG_ENDIAN
629 if (dlthis->reorder_map)
630 dload_reorder(strbuf, ssiz, dlthis->reorder_map);
631
632 if ((!sec_names_only) && (~dload_checksum(strbuf, ssiz) !=
633 dlthis->verify.dv_str_tab_checksum)) {
634 DL_ERROR(err_checksum, stringtbl);
635 }
636#else
637 if (dlthis->dfile_hdr.df_byte_reshuffle !=
638 HOST_BYTE_ORDER(REORDER_MAP(BYTE_RESHUFFLE_VALUE))) {
639 /* put strings in big-endian order, not in PC order */
640 dload_reorder(strbuf, ssiz,
641 HOST_BYTE_ORDER(dlthis->
642 dfile_hdr.df_byte_reshuffle));
643 }
644 if ((!sec_names_only) && (~dload_reverse_checksum(strbuf, ssiz) !=
645 dlthis->verify.dv_str_tab_checksum)) {
646 DL_ERROR(err_checksum, stringtbl);
647 }
648#endif
649} /* dload_strings */
650
651/*************************************************************************
652 * Procedure string_table_free
653 *
654 * Parameters:
655 * none
656 *
657 * Effect:
658 * Frees any state used by the string table.
659 *
660 * WARNING:
661 * This routine is not allowed to declare errors!
662 ************************************************************************ */
663static void string_table_free(struct dload_state *dlthis)
664{
665 if (dlthis->str_head)
666 dlthis->mysym->dload_deallocate(dlthis->mysym,
667 dlthis->str_head);
668
669} /* string_table_free */
670
671/*
672 * Symbol Table Maintenance Functions
673 *
674 * COFF symbols are read by dload_symbols(), which is called after
675 * sections have been allocated. Symbols which might be used in
676 * relocation (ie, not debug info) are retained in an internal temporary
677 * compressed table (type local_symbol). A particular symbol is recovered
678 * by index by calling dload_find_symbol(). dload_find_symbol
679 * reconstructs a more explicit representation (type SLOTVEC) which is
680 * used by reloc.c
681 */
682/* real size of debug header */
683#define DBG_HDR_SIZE (sizeof(struct dll_module) - sizeof(struct dll_sect))
684
685static const char sym_errid[] = { "symbol" };
686
687/**************************************************************************
688 * Procedure dload_symbols
689 *
690 * Parameters:
691 * none
692 *
693 * Effect:
694 * Reads in symbols and retains ones that might be needed for relocation
695 * purposes.
696 *********************************************************************** */
697/* size of symbol buffer no bigger than target data buffer, to limit stack
698 * usage */
699#define MY_SYM_BUF_SIZ (BYTE_TO_HOST(IMAGE_PACKET_SIZE)/\
700 sizeof(struct doff_syment_t))
701
702static void dload_symbols(struct dload_state *dlthis)
703{
704 u32 sym_count, siz, dsiz, symbols_left;
705 u32 checks;
706 struct local_symbol *sp;
707 struct dynload_symbol *symp;
708 struct dynload_symbol *newsym;
709
710 sym_count = dlthis->dfile_hdr.df_no_syms;
711 if (sym_count == 0)
712 return;
713
714 /*
715 * We keep a local symbol table for all of the symbols in the input.
716 * This table contains only section & value info, as we do not have
717 * to do any name processing for locals. We reuse this storage
718 * as a temporary for .dllview record construction.
719 * Allocate storage for the whole table. Add 1 to the section count
720 * in case a trampoline section is auto-generated as well as the
25985edc 721 * size of the trampoline section name so DLLView does't get lost.
26f8db7d
ORL
722 */
723
724 siz = sym_count * sizeof(struct local_symbol);
725 dsiz = DBG_HDR_SIZE +
726 (sizeof(struct dll_sect) * dlthis->allocated_secn_count) +
727 BYTE_TO_HOST_ROUND(dlthis->debug_string_size + 1);
728 if (dsiz > siz)
729 siz = dsiz; /* larger of symbols and .dllview temp */
730 sp = (struct local_symbol *)dlthis->mysym->dload_allocate(dlthis->mysym,
731 siz);
732 if (!sp) {
733 DL_ERROR(err_alloc, siz);
734 return;
735 }
736 dlthis->local_symtab = sp;
737 /* Read the symbols in the input, store them in the table, and post any
738 * globals to the global symbol table. In the process, externals
739 become defined from the global symbol table */
740 checks = dlthis->verify.dv_sym_tab_checksum;
741 symbols_left = sym_count;
742 do { /* read all symbols */
743 char *sname;
744 u32 val;
745 s32 delta;
746 struct doff_syment_t *input_sym;
747 unsigned syms_in_buf;
748 struct doff_syment_t my_sym_buf[MY_SYM_BUF_SIZ];
749 input_sym = my_sym_buf;
750 syms_in_buf = symbols_left > MY_SYM_BUF_SIZ ?
751 MY_SYM_BUF_SIZ : symbols_left;
752 siz = syms_in_buf * sizeof(struct doff_syment_t);
753 if (dlthis->strm->read_buffer(dlthis->strm, input_sym, siz) !=
754 siz) {
755 DL_ERROR(readstrm, sym_errid);
756 return;
757 }
758 if (dlthis->reorder_map)
759 dload_reorder(input_sym, siz, dlthis->reorder_map);
760
761 checks += dload_checksum(input_sym, siz);
762 do { /* process symbols in buffer */
763 symbols_left -= 1;
764 /* attempt to derive the name of this symbol */
765 sname = NULL;
766 if (input_sym->dn_offset > 0) {
767#if BITS_PER_AU <= BITS_PER_BYTE
768 if ((u32) input_sym->dn_offset <
769 dlthis->dfile_hdr.df_strtab_size)
770 sname = dlthis->str_head +
771 BYTE_TO_HOST(input_sym->dn_offset);
772 else
773 dload_error(dlthis,
774 "Bad name offset in symbol "
775 " %d", symbols_left);
776#else
777 sname = unpack_name(dlthis,
778 input_sym->dn_offset);
779#endif
780 }
781 val = input_sym->dn_value;
782 delta = 0;
783 sp->sclass = input_sym->dn_sclass;
784 sp->secnn = input_sym->dn_scnum;
785 /* if this is an undefined symbol,
786 * define it (or fail) now */
787 if (sp->secnn == DN_UNDEF) {
788 /* pointless for static undefined */
789 if (input_sym->dn_sclass != DN_EXT)
790 goto loop_cont;
791
792 /* try to define symbol from previously
793 * loaded images */
794 symp = dlthis->mysym->find_matching_symbol
795 (dlthis->mysym, sname);
796 if (!symp) {
797 DL_ERROR
798 ("Undefined external symbol %s",
799 sname);
800 goto loop_cont;
801 }
802 val = delta = symp->value;
803#ifdef ENABLE_TRAMP_DEBUG
804 dload_syms_error(dlthis->mysym,
805 "===> ext sym [%s] at %x",
806 sname, val);
807#endif
808
809 goto loop_cont;
810 }
811 /* symbol defined by this module */
812 if (sp->secnn > 0) {
813 /* symbol references a section */
814 if ((unsigned)sp->secnn <=
815 dlthis->allocated_secn_count) {
816 /* section was allocated */
817 struct doff_scnhdr_t *srefp =
818 &dlthis->sect_hdrs[sp->secnn - 1];
819
820 if (input_sym->dn_sclass ==
821 DN_STATLAB ||
822 input_sym->dn_sclass == DN_EXTLAB) {
823 /* load */
824 delta = srefp->ds_vaddr;
825 } else {
826 /* run */
827 delta = srefp->ds_paddr;
828 }
829 val += delta;
830 }
831 goto loop_itr;
832 }
833 /* This symbol is an absolute symbol */
834 if (sp->secnn == DN_ABS && ((sp->sclass == DN_EXT) ||
835 (sp->sclass ==
836 DN_EXTLAB))) {
837 symp =
838 dlthis->mysym->find_matching_symbol(dlthis->
839 mysym,
840 sname);
841 if (!symp)
842 goto loop_itr;
843 /* This absolute symbol is already defined. */
844 if (symp->value == input_sym->dn_value) {
845 /* If symbol values are equal, continue
846 * but don't add to the global symbol
847 * table */
848 sp->value = val;
849 sp->delta = delta;
850 sp += 1;
851 input_sym += 1;
852 continue;
853 } else {
854 /* If symbol values are not equal,
855 * return with redefinition error */
856 DL_ERROR("Absolute symbol %s is "
857 "defined multiple times with "
858 "different values", sname);
859 return;
860 }
861 }
862loop_itr:
863 /* if this is a global symbol, post it to the
864 * global table */
865 if (input_sym->dn_sclass == DN_EXT ||
866 input_sym->dn_sclass == DN_EXTLAB) {
867 /* Keep this global symbol for subsequent
868 * modules. Don't complain on error, to allow
869 * symbol API to suppress global symbols */
870 if (!sname)
871 goto loop_cont;
872
873 newsym = dlthis->mysym->add_to_symbol_table
874 (dlthis->mysym, sname,
875 (unsigned)dlthis->myhandle);
876 if (newsym)
877 newsym->value = val;
878
879 } /* global */
880loop_cont:
881 sp->value = val;
882 sp->delta = delta;
883 sp += 1;
884 input_sym += 1;
885 } while ((syms_in_buf -= 1) > 0); /* process sym in buf */
886 } while (symbols_left > 0); /* read all symbols */
887 if (~checks)
888 dload_error(dlthis, "Checksum of symbols failed");
889
890} /* dload_symbols */
891
892/*****************************************************************************
893 * Procedure symbol_table_free
894 *
895 * Parameters:
896 * none
897 *
898 * Effect:
899 * Frees any state used by the symbol table.
900 *
901 * WARNING:
902 * This routine is not allowed to declare errors!
903 **************************************************************************** */
904static void symbol_table_free(struct dload_state *dlthis)
905{
906 if (dlthis->local_symtab) {
907 if (dlthis->dload_errcount) { /* blow off our symbols */
908 dlthis->mysym->purge_symbol_table(dlthis->mysym,
909 (unsigned)
910 dlthis->myhandle);
911 }
912 dlthis->mysym->dload_deallocate(dlthis->mysym,
913 dlthis->local_symtab);
914 }
915} /* symbol_table_free */
916
917/* .cinit Processing
918 *
919 * The dynamic loader does .cinit interpretation. cload_cinit()
920 * acts as a special write-to-target function, in that it takes relocated
921 * data from the normal data flow, and interprets it as .cinit actions.
922 * Because the normal data flow does not necessarily process the whole
923 * .cinit section in one buffer, cload_cinit() must be prepared to
924 * interpret the data piecemeal. A state machine is used for this
925 * purpose.
926 */
927
928/* The following are only for use by reloc.c and things it calls */
929static const struct ldr_section_info cinit_info_init = { cinitname, 0, 0,
930 (ldr_addr)-1, 0, DLOAD_BSS, 0
931};
932
933/*************************************************************************
934 * Procedure cload_cinit
935 *
936 * Parameters:
937 * ipacket Pointer to data packet to be loaded
938 *
939 * Effect:
940 * Interprets the data in the buffer as .cinit data, and performs the
941 * appropriate initializations.
942 *********************************************************************** */
943static void cload_cinit(struct dload_state *dlthis,
944 struct image_packet_t *ipacket)
945{
946#if TDATA_TO_HOST(CINIT_COUNT)*BITS_PER_AU > 16
947 s32 init_count, left;
948#else
949 s16 init_count, left;
950#endif
951 unsigned char *pktp = ipacket->img_data;
952 unsigned char *pktend = pktp + BYTE_TO_HOST_ROUND(ipacket->packet_size);
953 int temp;
954 ldr_addr atmp;
955 struct ldr_section_info cinit_info;
956
9d7d0a52 957 /* PROCESS ALL THE INITIALIZATION RECORDS THE BUFFER. */
26f8db7d
ORL
958 while (true) {
959 left = pktend - pktp;
960 switch (dlthis->cinit_state) {
961 case CI_COUNT: /* count field */
962 if (left < TDATA_TO_HOST(CINIT_COUNT))
963 goto loopexit;
964 temp = dload_unpack(dlthis, (tgt_au_t *) pktp,
965 CINIT_COUNT * TDATA_AU_BITS, 0,
966 ROP_SGN);
967 pktp += TDATA_TO_HOST(CINIT_COUNT);
968 /* negative signifies BSS table, zero means done */
969 if (temp <= 0) {
970 dlthis->cinit_state = CI_DONE;
971 break;
972 }
973 dlthis->cinit_count = temp;
974 dlthis->cinit_state = CI_ADDRESS;
975 break;
976#if CINIT_ALIGN < CINIT_ADDRESS
977 case CI_PARTADDRESS:
978 pktp -= TDATA_TO_HOST(CINIT_ALIGN);
979 /* back up pointer into space courtesy of caller */
980 *(uint16_t *) pktp = dlthis->cinit_addr;
981 /* stuff in saved bits !! FALL THRU !! */
982#endif
983 case CI_ADDRESS: /* Address field for a copy packet */
984 if (left < TDATA_TO_HOST(CINIT_ADDRESS)) {
985#if CINIT_ALIGN < CINIT_ADDRESS
986 if (left == TDATA_TO_HOST(CINIT_ALIGN)) {
987 /* address broken into halves */
988 dlthis->cinit_addr = *(uint16_t *) pktp;
989 /* remember 1st half */
990 dlthis->cinit_state = CI_PARTADDRESS;
991 left = 0;
992 }
993#endif
994 goto loopexit;
995 }
996 atmp = dload_unpack(dlthis, (tgt_au_t *) pktp,
997 CINIT_ADDRESS * TDATA_AU_BITS, 0,
998 ROP_UNS);
999 pktp += TDATA_TO_HOST(CINIT_ADDRESS);
1000#if CINIT_PAGE_BITS > 0
1001 dlthis->cinit_page = atmp &
1002 ((1 << CINIT_PAGE_BITS) - 1);
1003 atmp >>= CINIT_PAGE_BITS;
1004#else
1005 dlthis->cinit_page = CINIT_DEFAULT_PAGE;
1006#endif
1007 dlthis->cinit_addr = atmp;
1008 dlthis->cinit_state = CI_COPY;
1009 break;
1010 case CI_COPY: /* copy bits to the target */
1011 init_count = HOST_TO_TDATA(left);
1012 if (init_count > dlthis->cinit_count)
1013 init_count = dlthis->cinit_count;
1014 if (init_count == 0)
1015 goto loopexit; /* get more bits */
1016 cinit_info = cinit_info_init;
1017 cinit_info.page = dlthis->cinit_page;
1018 if (!dlthis->myio->writemem(dlthis->myio, pktp,
1019 TDATA_TO_TADDR
1020 (dlthis->cinit_addr),
1021 &cinit_info,
1022 TDATA_TO_HOST(init_count))) {
1023 dload_error(dlthis, initfail, "write",
1024 dlthis->cinit_addr);
1025 }
1026 dlthis->cinit_count -= init_count;
1027 if (dlthis->cinit_count <= 0) {
1028 dlthis->cinit_state = CI_COUNT;
1029 init_count = (init_count + CINIT_ALIGN - 1) &
1030 -CINIT_ALIGN;
1031 /* align to next init */
1032 }
1033 pktp += TDATA_TO_HOST(init_count);
1034 dlthis->cinit_addr += init_count;
1035 break;
1036 case CI_DONE: /* no more .cinit to do */
1037 return;
1038 } /* switch (cinit_state) */
1039 } /* while */
1040
1041loopexit:
1042 if (left > 0) {
1043 dload_error(dlthis, "%d bytes left over in cinit packet", left);
1044 dlthis->cinit_state = CI_DONE; /* left over bytes are bad */
1045 }
1046} /* cload_cinit */
1047
1048/* Functions to interface to reloc.c
1049 *
1050 * reloc.c is the relocation module borrowed from the linker, with
1051 * minimal (we hope) changes for our purposes. cload_sect_data() invokes
1052 * this module on a section to relocate and load the image data for that
1053 * section. The actual read and write actions are supplied by the global
1054 * routines below.
1055 */
1056
1057/************************************************************************
1058 * Procedure relocate_packet
1059 *
1060 * Parameters:
1061 * ipacket Pointer to an image packet to relocate
1062 *
1063 * Effect:
1064 * Performs the required relocations on the packet. Returns a checksum
1065 * of the relocation operations.
1066 *********************************************************************** */
1067#define MY_RELOC_BUF_SIZ 8
1068/* careful! exists at the same time as the image buffer */
1069static int relocate_packet(struct dload_state *dlthis,
1070 struct image_packet_t *ipacket,
1071 u32 *checks, bool *tramps_generated)
1072{
1073 u32 rnum;
1074 *tramps_generated = false;
1075
1076 rnum = ipacket->num_relocs;
1077 do { /* all relocs */
1078 unsigned rinbuf;
1079 int siz;
1080 struct reloc_record_t *rp, rrec[MY_RELOC_BUF_SIZ];
1081 rp = rrec;
1082 rinbuf = rnum > MY_RELOC_BUF_SIZ ? MY_RELOC_BUF_SIZ : rnum;
1083 siz = rinbuf * sizeof(struct reloc_record_t);
1084 if (dlthis->strm->read_buffer(dlthis->strm, rp, siz) != siz) {
1085 DL_ERROR(readstrm, "relocation");
1086 return 0;
1087 }
1088 /* reorder the bytes if need be */
1089 if (dlthis->reorder_map)
1090 dload_reorder(rp, siz, dlthis->reorder_map);
1091
1092 *checks += dload_checksum(rp, siz);
1093 do {
1094 /* perform the relocation operation */
1095 dload_relocate(dlthis, (tgt_au_t *) ipacket->img_data,
1096 rp, tramps_generated, false);
1097 rp += 1;
1098 rnum -= 1;
1099 } while ((rinbuf -= 1) > 0);
1100 } while (rnum > 0); /* all relocs */
1101 /* If trampoline(s) were generated, we need to do an update of the
1102 * trampoline copy of the packet since a 2nd phase relo will be done
1103 * later. */
1104 if (*tramps_generated == true) {
1105 dload_tramp_pkt_udpate(dlthis,
1106 (dlthis->image_secn -
1107 dlthis->ldr_sections),
1108 dlthis->image_offset, ipacket);
1109 }
1110
1111 return 1;
1112} /* dload_read_reloc */
1113
1114#define IPH_SIZE (sizeof(struct image_packet_t) - sizeof(u32))
1115
1116/* VERY dangerous */
1117static const char imagepak[] = { "image packet" };
1118
1119/*************************************************************************
1120 * Procedure dload_data
1121 *
1122 * Parameters:
1123 * none
1124 *
1125 * Effect:
1126 * Read image data from input file, relocate it, and download it to the
1127 * target.
1128 *********************************************************************** */
1129static void dload_data(struct dload_state *dlthis)
1130{
1131 u16 curr_sect;
1132 struct doff_scnhdr_t *sptr = dlthis->sect_hdrs;
1133 struct ldr_section_info *lptr = dlthis->ldr_sections;
26f8db7d
ORL
1134 u8 *dest;
1135
1136 struct {
1137 struct image_packet_t ipacket;
1138 u8 bufr[BYTE_TO_HOST(IMAGE_PACKET_SIZE)];
1139 } ibuf;
1140
1141 /* Indicates whether CINIT processing has occurred */
1142 bool cinit_processed = false;
1143
1144 /* Loop through the sections and load them one at a time.
1145 */
1146 for (curr_sect = 0; curr_sect < dlthis->dfile_hdr.df_no_scns;
1147 curr_sect += 1) {
a563510f 1148 if (ds_needs_download(sptr)) {
26f8db7d
ORL
1149 s32 nip;
1150 ldr_addr image_offset = 0;
1151 /* set relocation info for this section */
1152 if (curr_sect < dlthis->allocated_secn_count)
1153 dlthis->delta_runaddr = sptr->ds_paddr;
1154 else {
803cd75e 1155 lptr = (struct ldr_section_info *)sptr;
26f8db7d
ORL
1156 dlthis->delta_runaddr = 0;
1157 }
1158 dlthis->image_secn = lptr;
1159#if BITS_PER_AU > BITS_PER_BYTE
1160 lptr->name = unpack_name(dlthis, sptr->ds_offset);
1161#endif
1162 nip = sptr->ds_nipacks;
1163 while ((nip -= 1) >= 0) { /* process packets */
1164
1165 s32 ipsize;
1166 u32 checks;
1167 bool tramp_generated = false;
1168
1169 /* get the fixed header bits */
1170 if (dlthis->strm->read_buffer(dlthis->strm,
1171 &ibuf.ipacket,
1172 IPH_SIZE) !=
1173 IPH_SIZE) {
1174 DL_ERROR(readstrm, imagepak);
1175 return;
1176 }
1177 /* reorder the header if need be */
1178 if (dlthis->reorder_map) {
1179 dload_reorder(&ibuf.ipacket, IPH_SIZE,
1180 dlthis->reorder_map);
1181 }
1182 /* now read the rest of the packet */
1183 ipsize =
1184 BYTE_TO_HOST(DOFF_ALIGN
1185 (ibuf.ipacket.packet_size));
1186 if (ipsize > BYTE_TO_HOST(IMAGE_PACKET_SIZE)) {
1187 DL_ERROR("Bad image packet size %d",
1188 ipsize);
1189 return;
1190 }
1191 dest = ibuf.bufr;
26f8db7d
ORL
1192 /* End of determination */
1193
1194 if (dlthis->strm->read_buffer(dlthis->strm,
1195 ibuf.bufr,
1196 ipsize) !=
1197 ipsize) {
1198 DL_ERROR(readstrm, imagepak);
1199 return;
1200 }
1201 ibuf.ipacket.img_data = dest;
1202
1203 /* reorder the bytes if need be */
1204#if !defined(_BIG_ENDIAN) || (TARGET_AU_BITS > 16)
1205 if (dlthis->reorder_map) {
1206 dload_reorder(dest, ipsize,
1207 dlthis->reorder_map);
1208 }
1209 checks = dload_checksum(dest, ipsize);
1210#else
1211 if (dlthis->dfile_hdr.df_byte_reshuffle !=
1212 TARGET_ORDER(REORDER_MAP
1213 (BYTE_RESHUFFLE_VALUE))) {
1214 /* put image bytes in big-endian order,
1215 * not PC order */
1216 dload_reorder(dest, ipsize,
1217 TARGET_ORDER
1218 (dlthis->dfile_hdr.
1219 df_byte_reshuffle));
1220 }
1221#if TARGET_AU_BITS > 8
1222 checks = dload_reverse_checksum16(dest, ipsize);
1223#else
1224 checks = dload_reverse_checksum(dest, ipsize);
1225#endif
1226#endif
1227
1228 checks += dload_checksum(&ibuf.ipacket,
1229 IPH_SIZE);
1230 /* relocate the image bits as needed */
1231 if (ibuf.ipacket.num_relocs) {
1232 dlthis->image_offset = image_offset;
1233 if (!relocate_packet(dlthis,
1234 &ibuf.ipacket,
1235 &checks,
1236 &tramp_generated))
1237 return; /* serious error */
1238 }
1239 if (~checks)
1240 DL_ERROR(err_checksum, imagepak);
1241 /* Only write the result to the target if no
1242 * trampoline was generated. Otherwise it
1243 *will be done during trampoline finalize. */
1244
1245 if (tramp_generated == false) {
1246
1247 /* stuff the result into target
1248 * memory */
a563510f
AU
1249 if (dload_check_type(sptr,
1250 DLOAD_CINIT)) {
26f8db7d
ORL
1251 cload_cinit(dlthis,
1252 &ibuf.ipacket);
1253 cinit_processed = true;
1254 } else {
92d02930
RFE
1255 /* FIXME */
1256 if (!dlthis->myio->
1257 writemem(dlthis->
1258 myio,
1259 ibuf.bufr,
1260 lptr->
1261 load_addr +
1262 image_offset,
1263 lptr,
1264 BYTE_TO_HOST
1265 (ibuf.
1266 ipacket.
1267 packet_size))) {
1268 DL_ERROR
1269 ("Write to "
1270 FMT_UI32
1271 " failed",
1272 lptr->
1273 load_addr +
1274 image_offset);
26f8db7d 1275 }
26f8db7d
ORL
1276 }
1277 }
1278 image_offset +=
1279 BYTE_TO_TADDR(ibuf.ipacket.packet_size);
1280 } /* process packets */
1281 /* if this is a BSS section, we may want to fill it */
a563510f 1282 if (!dload_check_type(sptr, DLOAD_BSS))
26f8db7d
ORL
1283 goto loop_cont;
1284
1285 if (!(dlthis->myoptions & DLOAD_INITBSS))
1286 goto loop_cont;
1287
1288 if (cinit_processed) {
1289 /* Don't clear BSS after load-time
1290 * initialization */
1291 DL_ERROR
1292 ("Zero-initialization at " FMT_UI32
1293 " after " "load-time initialization!",
1294 lptr->load_addr);
1295 goto loop_cont;
1296 }
1297 /* fill the .bss area */
1298 dlthis->myio->fillmem(dlthis->myio,
1299 TADDR_TO_HOST(lptr->load_addr),
1300 lptr, TADDR_TO_HOST(lptr->size),
1301 DLOAD_FILL_BSS);
1302 goto loop_cont;
1303 }
1304 /* if DS_DOWNLOAD_MASK */
1305 /* If not loading, but BSS, zero initialize */
a563510f 1306 if (!dload_check_type(sptr, DLOAD_BSS))
26f8db7d
ORL
1307 goto loop_cont;
1308
1309 if (!(dlthis->myoptions & DLOAD_INITBSS))
1310 goto loop_cont;
1311
1312 if (curr_sect >= dlthis->allocated_secn_count)
803cd75e 1313 lptr = (struct ldr_section_info *)sptr;
26f8db7d
ORL
1314
1315 if (cinit_processed) {
1316 /*Don't clear BSS after load-time initialization */
1317 DL_ERROR("Zero-initialization at " FMT_UI32
1318 " attempted after "
1319 "load-time initialization!", lptr->load_addr);
1320 goto loop_cont;
1321 }
1322 /* fill the .bss area */
1323 dlthis->myio->fillmem(dlthis->myio,
1324 TADDR_TO_HOST(lptr->load_addr), lptr,
1325 TADDR_TO_HOST(lptr->size),
1326 DLOAD_FILL_BSS);
1327loop_cont:
1328 sptr += 1;
1329 lptr += 1;
1330 } /* load sections */
1331
1332 /* Finalize any trampolines that were created during the load */
1333 if (dload_tramp_finalize(dlthis) == 0) {
1334 DL_ERROR("Finalization of auto-trampolines (size = " FMT_UI32
1335 ") failed", dlthis->tramp.tramp_sect_next_addr);
1336 }
1337} /* dload_data */
1338
1339/*************************************************************************
1340 * Procedure dload_reorder
1341 *
1342 * Parameters:
1343 * data 32-bit aligned pointer to data to be byte-swapped
1344 * dsiz size of the data to be reordered in sizeof() units.
1345 * map 32-bit map defining how to reorder the data. Value
1346 * must be REORDER_MAP() of some permutation
1347 * of 0x00 01 02 03
1348 *
1349 * Effect:
1350 * Re-arranges the bytes in each word according to the map specified.
1351 *
1352 *********************************************************************** */
1353/* mask for byte shift count */
1354#define SHIFT_COUNT_MASK (3 << LOG_BITS_PER_BYTE)
1355
1356void dload_reorder(void *data, int dsiz, unsigned int map)
1357{
1358 register u32 tmp, tmap, datv;
1359 u32 *dp = (u32 *) data;
1360
1361 map <<= LOG_BITS_PER_BYTE; /* align map with SHIFT_COUNT_MASK */
1362 do {
1363 tmp = 0;
1364 datv = *dp;
1365 tmap = map;
1366 do {
1367 tmp |= (datv & BYTE_MASK) << (tmap & SHIFT_COUNT_MASK);
1368 tmap >>= BITS_PER_BYTE;
1369 } while (datv >>= BITS_PER_BYTE);
1370 *dp++ = tmp;
1371 } while ((dsiz -= sizeof(u32)) > 0);
1372} /* dload_reorder */
1373
1374/*************************************************************************
1375 * Procedure dload_checksum
1376 *
1377 * Parameters:
1378 * data 32-bit aligned pointer to data to be checksummed
1379 * siz size of the data to be checksummed in sizeof() units.
1380 *
1381 * Effect:
1382 * Returns a checksum of the specified block
1383 *
1384 *********************************************************************** */
1385u32 dload_checksum(void *data, unsigned siz)
1386{
1387 u32 sum;
1388 u32 *dp;
1389 int left;
1390
1391 sum = 0;
1392 dp = (u32 *) data;
1393 for (left = siz; left > 0; left -= sizeof(u32))
1394 sum += *dp++;
1395 return sum;
1396} /* dload_checksum */
1397
1398#if HOST_ENDIANNESS
1399/*************************************************************************
1400 * Procedure dload_reverse_checksum
1401 *
1402 * Parameters:
1403 * data 32-bit aligned pointer to data to be checksummed
1404 * siz size of the data to be checksummed in sizeof() units.
1405 *
1406 * Effect:
1407 * Returns a checksum of the specified block, which is assumed to be bytes
1408 * in big-endian order.
1409 *
1410 * Notes:
1411 * In a big-endian host, things like the string table are stored as bytes
1412 * in host order. But dllcreate always checksums in little-endian order.
1413 * It is most efficient to just handle the difference a word at a time.
1414 *
1415 ********************************************************************** */
1416u32 dload_reverse_checksum(void *data, unsigned siz)
1417{
1418 u32 sum, temp;
1419 u32 *dp;
1420 int left;
1421
1422 sum = 0;
1423 dp = (u32 *) data;
1424
1425 for (left = siz; left > 0; left -= sizeof(u32)) {
1426 temp = *dp++;
1427 sum += temp << BITS_PER_BYTE * 3;
1428 sum += temp >> BITS_PER_BYTE * 3;
1429 sum += (temp >> BITS_PER_BYTE) & (BYTE_MASK << BITS_PER_BYTE);
1430 sum += (temp & (BYTE_MASK << BITS_PER_BYTE)) << BITS_PER_BYTE;
1431 }
1432
1433 return sum;
1434} /* dload_reverse_checksum */
1435
1436#if (TARGET_AU_BITS > 8) && (TARGET_AU_BITS < 32)
1437u32 dload_reverse_checksum16(void *data, unsigned siz)
1438{
1439 uint_fast32_t sum, temp;
1440 u32 *dp;
1441 int left;
1442
1443 sum = 0;
1444 dp = (u32 *) data;
1445
1446 for (left = siz; left > 0; left -= sizeof(u32)) {
1447 temp = *dp++;
1448 sum += temp << BITS_PER_BYTE * 2;
1449 sum += temp >> BITS_PER_BYTE * 2;
1450 }
1451
1452 return sum;
1453} /* dload_reverse_checksum16 */
1454#endif
1455#endif
1456
1457/*************************************************************************
1458 * Procedure swap_words
1459 *
1460 * Parameters:
1461 * data 32-bit aligned pointer to data to be swapped
1462 * siz size of the data to be swapped.
1463 * bitmap Bit map of how to swap each 32-bit word; 1 => 2 shorts,
1464 * 0 => 1 long
1465 *
1466 * Effect:
1467 * Swaps the specified data according to the specified map
1468 *
1469 *********************************************************************** */
1470static void swap_words(void *data, unsigned siz, unsigned bitmap)
1471{
1472 register int i;
1473#if TARGET_AU_BITS < 16
1474 register u16 *sp;
1475#endif
1476 register u32 *lp;
1477
1478 siz /= sizeof(u16);
1479
1480#if TARGET_AU_BITS < 16
1481 /* pass 1: do all the bytes */
1482 i = siz;
1483 sp = (u16 *) data;
1484 do {
1485 register u16 tmp;
1486 tmp = *sp;
1487 *sp++ = SWAP16BY8(tmp);
1488 } while ((i -= 1) > 0);
1489#endif
1490
1491#if TARGET_AU_BITS < 32
1492 /* pass 2: fixup the 32-bit words */
1493 i = siz >> 1;
1494 lp = (u32 *) data;
1495 do {
1496 if ((bitmap & 1) == 0) {
1497 register u32 tmp;
1498 tmp = *lp;
1499 *lp = SWAP32BY16(tmp);
1500 }
1501 lp += 1;
1502 bitmap >>= 1;
1503 } while ((i -= 1) > 0);
1504#endif
1505} /* swap_words */
1506
1507/*************************************************************************
1508 * Procedure copy_tgt_strings
1509 *
1510 * Parameters:
1511 * dstp Destination address. Assumed to be 32-bit aligned
1512 * srcp Source address. Assumed to be 32-bit aligned
1513 * charcount Number of characters to copy.
1514 *
1515 * Effect:
1516 * Copies strings from the source (which is in usual .dof file order on
1517 * the loading processor) to the destination buffer (which should be in proper
1518 * target addressable unit order). Makes sure the last string in the
1519 * buffer is NULL terminated (for safety).
1520 * Returns the first unused destination address.
1521 *********************************************************************** */
1522static char *copy_tgt_strings(void *dstp, void *srcp, unsigned charcount)
1523{
1524 register tgt_au_t *src = (tgt_au_t *) srcp;
1525 register tgt_au_t *dst = (tgt_au_t *) dstp;
1526 register int cnt = charcount;
1527 do {
1528#if TARGET_AU_BITS <= BITS_PER_AU
1529 /* byte-swapping issues may exist for strings on target */
1530 *dst++ = *src++;
1531#else
1532 *dst++ = *src++;
1533#endif
1534 } while ((cnt -= (sizeof(tgt_au_t) * BITS_PER_AU / BITS_PER_BYTE)) > 0);
1535 /*apply force to make sure that the string table has null terminator */
1536#if (BITS_PER_AU == BITS_PER_BYTE) && (TARGET_AU_BITS == BITS_PER_BYTE)
1537 dst[-1] = 0;
1538#else
1539 /* little endian */
1540 dst[-1] &= (1 << (BITS_PER_AU - BITS_PER_BYTE)) - 1;
1541#endif
1542 return (char *)dst;
1543} /* copy_tgt_strings */
1544
1545/*************************************************************************
1546 * Procedure init_module_handle
1547 *
1548 * Parameters:
1549 * none
1550 *
1551 * Effect:
1552 * Initializes the module handle we use to enable unloading, and installs
1553 * the debug information required by the target.
1554 *
1555 * Notes:
1556 * The handle returned from dynamic_load_module needs to encapsulate all the
1557 * allocations done for the module, and enable them plus the modules symbols to
1558 * be deallocated.
1559 *
1560 *********************************************************************** */
1561#ifndef _BIG_ENDIAN
1562static const struct ldr_section_info dllview_info_init = { ".dllview", 0, 0,
1563 (ldr_addr)-1, DBG_LIST_PAGE, DLOAD_DATA, 0
1564};
1565#else
1566static const struct ldr_section_info dllview_info_init = { ".dllview", 0, 0,
1567 (ldr_addr)-1, DLOAD_DATA, DBG_LIST_PAGE, 0
1568};
1569#endif
1570static void init_module_handle(struct dload_state *dlthis)
1571{
1572 struct my_handle *hndl;
1573 u16 curr_sect;
1574 struct ldr_section_info *asecs;
1575 struct dll_module *dbmod;
1576 struct dll_sect *dbsec;
1577 struct dbg_mirror_root *mlist;
1578 register char *cp;
1579 struct modules_header mhdr;
1580 struct ldr_section_info dllview_info;
1581 struct dynload_symbol *debug_mirror_sym;
1582 hndl = dlthis->myhandle;
1583 if (!hndl)
1584 return; /* must be errors detected, so forget it */
1585
1586 /* Store the section count */
1587 hndl->secn_count = dlthis->allocated_secn_count;
1588
1589 /* If a trampoline section was created, add it in */
1590 if (dlthis->tramp.tramp_sect_next_addr != 0)
1591 hndl->secn_count += 1;
1592
1593 hndl->secn_count = hndl->secn_count << 1;
1594
1595 hndl->secn_count = dlthis->allocated_secn_count << 1;
1596#ifndef TARGET_ENDIANNESS
1597 if (dlthis->big_e_target)
1598 hndl->secn_count += 1; /* flag for big-endian */
1599#endif
1600 if (dlthis->dload_errcount)
1601 return; /* abandon if errors detected */
1602 /* Locate the symbol that names the header for the CCS debug list
1603 of modules. If not found, we just don't generate the debug record.
1604 If found, we create our modules list. We make sure to create the
1605 loader_dllview_root even if there is no relocation info to record,
1606 just to try to put both symbols in the same symbol table and
1607 module. */
1608 debug_mirror_sym = dlthis->mysym->find_matching_symbol(dlthis->mysym,
1609 loader_dllview_root);
1610 if (!debug_mirror_sym) {
1611 struct dynload_symbol *dlmodsym;
1612 struct dbg_mirror_root *mlst;
1613
1614 /* our root symbol is not yet present;
1615 check if we have DLModules defined */
1616 dlmodsym = dlthis->mysym->find_matching_symbol(dlthis->mysym,
1617 LINKER_MODULES_HEADER);
1618 if (!dlmodsym)
1619 return; /* no DLModules list so no debug info */
1620 /* if we have DLModules defined, construct our header */
1621 mlst = (struct dbg_mirror_root *)
1622 dlthis->mysym->dload_allocate(dlthis->mysym,
1623 sizeof(struct
1624 dbg_mirror_root));
1625 if (!mlst) {
1626 DL_ERROR(err_alloc, sizeof(struct dbg_mirror_root));
1627 return;
1628 }
ee4317f7 1629 mlst->next = NULL;
26f8db7d
ORL
1630 mlst->changes = 0;
1631 mlst->refcount = 0;
1632 mlst->dbthis = TDATA_TO_TADDR(dlmodsym->value);
1633 /* add our root symbol */
1634 debug_mirror_sym = dlthis->mysym->add_to_symbol_table
1635 (dlthis->mysym, loader_dllview_root,
1636 (unsigned)dlthis->myhandle);
1637 if (!debug_mirror_sym) {
1638 /* failed, recover memory */
1639 dlthis->mysym->dload_deallocate(dlthis->mysym, mlst);
1640 return;
1641 }
1642 debug_mirror_sym->value = (u32) mlst;
1643 }
1644 /* First create the DLLview record and stuff it into the buffer.
1645 Then write it to the DSP. Record pertinent locations in our hndl,
1646 and add it to the per-processor list of handles with debug info. */
1647#ifndef DEBUG_HEADER_IN_LOADER
1648 mlist = (struct dbg_mirror_root *)debug_mirror_sym->value;
1649 if (!mlist)
1650 return;
1651#else
1652 mlist = (struct dbg_mirror_root *)&debug_list_header;
1653#endif
ee4317f7 1654 hndl->dm.root = mlist; /* set pointer to root into our handle */
26f8db7d
ORL
1655 if (!dlthis->allocated_secn_count)
1656 return; /* no load addresses to be recorded */
1657 /* reuse temporary symbol storage */
1658 dbmod = (struct dll_module *)dlthis->local_symtab;
1659 /* Create the DLLview record in the memory we retain for our handle */
1660 dbmod->num_sects = dlthis->allocated_secn_count;
1661 dbmod->timestamp = dlthis->verify.dv_timdat;
1662 dbmod->version = INIT_VERSION;
1663 dbmod->verification = VERIFICATION;
1664 asecs = dlthis->ldr_sections;
1665 dbsec = dbmod->sects;
1666 for (curr_sect = dlthis->allocated_secn_count;
1667 curr_sect > 0; curr_sect -= 1) {
1668 dbsec->sect_load_adr = asecs->load_addr;
1669 dbsec->sect_run_adr = asecs->run_addr;
1670 dbsec += 1;
1671 asecs += 1;
1672 }
1673
1674 /* If a trampoline section was created go ahead and add its info */
1675 if (dlthis->tramp.tramp_sect_next_addr != 0) {
1676 dbmod->num_sects++;
1677 dbsec->sect_load_adr = asecs->load_addr;
1678 dbsec->sect_run_adr = asecs->run_addr;
1679 dbsec++;
1680 asecs++;
1681 }
1682
1683 /* now cram in the names */
1684 cp = copy_tgt_strings(dbsec, dlthis->str_head,
1685 dlthis->debug_string_size);
1686
1687 /* If a trampoline section was created, add its name so DLLView
1688 * can show the user the section info. */
1689 if (dlthis->tramp.tramp_sect_next_addr != 0) {
1690 cp = copy_tgt_strings(cp,
1691 dlthis->tramp.final_string_table,
1692 strlen(dlthis->tramp.final_string_table) +
1693 1);
1694 }
1695
1696 /* round off the size of the debug record, and remember same */
1697 hndl->dm.dbsiz = HOST_TO_TDATA_ROUND(cp - (char *)dbmod);
1698 *cp = 0; /* strictly to make our test harness happy */
1699 dllview_info = dllview_info_init;
1700 dllview_info.size = TDATA_TO_TADDR(hndl->dm.dbsiz);
1701 /* Initialize memory context to default heap */
1702 dllview_info.context = 0;
1703 hndl->dm.context = 0;
1704 /* fill in next pointer and size */
ee4317f7
RS
1705 if (mlist->next) {
1706 dbmod->next_module = TADDR_TO_TDATA(mlist->next->dm.dbthis);
1707 dbmod->next_module_size = mlist->next->dm.dbsiz;
26f8db7d
ORL
1708 } else {
1709 dbmod->next_module_size = 0;
1710 dbmod->next_module = 0;
1711 }
1712 /* allocate memory for on-DSP DLLview debug record */
1713 if (!dlthis->myalloc)
1714 return;
1715 if (!dlthis->myalloc->dload_allocate(dlthis->myalloc, &dllview_info,
1716 HOST_TO_TADDR(sizeof(u32)))) {
1717 return;
1718 }
1719 /* Store load address of .dllview section */
1720 hndl->dm.dbthis = dllview_info.load_addr;
1721 /* Store memory context (segid) in which .dllview section
1722 * was allocated */
1723 hndl->dm.context = dllview_info.context;
1724 mlist->refcount += 1;
1725 /* swap bytes in the entire debug record, but not the string table */
1726 if (TARGET_ENDIANNESS_DIFFERS(TARGET_BIG_ENDIAN)) {
1727 swap_words(dbmod, (char *)dbsec - (char *)dbmod,
1728 DLL_MODULE_BITMAP);
1729 }
1730 /* Update the DLLview list on the DSP write new record */
1731 if (!dlthis->myio->writemem(dlthis->myio, dbmod,
1732 dllview_info.load_addr, &dllview_info,
1733 TADDR_TO_HOST(dllview_info.size))) {
1734 return;
1735 }
1736 /* write new header */
1737 mhdr.first_module_size = hndl->dm.dbsiz;
1738 mhdr.first_module = TADDR_TO_TDATA(dllview_info.load_addr);
1739 /* swap bytes in the module header, if needed */
1740 if (TARGET_ENDIANNESS_DIFFERS(TARGET_BIG_ENDIAN)) {
1741 swap_words(&mhdr, sizeof(struct modules_header) - sizeof(u16),
1742 MODULES_HEADER_BITMAP);
1743 }
1744 dllview_info = dllview_info_init;
1745 if (!dlthis->myio->writemem(dlthis->myio, &mhdr, mlist->dbthis,
1746 &dllview_info,
1747 sizeof(struct modules_header) -
1748 sizeof(u16))) {
1749 return;
1750 }
1751 /* Add the module handle to this processor's list
1752 of handles with debug info */
ee4317f7
RS
1753 hndl->dm.next = mlist->next;
1754 if (hndl->dm.next)
1755 hndl->dm.next->dm.prev = hndl;
1756 hndl->dm.prev = (struct my_handle *)mlist;
1757 mlist->next = hndl; /* insert after root */
26f8db7d
ORL
1758} /* init_module_handle */
1759
1760/*************************************************************************
1761 * Procedure dynamic_unload_module
1762 *
1763 * Parameters:
1764 * mhandle A module handle from dynamic_load_module
1765 * syms Host-side symbol table and malloc/free functions
1766 * alloc Target-side memory allocation
1767 *
1768 * Effect:
1769 * The module specified by mhandle is unloaded. Unloading causes all
1770 * target memory to be deallocated, all symbols defined by the module to
1771 * be purged, and any host-side storage used by the dynamic loader for
1772 * this module to be released.
1773 *
1774 * Returns:
1775 * Zero for success. On error, the number of errors detected is returned.
1776 * Individual errors are reported using syms->error_report().
1777 *********************************************************************** */
1778int dynamic_unload_module(void *mhandle,
1779 struct dynamic_loader_sym *syms,
1780 struct dynamic_loader_allocate *alloc,
1781 struct dynamic_loader_initialize *init)
1782{
1783 s16 curr_sect;
1784 struct ldr_section_info *asecs;
1785 struct my_handle *hndl;
1786 struct dbg_mirror_root *root;
1787 unsigned errcount = 0;
1788 struct ldr_section_info dllview_info = dllview_info_init;
1789 struct modules_header mhdr;
1790
1791 hndl = (struct my_handle *)mhandle;
1792 if (!hndl)
1793 return 0; /* if handle is null, nothing to do */
1794 /* Clear out the module symbols
1795 * Note that if this is the module that defined MODULES_HEADER
1796 (the head of the target debug list)
1797 * then this operation will blow away that symbol.
1798 It will therefore be impossible for subsequent
1799 * operations to add entries to this un-referenceable list. */
1800 if (!syms)
1801 return 1;
1802 syms->purge_symbol_table(syms, (unsigned)hndl);
1803 /* Deallocate target memory for sections
1804 * NOTE: The trampoline section, if created, gets deleted here, too */
1805
1806 asecs = hndl->secns;
1807 if (alloc)
1808 for (curr_sect = (hndl->secn_count >> 1); curr_sect > 0;
1809 curr_sect -= 1) {
1810 asecs->name = NULL;
1811 alloc->dload_deallocate(alloc, asecs++);
1812 }
ee4317f7 1813 root = hndl->dm.root;
26f8db7d
ORL
1814 if (!root) {
1815 /* there is a debug list containing this module */
1816 goto func_end;
1817 }
1818 if (!hndl->dm.dbthis) { /* target-side dllview record exists */
1819 goto loop_end;
1820 }
1821 /* Retrieve memory context in which .dllview was allocated */
1822 dllview_info.context = hndl->dm.context;
ee4317f7 1823 if (hndl->dm.prev == hndl)
26f8db7d
ORL
1824 goto exitunltgt;
1825
1826 /* target-side dllview record is in list */
1827 /* dequeue this record from our GPP-side mirror list */
ee4317f7
RS
1828 hndl->dm.prev->dm.next = hndl->dm.next;
1829 if (hndl->dm.next)
1830 hndl->dm.next->dm.prev = hndl->dm.prev;
26f8db7d
ORL
1831 /* Update next_module of previous entry in target list
1832 * We are using mhdr here as a surrogate for either a
1833 struct modules_header or a dll_module */
ee4317f7
RS
1834 if (hndl->dm.next) {
1835 mhdr.first_module = TADDR_TO_TDATA(hndl->dm.next->dm.dbthis);
1836 mhdr.first_module_size = hndl->dm.next->dm.dbsiz;
26f8db7d
ORL
1837 } else {
1838 mhdr.first_module = 0;
1839 mhdr.first_module_size = 0;
1840 }
1841 if (!init)
1842 goto exitunltgt;
1843
1844 if (!init->connect(init)) {
1845 dload_syms_error(syms, iconnect);
1846 errcount += 1;
1847 goto exitunltgt;
1848 }
1849 /* swap bytes in the module header, if needed */
1850 if (TARGET_ENDIANNESS_DIFFERS(hndl->secn_count & 0x1)) {
1851 swap_words(&mhdr, sizeof(struct modules_header) - sizeof(u16),
1852 MODULES_HEADER_BITMAP);
1853 }
ee4317f7 1854 if (!init->writemem(init, &mhdr, hndl->dm.prev->dm.dbthis,
26f8db7d
ORL
1855 &dllview_info, sizeof(struct modules_header) -
1856 sizeof(mhdr.update_flag))) {
1857 dload_syms_error(syms, dlvwrite);
1858 errcount += 1;
1859 }
1860 /* update change counter */
1861 root->changes += 1;
1862 if (!init->writemem(init, &(root->changes),
1863 root->dbthis + HOST_TO_TADDR
1864 (sizeof(mhdr.first_module) +
1865 sizeof(mhdr.first_module_size)),
1866 &dllview_info, sizeof(mhdr.update_flag))) {
1867 dload_syms_error(syms, dlvwrite);
1868 errcount += 1;
1869 }
1870 init->release(init);
1871exitunltgt:
1872 /* release target storage */
1873 dllview_info.size = TDATA_TO_TADDR(hndl->dm.dbsiz);
1874 dllview_info.load_addr = hndl->dm.dbthis;
1875 if (alloc)
1876 alloc->dload_deallocate(alloc, &dllview_info);
1877 root->refcount -= 1;
1878 /* target-side dllview record exists */
1879loop_end:
1880#ifndef DEBUG_HEADER_IN_LOADER
1881 if (root->refcount <= 0) {
1882 /* if all references gone, blow off the header */
1883 /* our root symbol may be gone due to the Purge above,
1884 but if not, do not destroy the root */
1885 if (syms->find_matching_symbol
1886 (syms, loader_dllview_root) == NULL)
1887 syms->dload_deallocate(syms, root);
1888 }
1889#endif
1890func_end:
1891 /* there is a debug list containing this module */
1892 syms->dload_deallocate(syms, mhandle); /* release our storage */
1893 return errcount;
1894} /* dynamic_unload_module */
1895
1896#if BITS_PER_AU > BITS_PER_BYTE
1897/*************************************************************************
1898 * Procedure unpack_name
1899 *
1900 * Parameters:
1901 * soffset Byte offset into the string table
1902 *
1903 * Effect:
1904 * Returns a pointer to the string specified by the offset supplied, or
1905 * NULL for error.
1906 *
1907 *********************************************************************** */
1908static char *unpack_name(struct dload_state *dlthis, u32 soffset)
1909{
1910 u8 tmp, *src;
1911 char *dst;
1912
1913 if (soffset >= dlthis->dfile_hdr.df_strtab_size) {
1914 dload_error(dlthis, "Bad string table offset " FMT_UI32,
1915 soffset);
1916 return NULL;
1917 }
1918 src = (uint_least8_t *) dlthis->str_head +
1919 (soffset >> (LOG_BITS_PER_AU - LOG_BITS_PER_BYTE));
1920 dst = dlthis->str_temp;
1921 if (soffset & 1)
1922 *dst++ = *src++; /* only 1 character in first word */
1923 do {
1924 tmp = *src++;
1925 *dst = (tmp >> BITS_PER_BYTE);
1926 if (!(*dst++))
1927 break;
1928 } while ((*dst++ = tmp & BYTE_MASK));
1929 dlthis->temp_len = dst - dlthis->str_temp;
1930 /* squirrel away length including terminating null */
1931 return dlthis->str_temp;
1932} /* unpack_name */
1933#endif