Subversion Repositories QNX 8.QNX8 IFS tool

Rev

Rev 19 | Rev 21 | Go to most recent revision | Show entire file | Ignore whitespace | Details | Blame | Last modification | View Log | RSS feed

Rev 19 Rev 20
Line 19... Line 19...
19
#include <time.h>
19
#include <time.h>
20
 
20
 
21
// platform-specific includes
21
// platform-specific includes
22
#ifdef _MSC_VER
22
#ifdef _MSC_VER
23
#include <sys/utime.h>
23
#include <sys/utime.h>
-
 
24
#include <process.h>
24
#else // !_MSC_VER
25
#else // !_MSC_VER
25
#include <sys/param.h>
26
#include <sys/param.h>
26
#include <sys/sysmacros.h>
27
#include <sys/sysmacros.h>
-
 
28
#include <sys/wait.h>
27
#include <unistd.h>
29
#include <unistd.h>
28
#include <dirent.h>
30
#include <dirent.h>
29
#include <utime.h>
31
#include <utime.h>
30
#endif // _MSC_VER
32
#endif // _MSC_VER
31
 
33
 
Line 88... Line 90...
88
   bool should_follow_symlinks; // follow symlinks
90
   bool should_follow_symlinks; // follow symlinks
89
   bool should_autosymlink_dylib; // dynamic libraries should be written under their official SONAME and a named symlink be created pointing at them
91
   bool should_autosymlink_dylib; // dynamic libraries should be written under their official SONAME and a named symlink be created pointing at them
90
   bool should_keep_ld_output; // whether to keep .sym files produced by ld calls, togglable by the [+keeplinked] attribute
92
   bool should_keep_ld_output; // whether to keep .sym files produced by ld calls, togglable by the [+keeplinked] attribute
91
   bool should_ignore_duplicates; // [+|-dupignore] whether to ignore duplicates
93
   bool should_ignore_duplicates; // [+|-dupignore] whether to ignore duplicates
92
   bool should_allow_nonexistent_files; // [+|-optional] whether to continue processing on unexistent files
94
   bool should_allow_nonexistent_files; // [+|-optional] whether to continue processing on unexistent files
-
 
95
   bool is_bootstrap_file; // entry has the [virtual] attribute
93
   bool is_compiled_bootscript; // entry has [+script] attribute
96
   bool is_compiled_bootscript; // entry has [+script] attribute
94
   int extra_ino_flags; // bitmap of extra inode flags (IFS_INO_xxx)
97
   int extra_ino_flags; // bitmap of extra inode flags (IFS_INO_xxx)
95
   char *search; // [search=path[:path]] binary search path (the default one will be constructed at startup)
98
   char *search; // [search=path[:path]] binary search path (the default one will be constructed at startup)
96
 
99
 
97
 
100
 
Line 133... Line 136...
133
// bootable IFS support
136
// bootable IFS support
134
static char *bootfile_pathname = NULL;           // HACK: pathname to bootcode binary blob file to put at the start of a bootable IFS
137
static char *bootfile_pathname = NULL;           // HACK: pathname to bootcode binary blob file to put at the start of a bootable IFS
135
static size_t bootfile_size = 0;                 // HACK: size of the bootcode binary blob file to put at the start of a bootable IFS
138
static size_t bootfile_size = 0;                 // HACK: size of the bootcode binary blob file to put at the start of a bootable IFS
136
static char *startupfile_pathname = NULL;        // HACK: pathname to precompiled startup file blob to put in the startup header of a bootable IFS
139
static char *startupfile_pathname = NULL;        // HACK: pathname to precompiled startup file blob to put in the startup header of a bootable IFS
137
static size_t startupfile_ep_from_imagebase = 0; // HACK: startup code entrypoint offset from image base for a bootable IFS 
140
static size_t startupfile_ep_from_imagebase = 0; // HACK: startup code entrypoint offset from image base for a bootable IFS 
138
static char *kernelfile_pathname = NULL;         // HACK: pathname to precompiled kernel file blob to put in a bootable IFS
-
 
139
static size_t kernelfile_offset = 0;             // HACK: kernel file offset in bootable IFS
141
static size_t kernelfile_offset = 0x32000;       // kernel file offset in the IFS (is it ever supposed to change)
140
 
142
 
141
 
143
 
142
// exported function prototypes
144
// exported function prototypes
143
int32_t update_checksum (const void *data, const size_t data_len, const bool is_foreign_endianness); // compute an IFS image or startup checksum to store in the trailer
145
int32_t update_checksum (const void *data, const size_t data_len, const bool is_foreign_endianness); // compute an IFS image or startup checksum to store in the trailer
144
 
146
 
Line 146... Line 148...
146
// prototypes of local functions
148
// prototypes of local functions
147
static long long read_integer (const char *str); // reads an integer number for a string that may be specified in either hex, octal or decimal base, and may have an optional unit suffix (k, m, g, t)
149
static long long read_integer (const char *str); // reads an integer number for a string that may be specified in either hex, octal or decimal base, and may have an optional unit suffix (k, m, g, t)
148
static char *resolve_pathname (const char *pathname, const char *search_paths_or_NULL_for_MKIFS_PATH_envvar); // locates pathname among the known search paths and returns a pointer to the resolved pathname (static string)
150
static char *resolve_pathname (const char *pathname, const char *search_paths_or_NULL_for_MKIFS_PATH_envvar); // locates pathname among the known search paths and returns a pointer to the resolved pathname (static string)
149
static elf_section_header_t *elf_get_section_header_by_name (const elf_header_t *elf, const char *section_name); // get a pointer to a named section header in an ELF file
151
static elf_section_header_t *elf_get_section_header_by_name (const elf_header_t *elf, const char *section_name); // get a pointer to a named section header in an ELF file
150
static size_t Buffer_WriteIFSDirectoryEntryAt (buffer_t *ifs_data, const size_t write_offset, const fsentry_t *fsentry); // writes the given filesystem entry (without its contents) to the IFS buffer
152
static size_t Buffer_WriteIFSDirectoryEntryAt (buffer_t *ifs_data, const size_t write_offset, const fsentry_t *fsentry); // writes the given filesystem entry (without its contents) to the IFS buffer
151
static size_t Buffer_AppendIFSFileData (buffer_t *ifs_data, fsentry_t *fsentry); // writes the given filesystem entry's file data (i.e. its contents) to the IFS buffer
153
static size_t Buffer_AppendIFSFileData (buffer_t *ifs_data, const fsentry_t *fsentry); // writes the given filesystem entry's file data (i.e. its contents) to the IFS buffer
152
static int Buffer_StripELFFile (buffer_t *file, const char **saved_sections, const size_t saved_section_count, const char *indicative_pathname); // strips an ELF file buffer the way mkifs does it and returns whether it succeeded
154
static int Buffer_StripELFFile (buffer_t *file, const char **saved_sections, const size_t saved_section_count, const bool should_align_segsize_with_ramsize, const char *indicative_pathname); // strips an ELF file buffer the way mkifs does it and returns whether it succeeded
153
static void add_fsentry (fsentry_t **fsentries, size_t *fsentry_count, parms_t *entry_parms, const char *stored_pathname, const char *buildhost_pathname); // stack up a new filesystem entry in the the fsentries array
155
static void add_fsentry (fsentry_t **fsentries, size_t *fsentry_count, parms_t *entry_parms, const char *stored_pathname, const char *buildhost_pathname); // stack up a new filesystem entry in the the fsentries array
154
static void add_directory_contents_recursively (fsentry_t **fsentries, size_t *fsentry_count, const char *dir_pathname, const size_t start_pathname_len, parms_t *default_parms); // adds the contents of the directory pointed to by dir_pathname to the fsentries array, recursively
156
static void add_directory_contents_recursively (fsentry_t **fsentries, size_t *fsentry_count, const char *dir_pathname, const size_t start_pathname_len, parms_t *default_parms); // adds the contents of the directory pointed to by dir_pathname to the fsentries array, recursively
155
static int fsentry_compare_pathnames_cb (const void *a, const void *b); // qsort() comparison callback that sorts filesystem entries by pathnames
157
static int fsentry_compare_pathnames_cb (const void *a, const void *b); // qsort() comparison callback that sorts filesystem entries by pathnames
156
static void parse_line (FILE *buildfile_fp, char *line_buffer, fsentry_t **fsentries, size_t *fsentry_count, parms_t *default_parms); // parses a line in the build file and make the relevant changes to the fsentries array
158
static void parse_line (FILE *buildfile_fp, char *line_buffer, fsentry_t **fsentries, size_t *fsentry_count, parms_t *default_parms); // parses a line in the build file and make the relevant changes to the fsentries array
157
 
159
 
Line 448... Line 450...
448
 
450
 
449
   return (count);
451
   return (count);
450
}
452
}
451
 
453
 
452
 
454
 
453
static size_t Buffer_AppendIFSFileData (buffer_t *ifs_data, fsentry_t *fsentry)
455
static size_t Buffer_AppendIFSFileData (buffer_t *ifs_data, const fsentry_t *fsentry)
454
{
456
{
455
   // writes the given filesystem entry's file data (i.e. its contents) to the IFS buffer
457
   // writes the given filesystem entry's file data (i.e. its contents) to the IFS buffer
456
 
458
 
457
   elf_program_header_t *phdr;
459
   elf_program_header_t *phdr;
458
   elf_header_t *elf;
460
   elf_header_t *elf;
459
   size_t fixed_physical_addr;
461
   size_t fixed_physical_addr;
460
   size_t corrective_offset;
462
   size_t corrective_offset;
461
   //size_t segment_type;
463
   //size_t segment_type;
462
   size_t segment_size;
464
   size_t size_in_memory;
463
   size_t table_index;
465
   size_t table_index;
464
   size_t table_count;
466
   size_t table_count;
465
   size_t data_offset;
467
   size_t data_offset;
466
 
468
 
467
   ASSERT (S_ISREG (fsentry->header.mode), "function called for invalid dirent"); // consistency check
469
   ASSERT (S_ISREG (fsentry->header.mode), "function called for invalid dirent"); // consistency check
468
   data_offset = ifs_data->size; // see where we are
470
   data_offset = ifs_data->size; // see where we are
469
 
471
 
470
   // is the file we're storing a preprocessed ELF file ?
472
   // is the file we're storing a preprocessed ELF file ?
471
   if ((fsentry->header.ino & IFS_INO_PROCESSED_ELF)
473
   if (fsentry->header.ino & IFS_INO_PROCESSED_ELF)
472
#ifndef PROCNTO_WIP
-
 
473
      && (strstr (fsentry->u.file.path, "/procnto-smp-instr") == NULL)
-
 
474
#endif // !PROCNTO_WIP
-
 
475
       )
-
 
476
   {
474
   {
477
 
475
 
478
      elf = (elf_header_t *) fsentry->u.file.UNSAVED_databuf; // quick access to ELF header
476
      elf = (elf_header_t *) fsentry->u.file.UNSAVED_databuf; // quick access to ELF header
479
      table_count = ELF_GET_NUMERIC (elf, elf, program_header_table_len); // get the number of program headers
477
      table_count = ELF_GET_NUMERIC (elf, elf, program_header_table_len); // get the number of program headers
480
      for (table_index = 0; table_index < table_count; table_index++)
478
      for (table_index = 0; table_index < table_count; table_index++)
Line 484... Line 482...
484
         //if (!((segment_type >= 2) && (segment_type <= 7) || ((segment_type >= 0x6474e550) && (segment_type <= 0x6474e552)) || (segment_type == 0x70000001)))
482
         //if (!((segment_type >= 2) && (segment_type <= 7) || ((segment_type >= 0x6474e550) && (segment_type <= 0x6474e552)) || (segment_type == 0x70000001)))
485
         //   continue; // NOTE: only certain segments types must be corrected
483
         //   continue; // NOTE: only certain segments types must be corrected
486
 
484
 
487
 
485
 
488
         corrective_offset = ELF_GET_NUMERIC (elf, phdr, virtual_addr) - ELF_GET_NUMERIC (elf, phdr, file_offset);
486
         corrective_offset = ELF_GET_NUMERIC (elf, phdr, virtual_addr) - ELF_GET_NUMERIC (elf, phdr, file_offset);
489
         segment_size = ELF_GET_NUMERIC (elf, phdr, size_in_memory); // get this ELF segment's occupied size in memory
487
         size_in_memory = ELF_GET_NUMERIC (elf, phdr, size_in_memory); // get this ELF segment's occupied size in memory
490
         if (segment_size != 0) // only patch the physical address of segments that have an actual size in memory
488
         if (size_in_memory != 0) // only patch the physical address of segments that have an actual size in memory
491
         {
489
         {
492
            fixed_physical_addr = ELF_GET_NUMERIC (elf, phdr, physical_addr) + image_base + data_offset - corrective_offset;
490
            fixed_physical_addr = ELF_GET_NUMERIC (elf, phdr, physical_addr) + image_base + data_offset - corrective_offset;
493
            ELF_SET_NUMERIC (elf, phdr, physical_addr, fixed_physical_addr); // patch the physical address member of the program header table (NOTE: data_offset is the location where the file data is about to be written)
491
            ELF_SET_NUMERIC (elf, phdr, physical_addr, fixed_physical_addr); // patch the physical address member of the program header table (NOTE: data_offset is the location where the file data is about to be written)
494
         }
492
         }
495
      }
493
      }
Line 514... Line 512...
514
   }
512
   }
515
   return (Buffer_OffsetOf (buffer, occurrence)); // can't fail
513
   return (Buffer_OffsetOf (buffer, occurrence)); // can't fail
516
}
514
}
517
 
515
 
518
 
516
 
519
static int Buffer_StripELFFile (buffer_t *file, const char **saved_sections, const size_t saved_section_count, const char *indicative_pathname)
517
static int Buffer_StripELFFile (buffer_t *file, const char **saved_sections, const size_t saved_section_count, const bool should_align_segsize_with_ramsize, const char *indicative_pathname)
520
{
518
{
521
   // NOTE: for each ELF file, mkifs
519
   // NOTE: for each ELF file, mkifs
522
   // -> alters the program header table and offsets each p_addr (physical address) member by <image_base> plus the current file offset (this cannot be done right now, will need to be done once they are known)
520
   // -> alters the program header table and offsets each p_addr (physical address) member by <image_base> plus the current file offset (this cannot be done right now, will need to be done once they are known)
523
   // -> throws away and reconstructs the sections table by keeping only the sections that are in the program header, and writes the section table at the start of the first thrown-away section
521
   // -> throws away and reconstructs the sections table by keeping only the sections that are in the program header, and writes the section table at the start of the first thrown-away section
524
   // FIXME: what if a thrown away section is located between two program segments ? are they collapsed, moving the segments beyond it one slot down ?
522
   // FIXME: what if a thrown away section is located between two program segments ? are they collapsed, moving the segments beyond it one slot down ?
Line 569... Line 567...
569
      const char *name;
567
      const char *name;
570
      elf_section_header_t header;
568
      elf_section_header_t header;
571
      buffer_t data;
569
      buffer_t data;
572
   } elf_section_t;
570
   } elf_section_t;
573
 
571
 
574
   const elf_program_header_t *phdr;
-
 
575
   const elf_section_header_t *shdr;
572
   const elf_section_header_t *shdr;
-
 
573
   elf_program_header_t *phdr;
-
 
574
   elf_program_header_t *other_phdr;
576
   elf_section_t *elf_sections = NULL; // mallocated
575
   elf_section_t *elf_sections = NULL; // mallocated
577
   elf_section_t *elf_section = NULL;
576
   elf_section_t *elf_section = NULL;
578
   size_t elf_section_count = 0;
577
   size_t elf_section_count = 0;
579
   size_t new_shdrtable_offset;
578
   size_t new_shdrtable_offset;
580
   size_t new_shdrtable_len;
579
   size_t new_shdrtable_len;
581
   size_t sectiondata_start;
580
   size_t sectiondata_start;
582
   size_t sectiondata_size;
581
   size_t sectiondata_size;
-
 
582
   size_t size_in_memory;
-
 
583
   size_t size_in_file;
-
 
584
   size_t file_offset;
583
   size_t array_index;
585
   size_t array_index;
584
   size_t table_index;
586
   size_t table_index;
585
   size_t table_count;
587
   size_t table_count;
586
   size_t page_size;
588
   size_t page_size;
587
 
589
 
Line 594... Line 596...
594
   {
596
   {
595
      errno = ENOTSUP; // unsupported architecture: set errno to something meaningful
597
      errno = ENOTSUP; // unsupported architecture: set errno to something meaningful
596
      return (0); // and return an error value
598
      return (0); // and return an error value
597
   }
599
   }
598
 
600
 
599
   // parse the program header table, and measure the farthest offset known by this table where we'll write the reconstructed section headers table
601
   // if we should align the segment sizes in the ELF file with their occupied memory size (such is the case for e.g. procnto), do that first
-
 
602
   table_count = ELF_GET_NUMERIC (ELFHDR, ELFHDR, program_header_table_len); // get the number of program headers
-
 
603
   for (table_index = 0; table_index < table_count; table_index++)
-
 
604
   {
-
 
605
      phdr = (elf_program_header_t *) &file->bytes[ELF_GET_NUMERIC (ELFHDR, ELFHDR, program_header_table_offset) + (size_t) ELF_GET_NUMERIC (ELFHDR, ELFHDR, program_header_item_size) * table_index]; // quick access to program header
-
 
606
      file_offset    = ELF_GET_NUMERIC (ELFHDR, phdr, file_offset); // get this ELF segment's start offset in the ELF file
-
 
607
      size_in_memory = ELF_GET_NUMERIC (ELFHDR, phdr, size_in_memory); // get this ELF segment's occupied size in memory
-
 
608
      size_in_file   = ELF_GET_NUMERIC (ELFHDR, phdr, size_in_file); // get this ELF segment's occupied size in the ELF file
-
 
609
      if (should_align_segsize_with_ramsize && (size_in_memory != size_in_file)) // should we align this segment's file size with its claimed RAM size ? (such is the case for e.g. procnto)
-
 
610
      {
-
 
611
         if (size_in_memory > size_in_file) // is it bigger ? if so, make sure we won't be overwriting other segments beyond this one
-
 
612
         {
-
 
613
            for (array_index = 0; array_index < table_count; array_index++)
-
 
614
            {
-
 
615
               other_phdr = (elf_program_header_t *) &file->bytes[ELF_GET_NUMERIC (ELFHDR, ELFHDR, program_header_table_offset) + (size_t) ELF_GET_NUMERIC (ELFHDR, ELFHDR, program_header_item_size) * array_index]; // quick access to program header
-
 
616
               if (other_phdr == phdr)
-
 
617
                  continue; // skip self
-
 
618
               if (ELF_GET_NUMERIC (ELFHDR, other_phdr, file_offset) + ELF_GET_NUMERIC (ELFHDR, other_phdr, size_in_file) < file_offset)
-
 
619
                  continue; // skip segments that are located before this one
-
 
620
               if (ELF_GET_NUMERIC (ELFHDR, other_phdr, file_offset) > file_offset + size_in_memory)
-
 
621
                  continue; // skip segments that are located after this one, including its corrected size
-
 
622
               DIE_WITH_EXITCODE (1, "remapping ELF segment would overwrite segment #%zd in the same file", array_index);
-
 
623
            }
-
 
624
 
-
 
625
            // finally, memset() the extra area
-
 
626
            Buffer_WriteAt (file, file_offset + size_in_memory, NULL, 0); // reallocate the ELF file data buffer if necessary
-
 
627
            memset (&file->bytes[file_offset + size_in_file], 0, size_in_memory - size_in_file); // and write zeroes over the extra space
-
 
628
         }
-
 
629
         ELF_SET_NUMERIC (ELFHDR, phdr, size_in_file, size_in_memory); // patch this segment's size in the ELF file so that it matches the RAM size
-
 
630
      }
-
 
631
   }
600
 
632
 
-
 
633
   // now parse the program header table, and measure the farthest offset known by this table where we'll write the reconstructed section headers table
601
   new_shdrtable_offset = 0;
634
   new_shdrtable_offset = 0;
602
   table_count = ELF_GET_NUMERIC (ELFHDR, ELFHDR, program_header_table_len);
635
   table_count = ELF_GET_NUMERIC (ELFHDR, ELFHDR, program_header_table_len);
603
   for (table_index = 0; table_index < table_count; table_index++)
636
   for (table_index = 0; table_index < table_count; table_index++)
604
   {
637
   {
605
      phdr = (elf_program_header_t *) &file->bytes[ELF_GET_NUMERIC (ELFHDR, ELFHDR, program_header_table_offset) + (size_t) ELF_GET_NUMERIC (ELFHDR, ELFHDR, program_header_item_size) * table_index]; // quick access to program header
638
      phdr = (elf_program_header_t *) &file->bytes[ELF_GET_NUMERIC (ELFHDR, ELFHDR, program_header_table_offset) + (size_t) ELF_GET_NUMERIC (ELFHDR, ELFHDR, program_header_item_size) * table_index]; // quick access to program header
Line 693... Line 726...
693
}
726
}
694
 
727
 
695
 
728
 
696
static void add_fsentry (fsentry_t **fsentries, size_t *fsentry_count, parms_t *entry_parms, const char *stored_pathname, const char *buildhost_pathname)
729
static void add_fsentry (fsentry_t **fsentries, size_t *fsentry_count, parms_t *entry_parms, const char *stored_pathname, const char *buildhost_pathname)
697
{
730
{
-
 
731
   #define STRINGARRAY_INIT(string_array) do { (string_array)->args = NULL; (string_array)->count = 0; } while (0)
-
 
732
   #define STRINGARRAY_PUSH(string_array,str) do { \
-
 
733
      reallocated_ptr = realloc ((string_array)->args, ((string_array)->count + 1) * sizeof (char *)); \
-
 
734
      ASSERT_WITH_ERRNO (reallocated_ptr); \
-
 
735
      (string_array)->args = reallocated_ptr; \
-
 
736
      (string_array)->args[(string_array)->count] = ((str) != NULL ? strdup ((str)) : NULL); \
-
 
737
      if ((str) != NULL) \
-
 
738
         ASSERT_WITH_ERRNO ((string_array)->args[(string_array)->count]); \
-
 
739
      (string_array)->count++; \
-
 
740
   } while (0)
-
 
741
   #define STRINGARRAY_FREE(string_array) do { \
-
 
742
      if ((string_array)->args != NULL) { \
-
 
743
         for (array_index = 0; array_index < (string_array)->count; array_index++) \
-
 
744
            if ((string_array)->args[array_index] != NULL) \
-
 
745
               free ((string_array)->args[array_index]); \
-
 
746
         free ((string_array)->args); \
-
 
747
         (string_array)->args = NULL; \
-
 
748
      } \
-
 
749
      (string_array)->count = 0; \
-
 
750
   } while (0)
-
 
751
 
-
 
752
   typedef struct stringarray_s
-
 
753
   {
-
 
754
      char **args;
-
 
755
      size_t count;
-
 
756
   } stringarray_t;
-
 
757
 
698
   static thread_local char *candidate_pathname = NULL;
758
   static thread_local char *candidate_pathname = NULL;
699
   static int inode_count = 0; // will be preincremented each time this function is called
759
   static int inode_count = 0; // will be preincremented each time this function is called
700
 
760
 
-
 
761
   stringarray_t global_argv = { NULL, 0 };
-
 
762
   stringarray_t global_envp = { NULL, 0 };
-
 
763
   stringarray_t line_argv = { NULL, 0 };
-
 
764
   stringarray_t line_envp = { NULL, 0 };
-
 
765
   stringarray_t startup_argv = { NULL, 0 };
-
 
766
   stringarray_t startup_envp = { NULL, 0 };
-
 
767
   stringarray_t procnto_argv = { NULL, 0 };
-
 
768
   stringarray_t procnto_envp = { NULL, 0 };
-
 
769
   stringarray_t linker_argv = { NULL, 0 };
701
   const char *stored_pathname_without_leading_slash;
770
   const char *stored_pathname_without_leading_slash;
702
   const char *original_stored_pathname = NULL;
771
   const char *original_stored_pathname = NULL;
-
 
772
   buffer_t current_line;
703
   buffer_t *shstrtab = NULL;
773
   buffer_t *shstrtab = NULL;
704
   const char *canonical_dylib_name;
774
   const char *canonical_dylib_name;
705
   const char *dynamic_strings; // strings table of the ".dynamic" section
775
   const char *dynamic_strings; // strings table of the ".dynamic" section
706
   const char *last_dirsep;
776
   const char *last_dirsep;
707
   char *global_envstring = NULL;
777
   size_t array_index;
708
   size_t global_envstring_len = 0;
778
   size_t line_index;
709
   size_t fsentry_index;
779
   size_t fsentry_index;
710
   char *startup_name = NULL;
-
 
711
   char *procnto_name = NULL;
-
 
712
   char *resolved_pathname;
780
   char *resolved_pathname;
-
 
781
   char *linebit_start;
-
 
782
   char *write_ptr;
-
 
783
   char *read_ptr;
-
 
784
   char *token;
-
 
785
   char *value;
-
 
786
   char *ctx;
713
   void *reallocated_ptr;
787
   void *reallocated_ptr;
714
   void *old_data;
788
   void *old_data;
-
 
789
   bool is_quoted_context;
-
 
790
   bool is_end_of_line;
715
   struct stat stat_buf;
791
   struct stat stat_buf;
716
   fsentry_t *fsentry;
792
   fsentry_t *fsentry;
717
   int retval;
793
   int retval;
718
 
794
 
719
   // initial allocation (per thread)
795
   // initial allocation (per thread)
Line 727... Line 803...
727
   {
803
   {
728
      LOG_INFO ("directory: ino 0x%x uid %d gid %d mode 0%o path \"%s\"", inode_count + 1, entry_parms->uid, entry_parms->gid, entry_parms->st_mode, stored_pathname);
804
      LOG_INFO ("directory: ino 0x%x uid %d gid %d mode 0%o path \"%s\"", inode_count + 1, entry_parms->uid, entry_parms->gid, entry_parms->st_mode, stored_pathname);
729
   }
805
   }
730
   else if (S_ISREG (entry_parms->st_mode)) // else are we storing a regular file ?
806
   else if (S_ISREG (entry_parms->st_mode)) // else are we storing a regular file ?
731
   {
807
   {
732
      if (strcmp (stored_pathname, "/proc/boot/boot") == 0) // is it the kernel ?
808
      if (entry_parms->is_bootstrap_file) // is it the bootstrap file ?
733
      {
809
      {
734
         // HACK: for now just consider the kernel as a binary blob
-
 
735
         // FIXME: reimplement properly
-
 
736
#ifdef PROCNTO_WIP
-
 
737
         char *linebit_start;
-
 
738
         char *content_line;
-
 
739
         char *write_ptr;
-
 
740
         char *token;
-
 
741
         char *value;
-
 
742
         char *ctx;
-
 
743
         bool is_quoted_context;
-
 
744
         bool was_string_split;
-
 
745
 
-
 
746
         // parse each line of contents
810
         // parse each line of contents
747
         ASSERT (entry_parms->data.len > 0, "kernel specification without inline contents");
811
         ASSERT (entry_parms->data.size > 0, "kernel specification without inline contents");
-
 
812
 
-
 
813
         // parse buffer (non-destructively) line after line
-
 
814
         Buffer_Initialize (&current_line);
748
         for (content_line = strtok_r (entry_parms->data.bytes, "\n", &ctx); content_line != NULL; content_line = strtok_r (NULL, "\n", ctx))
815
         for (line_index = 0; Buffer_GetNthLine (&entry_parms->data, line_index, &current_line); line_index++)
749
         {
816
         {
-
 
817
            read_ptr = current_line.bytes;
750
            while (isspace (*content_line))
818
            while (isspace (*read_ptr))
751
               content_line++; // skip leading spaces
819
               read_ptr++; // skip leading spaces
752
            if ((*content_line == '#') || (*content_line == 0))
820
            if ((*read_ptr == '#') || (*read_ptr == 0))
753
               continue; // skip comments and empty lines
821
               continue; // skip comments and empty lines
754
 
822
 
755
            // format of a line: [attributes] [env assignation] [...] [executable] [arg] [...] [comment]
823
            // format of a line: [attributes] [env assignation] [...] [executable] [arg] [...] [comment]
756
            // example: "[uid=0 gid=0 perms=0700] CONFIG_PATH=/proc/boot:/etc procnto-smp-instr -v -mr -d 0777 -u 0777"
824
            // example: "[uid=0 gid=0 perms=0700] CONFIG_PATH=/proc/boot:/etc procnto-smp-instr -v -mr -d 0777 -u 0777"
-
 
825
 
757
            //LOG_DEBUG ("parsing line: %s", content_line);
826
            LOG_DEBUG ("parsing line: %s", read_ptr);
758
 
827
 
759
            // does this line start with an attribute block ?
828
            // does this line start with an attribute block ?
760
            if (*content_line == '[')
829
            if (*read_ptr == '[')
761
            {
830
            {
762
               content_line++; // skip the leading square bracket
831
               read_ptr++; // skip the leading square bracket
763
               linebit_start = content_line; // remember where it starts
832
               linebit_start = read_ptr; // remember where it starts
764
               is_quoted_context = false; // reach the next unescaped closing square bracket that is not between quotes
833
               is_quoted_context = false; // reach the next unescaped closing square bracket that is not between quotes
765
               while ((*content_line != 0) && !((*content_line == ']') && (content_line[-1] != '\\') && !is_quoted_context))
834
               while ((*read_ptr != 0) && !((*read_ptr == ']') && (read_ptr[-1] != '\\') && !is_quoted_context))
766
               {
835
               {
767
                  if (*content_line == '"')
836
                  if (*read_ptr == '"')
768
                     is_quoted_context ^= true; // remember when we're between quotes
837
                     is_quoted_context ^= true; // remember when we're between quotes
769
                  else if (!is_quoted_context && (*content_line == ' '))
838
                  else if (!is_quoted_context && (*read_ptr == ' '))
770
                     *content_line = RECORD_SEP[0]; // turn all spaces outside quoted contexts into an ASCII record separator to ease token splitting
839
                     *read_ptr = RECORD_SEP[0]; // turn all spaces outside quoted contexts into an ASCII record separator to ease token splitting
771
                  content_line++; // reach the next unescaped closing square bracket
840
                  read_ptr++; // reach the next unescaped closing square bracket
772
               }
841
               }
773
               if (*content_line != ']')
842
               if (*read_ptr != ']')
774
               {
843
               {
775
                  LOG ("warning", 0, "syntax error in \"%s\" line %d: unterminated attributes block (skipping)", buildfile_pathname, lineno);
844
                  LOG ("warning", 0, "syntax error in \"%s\" line %d: unterminated attributes block (skipping)", buildfile_pathname, lineno);
776
                  continue; // invalid attribute block, skip line
845
                  continue; // invalid attribute block, skip line
777
               }
846
               }
-
 
847
               is_end_of_line = (*read_ptr == 0); // see if we're at the end of line already
778
               *content_line = 0; // end the attribute block so that it is a parsable C string
848
               *read_ptr = 0; // end the attribute block in all cases so that it is a parsable C string
779
 
849
 
780
               // now parse the attribute tokens (NOTE: THE LIST OF ALLOWED ATTRIBUTES HERE IS NOT DOCUMENTED)
850
               // now parse the attribute tokens (NOTE: THE LIST OF ALLOWED ATTRIBUTES HERE IS NOT DOCUMENTED)
781
               token = strtok_r (linebit_start, RECORD_SEP, &ctx);
851
               token = strtok_r (linebit_start, RECORD_SEP, &ctx);
782
               while (token != NULL)
852
               while (token != NULL)
783
               {
853
               {
784
                  #define REACH_TOKEN_VALUE() do { value = strchr (token, '=') + 1; if (*value == '"') value++; } while (0)
854
                  #define REACH_TOKEN_VALUE() do { value = strchr (token, '=') + 1; if (*value == '"') value++; } while (0)
785
                  if (false)
855
                  if (false) {}
786
                  else if (strncmp (token, "prefix=",  7) == 0) { REACH_TOKEN_VALUE (); entry_parms->prefix  = (*value == '/' ? value + 1 : value); } // skip possible leading slash in prefix (NOTE: stolen pointer. Do not free.)
856
                  else if (strncmp (token, "prefix=",  7) == 0) { REACH_TOKEN_VALUE (); entry_parms->prefix  = (*value == '/' ? value + 1 : value); } // skip possible leading slash in prefix (NOTE: stolen pointer. Do not free.)
787
                  else if (strncmp (token, "uid=",     4) == 0) { REACH_TOKEN_VALUE (); entry_parms->uid     = (int) read_integer (value); }
857
                  else if (strncmp (token, "uid=",     4) == 0) { REACH_TOKEN_VALUE (); entry_parms->uid     = (int) read_integer (value); }
788
                  else if (strncmp (token, "gid=",     4) == 0) { REACH_TOKEN_VALUE (); entry_parms->gid     = (int) read_integer (value); }
858
                  else if (strncmp (token, "gid=",     4) == 0) { REACH_TOKEN_VALUE (); entry_parms->gid     = (int) read_integer (value); }
789
                  else if (strncmp (token, "perms=",   6) == 0) { REACH_TOKEN_VALUE (); entry_parms->perms   = (int) read_integer (value); }
859
                  else if (strncmp (token, "perms=",   6) == 0) { REACH_TOKEN_VALUE (); entry_parms->perms   = (int) read_integer (value); }
790
                  else if (strcmp (token, "+followlink") == 0) entry_parms->should_follow_symlinks = true;
860
                  else if (strcmp (token, "+followlink") == 0) entry_parms->should_follow_symlinks = true;
Line 794... Line 864...
794
                  else LOG_WARNING ("unimplemented bootstrap executable attribute in \"%s\" line %d: '%s'", buildfile_pathname, lineno, token);
864
                  else LOG_WARNING ("unimplemented bootstrap executable attribute in \"%s\" line %d: '%s'", buildfile_pathname, lineno, token);
795
                  #undef REACH_TOKEN_VALUE
865
                  #undef REACH_TOKEN_VALUE
796
                  token = strtok_r (NULL, RECORD_SEP, &ctx); // proceed to next attribute token
866
                  token = strtok_r (NULL, RECORD_SEP, &ctx); // proceed to next attribute token
797
               }
867
               }
798
 
868
 
799
               content_line++; // reach the next character
869
               if (is_end_of_line)
800
               while ((*content_line != 0) && isspace (*content_line))
870
                  continue; // if end of line was reached, proceed to the next line
801
                  content_line++; // skip leading spaces
871
               else
-
 
872
                  read_ptr++; // else reach the next character (after the NUL split) and continue processing the same line
802
            } // end of "this line starts with an attributes block"
873
            } // end of "this line starts with an attributes block"
803
 
874
 
-
 
875
            // at this point we are past the attributes block
-
 
876
 
-
 
877
            // reset contextual argv/envp arrays
-
 
878
            line_argv.args = NULL;
-
 
879
            line_argv.count = 0;
-
 
880
            line_envp.args = NULL;
-
 
881
            line_envp.count = 0;
-
 
882
 
804
            // there's data in this line. We expect an executable OR a variable name. Read it and unescape escaped characters
883
            // now read each word (or quoted group of words), unescaping escaped characters
805
            while (*content_line != 0)
884
            while (*read_ptr != 0)
806
            {
885
            {
-
 
886
               while ((*read_ptr != 0) && isspace (*read_ptr))
-
 
887
                  read_ptr++; // skip intermediate spaces and reach the next word
-
 
888
 
-
 
889
               if (*read_ptr == '#')
-
 
890
                  break; // if the rest of the line is commented out, stop parsing it and proceed to the next line
-
 
891
 
807
               linebit_start = content_line; // remember the name starts here
892
               linebit_start = read_ptr; // remember the word (or quoted group of words) starts here
808
               write_ptr = linebit_start;
893
               write_ptr = read_ptr;
809
               is_quoted_context = (*content_line == '"');
894
               is_quoted_context = (*read_ptr == '"'); // see if we're entering a quoted context or not
810
               if (is_quoted_context)
895
               if (is_quoted_context)
811
                  content_line++; // skip a possible initial quote in the name
896
                  read_ptr++; // skip a possible initial quote in the word
812
               while ((*content_line != 0) && ((!is_quoted_context && (*content_line != '=') && !isspace (*content_line)) || (is_quoted_context && (*content_line == '"'))))
897
               while ((*read_ptr != 0) && ((!is_quoted_context && !isspace (*read_ptr)) || (is_quoted_context && (*read_ptr == '"'))))
813
               {
898
               {
814
                  if (*content_line == '\\')
899
                  if (*read_ptr == '\\')
815
                  {
-
 
816
                     content_line++;
-
 
817
                     *write_ptr++ = *content_line; // unescape characters that are escaped with '\'
900
                     read_ptr++; // unescape characters that are escaped with '\' by advancing the read pointer
818
                  }
-
 
819
                  else
-
 
820
                     *write_ptr++ = *content_line;
901
                  *write_ptr++ = *read_ptr++; // recopy characters as we read them
821
                  content_line++;
-
 
822
               }
902
               }
-
 
903
               is_end_of_line = (*read_ptr == 0); // see if we're at the end of line already
-
 
904
               *write_ptr = 0; // stop the rewritten string here
823
 
905
 
824
               // we reached a closing quote, a space OR an equal sign
-
 
825
               if (*content_line == '=')
-
 
826
               {
-
 
827
                  // it's an environment variable assignation
-
 
828
                  *write_ptr++ = *content_line++; // skip the equal sign
-
 
829
                  is_quoted_context = (*content_line == '"');
-
 
830
                  if (is_quoted_context)
-
 
831
                     content_line++; // skip a possible initial quote in the value
-
 
832
                  while ((*content_line != 0) && ((!is_quoted_context && (*content_line != '=') && !isspace (*content_line)) || (is_quoted_context && (*content_line == '"'))))
906
               // end of word, i.e. we reached either a closing quote or a space. The string bit has been rewritted at linebit_start without quotes and with characters unescaped.
833
                  {
-
 
834
                     if (*content_line == '\\')
-
 
835
                     {
-
 
836
                        content_line++;
-
 
837
                        *write_ptr++ = *content_line; // unescape characters that are escaped with '\'
-
 
838
                     }
-
 
839
                     else
-
 
840
                        *write_ptr++ = *content_line;
-
 
841
                     content_line++;
-
 
842
                  }
-
 
843
                  if (*write_ptr != 0)
-
 
844
                  {
-
 
845
                     *write_ptr = 0; // terminate the string if necessary
-
 
846
                     was_string_split = true;
-
 
847
                  }
-
 
848
                  else
-
 
849
                     was_string_split = false;
-
 
850
                  if (is_quoted_context && (*content_line == '"'))
-
 
851
                     content_line++; // skip a possible final quote
-
 
852
                  while ((*content_line != 0) && isspace (*content_line))
-
 
853
                     content_line++; // skip spaces
-
 
854
 
907
 
-
 
908
               if ((strchr (linebit_start, '=') != NULL) && (line_argv.count == 0)) // is it an assignation AND have we not started constructing argv yet?
-
 
909
               {
-
 
910
                  STRINGARRAY_PUSH (&line_envp, linebit_start); // linebit_start is of the form "NAME=VALUE": it's an environment variable assignation
-
 
911
                  LOG_DEBUG ("collected envp: [%s]", linebit_start);
-
 
912
               }
855
                  // now linebit_start is of the form "NAME=VALUE"
913
               else // it's an executable argument (argv)
-
 
914
               {
-
 
915
                  STRINGARRAY_PUSH (&line_argv, linebit_start); // linebit_start is either NOT of the form "NAME=VALUE" OR we started constructing argv: it's a command-line argument
856
                  LOG_DEBUG ("assignation: [%s]", linebit_start);
916
                  LOG_DEBUG ("collected argv: [%s]", linebit_start);
-
 
917
               }
857
 
918
 
-
 
919
               if (!is_end_of_line)
-
 
920
                  read_ptr++; // if we haven't reach the end of the line yet, advance to the next character (after the NUL split)
858
                  // TODO: grow global_envstring
921
            } // end while (*read_ptr != 0)
859
 
922
 
860
                  //reallocated_ptr = realloc (global_envstring, global_envstring_len + strlen ())
923
            // we finished parsing the line
861
 
924
 
-
 
925
            // did we fill an executable argv? As per QNX docs, the first executable must be startup-*, the last executable must be procnto.
-
 
926
            if (line_argv.count > 0)
-
 
927
            {
862
                  if (was_string_split)
928
               if (startup_argv.args == NULL)
-
 
929
               {
863
                     *write_ptr = ' '; // restore string continuity for parsing to continue
930
                  startup_argv.args = line_argv.args; // relocate these pointers to the right place
864
                  while ((*content_line != 0) && isspace (*content_line))
931
                  startup_argv.count = line_argv.count;
-
 
932
                  startup_envp.args = line_envp.args; // relocate these pointers to the right place
865
                     content_line++; // skip spaces
933
                  startup_envp.count = line_envp.count;
866
               }
934
               }
867
               else // it's either a closing quote or a space
935
               else
868
               {
936
               {
869
                  *write_ptr = 0; // terminate the string
-
 
870
                  if (is_quoted_context && (*content_line == '"'))
-
 
871
                     content_line++; // skip a possible final quote
-
 
872
 
-
 
873
                  LOG_DEBUG ("exe name: [%s]", linebit_start);
-
 
874
 
-
 
875
                  while ((*content_line != 0) && isspace (*content_line))
-
 
876
                     content_line++; // skip leading spaces
-
 
877
 
-
 
878
                  // it's an executable name. As per QNX docs, the first executable must be startup-*, the last executable must be procnto.
937
                  STRINGARRAY_FREE (&procnto_argv); // if procnto's argv was already assigned, free the previous array as we'll be replacing it with a new one
879
                  if (startup_name == NULL)
-
 
880
                     startup_name = strdup (linebit_start);
938
                  procnto_argv.args = line_argv.args; // relocate these pointers to the right place
881
                  else
-
 
882
                  {
-
 
883
                     if (procnto_name != NULL)
-
 
884
                        free (procnto_name);
-
 
885
                     procnto_name = strdup (linebit_start);
939
                  procnto_argv.count = line_argv.count;
886
                  }
-
 
887
 
-
 
888
                  if ((*content_line == '#') || (*content_line == 0))
-
 
889
                     break; // if we reach the end of the line, stop parsing
940
                  STRINGARRAY_FREE (&procnto_envp); // if procnto's envp was already assigned, free the previous array as we'll be replacing it with a new one
890
 
-
 
891
                  // what comes after now must be optional arguments
-
 
892
                  while ((*content_line != 0) && isspace (*content_line))
941
                  procnto_envp.args = line_envp.args; // relocate these pointers to the right place
893
                     content_line++; // skip leading spaces
942
                  procnto_envp.count = line_envp.count;
894
 
-
 
895
                  // FIXME: parse executable command-line arguments
-
 
896
 
-
 
897
                  break; // stop parsing once all the arguments have been read
-
 
898
               }
943
               }
-
 
944
               line_argv.args = NULL; // void the line_argv array so as to not free it as we stole its args pointers
-
 
945
               line_argv.count = 0;
-
 
946
               line_envp.args = NULL; // void the line_envp array so as to not free it as we stole its args pointers
-
 
947
               line_envp.count = 0;
899
            }
948
            }
-
 
949
            else // this line contained no executable invokation, so stack up its envp assignations into the global envp array
-
 
950
               for (array_index = 0; array_index < line_envp.count; array_index++)
-
 
951
                  STRINGARRAY_PUSH (&global_envp, line_envp.args[array_index]);
-
 
952
 
-
 
953
            // release the contextual argv/envp arrays
900
         } // end of parsing
954
            STRINGARRAY_FREE (&line_argv);
-
 
955
            STRINGARRAY_FREE (&line_envp);
-
 
956
 
-
 
957
         } // end for (line_index = 0; Buffer_GetNthLine (&entry_parms->data, line_index, &current_line); line_index++)
901
         free (entry_parms->data.bytes); // free the inline specification once it's parsed
958
         free (entry_parms->data.bytes); // free the inline specification once it's parsed
902
         entry_parms->data.bytes = NULL;
959
         entry_parms->data.bytes = NULL;
903
         entry_parms->data.len = 0;
960
         entry_parms->data.size = 0;
904
 
961
 
905
         ASSERT (startup_name && *startup_name, "the QNX startup executable (startup-*) is missing in this bootstrap inline specification");
962
         ASSERT (startup_argv.args && startup_argv.args[0] && *startup_argv.args[0], "the QNX startup executable (startup-*) is missing in this bootstrap inline specification");
906
         ASSERT (procnto_name && *procnto_name, "the QNX kernel (procnto-*) is missing in this bootstrap inline specification");
963
         ASSERT (procnto_argv.args && procnto_argv.args[0] && *procnto_argv.args[0], "the QNX kernel (procnto-*) is missing in this bootstrap inline specification");
907
 
964
 
908
         // now we know which startup and procnto executables to use
965
         // now we know which startup and procnto executables to use
909
         LOG_DEBUG ("Startup: %s", startup_name);
966
         LOG_DEBUG ("Startup: %s", startup_argv.args[0]);
910
         LOG_DEBUG ("Kernel: %s", procnto_name);
967
         LOG_DEBUG ("Kernel: %s",  procnto_argv.args[0]);
911
 
-
 
912
         sprintf (candidate_pathname, "%s/%s", (entry_parms->prefix != NULL ? entry_parms->prefix : ""), procnto_name); // fix the entry name
-
 
913
         stored_pathname = candidate_pathname;
-
 
914
         entry_parms->extra_ino_flags |= /*IFS_INO_PROCESSED_ELF | */IFS_INO_BOOTSTRAP_EXE; // procnto needs to have these flags stamped on the inode
-
 
915
         entry_parms->st_mode = S_IFREG | entry_parms->perms; // apply specified procnto permissions
-
 
916
         image_kernel_ino = entry_parms->extra_ino_flags | (inode_count + 1);
-
 
917
 
968
 
918
         static thread_local char linker_pathname[MAXPATHLEN] = "";
969
         static thread_local char linker_pathname[MAXPATHLEN] = "";
919
         static thread_local char linker_sysroot_arg[MAXPATHLEN] = "";
970
         static thread_local char linker_sysroot_arg[MAXPATHLEN] = "";
920
         static thread_local char linker_script_pathname_arg[MAXPATHLEN] = "";
971
         static thread_local char linker_script_pathname_arg[MAXPATHLEN] = "";
921
         static thread_local char procnto_buildhost_pathname[MAXPATHLEN] = "";
972
         static thread_local char procnto_buildhost_pathname[MAXPATHLEN] = "";
922
         static thread_local char procnto_sym_filename[MAXPATHLEN] = "";
973
         static thread_local char procnto_sym_filename[MAXPATHLEN] = "";
-
 
974
         buffer_t bootargs_buffer = { 0 };
-
 
975
         char *bootargs_location;
923
 
976
 
924
         // construct the arguments that are based on environment variables (infer QNX_HOST from QNX_TARGET)
977
         // construct the arguments that are based on environment variables (infer QNX_HOST from QNX_TARGET)
925
#if defined(_WIN32)
978
#if defined(_WIN32)
926
         sprintf (linker_pathname, "%s/../../host/win64/x86_64/usr/bin/%s-ld.exe", QNX_TARGET, (strcmp (image_processor, "x86_64") == 0 ? "x86_64-pc-nto-qnx8.0.0" : "aarch64-unknown-nto-qnx8.0.0")); // Win32: note the .exe extension
979
         sprintf_s (linker_pathname, sizeof (linker_pathname), "%s/../../host/win64/x86_64/usr/bin/%s-ld.exe", QNX_TARGET, (strcmp (image_processor, "x86_64") == 0 ? "x86_64-pc-nto-qnx8.0.0" : "aarch64-unknown-nto-qnx8.0.0")); // Win32: note the .exe extension
927
#elif defined(__linux__)
980
#elif defined(__linux__)
928
         sprintf (linker_pathname, "%s/../../host/linux/x86_64/usr/bin/%s-ld", QNX_TARGET, (strcmp (image_processor, "x86_64") == 0 ? "x86_64-pc-nto-qnx8.0.0" : "aarch64-unknown-nto-qnx8.0.0"));
981
         sprintf_s (linker_pathname, sizeof (linker_pathname), "%s/../../host/linux/x86_64/usr/bin/%s-ld", QNX_TARGET, (strcmp (image_processor, "x86_64") == 0 ? "x86_64-pc-nto-qnx8.0.0" : "aarch64-unknown-nto-qnx8.0.0"));
929
#elif defined(__QNXNTO__)
982
#elif defined(__QNXNTO__)
930
         sprintf (linker_pathname, "%s/../../host/qnx8/x86_64/usr/bin/%s-ld", QNX_TARGET, (strcmp (image_processor, "x86_64") == 0 ? "x86_64-pc-nto-qnx8.0.0" : "aarch64-unknown-nto-qnx8.0.0"));
983
         sprintf_s (linker_pathname, sizeof (linker_pathname), "%s/../../host/qnx8/x86_64/usr/bin/%s-ld", QNX_TARGET, (strcmp (image_processor, "x86_64") == 0 ? "x86_64-pc-nto-qnx8.0.0" : "aarch64-unknown-nto-qnx8.0.0"));
931
#else // wtf are you building this on?
984
#else // wtf are you building this on?
932
#error Please port the GNU linker x86_64-pc-nto-qnx8.0.0-ld and aarch64-unknown-nto-qnx8.0.0-ld to your host architecture first before compiling ifstool.
985
#error Please port the GNU linker x86_64-pc-nto-qnx8.0.0-ld and aarch64-unknown-nto-qnx8.0.0-ld to your host architecture first before compiling ifstool.
933
#endif
986
#endif
934
         ASSERT (access (linker_pathname, 0) == 0, "host cross-linker for QNX8 \"%s\" not found", linker_pathname);
987
         ASSERT (access (linker_pathname, 0) == 0, "host cross-linker for QNX8 \"%s\" not found", linker_pathname);
935
         sprintf (linker_sysroot_arg, "--sysroot=%s/%s/", QNX_TARGET, image_processor);
988
         sprintf_s (linker_sysroot_arg, sizeof (linker_sysroot_arg), "--sysroot=%s/%s/", QNX_TARGET, image_processor);
936
         sprintf (linker_script_pathname_arg, "-T%s/%s/lib/nto.link", QNX_TARGET, image_processor);
989
         sprintf_s (linker_script_pathname_arg, sizeof (linker_script_pathname_arg), "-T%s/%s/lib/nto.link", QNX_TARGET, image_processor);
937
 
990
 
938
         resolved_pathname = resolve_pathname (procnto_name, entry_parms->search); // locate the procnto kernel location
991
         resolved_pathname = resolve_pathname (procnto_argv.args[0], entry_parms->search); // locate the procnto kernel location
939
         ASSERT (resolved_pathname, "QNX kernel \"%s\" not found in search path", procnto_name);
992
         ASSERT (resolved_pathname, "QNX kernel \"%s\" not found in search path", procnto_argv.args[0]);
940
         strcpy (procnto_buildhost_pathname, resolved_pathname);
993
         strcpy_s (procnto_buildhost_pathname, sizeof (procnto_buildhost_pathname), resolved_pathname);
941
 
994
 
942
         sprintf_s (procnto_sym_filename, sizeof (procnto_sym_filename), "%s.sym%s", procnto_name, sym_suffix);
995
         sprintf_s (procnto_sym_filename, sizeof (procnto_sym_filename), "%s.sym%s", procnto_argv.args[0], sym_suffix);
943
 
996
 
944
         const char *linker_argv[] = // construct the linker invokation argv
997
         // construct the linker invokation command-line arguments array (argv)
945
         {
998
         STRINGARRAY_INIT (&linker_argv);
946
            strrchr (linker_pathname, '/') + 1, // "${TARGET_TRIPLE}-ld"
999
         STRINGARRAY_PUSH (&linker_argv, strrchr (linker_pathname, '/') + 1); // "${TARGET_TRIPLE}-ld"
947
            linker_sysroot_arg, // "--sysroot=${QNX_TARGET}/${TARGET_CPU}/"
1000
         STRINGARRAY_PUSH (&linker_argv, linker_sysroot_arg); // "--sysroot=${QNX_TARGET}/${TARGET_CPU}/"
948
            linker_script_pathname_arg, // "-T${QNX_TARGET}/${TARGET_CPU}/lib/nto.link"
1001
         STRINGARRAY_PUSH (&linker_argv, linker_script_pathname_arg); // "-T${QNX_TARGET}/${TARGET_CPU}/lib/nto.link"
949
            "--section-start",
1002
         STRINGARRAY_PUSH (&linker_argv, "--section-start");
950
            ".text=0xffff800000001000",
1003
         STRINGARRAY_PUSH (&linker_argv, ".text=0xffff800000001000");
951
            "--no-relax",
1004
         STRINGARRAY_PUSH (&linker_argv, "--no-relax");
952
            procnto_buildhost_pathname, // "${QNX_TARGET}/${TARGET_CPU}/boot/sys/procnto-smp-instr"
1005
         STRINGARRAY_PUSH (&linker_argv, procnto_buildhost_pathname); // "${QNX_TARGET}/${TARGET_CPU}/boot/sys/procnto-smp-instr"
953
            "-o",
1006
         STRINGARRAY_PUSH (&linker_argv, "-o");
954
            procnto_sym_filename, // "procnto-smp-instr.sym"
1007
         STRINGARRAY_PUSH (&linker_argv, procnto_sym_filename); // "procnto-smp-instr.sym"
955
            NULL
1008
         STRINGARRAY_PUSH (&linker_argv, NULL); // don't forget to terminate the argv array with a NULL pointer
956
         };
-
 
957
         if (verbose_level > 2)
1009
         if (verbose_level > 2)
958
         {
1010
         {
959
            fprintf (stderr, "ifstool: calling:");
1011
            fprintf (stderr, "ifstool: calling:");
960
            for (table_index = 0; table_index < sizeof (linker_argv) / sizeof (linker_argv[0]) - 1; table_index++)
1012
            for (array_index = 0; array_index < linker_argv.count - 1; array_index++)
961
               fprintf (stderr, " '%s'", linker_argv[table_index]);
1013
               fprintf (stderr, " '%s'", linker_argv.args[array_index]);
962
            fputc ('\n', stderr);
1014
            fputc ('\n', stderr);
963
         }
1015
         }
-
 
1016
#ifdef _WIN32
964
         _spawnv (_P_WAIT, linker_pathname, linker_argv); // spawn the linker and produce a stripped procnto (wait for completion)
1017
         _spawnv (_P_WAIT, linker_pathname, linker_argv.args); // spawn the linker and produce a stripped procnto (wait for completion)
-
 
1018
#else // !_WIN32, thus POSIX
-
 
1019
         do {
-
 
1020
            int status;
-
 
1021
            pid_t pid = fork (); // duplicate ourselves so as to create a new process
-
 
1022
            ASSERT_WITH_ERRNO (pid != -1);
-
 
1023
            if (pid == 0)
-
 
1024
            {
-
 
1025
               execv (linker_pathname, linker_argv); // spawn the child process
-
 
1026
               DIE_WITH_EXITCODE (1, "execve() failed"); // exec never returns
-
 
1027
            }
-
 
1028
            else
-
 
1029
               waitpid (pid, &status, 0); // wait for the child to finish
-
 
1030
         } while (0);
-
 
1031
#endif // _WIN32
-
 
1032
         STRINGARRAY_FREE (&linker_argv);
965
         if (!Buffer_ReadFromFile (&entry_parms->data, procnto_sym_filename)) // load the output file
1033
         if (!Buffer_ReadFromFile (&entry_parms->data, procnto_sym_filename)) // load the output file
966
            DIE_WITH_EXITCODE (1, "the host cross-linker failed to produce a readable stripped \"%s\" kernel: %s", procnto_sym_filename, strerror (errno));
1034
            DIE_WITH_EXITCODE (1, "the host cross-linker failed to produce a readable stripped \"%s\" kernel: %s", procnto_sym_filename, strerror (errno));
967
         if (!entry_parms->should_keep_ld_output)
1035
         if (!entry_parms->should_keep_ld_output)
968
            unlink (procnto_sym_filename); // remove the linker output file if we want to
1036
            unlink (procnto_sym_filename); // remove the linker output file if we want to
-
 
1037
 
-
 
1038
         // save the boot arguments. The magic to look for is "ddpvbskr" -- whatever that means
-
 
1039
         if ((bootargs_location = Buffer_FindFirstByteArray (&entry_parms->data, "ddpvbskr")) == NULL)
-
 
1040
            DIE_WITH_EXITCODE (1, "unable to find boot args location in the stripped \"%s\" kernel", stored_pathname);
-
 
1041
         Buffer_InitWithSize (&bootargs_buffer, sizeof (bootargs_entry_t)); // prepare a boot args entry
-
 
1042
         ((bootargs_entry_t *) bootargs_buffer.bytes)->argc = (uint8_t) procnto_argv.count;
-
 
1043
         ((bootargs_entry_t *) bootargs_buffer.bytes)->envc = (uint8_t) (global_envp.count + procnto_envp.count);
-
 
1044
         ((bootargs_entry_t *) bootargs_buffer.bytes)->shdr_addr = (uint32_t) (image_base + bootfile_size); // same value as startup_header.image_paddr (which is not set yet) (TODO: support 64-bit shdr_addr offsets -- see comment in bootargs_entry_t struct)
-
 
1045
         for (array_index = 0; array_index < procnto_argv.count; array_index++)
-
 
1046
            ASSERT_WITH_ERRNO (Buffer_Append (&bootargs_buffer, procnto_argv.args[array_index], strlen (procnto_argv.args[array_index]) + 1)); // append string including NUL terminator
-
 
1047
         for (array_index = 0; array_index < global_envp.count; array_index++)
-
 
1048
            ASSERT_WITH_ERRNO (Buffer_Append (&bootargs_buffer, global_envp.args[array_index], strlen (global_envp.args[array_index]) + 1)); // append string including NUL terminator
-
 
1049
         for (array_index = 0; array_index < procnto_envp.count; array_index++)
-
 
1050
            ASSERT_WITH_ERRNO (Buffer_Append (&bootargs_buffer, procnto_envp.args[array_index], strlen (procnto_envp.args[array_index]) + 1)); // append string including NUL terminator
-
 
1051
         ((bootargs_entry_t *) bootargs_buffer.bytes)->size_hi = (uint8_t) ((bootargs_buffer.size >> 8) & 0xff);
-
 
1052
         ((bootargs_entry_t *) bootargs_buffer.bytes)->size_lo = (uint8_t) ((bootargs_buffer.size >> 0) & 0xff);
-
 
1053
         ASSERT_WITH_ERRNO (Buffer_WriteBufferAt (&entry_parms->data, (size_t) bootargs_location - (size_t) entry_parms->data.bytes, &bootargs_buffer));
-
 
1054
         Buffer_Forget (&bootargs_buffer); // release the boot args buffer once it's written
969
 
1055
 
970
         // now strip this prelinked ELF kernel file
1056
         // now strip this prelinked ELF kernel file
971
         Buffer_StripELFFile (&entry_parms->data, (const char **) saved_ELF_sections, 1, stored_pathname); // strip the ELF file as per QNX docs (only keep ONE section, which is "QNX_info")
1057
         ASSERT_WITH_ERRNO (Buffer_StripELFFile (&entry_parms->data, (const char **) saved_ELF_sections, 1, true, stored_pathname)); // strip the ELF file as per QNX docs (only keep ONE section, which is "QNX_info", and align the segment size in file with the size it occupies in memory)
-
 
1058
 
-
 
1059
         sprintf_s (candidate_pathname, MAXPATHLEN, "%s/%s", (entry_parms->prefix != NULL ? entry_parms->prefix : ""), procnto_argv.args[0]); // fix the entry name
-
 
1060
         stored_pathname = candidate_pathname;
-
 
1061
 
972
         entry_parms->extra_ino_flags |= IFS_INO_PROCESSED_ELF; // mark this inode as a preprocessed ELF file
1062
         entry_parms->extra_ino_flags |= IFS_INO_PROCESSED_ELF | IFS_INO_BOOTSTRAP_EXE; // mark this inode as a preprocessed *bootstrap* ELF file
-
 
1063
         entry_parms->st_mode = S_IFREG | entry_parms->perms; // procnto is a regular file
-
 
1064
         image_kernel_ino = entry_parms->extra_ino_flags | (inode_count + 1);
973
 
1065
 
974
#else // !PROCNTO_WIP
-
 
975
         /* HACK *//* HACK *//* HACK *//* HACK *//* HACK *//* HACK *//* HACK *//* HACK *//* HACK *//* HACK *//* HACK *//* HACK *//* HACK *//* HACK *//* HACK *//* HACK */
-
 
976
         /* HACK *//* HACK *//* HACK *//* HACK *//* HACK *//* HACK *//* HACK *//* HACK *//* HACK *//* HACK *//* HACK *//* HACK *//* HACK *//* HACK *//* HACK *//* HACK */
-
 
977
         /* HACK */
-
 
978
         /* HACK */ sprintf_s (candidate_pathname, MAXPATHLEN, "%s/procnto-smp-instr", (entry_parms->prefix != NULL ? entry_parms->prefix : "")); // HACK: fix the entry name
-
 
979
         /* HACK */ stored_pathname = candidate_pathname;
-
 
980
         /* HACK */ entry_parms->extra_ino_flags |= IFS_INO_PROCESSED_ELF | IFS_INO_BOOTSTRAP_EXE; // procnto needs to have these flags stamped on the inode
-
 
981
         /* HACK */ entry_parms->st_mode = S_IFREG | 0700; // procnto requires 0700 permissions
1066
         STRINGARRAY_FREE (&procnto_argv); // release procnto's argv array
982
         /* HACK */ image_kernel_ino = entry_parms->extra_ino_flags | (inode_count + 1);
-
 
983
         /* HACK */ free (entry_parms->data.bytes); // discard inline contents
1067
         STRINGARRAY_FREE (&procnto_envp); // release procnto's envp array
984
         /* HACK */ Buffer_Initialize (&entry_parms->data);
1068
         STRINGARRAY_FREE (&global_envp); // release the global envp array
985
         /* HACK */ if (!Buffer_ReadFromFile (&entry_parms->data, kernelfile_pathname)) // read kernel file as a precompiled binary blob
-
 
986
         /* HACK */ {
-
 
987
         /* HACK */    fprintf (stderr, "fatal error: unable to read precompiled kernel file \"%s\" specified in --kernelfile argument\n", kernelfile_pathname);
-
 
988
         /* HACK */    exit (1);
-
 
989
         /* HACK */ }
-
 
990
         /* HACK */
-
 
991
         /* HACK *//* HACK *//* HACK *//* HACK *//* HACK *//* HACK *//* HACK *//* HACK *//* HACK *//* HACK *//* HACK *//* HACK *//* HACK *//* HACK *//* HACK *//* HACK */
-
 
992
         /* HACK *//* HACK *//* HACK *//* HACK *//* HACK *//* HACK *//* HACK *//* HACK *//* HACK *//* HACK *//* HACK *//* HACK *//* HACK *//* HACK *//* HACK *//* HACK */
-
 
993
#endif // PROCNTO_WIP
-
 
994
      }
1069
      }
995
      else if (entry_parms->is_compiled_bootscript) // else is it a startup script ?
1070
      else if (entry_parms->is_compiled_bootscript) // else is it a startup script ?
996
         image_bootscript_ino = inode_count + 1; // save boot script inode number for image header
1071
         image_bootscript_ino = inode_count + 1; // save boot script inode number for image header
997
 
1072
 
998
      // do we already know the data for this data blob ?
1073
      // do we already know the data for this data blob ?
Line 1065... Line 1140...
1065
         } // end if the file we're storing is a dylib
1140
         } // end if the file we're storing is a dylib
1066
 
1141
 
1067
         // now strip this ELF file if necessary
1142
         // now strip this ELF file if necessary
1068
         if (!(entry_parms->extra_ino_flags & IFS_INO_PROCESSED_ELF))
1143
         if (!(entry_parms->extra_ino_flags & IFS_INO_PROCESSED_ELF))
1069
         {
1144
         {
1070
            Buffer_StripELFFile (&entry_parms->data, (const char **) saved_ELF_sections, saved_ELF_section_count, stored_pathname); // strip the ELF file à la mkifs
1145
            Buffer_StripELFFile (&entry_parms->data, (const char **) saved_ELF_sections, saved_ELF_section_count, false, stored_pathname); // strip the ELF file à la mkifs
1071
            entry_parms->extra_ino_flags |= IFS_INO_PROCESSED_ELF; // mark this inode as a preprocessed ELF file
1146
            entry_parms->extra_ino_flags |= IFS_INO_PROCESSED_ELF; // mark this inode as a preprocessed ELF file
1072
         } // end if the file is not yet a processed ELF
1147
         } // end if the file is not yet a processed ELF
1073
      } // end if the file we're storing is an ELF file
1148
      } // end if the file we're storing is an ELF file
1074
      #undef ELFHDR // undefine the macro that used to always point to the ELF header at the beginning of the file
1149
      #undef ELFHDR // undefine the macro that used to always point to the ELF header at the beginning of the file
1075
   }
1150
   }
Line 1357... Line 1432...
1357
            if ((sep = strchr (value, '=')) != NULL) image_totalsize = (uint32_t) read_integer (sep + 1); // if we have an equal sign, read optional image padding size
1432
            if ((sep = strchr (value, '=')) != NULL) image_totalsize = (uint32_t) read_integer (sep + 1); // if we have an equal sign, read optional image padding size
1358
            if ((sep = strchr (value, '%')) != NULL) image_align     = (uint32_t) read_integer (sep + 1); // if we have a modulo sign, read optional image aligmnent
1433
            if ((sep = strchr (value, '%')) != NULL) image_align     = (uint32_t) read_integer (sep + 1); // if we have a modulo sign, read optional image aligmnent
1359
            LOG_INFO ("image 0x%x-0x%x maxsize %d totalsize %d align %d", image_base, image_end, image_maxsize, image_totalsize, image_align);
1434
            LOG_INFO ("image 0x%x-0x%x maxsize %d totalsize %d align %d", image_base, image_end, image_maxsize, image_totalsize, image_align);
1360
         }
1435
         }
1361
         else if (strncmp (token, "virtual=", 8) == 0) { REACH_TOKEN_VALUE ();
1436
         else if (strncmp (token, "virtual=", 8) == 0) { REACH_TOKEN_VALUE ();
1362
            if ((bootfile_pathname == NULL) || (startupfile_pathname == NULL) || (kernelfile_pathname == NULL)) // HACK until I figure out how to re-create them
1437
            if ((bootfile_pathname == NULL) || (startupfile_pathname == NULL)) // HACK until I figure out how to re-create them
1363
               DIE_WITH_EXITCODE (1, "creating bootable images require the --bootfile, --startupfile and --kernelfile command-line options in \"%s\" line %d", buildfile_pathname, lineno);
1438
               DIE_WITH_EXITCODE (1, "creating bootable images require the --bootfile, --startupfile and --kernelfile command-line options in \"%s\" line %d", buildfile_pathname, lineno);
1364
            if ((sep = strchr (value, ',')) != NULL) // do we have a comma separating (optional) processor and boot file name ?
1439
            if ((sep = strchr (value, ',')) != NULL) // do we have a comma separating (optional) processor and boot file name ?
1365
            {
1440
            {
1366
               *sep = 0;
1441
               *sep = 0;
1367
               strcpy_s (image_processor, sizeof (image_processor), value); // save processor
1442
               strcpy_s (image_processor, sizeof (image_processor), value); // save processor
Line 1371... Line 1446...
1371
            //strcpy (image_bootfile, bootfile_pathname); // FIXME: HACK
1446
            //strcpy (image_bootfile, bootfile_pathname); // FIXME: HACK
1372
            if (stat (bootfile_pathname, &stat_buf) != 0)
1447
            if (stat (bootfile_pathname, &stat_buf) != 0)
1373
               DIE_WITH_EXITCODE (1, "unable to stat the boot file \"%s\" specified in \"%s\" line %d: %s", bootfile_pathname, buildfile_pathname, lineno, strerror (errno));
1448
               DIE_WITH_EXITCODE (1, "unable to stat the boot file \"%s\" specified in \"%s\" line %d: %s", bootfile_pathname, buildfile_pathname, lineno, strerror (errno));
1374
            bootfile_size = stat_buf.st_size; // save preboot file size
1449
            bootfile_size = stat_buf.st_size; // save preboot file size
1375
            LOG_INFO ("processor \"%s\" bootfile \"%s\"\n", image_processor, bootfile_pathname);
1450
            LOG_INFO ("processor \"%s\" bootfile \"%s\"\n", image_processor, bootfile_pathname);
1376
#if 1
-
 
1377
            // ######################################################################################################################################################################################################################################
-
 
1378
            // # FIXME: figure out how to re-create it: linker call involved
-
 
1379
            // # $ x86_64-pc-nto-qnx8.0.0-ld --sysroot=${QNX_TARGET}/x86_64/ -T${QNX_TARGET}/x86_64/lib/nto.link --section-start .text=0xffff800000001000 --no-relax ${QNX_TARGET}/x86_64/boot/sys/procnto-smp-instr -o procnto-smp-instr.sym.UNSTRIPPED
-
 
1380
            // ######################################################################################################################################################################################################################################
-
 
1381
//               if (!Buffer_ReadFromFile (&entry_parms.data, kernelfile_pathname))
-
 
1382
//                  DIE_WITH_EXITCODE (1, "unable to read precompiled kernel file \"%s\" specified in --kernelfile argument: %s", kernelfile_pathname, strerror (errno));
-
 
1383
#else // nonworking
-
 
1384
            strcpy (path_on_buildhost, "procnto-smp-instr");
1451
            entry_parms.is_bootstrap_file = true;
1385
#endif // nonworking
-
 
1386
         }
1452
         }
1387
         else if (strncmp (token, "mtime=", 6) == 0) { REACH_TOKEN_VALUE (); if (strcmp (value, "*") == 0) entry_parms.mtime = UINT32_MAX; else {
1453
         else if (strncmp (token, "mtime=", 6) == 0) { REACH_TOKEN_VALUE (); if (strcmp (value, "*") == 0) entry_parms.mtime = UINT32_MAX; else {
1388
               // value *must* be "YYYY-MM-DD-HH:MM:SS" by specification
1454
               // value *must* be "YYYY-MM-DD-HH:MM:SS" by specification
1389
               memset (&utc_time, 0, sizeof (utc_time));
1455
               memset (&utc_time, 0, sizeof (utc_time));
1390
               if (sscanf_s (value, "%u-%u-%u-%u:%u:%u", &utc_time.tm_year, &utc_time.tm_mon, &utc_time.tm_mday, &utc_time.tm_hour, &utc_time.tm_min, &utc_time.tm_sec) != 6)
1456
               if (sscanf_s (value, "%u-%u-%u-%u:%u:%u", &utc_time.tm_year, &utc_time.tm_mon, &utc_time.tm_mday, &utc_time.tm_hour, &utc_time.tm_min, &utc_time.tm_sec) != 6)
Line 1692... Line 1758...
1692
            DIE_WITH_EXITCODE (1, "the --startupfile arguments expects <pathname>@<entrypoint_from_image_base>");
1758
            DIE_WITH_EXITCODE (1, "the --startupfile arguments expects <pathname>@<entrypoint_from_image_base>");
1693
         *sep = 0;
1759
         *sep = 0;
1694
         startupfile_pathname = argv[arg_index];
1760
         startupfile_pathname = argv[arg_index];
1695
         startupfile_ep_from_imagebase = (size_t) read_integer (sep + 1);
1761
         startupfile_ep_from_imagebase = (size_t) read_integer (sep + 1);
1696
      }
1762
      }
1697
      else if ((strcmp (argv[arg_index], "--kernelfile") == 0) && (arg_index + 1 < argc)) // --kernelfile path/to/blob.bin@0x32000
1763
      else if ((strcmp (argv[arg_index], "--kerneloffs") == 0) && (arg_index + 1 < argc)) // --kerneloffs 0x32000 (undocumented)
1698
      {
-
 
1699
         sep = strchr (argv[++arg_index], '@');
-
 
1700
         if ((sep == NULL) || (sep[1] == 0))
-
 
1701
            DIE_WITH_EXITCODE (1, "the --kernelfile arguments expects <pathname>@<fileoffset>");
-
 
1702
         *sep = 0;
-
 
1703
         kernelfile_pathname = argv[arg_index];
-
 
1704
         kernelfile_offset = (size_t) read_integer (sep + 1);
1764
         kernelfile_offset = (size_t) read_integer (argv[++arg_index]);
1705
      }
-
 
1706
      else if ((strcmp (argv[arg_index], "-a") == 0) && (arg_index + 1 < argc)) // -a suffix
1765
      else if ((strcmp (argv[arg_index], "-a") == 0) && (arg_index + 1 < argc)) // -a suffix
1707
         sym_suffix = argv[++arg_index];
1766
         sym_suffix = argv[++arg_index];
1708
      else if (strcmp (argv[arg_index], "-n") == 0)
1767
      else if (strcmp (argv[arg_index], "-n") == 0)
1709
         default_parms.mtime_for_inline_files = 0; // inline files should have a mtime set to zero
1768
         default_parms.mtime_for_inline_files = 0; // inline files should have a mtime set to zero
1710
      else if (strcmp (argv[arg_index], "-nn") == 0)
1769
      else if (strcmp (argv[arg_index], "-nn") == 0)
Line 1747... Line 1806...
1747
         saved_ELF_sections = reallocated_ptr;
1806
         saved_ELF_sections = reallocated_ptr;
1748
         saved_ELF_sections[saved_ELF_section_count++] = argv[++arg_index]; // stack up another ELF section name to preserve
1807
         saved_ELF_sections[saved_ELF_section_count++] = argv[++arg_index]; // stack up another ELF section name to preserve
1749
      }
1808
      }
1750
      else if ((strcmp (argv[arg_index], "-?") == 0) || (strcmp (argv[arg_index], "--help") == 0))
1809
      else if ((strcmp (argv[arg_index], "-?") == 0) || (strcmp (argv[arg_index], "--help") == 0))
1751
         want_help = true;
1810
         want_help = true;
1752
      else if (first_pathname == NULL)
1811
      else if ((first_pathname == NULL) && (*argv[arg_index] != '-'))
1753
         first_pathname = argv[arg_index];
1812
         first_pathname = argv[arg_index];
1754
      else if (second_pathname == NULL)
1813
      else if ((second_pathname == NULL) && (*argv[arg_index] != '-'))
1755
         second_pathname = argv[arg_index];
1814
         second_pathname = argv[arg_index];
1756
      else if (third_pathname == NULL)
1815
      else if ((third_pathname == NULL) && (*argv[arg_index] != '-'))
1757
         third_pathname = argv[arg_index];
1816
         third_pathname = argv[arg_index];
1758
      else
1817
      else
1759
         DIE_WITH_EXITCODE (1, "unrecognized option: '%s'", argv[arg_index]);
1818
         DIE_WITH_EXITCODE (1, "unrecognized option: '%s'", argv[arg_index]);
1760
   }
1819
   }
1761
 
1820
 
Line 1860... Line 1919...
1860
   // else do we want to strip an ELF file ? if so, do so
1919
   // else do we want to strip an ELF file ? if so, do so
1861
   else if (want_strip)
1920
   else if (want_strip)
1862
   {
1921
   {
1863
      buffer_t file;
1922
      buffer_t file;
1864
      ASSERT (Buffer_ReadFromFile (&file, first_pathname), "can't open \"%s\" for reading: %s", first_pathname, strerror (errno));
1923
      ASSERT (Buffer_ReadFromFile (&file, first_pathname), "can't open \"%s\" for reading: %s", first_pathname, strerror (errno));
1865
      ASSERT (Buffer_StripELFFile (&file, (const char **) saved_ELF_sections, saved_ELF_section_count, first_pathname), "error stripping \"%s\": %s", first_pathname, strerror (errno));
1924
      ASSERT (Buffer_StripELFFile (&file, (const char **) saved_ELF_sections, saved_ELF_section_count, false, first_pathname), "error stripping \"%s\": %s", first_pathname, strerror (errno));
1866
      ASSERT_WITH_ERRNO (Buffer_WriteToFile (&file, (second_pathname != NULL ? second_pathname : "<stdout>")));
1925
      ASSERT_WITH_ERRNO (Buffer_WriteToFile (&file, (second_pathname != NULL ? second_pathname : "<stdout>")));
1867
      exit (0);
1926
      exit (0);
1868
   }
1927
   }
1869
 
1928
 
1870
   // we want to CREATE an IFS file
1929
   // we want to CREATE an IFS file
Line 2006... Line 2065...
2006
      curr_offset += fsentries[fsentry_index].header.size; // advance to the next one
2065
      curr_offset += fsentries[fsentry_index].header.size; // advance to the next one
2007
   }
2066
   }
2008
   ASSERT_WITH_ERRNO (Buffer_AppendByteArray (&ifs.data, "\0\0\0\0")); // there seems to be 4 bytes of padding after the image directory
2067
   ASSERT_WITH_ERRNO (Buffer_AppendByteArray (&ifs.data, "\0\0\0\0")); // there seems to be 4 bytes of padding after the image directory
2009
   imgdir_size = ifs.data.size - ifs.offsets.imagedir; // measure image dir size and save it for future use
2068
   imgdir_size = ifs.data.size - ifs.offsets.imagedir; // measure image dir size and save it for future use
2010
 
2069
 
2011
   // is it a bootable image with a kernel file ?
2070
   // is it a bootable image with a startup file ?
2012
   if ((startupfile_pathname != NULL) && (kernelfile_pathname != NULL))
2071
   if (startupfile_pathname != NULL)
2013
   {
2072
   {
2014
      // start by writing the startup script data blob, if we have one
2073
      // start by writing the startup script data blob, if we have one
2015
      for (fsentry_index = 1; fsentry_index < fsentry_count; fsentry_index++)
2074
      for (fsentry_index = 1; fsentry_index < fsentry_count; fsentry_index++)
2016
         if (fsentries[fsentry_index].header.ino == image_bootscript_ino)
2075
         if (fsentries[fsentry_index].header.ino == image_bootscript_ino)
2017
            break; // locate the startup script directory entry
2076
            break; // locate the startup script directory entry
2018
      if (fsentry_index < fsentry_count) // found it ?
2077
      if (fsentry_index < fsentry_count) // found it ?
2019
      {
2078
      {
2020
         if (ifs.data.size + fsentries[fsentry_index].u.file.size >= kernelfile_offset)
2079
         if (ifs.data.size + fsentries[fsentry_index].u.file.size >= kernelfile_offset)
2021
            DIE_WITH_EXITCODE (1, "the compiled startup script is too big (%zd bytes, max is %zd) to fit at current offset %zd", (size_t) fsentries[fsentry_index].u.file.size, kernelfile_offset - ifs.data.size, ifs.data.size);
2080
            DIE_WITH_EXITCODE (1, "the compiled startup script is too big (%zd bytes, max is %zd) to fit at current offset %zd. Use --kerneloffs <addr> to relocate (warning: untested)", (size_t) fsentries[fsentry_index].u.file.size, kernelfile_offset - ifs.data.size, ifs.data.size);
2022
         fsentries[fsentry_index].u.file.offset = (uint32_t) (ifs.data.size - ifs.offsets.imageheader); // save file data blob offset in file structure
2081
         fsentries[fsentry_index].u.file.offset = (uint32_t) (ifs.data.size - ifs.offsets.imageheader); // save file data blob offset in file structure
2023
         Buffer_AppendIFSFileData (&ifs.data, &fsentries[fsentry_index]); // write file data
2082
         Buffer_AppendIFSFileData (&ifs.data, &fsentries[fsentry_index]); // write file data
2024
         fsentries[fsentry_index].UNSAVED_was_data_written = true; // and remember this file's data was written
2083
         fsentries[fsentry_index].UNSAVED_was_data_written = true; // and remember this file's data was written
2025
      }
2084
      }
2026
 
2085
 
Line 2057... Line 2116...
2057
      // now write the QNX kernel
2116
      // now write the QNX kernel
2058
      for (fsentry_index = 1; fsentry_index < fsentry_count; fsentry_index++)
2117
      for (fsentry_index = 1; fsentry_index < fsentry_count; fsentry_index++)
2059
         if (fsentries[fsentry_index].header.ino == image_kernel_ino)
2118
         if (fsentries[fsentry_index].header.ino == image_kernel_ino)
2060
            break; // locate the kernel directory entry (can't fail)
2119
            break; // locate the kernel directory entry (can't fail)
2061
      fsentries[fsentry_index].u.file.offset = (uint32_t) (ifs.data.size - ifs.offsets.imageheader); // save file data blob offset in file structure
2120
      fsentries[fsentry_index].u.file.offset = (uint32_t) (ifs.data.size - ifs.offsets.imageheader); // save file data blob offset in file structure
2062
#ifdef PROCNTO_WIP
-
 
2063
      // is the kernel we're storing a preprocessed ELF kernel ?
-
 
2064
      if (fsentries[fsentry_index].header.ino & IFS_INO_PROCESSED_ELF)
-
 
2065
      {
-
 
2066
         elf = (elf_header_t *) fsentries[fsentry_index].u.file.UNSAVED_databuf; // quick access to ELF header
-
 
2067
         table_count = ELF_GET_NUMERIC (elf, elf, program_header_table_len); // get the number of program headers
-
 
2068
         for (table_index = 0; table_index < table_count; table_index++)
-
 
2069
         {
-
 
2070
            phdr = (elf_program_header_t *) &fsentries[fsentry_index].u.file.UNSAVED_databuf[ELF_GET_NUMERIC (elf, elf, program_header_table_offset) + (size_t) ELF_GET_NUMERIC (elf, elf, program_header_item_size) * table_index]; // quick access to program header
-
 
2071
            corrective_offset = ELF_GET_NUMERIC (elf, phdr, virtual_addr) - ELF_GET_NUMERIC (elf, phdr, file_offset);
-
 
2072
            if (ELF_GET_NUMERIC (elf, phdr, size_in_memory) != 0) // only patch the physical address of segments that have an actual size in memory
-
 
2073
               ELF_SET_NUMERIC (elf, phdr, physical_addr, ELF_GET_NUMERIC (elf, phdr, physical_addr) + image_base + ifs.data.size - corrective_offset); // patch the physical address member of the program header table (NOTE: ifs.data.size is the location where the file data is about to be written)
-
 
2074
         }
-
 
2075
      }
-
 
2076
#endif // PROCNTO_WIP
-
 
2077
      Buffer_AppendIFSFileData (&ifs.data, &fsentries[fsentry_index]); // write kernel file data
2121
      Buffer_AppendIFSFileData (&ifs.data, &fsentries[fsentry_index]); // write kernel file data
2078
      fsentries[fsentry_index].UNSAVED_was_data_written = true; // and remember this file's data was written
2122
      fsentries[fsentry_index].UNSAVED_was_data_written = true; // and remember this file's data was written
2079
   }
2123
   }
2080
 
2124
 
2081
   // then write all the other files by increasing inode number: ELF files first
2125
   // then write all the other files by increasing inode number: ELF files first