Rev 10 | Rev 12 | Go to most recent revision | Show entire file | Ignore whitespace | Details | Blame | Last modification | View Log | RSS feed
Rev 10 | Rev 11 | ||
---|---|---|---|
Line 10... | Line 10... | ||
10 | #include <sys/stat.h> |
10 | #include <sys/stat.h> |
11 | #include <ctype.h> |
11 | #include <ctype.h> |
12 | #include <time.h> |
12 | #include <time.h> |
13 | 13 | ||
14 | 14 | ||
- | 15 | // compiler-specific glue |
|
15 | #ifdef _MSC_VER |
16 | #ifdef _MSC_VER |
16 | #include <io.h> |
17 | #include <io.h> |
17 | #define __x86_64__ 1 |
18 | #define __x86_64__ 1 |
18 | #define __ORDER_BIG_ENDIAN__ 4321 |
19 | #define __ORDER_BIG_ENDIAN__ 4321 |
19 | #define __ORDER_LITTLE_ENDIAN__ 1234 |
20 | #define __ORDER_LITTLE_ENDIAN__ 1234 |
Line 33... | Line 34... | ||
33 | #define access(p,m) _access ((p), (m)) |
34 | #define access(p,m) _access ((p), (m)) |
34 | #define MAXPATHLEN 1024 |
35 | #define MAXPATHLEN 1024 |
35 | #ifndef thread_local |
36 | #ifndef thread_local |
36 | #define thread_local __declspec(thread) // the thread_local keyword wasn't defined before C++11 and C23 |
37 | #define thread_local __declspec(thread) // the thread_local keyword wasn't defined before C++11 and C23 |
37 | #endif // !thread_local |
38 | #endif // !thread_local |
- | 39 | #define START_OF_PACKED_STRUCT() __pragma(pack(push)) __pragma(pack(1)) |
|
- | 40 | #define END_OF_PACKED_STRUCT() __pragma(pack(pop)) |
|
- | 41 | #define PACKED(thing) thing |
|
38 | #else // !_MSC_VER |
42 | #else // !_MSC_VER |
39 | #include <sys/param.h> |
43 | #include <sys/param.h> |
40 | #include <unistd.h> |
44 | #include <unistd.h> |
41 | #ifndef thread_local |
45 | #ifndef thread_local |
42 | #define thread_local __thread // the thread_local keyword wasn't defined before C++11 and C23 |
46 | #define thread_local __thread // the thread_local keyword wasn't defined before C++11 and C23 |
43 | #endif // !thread_local |
47 | #endif // !thread_local |
- | 48 | #define START_OF_PACKED_STRUCT() |
|
- | 49 | #define END_OF_PACKED_STRUCT() |
|
- | 50 | #define PACKED(thing) thing __attribute__((packed)) |
|
44 | #endif // _MSC_VER |
51 | #endif // _MSC_VER |
45 | 52 | ||
46 | 53 | ||
47 | // handy macros that generate a version number in the format "YYYYMMDD" corresponding to the build date. Usage: printf ("version " VERSION_FMT_YYYYMMDD "\n", VERSION_ARG_YYYYMMDD); |
54 | // handy macros that generate a version number in the format "YYYYMMDD" corresponding to the build date. Usage: printf ("version " VERSION_FMT_YYYYMMDD "\n", VERSION_ARG_YYYYMMDD); |
48 | #ifndef VERSION_ARG_YYYYMMDD |
55 | #ifndef VERSION_ARG_YYYYMMDD |
49 | #define BUILDDATE_YEAR (&__DATE__[7]) // compiler will optimize this into a const string, e.g. "2021" |
56 | #define BUILDDATE_YEAR (&__DATE__[7]) // compiler will optimize this into a const string, e.g. "2021" |
- | 57 | #define BUILDDATE_MONTH ( \ |
|
50 |
|
58 | *((uint32_t *) __DATE__) == *((uint32_t *) "Jan ") ? "01" : \ |
51 | |
59 | *((uint32_t *) __DATE__) == *((uint32_t *) "Feb ") ? "02" : \ |
52 | |
60 | *((uint32_t *) __DATE__) == *((uint32_t *) "Mar ") ? "03" : \ |
53 | |
61 | *((uint32_t *) __DATE__) == *((uint32_t *) "Apr ") ? "04" : \ |
54 | |
62 | *((uint32_t *) __DATE__) == *((uint32_t *) "May ") ? "05" : \ |
55 | |
63 | *((uint32_t *) __DATE__) == *((uint32_t *) "Jun ") ? "06" : \ |
56 | |
64 | *((uint32_t *) __DATE__) == *((uint32_t *) "Jul ") ? "07" : \ |
57 | |
65 | *((uint32_t *) __DATE__) == *((uint32_t *) "Aug ") ? "08" : \ |
58 | |
66 | *((uint32_t *) __DATE__) == *((uint32_t *) "Sep ") ? "09" : \ |
59 | |
67 | *((uint32_t *) __DATE__) == *((uint32_t *) "Oct ") ? "10" : \ |
60 | |
68 | *((uint32_t *) __DATE__) == *((uint32_t *) "Nov ") ? "11" : \ |
61 | |
69 | *((uint32_t *) __DATE__) == *((uint32_t *) "Dec ") ? "12" : \ |
- | 70 | "XX" \ |
|
- | 71 | ) // compiler will optimize this into a const string, e.g. "11" |
|
- | 72 | #define BUILDDATE_DAY ( \ |
|
62 |
|
73 | *((uint32_t *) &__DATE__[3]) == *((uint32_t *) " 1 ") ? "01" : \ |
63 | |
74 | *((uint32_t *) &__DATE__[3]) == *((uint32_t *) " 2 ") ? "02" : \ |
64 | |
75 | *((uint32_t *) &__DATE__[3]) == *((uint32_t *) " 3 ") ? "03" : \ |
65 | |
76 | *((uint32_t *) &__DATE__[3]) == *((uint32_t *) " 4 ") ? "04" : \ |
66 | |
77 | *((uint32_t *) &__DATE__[3]) == *((uint32_t *) " 5 ") ? "05" : \ |
67 | |
78 | *((uint32_t *) &__DATE__[3]) == *((uint32_t *) " 6 ") ? "06" : \ |
68 | |
79 | *((uint32_t *) &__DATE__[3]) == *((uint32_t *) " 7 ") ? "07" : \ |
69 | |
80 | *((uint32_t *) &__DATE__[3]) == *((uint32_t *) " 8 ") ? "08" : \ |
70 | |
81 | *((uint32_t *) &__DATE__[3]) == *((uint32_t *) " 9 ") ? "09" : \ |
71 | |
82 | *((uint32_t *) &__DATE__[3]) == *((uint32_t *) " 10 ") ? "10" : \ |
72 | |
83 | *((uint32_t *) &__DATE__[3]) == *((uint32_t *) " 11 ") ? "11" : \ |
73 | |
84 | *((uint32_t *) &__DATE__[3]) == *((uint32_t *) " 12 ") ? "12" : \ |
74 | |
85 | *((uint32_t *) &__DATE__[3]) == *((uint32_t *) " 13 ") ? "13" : \ |
75 | |
86 | *((uint32_t *) &__DATE__[3]) == *((uint32_t *) " 14 ") ? "14" : \ |
76 | |
87 | *((uint32_t *) &__DATE__[3]) == *((uint32_t *) " 15 ") ? "15" : \ |
77 | |
88 | *((uint32_t *) &__DATE__[3]) == *((uint32_t *) " 16 ") ? "16" : \ |
78 | |
89 | *((uint32_t *) &__DATE__[3]) == *((uint32_t *) " 17 ") ? "17" : \ |
79 | |
90 | *((uint32_t *) &__DATE__[3]) == *((uint32_t *) " 18 ") ? "18" : \ |
80 | |
91 | *((uint32_t *) &__DATE__[3]) == *((uint32_t *) " 19 ") ? "19" : \ |
81 | |
92 | *((uint32_t *) &__DATE__[3]) == *((uint32_t *) " 20 ") ? "20" : \ |
82 | |
93 | *((uint32_t *) &__DATE__[3]) == *((uint32_t *) " 21 ") ? "21" : \ |
83 | |
94 | *((uint32_t *) &__DATE__[3]) == *((uint32_t *) " 22 ") ? "22" : \ |
84 | |
95 | *((uint32_t *) &__DATE__[3]) == *((uint32_t *) " 23 ") ? "23" : \ |
85 | |
96 | *((uint32_t *) &__DATE__[3]) == *((uint32_t *) " 24 ") ? "24" : \ |
86 | |
97 | *((uint32_t *) &__DATE__[3]) == *((uint32_t *) " 25 ") ? "25" : \ |
87 | |
98 | *((uint32_t *) &__DATE__[3]) == *((uint32_t *) " 26 ") ? "26" : \ |
88 | |
99 | *((uint32_t *) &__DATE__[3]) == *((uint32_t *) " 27 ") ? "27" : \ |
89 | |
100 | *((uint32_t *) &__DATE__[3]) == *((uint32_t *) " 28 ") ? "28" : \ |
90 | |
101 | *((uint32_t *) &__DATE__[3]) == *((uint32_t *) " 29 ") ? "29" : \ |
91 | |
102 | *((uint32_t *) &__DATE__[3]) == *((uint32_t *) " 30 ") ? "30" : \ |
92 | |
103 | *((uint32_t *) &__DATE__[3]) == *((uint32_t *) " 31 ") ? "31" : \ |
- | 104 | "XX" \ |
|
- | 105 | ) // compiler will optimize this into a const string, e.g. "14" |
|
93 | #define VERSION_FMT_YYYYMMDD "%04s%02s%02s" |
106 | #define VERSION_FMT_YYYYMMDD "%04s%02s%02s" |
94 | #define VERSION_ARG_YYYYMMDD BUILDDATE_YEAR, BUILDDATE_MONTH, BUILDDATE_DAY |
107 | #define VERSION_ARG_YYYYMMDD BUILDDATE_YEAR, BUILDDATE_MONTH, BUILDDATE_DAY |
95 | #endif // !VERSION_ARG_YYYYMMDD |
108 | #endif // !VERSION_ARG_YYYYMMDD |
96 | 109 | ||
97 | 110 | ||
98 | // |
111 | // macro to bring __FILE_NAME__ support to moronic compilers |
- | 112 | #ifndef __FILE_NAME__ // Clang 9+ has the macro, GCC 12+ added it too in 2021, MSVC obviously won't do it. Heh. |
|
- | 113 | #define __FILE_NAME__ ( \ |
|
- | 114 | (sizeof (__FILE__) > 2) && (__FILE__[sizeof (__FILE__) - 2] == '/') ? &__FILE__[sizeof (__FILE__) - 1] : \ |
|
- | 115 | (sizeof (__FILE__) > 3) && (__FILE__[sizeof (__FILE__) - 3] == '/') ? &__FILE__[sizeof (__FILE__) - 2] : \ |
|
- | 116 | (sizeof (__FILE__) > 4) && (__FILE__[sizeof (__FILE__) - 4] == '/') ? &__FILE__[sizeof (__FILE__) - 3] : \ |
|
- | 117 | (sizeof (__FILE__) > 5) && (__FILE__[sizeof (__FILE__) - 5] == '/') ? &__FILE__[sizeof (__FILE__) - 4] : \ |
|
- | 118 | (sizeof (__FILE__) > 6) && (__FILE__[sizeof (__FILE__) - 6] == '/') ? &__FILE__[sizeof (__FILE__) - 5] : \ |
|
- | 119 | (sizeof (__FILE__) > 7) && (__FILE__[sizeof (__FILE__) - 7] == '/') ? &__FILE__[sizeof (__FILE__) - 6] : \ |
|
- | 120 | (sizeof (__FILE__) > 8) && (__FILE__[sizeof (__FILE__) - 8] == '/') ? &__FILE__[sizeof (__FILE__) - 7] : \ |
|
- | 121 | (sizeof (__FILE__) > 9) && (__FILE__[sizeof (__FILE__) - 9] == '/') ? &__FILE__[sizeof (__FILE__) - 8] : \ |
|
- | 122 | (sizeof (__FILE__) > 10) && (__FILE__[sizeof (__FILE__) - 10] == '/') ? &__FILE__[sizeof (__FILE__) - 9] : \ |
|
- | 123 | (sizeof (__FILE__) > 11) && (__FILE__[sizeof (__FILE__) - 11] == '/') ? &__FILE__[sizeof (__FILE__) - 10] : \ |
|
- | 124 | (sizeof (__FILE__) > 12) && (__FILE__[sizeof (__FILE__) - 12] == '/') ? &__FILE__[sizeof (__FILE__) - 11] : \ |
|
- | 125 | (sizeof (__FILE__) > 13) && (__FILE__[sizeof (__FILE__) - 13] == '/') ? &__FILE__[sizeof (__FILE__) - 12] : \ |
|
- | 126 | (sizeof (__FILE__) > 14) && (__FILE__[sizeof (__FILE__) - 14] == '/') ? &__FILE__[sizeof (__FILE__) - 13] : \ |
|
- | 127 | (sizeof (__FILE__) > 15) && (__FILE__[sizeof (__FILE__) - 15] == '/') ? &__FILE__[sizeof (__FILE__) - 14] : \ |
|
- | 128 | (sizeof (__FILE__) > 16) && (__FILE__[sizeof (__FILE__) - 16] == '/') ? &__FILE__[sizeof (__FILE__) - 15] : \ |
|
- | 129 | (sizeof (__FILE__) > 17) && (__FILE__[sizeof (__FILE__) - 17] == '/') ? &__FILE__[sizeof (__FILE__) - 16] : \ |
|
- | 130 | (sizeof (__FILE__) > 18) && (__FILE__[sizeof (__FILE__) - 18] == '/') ? &__FILE__[sizeof (__FILE__) - 17] : \ |
|
99 |
|
131 | (sizeof (__FILE__) > 19) && (__FILE__[sizeof (__FILE__) - 19] == '/') ? &__FILE__[sizeof (__FILE__) - 18] : \ |
- | 132 | (sizeof (__FILE__) > 20) && (__FILE__[sizeof (__FILE__) - 20] == '/') ? &__FILE__[sizeof (__FILE__) - 19] : \ |
|
- | 133 | (sizeof (__FILE__) > 21) && (__FILE__[sizeof (__FILE__) - 21] == '/') ? &__FILE__[sizeof (__FILE__) - 20] : \ |
|
- | 134 | (sizeof (__FILE__) > 22) && (__FILE__[sizeof (__FILE__) - 22] == '/') ? &__FILE__[sizeof (__FILE__) - 21] : \ |
|
- | 135 | (sizeof (__FILE__) > 23) && (__FILE__[sizeof (__FILE__) - 23] == '/') ? &__FILE__[sizeof (__FILE__) - 22] : \ |
|
- | 136 | (sizeof (__FILE__) > 24) && (__FILE__[sizeof (__FILE__) - 24] == '/') ? &__FILE__[sizeof (__FILE__) - 23] : \ |
|
- | 137 | (sizeof (__FILE__) > 25) && (__FILE__[sizeof (__FILE__) - 25] == '/') ? &__FILE__[sizeof (__FILE__) - 24] : \ |
|
- | 138 | (sizeof (__FILE__) > 26) && (__FILE__[sizeof (__FILE__) - 26] == '/') ? &__FILE__[sizeof (__FILE__) - 25] : \ |
|
- | 139 | (sizeof (__FILE__) > 27) && (__FILE__[sizeof (__FILE__) - 27] == '/') ? &__FILE__[sizeof (__FILE__) - 26] : \ |
|
- | 140 | (sizeof (__FILE__) > 28) && (__FILE__[sizeof (__FILE__) - 28] == '/') ? &__FILE__[sizeof (__FILE__) - 27] : \ |
|
- | 141 | (sizeof (__FILE__) > 29) && (__FILE__[sizeof (__FILE__) - 29] == '/') ? &__FILE__[sizeof (__FILE__) - 28] : \ |
|
- | 142 | (sizeof (__FILE__) > 30) && (__FILE__[sizeof (__FILE__) - 30] == '/') ? &__FILE__[sizeof (__FILE__) - 29] : \ |
|
- | 143 | (sizeof (__FILE__) > 31) && (__FILE__[sizeof (__FILE__) - 31] == '/') ? &__FILE__[sizeof (__FILE__) - 30] : \ |
|
- | 144 | (sizeof (__FILE__) > 32) && (__FILE__[sizeof (__FILE__) - 32] == '/') ? &__FILE__[sizeof (__FILE__) - 31] : \ |
|
- | 145 | (sizeof (__FILE__) > 33) && (__FILE__[sizeof (__FILE__) - 33] == '/') ? &__FILE__[sizeof (__FILE__) - 32] : \ |
|
- | 146 | __FILE__) // this *COMPILE-TIME* macro complements the __FILE__ macro defined by the C standard by returning just the filename portion of the full path. Supports filenames up to 32 chars. Expand as necessary. |
|
- | 147 | #endif // !__FILE_NAME__ |
|
100 | 148 | ||
101 | 149 | ||
102 | // exit less brutally than with abort() if something doesn't go the way we'd like to |
150 | // macro to exit less brutally than with abort() if something doesn't go the way we'd like to |
103 | #define WELLMANNERED_ASSERT(is_is_true,...) do { if (!(is_is_true)) { fprintf (stderr, "ifstool: fatal error: |
151 | #define WELLMANNERED_ASSERT(is_is_true,...) do { if (!(is_is_true)) { fprintf (stderr, "ifstool: fatal error: consistency check in %s() at %s line %d failed: ", __FUNCTION__, __FILE_NAME__, __LINE__); fprintf (stderr, __VA_ARGS__); fputc ('\n', stderr); exit (1); } } while (0) |
104 | 152 | ||
105 | 153 | ||
106 | // checked read/write/seek operations |
154 | // macros for checked read/write/seek operations |
107 | #define fseek_or_die(fp,pos,mode) |
155 | #define fseek_or_die(fp,pos,mode) WELLMANNERED_ASSERT (fseek ((fp), (pos), (mode)) == 0, "fseek() failed with errno %d (%s)", errno, strerror (errno)) |
108 | #define fread_or_die(buf,sz,len,fp) |
156 | #define fread_or_die(buf,sz,len,fp) WELLMANNERED_ASSERT (fread ((buf), (sz), (len), (fp)) == (len), "fread() failed with errno %d (%s)", errno, strerror (errno)) |
109 | #define fwrite_or_die(buf,sz,len,fp) |
157 | #define fwrite_or_die(buf,sz,len,fp) WELLMANNERED_ASSERT ((fwrite ((buf), (sz), (len), (fp)) == (len)) && (fflush ((fp)) == 0), "flushed fwrite() failed with errno %d (%s)", errno, strerror (errno)) |
110 | 158 | ||
111 | - | ||
112 | #define ROUND_TO_UPPER_MULTIPLE(val,multiple) ((((val) + (size_t) (multiple) - 1) / (multiple)) * (multiple)) // note that val is being evaluated once, so it can be the result of a function call |
- | |
113 | #ifdef _WIN32 |
- | |
114 | #define IS_DIRSEP(c) (((c) == '/') || ((c) == '\\')) |
- | |
115 | #define PATH_SEP ';' |
- | |
116 | #define PATH_SEP_STR ";" |
- | |
117 | #else // !_WIN32, thus POSIX |
- | |
118 | #define IS_DIRSEP(c) ((c) == '/') |
- | |
119 | #define PATH_SEP ':' |
- | |
120 | #define PATH_SEP_STR ":" |
- | |
121 | #endif // _WIN32 |
- | |
122 | #define RECORD_SEP '\x1e' // ASCII record separator |
- | |
123 | #define RECORD_SEP_STR "\x1e" // ASCII record separator (as string) |
- | |
124 | 159 | ||
125 | // macros for accessing ELF files |
160 | // macros for accessing ELF files |
126 | #define ELF_MAGIC_STR "\x7f" "ELF" |
161 | #define ELF_MAGIC_STR "\x7f" "ELF" |
127 | #define ELF_ENDIAN_LITTLE 1 // 'endianness' member of an ELF header: ELF file is little endian |
162 | #define ELF_ENDIAN_LITTLE 1 // 'endianness' member of an ELF header: ELF file is little endian |
128 | #define ELF_ENDIAN_BIG 2 // 'endianness' member of an ELF header: ELF file is big endian |
163 | #define ELF_ENDIAN_BIG 2 // 'endianness' member of an ELF header: ELF file is big endian |
Line 164... | Line 199... | ||
164 | #define ELF_GET_STRING(elfhdr,elfstruct,member) ((elfhdr)->u.elf.platform_size == 2 ? (elfstruct)->u.elf64.member : (elfstruct)->u.elf32.member) // this macro supports 32- and 64-bit ELF files transparently |
199 | #define ELF_GET_STRING(elfhdr,elfstruct,member) ((elfhdr)->u.elf.platform_size == 2 ? (elfstruct)->u.elf64.member : (elfstruct)->u.elf32.member) // this macro supports 32- and 64-bit ELF files transparently |
165 | #define ELF_SET_STRING(elfhdr,elfstruct,member,data,len) memcpy (((elfhdr)->u.elf.platform_size == 2 ? (elfstruct)->u.elf64.member : (elfstruct)->u.elf32.member), (data), (len)) // this macro supports 32- and 64-bit ELF files transparently |
200 | #define ELF_SET_STRING(elfhdr,elfstruct,member,data,len) memcpy (((elfhdr)->u.elf.platform_size == 2 ? (elfstruct)->u.elf64.member : (elfstruct)->u.elf32.member), (data), (len)) // this macro supports 32- and 64-bit ELF files transparently |
166 | #define ELF_STRUCT_SIZE(elfhdr,elfstruct) ((elfhdr)->u.elf.platform_size == 2 ? sizeof ((elfstruct)->u.elf64) : sizeof ((elfstruct)->u.elf32)) // this macro supports 32- and 64-bit ELF files transparently |
201 | #define ELF_STRUCT_SIZE(elfhdr,elfstruct) ((elfhdr)->u.elf.platform_size == 2 ? sizeof ((elfstruct)->u.elf64) : sizeof ((elfstruct)->u.elf32)) // this macro supports 32- and 64-bit ELF files transparently |
167 | 202 | ||
168 | 203 | ||
169 | - | ||
- | 204 | // placeholder value |
|
170 | #define WILL_BE_FILLED_LATER 0xbaadf00d |
205 | #define WILL_BE_FILLED_LATER 0xbaadf00d // urgh |
171 | 206 | ||
172 | 207 | ||
173 | // bitmapped flags used in the flags1 member of the startup header |
208 | // bitmapped flags used in the flags1 member of the startup header |
174 | #define STARTUP_HDR_FLAGS1_VIRTUAL (1 << 0) |
209 | #define STARTUP_HDR_FLAGS1_VIRTUAL (1 << 0) |
175 | #define STARTUP_HDR_FLAGS1_BIGENDIAN (1 << 1) |
210 | #define STARTUP_HDR_FLAGS1_BIGENDIAN (1 << 1) |
Line 192... | Line 227... | ||
192 | 227 | ||
193 | // bitmapped flags superposed to a filesystem entry's inode number |
228 | // bitmapped flags superposed to a filesystem entry's inode number |
194 | #define IFS_INO_PROCESSED_ELF 0x80000000 |
229 | #define IFS_INO_PROCESSED_ELF 0x80000000 |
195 | #define IFS_INO_RUNONCE_ELF 0x40000000 |
230 | #define IFS_INO_RUNONCE_ELF 0x40000000 |
196 | #define IFS_INO_BOOTSTRAP_EXE 0x20000000 |
231 | #define IFS_INO_BOOTSTRAP_EXE 0x20000000 |
- | 232 | ||
- | 233 | ||
- | 234 | // miscellaneous macros |
|
- | 235 | #define ROUND_TO_UPPER_MULTIPLE(val,multiple) ((((val) + (size_t) (multiple) - 1) / (multiple)) * (multiple)) // note that val is being evaluated once, so it can be the result of a function call |
|
- | 236 | #ifdef _WIN32 |
|
- | 237 | #define IS_DIRSEP(c) (((c) == '/') || ((c) == '\\')) // platform-specific directory separator, Win32 variant |
|
- | 238 | #define PATH_SEP ';' // platform-specific PATH element separator, Win32 variant |
|
- | 239 | #define PATH_SEP_STR ";" // platform-specific PATH element separator (as string), Win32 variant |
|
- | 240 | #else // !_WIN32, thus POSIX |
|
- | 241 | #define IS_DIRSEP(c) ((c) == '/') // platform-specific directory separator, UNIX variant |
|
- | 242 | #define PATH_SEP ':' // platform-specific PATH element separator, UNIX variant |
|
- | 243 | #define PATH_SEP_STR ":" // platform-specific PATH element separator (as string), UNIX variant |
|
- | 244 | #endif // _WIN32 |
|
- | 245 | #define RECORD_SEP '\x1e' // arbitrarily-chosen ASCII record separator |
|
- | 246 | #define RECORD_SEP_STR "\x1e" // arbitrarily-chosen ASCII record separator (as string) |
|
197 | 247 | ||
198 | 248 | ||
199 | // SHA-512 block and digest sizes |
249 | // SHA-512 block and digest sizes |
200 | #define SHA512_BLOCK_LENGTH 128 // in bytes |
250 | #define SHA512_BLOCK_LENGTH 128 // in bytes |
201 | #define SHA512_DIGEST_LENGTH 64 // in bytes |
251 | #define SHA512_DIGEST_LENGTH 64 // in bytes |
Line 206... | Line 256... | ||
206 | { |
256 | { |
207 | uint64_t state[8]; |
257 | uint64_t state[8]; |
208 | uint64_t bitcount[2]; |
258 | uint64_t bitcount[2]; |
209 | uint8_t buffer[SHA512_BLOCK_LENGTH]; |
259 | uint8_t buffer[SHA512_BLOCK_LENGTH]; |
210 | } SHA512_CTX; |
260 | } SHA512_CTX; |
211 | - | ||
212 | - | ||
213 | #ifdef _MSC_VER |
- | |
214 | #pragma pack(push) |
- | |
215 | #pragma pack(1) |
- | |
216 | #endif // _MSC_VER |
- | |
217 | 261 | ||
218 | 262 | ||
219 | #if 0 // TODO: startup script compiler. Someday. |
263 | #if 0 // TODO: startup script compiler. Someday. |
220 | #define SCRIPT_FLAGS_EXTSCHED 0x01 |
264 | #define SCRIPT_FLAGS_EXTSCHED 0x01 |
221 | #define SCRIPT_FLAGS_SESSION 0x02 |
265 | #define SCRIPT_FLAGS_SESSION 0x02 |
Line 245... | Line 289... | ||
245 | #define SCRIPT_APS_SYSTEM_PARTITION_NAME "System" |
289 | #define SCRIPT_APS_SYSTEM_PARTITION_NAME "System" |
246 | #define SCRIPT_APS_PARTITION_NAME_LENGTH 15 |
290 | #define SCRIPT_APS_PARTITION_NAME_LENGTH 15 |
247 | #define SCRIPT_APS_MAX_PARTITIONS 8 |
291 | #define SCRIPT_APS_MAX_PARTITIONS 8 |
248 | 292 | ||
249 | 293 | ||
- | 294 | START_OF_PACKED_STRUCT () // we need byte-alignment for this struct |
|
250 | typedef |
295 | typedef PACKED (struct) bootscriptcmd_header_s |
251 | { |
296 | { |
252 | uint16_t size; // size of cmd entry |
297 | uint16_t size; // size of cmd entry |
253 | uint8_t type; |
298 | uint8_t type; |
254 | uint8_t spare; |
299 | uint8_t spare; |
255 | } bootscriptcmd_header_t; |
300 | } bootscriptcmd_header_t; |
- | 301 | END_OF_PACKED_STRUCT () // restore default alignment |
|
256 | 302 | ||
257 | 303 | ||
- | 304 | START_OF_PACKED_STRUCT () // we need byte-alignment for this struct |
|
258 | typedef union bootscriptcmd_s |
305 | typedef union bootscriptcmd_s |
259 | { |
306 | { |
260 |
|
307 | PACKED (struct) script_external |
261 | { |
308 | { |
262 | bootscriptcmd_header_t hdr; |
309 | bootscriptcmd_header_t hdr; |
263 | uint8_t cpu; // CPU (turn into runmask) |
310 | uint8_t cpu; // CPU (turn into runmask) |
264 | uint8_t flags; |
311 | uint8_t flags; |
265 | union script_external_extsched |
312 | union script_external_extsched |
266 | { |
313 | { |
267 | uint8_t reserved[2]; |
314 | uint8_t reserved[2]; |
268 |
|
315 | PACKED (struct) |
269 | { |
316 | { |
270 | uint8_t id; |
317 | uint8_t id; |
271 | uint8_t reserved[1]; |
318 | uint8_t reserved[1]; |
272 | } aps; |
319 | } aps; |
273 | } extsched; // extended scheduler |
320 | } extsched; // extended scheduler |
Line 275... | Line 322... | ||
275 | uint8_t priority; // priority to run cmd at |
322 | uint8_t priority; // priority to run cmd at |
276 | uint8_t argc; // # of args |
323 | uint8_t argc; // # of args |
277 | uint8_t envc; // # of environment entries |
324 | uint8_t envc; // # of environment entries |
278 | char args[0]; // executable, argv, envp (null padded to 32-bit align) |
325 | char args[0]; // executable, argv, envp (null padded to 32-bit align) |
279 | } external; |
326 | } external; |
280 |
|
327 | PACKED (struct) script_waitfor_reopen |
281 | { |
328 | { |
282 | bootscriptcmd_header_t hdr; |
329 | bootscriptcmd_header_t hdr; |
283 | uint16_t checks; |
330 | uint16_t checks; |
284 | char fname[0]; // char fname[] (null padded to 32-bit align) |
331 | char fname[0]; // char fname[] (null padded to 32-bit align) |
285 | } waitfor_reopen; |
332 | } waitfor_reopen; |
286 |
|
333 | PACKED (struct) script_display_msg |
287 | { |
334 | { |
288 | bootscriptcmd_header_t hdr; |
335 | bootscriptcmd_header_t hdr; |
289 | char msg[0]; // char msg[] (null padded to 32-bit align) |
336 | char msg[0]; // char msg[] (null padded to 32-bit align) |
290 | } display_msg; |
337 | } display_msg; |
291 |
|
338 | PACKED (struct) script_procmgr_symlink |
292 | { |
339 | { |
293 | bootscriptcmd_header_t hdr; |
340 | bootscriptcmd_header_t hdr; |
294 | char src_dest[0]; // <src_name>, '\0', <dest_name> '\0' (null padded to 32-bit align) |
341 | char src_dest[0]; // <src_name>, '\0', <dest_name> '\0' (null padded to 32-bit align) |
295 | } procmgr_symlink; |
342 | } procmgr_symlink; |
296 |
|
343 | PACKED (struct) script_extsched_aps |
297 | { |
344 | { |
298 | bootscriptcmd_header_t hdr; |
345 | bootscriptcmd_header_t hdr; |
299 | uint8_t parent; |
346 | uint8_t parent; |
300 | uint8_t budget; |
347 | uint8_t budget; |
301 | uint16_t critical; |
348 | uint16_t critical; |
302 | uint8_t id; |
349 | uint8_t id; |
303 | char pname[0]; // char pname[] (null padded to 32-bit align) |
350 | char pname[0]; // char pname[] (null padded to 32-bit align) |
304 | } extsched_aps; |
351 | } extsched_aps; |
305 | } bootscriptcmd_t; |
352 | } bootscriptcmd_t; |
- | 353 | END_OF_PACKED_STRUCT () // restore default alignment |
|
306 | #endif // 0 |
354 | #endif // 0 |
307 | 355 | ||
308 | 356 | ||
309 | #define INITIAL_STARTUP_SCRIPT \ |
357 | #define INITIAL_STARTUP_SCRIPT \ |
310 | /* procmgr_symlink /proc/boot/ldqnx-64.so.2 /usr/lib/ldqnx-64.so.2 */ \ |
358 | /* procmgr_symlink /proc/boot/ldqnx-64.so.2 /usr/lib/ldqnx-64.so.2 */ \ |
Line 315... | Line 363... | ||
315 | "\x18\x00" /*size*/ "\x03" /*type*/ "\x00" /*spare*/ "Startup complete\n\0" "\x00\00" /*padding*/ \ |
363 | "\x18\x00" /*size*/ "\x03" /*type*/ "\x00" /*spare*/ "Startup complete\n\0" "\x00\00" /*padding*/ \ |
316 | /* trailer */ \ |
364 | /* trailer */ \ |
317 | "\x00\x00\x00\x00" |
365 | "\x00\x00\x00\x00" |
318 | 366 | ||
319 | 367 | ||
- | 368 | START_OF_PACKED_STRUCT () // we need byte-alignment for this struct |
|
320 | typedef |
369 | typedef PACKED (struct) fsentry_s |
321 | { |
370 | { |
322 |
|
371 | PACKED (struct) fsentry_header_s |
323 | { |
372 | { |
324 | uint16_t size; // size of dirent |
373 | uint16_t size; // size of dirent |
325 | uint16_t extattr_offset; // if zero, no extattr data |
374 | uint16_t extattr_offset; // if zero, no extattr data |
326 | uint32_t ino; // if zero, skip entry |
375 | uint32_t ino; // if zero, skip entry |
327 | uint32_t mode; // mode and perms of entry |
376 | uint32_t mode; // mode and perms of entry |
328 | uint32_t gid; |
377 | uint32_t gid; |
329 | uint32_t uid; |
378 | uint32_t uid; |
330 | uint32_t mtime; |
379 | uint32_t mtime; |
331 | } header; |
380 | } header; |
332 |
|
381 | PACKED (union) fsentry_specific_u |
333 | { |
382 | { |
334 |
|
383 | PACKED (struct) fsentry_file_s // when (mode & S_IFMT) == S_IFREG |
335 | { |
384 | { |
336 | uint32_t offset; // offset from header |
385 | uint32_t offset; // offset from header |
337 | uint32_t size; |
386 | uint32_t size; |
338 | char *path; // null terminated path (no leading slash) |
387 | char *path; // null terminated path (no leading slash) |
339 | char *UNSAVED_databuf; // file data blob buffer (NOT SAVED IN THE IFS) |
388 | char *UNSAVED_databuf; // file data blob buffer (NOT SAVED IN THE IFS) |
340 | } file; |
389 | } file; |
341 |
|
390 | PACKED (struct) fsentry_dir_s // when (mode & S_IFMT) == S_IFDIR |
342 | { |
391 | { |
343 | char *path; // null terminated path (no leading slash) |
392 | char *path; // null terminated path (no leading slash) |
344 | } dir; |
393 | } dir; |
345 |
|
394 | PACKED (struct) fsentry_symlink_s // when (mode & S_IFMT) == S_IFLNK |
346 | { |
395 | { |
347 | uint16_t sym_offset; // offset to 'contents' from 'path' |
396 | uint16_t sym_offset; // offset to 'contents' from 'path' |
348 | uint16_t sym_size; // strlen (contents) |
397 | uint16_t sym_size; // strlen (contents) |
349 | char *path; // null terminated path (no leading slash) |
398 | char *path; // null terminated path (no leading slash) |
350 | char *contents; // null terminated symlink contents |
399 | char *contents; // null terminated symlink contents |
351 | } symlink; |
400 | } symlink; |
352 |
|
401 | PACKED (struct) fsentry_device_s // when (mode & S_IFMT) == S_IF<CHR|BLK|FIFO|NAM|SOCK> |
353 | { |
402 | { |
354 | uint32_t dev; |
403 | uint32_t dev; |
355 | uint32_t rdev; |
404 | uint32_t rdev; |
356 | char *path; // null terminated path (no leading slash) |
405 | char *path; // null terminated path (no leading slash) |
357 | } device; |
406 | } device; |
358 | } u; |
407 | } u; |
359 | bool UNSAVED_was_data_written; // whether this entry's data was written to the image (NOT SAVED IN THE IFS) |
408 | bool UNSAVED_was_data_written; // whether this entry's data was written to the image (NOT SAVED IN THE IFS) |
360 | } fsentry_t; |
409 | } fsentry_t; |
- | 410 | END_OF_PACKED_STRUCT () // restore default alignment |
|
361 | 411 | ||
362 | 412 | ||
- | 413 | START_OF_PACKED_STRUCT () // we need byte-alignment for this struct |
|
363 | typedef |
414 | typedef PACKED (struct) startup_header_s // size 256 bytes |
364 | { |
415 | { |
365 |
|
416 | // I - used by the QNX IPL |
366 |
|
417 | // S - used by the startup program |
367 | uint8_t signature[4]; // [I ] Header signature, "\xeb\x7e\xff\x00" |
418 | uint8_t signature[4]; // [I ] Header signature, "\xeb\x7e\xff\x00" |
368 | uint16_t version; // [I ] Header version, i.e. 1 |
419 | uint16_t version; // [I ] Header version, i.e. 1 |
369 | uint8_t flags1; // [IS] Misc flags, 0x21 (= 0x20 | STARTUP_HDR_FLAGS1_VIRTUAL) |
420 | uint8_t flags1; // [IS] Misc flags, 0x21 (= 0x20 | STARTUP_HDR_FLAGS1_VIRTUAL) |
370 | uint8_t flags2; // [ ] No flags defined yet (0) |
421 | uint8_t flags2; // [ ] No flags defined yet (0) |
371 | uint16_t header_size; // [ S] sizeof(struct startup_header), i.e. 256 |
422 | uint16_t header_size; // [ S] sizeof(struct startup_header), i.e. 256 |
Line 383... | Line 434... | ||
383 | uint16_t zero0; // [ ] Zeros |
434 | uint16_t zero0; // [ ] Zeros |
384 | uint32_t zero[1]; // [ ] Zeros |
435 | uint32_t zero[1]; // [ ] Zeros |
385 | uint64_t addr_off; // [ S] Offset to add to startup_vaddr, image_paddr, ram_paddr, and imagefs_paddr members, here zero (0) |
436 | uint64_t addr_off; // [ S] Offset to add to startup_vaddr, image_paddr, ram_paddr, and imagefs_paddr members, here zero (0) |
386 | uint32_t info[48]; // [IS] Array of startup_info* structures (zero filled) |
437 | uint32_t info[48]; // [IS] Array of startup_info* structures (zero filled) |
387 | } startup_header_t; |
438 | } startup_header_t; |
- | 439 | END_OF_PACKED_STRUCT () // restore default alignment |
|
388 | 440 | ||
389 | 441 | ||
- | 442 | START_OF_PACKED_STRUCT () // we need byte-alignment for this struct |
|
390 | typedef |
443 | typedef PACKED (struct) startup_trailer_s |
391 | { |
444 | { |
392 | uint32_t cksum; // checksum from start of header to start of trailer |
445 | uint32_t cksum; // checksum from start of header to start of trailer |
393 | } startup_trailer_v1_t; |
446 | } startup_trailer_v1_t; |
- | 447 | END_OF_PACKED_STRUCT () // restore default alignment |
|
394 | 448 | ||
395 | 449 | ||
396 | // NOTE: The checksums in this trailer will only be valid prior to entering startup. |
450 | // NOTE: The checksums in this trailer will only be valid prior to entering startup. |
397 | // Because the startup binary is executed in-place, its data segment will change once the program is running. |
451 | // Because the startup binary is executed in-place, its data segment will change once the program is running. |
398 | // Hence, any checksum validation would need to be done by the boot loader / IFS. |
452 | // Hence, any checksum validation would need to be done by the boot loader / IFS. |
- | 453 | START_OF_PACKED_STRUCT () // we need byte-alignment for this struct |
|
399 | typedef |
454 | typedef PACKED (struct) startup_trailer_v2_s |
400 | { |
455 | { |
401 | uint8_t sha512[64]; // SHA512 from start of header to start of trailer |
456 | uint8_t sha512[64]; // SHA512 from start of header to start of trailer |
402 | uint32_t cksum; // checksum from start of header to start of this member |
457 | uint32_t cksum; // checksum from start of header to start of this member |
403 | } startup_trailer_v2_t; |
458 | } startup_trailer_v2_t; |
- | 459 | END_OF_PACKED_STRUCT () // restore default alignment |
|
404 | 460 | ||
405 | 461 | ||
- | 462 | START_OF_PACKED_STRUCT () // we need byte-alignment for this struct |
|
406 | typedef |
463 | typedef PACKED (struct) image_header_s |
407 | { |
464 | { |
408 | uint8_t signature[7]; // image filesystem signature, i.e. "imagefs" |
465 | uint8_t signature[7]; // image filesystem signature, i.e. "imagefs" |
409 | uint8_t flags; // endian neutral flags, 0x1c |
466 | uint8_t flags; // endian neutral flags, 0x1c |
410 | uint32_t image_size; // size from start of header to end of trailer (here 0xca6fe0 or 13 266 912) |
467 | uint32_t image_size; // size from start of header to end of trailer (here 0xca6fe0 or 13 266 912) |
411 | uint32_t hdr_dir_size; // size from start of header to last dirent (here 0x12b8 or 4792) |
468 | uint32_t hdr_dir_size; // size from start of header to last dirent (here 0x12b8 or 4792) |
Line 415... | Line 472... | ||
415 | uint32_t chain_paddr; // offset to next filesystem signature (0) |
472 | uint32_t chain_paddr; // offset to next filesystem signature (0) |
416 | uint32_t spare[10]; // zerofill |
473 | uint32_t spare[10]; // zerofill |
417 | uint32_t mountflags; // default _MOUNT_* from sys/iomsg.h (0) |
474 | uint32_t mountflags; // default _MOUNT_* from sys/iomsg.h (0) |
418 | char mountpoint[4]; // default mountpoint for image ("/" + "\0\0\0") |
475 | char mountpoint[4]; // default mountpoint for image ("/" + "\0\0\0") |
419 | } image_header_t; |
476 | } image_header_t; |
- | 477 | END_OF_PACKED_STRUCT () // restore default alignment |
|
420 | 478 | ||
421 | 479 | ||
- | 480 | START_OF_PACKED_STRUCT () // we need byte-alignment for this struct |
|
422 | typedef |
481 | typedef PACKED (struct) image_trailer_v1_s |
423 | { |
482 | { |
424 | uint32_t cksum; // checksum from start of header to start of trailer |
483 | uint32_t cksum; // checksum from start of header to start of trailer |
425 | } image_trailer_v1_t; // NOTE: this is the same structure as startup_trailer_v1_t |
484 | } image_trailer_v1_t; // NOTE: this is the same structure as startup_trailer_v1_t |
- | 485 | END_OF_PACKED_STRUCT () // restore default alignment |
|
426 | 486 | ||
427 | 487 | ||
428 | // NOTE: the checksums in this trailer will only be valid until the first non-startup bootstrap binary (e.g., startup-verifier, procnto, ...) is invoked. |
488 | // NOTE: the checksums in this trailer will only be valid until the first non-startup bootstrap binary (e.g., startup-verifier, procnto, ...) is invoked. |
429 | // Because bootstrap binaries execute in-place, their data segments will change once the programs are running. |
489 | // Because bootstrap binaries execute in-place, their data segments will change once the programs are running. |
430 | // Hence, any checksum validation would need to be done either by the boot loader / IFS or by the startup. |
490 | // Hence, any checksum validation would need to be done either by the boot loader / IFS or by the startup. |
- | 491 | START_OF_PACKED_STRUCT () // we need byte-alignment for this struct |
|
431 | typedef |
492 | typedef PACKED (struct) image_trailer_v2_s |
432 | { |
493 | { |
433 | uint8_t sha512[64]; // SHA512 from start of image header to start of trailer |
494 | uint8_t sha512[64]; // SHA512 from start of image header to start of trailer |
434 | uint32_t cksum; // checksum from start of header to start of this member |
495 | uint32_t cksum; // checksum from start of header to start of this member |
435 | } image_trailer_v2_t; // NOTE: this is the same structure as startup_trailer_v2_t |
496 | } image_trailer_v2_t; // NOTE: this is the same structure as startup_trailer_v2_t |
- | 497 | END_OF_PACKED_STRUCT () // restore default alignment |
|
436 | 498 | ||
437 | 499 | ||
438 | // Executable and Linkable Format master header structure type definition |
500 | // Executable and Linkable Format master header structure type definition |
- | 501 | START_OF_PACKED_STRUCT () // we need byte-alignment for this struct |
|
439 | typedef |
502 | typedef PACKED (struct) elf_header_s |
440 | { |
503 | { |
441 |
|
504 | PACKED (union) |
442 | { |
505 | { |
443 |
|
506 | PACKED (struct) |
444 | { |
507 | { |
445 | uint8_t magic[4]; // offset 0: "\x7f" + "ELF" |
508 | uint8_t magic[4]; // offset 0: "\x7f" + "ELF" |
446 | uint8_t platform_size; // offset 4: 1 = 32-bit, 2 = 64-bit |
509 | uint8_t platform_size; // offset 4: 1 = 32-bit, 2 = 64-bit |
447 | uint8_t endianness; // offset 5: 1 = little endian, 2 = big endian |
510 | uint8_t endianness; // offset 5: 1 = little endian, 2 = big endian |
448 | uint8_t header_version; // offset 6: typically 1 |
511 | uint8_t header_version; // offset 6: typically 1 |
Line 450... | Line 513... | ||
450 | uint8_t spare[8]; // offset 8: zeroes |
513 | uint8_t spare[8]; // offset 8: zeroes |
451 | uint16_t type; // offset 16: 1 = relocatable, 2 = executable, 3 = shared, 4 = core dump |
514 | uint16_t type; // offset 16: 1 = relocatable, 2 = executable, 3 = shared, 4 = core dump |
452 | uint16_t instruction_set; // offset 18: 2 = Sparc, 3 = i386, 8 = MIPS, 20 = PowerPC, 40 = ARM, 42 = SuperH, 50 = IA-64, 62 = x86_64, 183 = AArch64, 243 = RISC-V |
515 | uint16_t instruction_set; // offset 18: 2 = Sparc, 3 = i386, 8 = MIPS, 20 = PowerPC, 40 = ARM, 42 = SuperH, 50 = IA-64, 62 = x86_64, 183 = AArch64, 243 = RISC-V |
453 | uint32_t elf_version; // offset 20: typically 1 |
516 | uint32_t elf_version; // offset 20: typically 1 |
454 | } elf; |
517 | } elf; |
455 |
|
518 | PACKED (struct) // size == 52 |
456 | { |
519 | { |
457 | uint8_t magic[4]; // offset 0: "\x7f" + "ELF" |
520 | uint8_t magic[4]; // offset 0: "\x7f" + "ELF" |
458 | uint8_t platform_size; // offset 4: 1 = 32-bit, 2 = 64-bit |
521 | uint8_t platform_size; // offset 4: 1 = 32-bit, 2 = 64-bit |
459 | uint8_t endianness; // offset 5: 1 = little endian, 2 = big endian |
522 | uint8_t endianness; // offset 5: 1 = little endian, 2 = big endian |
460 | uint8_t header_version; // offset 6: typically 1 |
523 | uint8_t header_version; // offset 6: typically 1 |
Line 472... | Line 535... | ||
472 | uint16_t program_header_table_len; // offset 44: number of entries in the program header table |
535 | uint16_t program_header_table_len; // offset 44: number of entries in the program header table |
473 | uint16_t section_header_item_size; // offset 46: size of an entry in the section header table |
536 | uint16_t section_header_item_size; // offset 46: size of an entry in the section header table |
474 | uint16_t section_header_table_len; // offset 48: number of entries in the section header table |
537 | uint16_t section_header_table_len; // offset 48: number of entries in the section header table |
475 | uint16_t section_header_names_idx; // offset 50: index of the entry in the section header table that contains the section names |
538 | uint16_t section_header_names_idx; // offset 50: index of the entry in the section header table that contains the section names |
476 | } elf32; // size == 52 |
539 | } elf32; // size == 52 |
477 |
|
540 | PACKED (struct) // size == 64 |
478 | { |
541 | { |
479 | uint8_t magic[4]; // offset 0: "\x7f" + "ELF" |
542 | uint8_t magic[4]; // offset 0: "\x7f" + "ELF" |
480 | uint8_t platform_size; // offset 4: 1 = 32-bit, 2 = 64-bit |
543 | uint8_t platform_size; // offset 4: 1 = 32-bit, 2 = 64-bit |
481 | uint8_t endianness; // offset 5: 1 = little endian, 2 = big endian |
544 | uint8_t endianness; // offset 5: 1 = little endian, 2 = big endian |
482 | uint8_t header_version; // offset 6: typically 1 |
545 | uint8_t header_version; // offset 6: typically 1 |
Line 496... | Line 559... | ||
496 | uint16_t section_header_table_len; // offset 60: number of entries in the section header table |
559 | uint16_t section_header_table_len; // offset 60: number of entries in the section header table |
497 | uint16_t section_header_names_idx; // offset 62: index of the entry in the section header table that contains the section names |
560 | uint16_t section_header_names_idx; // offset 62: index of the entry in the section header table that contains the section names |
498 | } elf64; // size == 64 |
561 | } elf64; // size == 64 |
499 | } u; |
562 | } u; |
500 | } elf_header_t; |
563 | } elf_header_t; |
- | 564 | END_OF_PACKED_STRUCT () // restore default alignment |
|
501 | 565 | ||
502 | 566 | ||
503 | // Executable and Linkable Format program header structure type definition |
567 | // Executable and Linkable Format program header structure type definition |
- | 568 | START_OF_PACKED_STRUCT () // we need byte-alignment for this struct |
|
504 | typedef |
569 | typedef PACKED (struct) elf_program_header_s |
505 | { |
570 | { |
506 |
|
571 | PACKED (union) |
507 | { |
572 | { |
508 |
|
573 | PACKED (struct) |
509 | { |
574 | { |
510 | uint32_t segment_type; // offset 0: type of segment (0: unused table entry, 1: loadable, 2: dynamic linking information, 3: interpreter information, 4: auxiliary information, 5: reserved, 6: this very segment, 7: TLS template) |
575 | uint32_t segment_type; // offset 0: type of segment (0: unused table entry, 1: loadable, 2: dynamic linking information, 3: interpreter information, 4: auxiliary information, 5: reserved, 6: this very segment, 7: TLS template) |
511 | } elf; |
576 | } elf; |
512 |
|
577 | PACKED (struct) // size == 32 |
513 | { |
578 | { |
514 | uint32_t segment_type; // offset 0: type of segment (0: unused table entry, 1: loadable, 2: dynamic linking information, 3: interpreter information, 4: auxiliary information, 5: reserved, 6: this very segment, 7: TLS template) |
579 | uint32_t segment_type; // offset 0: type of segment (0: unused table entry, 1: loadable, 2: dynamic linking information, 3: interpreter information, 4: auxiliary information, 5: reserved, 6: this very segment, 7: TLS template) |
515 | uint32_t file_offset; // offset 4: file offset of this segment |
580 | uint32_t file_offset; // offset 4: file offset of this segment |
516 | uint32_t virtual_addr; // offset 8: virtual address where this segment should be mapped in memory |
581 | uint32_t virtual_addr; // offset 8: virtual address where this segment should be mapped in memory |
517 | uint32_t physical_addr; // offset 12: on systems where this is relevant, PHYSICAL address where this segment should be mapped in memory |
582 | uint32_t physical_addr; // offset 12: on systems where this is relevant, PHYSICAL address where this segment should be mapped in memory |
518 | uint32_t size_in_file; // offset 16: size of this segment in the ELF file (may be zero) |
583 | uint32_t size_in_file; // offset 16: size of this segment in the ELF file (may be zero) |
519 | uint32_t size_in_memory; // offset 20: size of this segment in memory (may be zero) |
584 | uint32_t size_in_memory; // offset 20: size of this segment in memory (may be zero) |
520 | uint32_t segment_flags; // offset 24: bitmap of segment flags (1: executable, 2: writable, 4: readable) |
585 | uint32_t segment_flags; // offset 24: bitmap of segment flags (1: executable, 2: writable, 4: readable) |
521 | uint32_t alignment; // offset 28: memory alignment (0 or 1 mean non alignment, else must be a power of 2 where virtual_addr == file_offset % alignment) |
586 | uint32_t alignment; // offset 28: memory alignment (0 or 1 mean non alignment, else must be a power of 2 where virtual_addr == file_offset % alignment) |
522 | } elf32; // size == 32 |
587 | } elf32; // size == 32 |
523 |
|
588 | PACKED (struct) // size == 56 |
524 | { |
589 | { |
525 | uint32_t segment_type; // offset 0: type of segment (0: unused table entry, 1: loadable, 2: dynamic linking information, 3: interpreter information, 4: auxiliary information, 5: reserved, 6: this very segment, 7: TLS template) |
590 | uint32_t segment_type; // offset 0: type of segment (0: unused table entry, 1: loadable, 2: dynamic linking information, 3: interpreter information, 4: auxiliary information, 5: reserved, 6: this very segment, 7: TLS template) |
526 | uint32_t segment_flags; // offset 4: bitmap of segment flags (1: executable, 2: writable, 4: readable) |
591 | uint32_t segment_flags; // offset 4: bitmap of segment flags (1: executable, 2: writable, 4: readable) |
527 | uint64_t file_offset; // offset 8: file offset of this segment |
592 | uint64_t file_offset; // offset 8: file offset of this segment |
528 | uint64_t virtual_addr; // offset 16: virtual address where this segment should be mapped in memory |
593 | uint64_t virtual_addr; // offset 16: virtual address where this segment should be mapped in memory |
Line 531... | Line 596... | ||
531 | uint64_t size_in_memory; // offset 40: size of this segment in memory (may be zero) |
596 | uint64_t size_in_memory; // offset 40: size of this segment in memory (may be zero) |
532 | uint64_t alignment; // offset 48: memory alignment (0 or 1 mean non alignment, else must be a power of 2 where virtual_addr == file_offset % alignment) |
597 | uint64_t alignment; // offset 48: memory alignment (0 or 1 mean non alignment, else must be a power of 2 where virtual_addr == file_offset % alignment) |
533 | } elf64; // size == 56 |
598 | } elf64; // size == 56 |
534 | } u; |
599 | } u; |
535 | } elf_program_header_t; |
600 | } elf_program_header_t; |
- | 601 | END_OF_PACKED_STRUCT () // restore default alignment |
|
536 | 602 | ||
537 | 603 | ||
538 | // Executable and Linkable Format section header structure type definition |
604 | // Executable and Linkable Format section header structure type definition |
- | 605 | START_OF_PACKED_STRUCT () // we need byte-alignment for this struct |
|
539 | typedef |
606 | typedef PACKED (struct) elf_section_header_s |
540 | { |
607 | { |
541 |
|
608 | PACKED (union) |
542 | { |
609 | { |
- | 610 | PACKED (struct) |
|
- | 611 | { |
|
- | 612 | uint32_t name_offset; // offset 0: offset in the string table of the name of this section |
|
543 |
|
613 | uint32_t type; // offset 4: section type (0: unused, 1: program data, 2: symbols table, 3: strings table, 4: relocs with addends, 5: symbols hash table, 6: dyld info, 7: notes, 8: BSS, 9: relocs without addends, 11: dyld symbols table, 14: constructors, 15: destructors, 16, preconstructors, 17: group, 18: extended section indices, 19: number of typedefs ...) |
- | 614 | } elf; |
|
- | 615 | PACKED (struct) // size == 40 |
|
544 | { |
616 | { |
545 | uint32_t name_offset; // offset 0: offset in the string table of the name of this section |
617 | uint32_t name_offset; // offset 0: offset in the string table of the name of this section |
546 | uint32_t type; // offset 4: |
618 | uint32_t type; // offset 4: section type (0: unused, 1: program data, 2: symbols table, 3: strings table, 4: relocs with addends, 5: symbols hash table, 6: dyld info, 7: notes, 8: BSS, 9: relocs without addends, 11: dyld symbols table, 14: constructors, 15: destructors, 16, preconstructors, 17: group, 18: extended section indices, 19: number of typedefs ...) |
547 | uint32_t flags; // offset 8: |
619 | uint32_t flags; // offset 8: bitmapped flags (1: writable, 2: takes RAM, 4: executable, 8: reserved, 16: mergeable, 32: contains C-strings, 64: sh_info contains SHT index, 128: preserve order, 256: OS-specific, 512: group member, 1024: TLS template ...) |
548 | uint32_t virtual_addr; // offset 12: address in virtual memory where this section may be loaded |
620 | uint32_t virtual_addr; // offset 12: address in virtual memory where this section may be loaded |
549 | uint32_t file_offset; // offset 16: offset of this section in the ELF file |
621 | uint32_t file_offset; // offset 16: offset of this section in the ELF file |
550 | uint32_t size; // offset 20: size of this section |
622 | uint32_t size; // offset 20: size of this section |
551 | uint32_t linked_index; // offset 24: optional section index of an associated section |
623 | uint32_t linked_index; // offset 24: optional section index of an associated section |
552 | uint32_t info; // offset 28: optional extra information |
624 | uint32_t info; // offset 28: optional extra information |
553 | uint32_t alignment; // offset 32: required memory alignment (must be a power of 2) |
625 | uint32_t alignment; // offset 32: required memory alignment (must be a power of 2) |
554 | uint32_t entry_size; // offset 36: for table-like sections, size of an element in the table |
626 | uint32_t entry_size; // offset 36: for table-like sections, size of an element in the table |
555 | } elf32; // size == 40 |
627 | } elf32; // size == 40 |
556 |
|
628 | PACKED (struct) // size == 64 |
557 | { |
629 | { |
558 | uint32_t name_offset; // offset 0: offset in the string table of the name of this section |
630 | uint32_t name_offset; // offset 0: offset in the string table of the name of this section |
559 | uint32_t type; // offset 4: |
631 | uint32_t type; // offset 4: section type (0: unused, 1: program data, 2: symbols table, 3: strings table, 4: relocs with addends, 5: symbols hash table, 6: dyld info, 7: notes, 8: BSS, 9: relocs without addends, 11: dyld symbols table, 14: constructors, 15: destructors, 16, preconstructors, 17: group, 18: extended section indices, 19: number of typedefs ...) |
560 | uint64_t flags; // offset 8: |
632 | uint64_t flags; // offset 8: bitmapped flags (1: writable, 2: takes RAM, 4: executable, 8: reserved, 16: mergeable, 32: contains C-strings, 64: sh_info contains SHT index, 128: preserve order, 256: OS-specific, 512: group member, 1024: TLS template ...) |
561 | uint64_t virtual_addr; // offset 16: address in virtual memory where this section may be loaded |
633 | uint64_t virtual_addr; // offset 16: address in virtual memory where this section may be loaded |
562 | uint64_t file_offset; // offset 24: offset of this section in the ELF file |
634 | uint64_t file_offset; // offset 24: offset of this section in the ELF file |
563 | uint64_t size; // offset 32: size of this section |
635 | uint64_t size; // offset 32: size of this section |
564 | uint32_t linked_index; // offset 40: optional section index of an associated section |
636 | uint32_t linked_index; // offset 40: optional section index of an associated section |
565 | uint32_t info; // offset 44: optional extra information |
637 | uint32_t info; // offset 44: optional extra information |
566 | uint64_t alignment; // offset 48: required memory alignment (must be a power of 2) |
638 | uint64_t alignment; // offset 48: required memory alignment (must be a power of 2) |
567 | uint64_t entry_size; // offset 56: for table-like sections, size of an element in the table |
639 | uint64_t entry_size; // offset 56: for table-like sections, size of an element in the table |
568 | } elf64; // size == 64 |
640 | } elf64; // size == 64 |
569 | } u; |
641 | } u; |
570 | } elf_section_header_t; |
642 | } elf_section_header_t; |
- | 643 | END_OF_PACKED_STRUCT () // restore default alignment |
|
571 | 644 | ||
572 | 645 | ||
573 | // Executable and Linkable Format dynamic section entry structure type definition |
646 | // Executable and Linkable Format dynamic section entry structure type definition |
- | 647 | START_OF_PACKED_STRUCT () // we need byte-alignment for this struct |
|
574 | typedef |
648 | typedef PACKED (struct) elf_dynamic_section_entry_s |
575 | { |
649 | { |
576 |
|
650 | PACKED (union) |
577 | { |
651 | { |
578 |
|
652 | PACKED (struct) // size == 8 |
579 | { |
653 | { |
580 | int32_t tag; // dynamic entry type (one of ELF_DT_xxx #defines) |
654 | int32_t tag; // dynamic entry type (one of ELF_DT_xxx #defines) |
581 | union |
- | |
582 | { |
- | |
583 | uint32_t as_integer; // value as integer |
- | |
584 |
|
655 | uint32_t value; // value (as integer, or as pointed address) |
585 | } value; |
- | |
586 | } elf32; // size == 8 |
656 | } elf32; // size == 8 |
587 |
|
657 | PACKED (struct) // size == 16 |
588 | { |
658 | { |
589 | int64_t tag; // dynamic entry type (one of ELF_DT_xxx #defines) |
659 | int64_t tag; // dynamic entry type (one of ELF_DT_xxx #defines) |
590 | union |
- | |
591 | { |
- | |
592 | uint64_t as_integer; // value as intege |
- | |
593 |
|
660 | uint64_t value; // value (as integer, or as pointed address) |
594 | } value; |
- | |
595 | } elf64; // size == 16 |
661 | } elf64; // size == 16 |
596 | } u; |
662 | } u; |
597 | } elf_dynamic_section_entry_t; |
663 | } elf_dynamic_section_entry_t; |
- | 664 | END_OF_PACKED_STRUCT () // restore default alignment |
|
598 | 665 | ||
599 | 666 | ||
- | 667 | // generic buffer structure type definition |
|
600 |
|
668 | typedef struct buffer_s |
- | 669 | { |
|
601 |
|
670 | uint8_t *bytes; // mallocated data |
- | 671 | size_t len; // length of allocated data |
|
602 |
|
672 | } buffer_t; |
603 | 673 | ||
604 | 674 | ||
- | 675 | // IFS directory entry insertion parameters structure type definition |
|
605 | typedef struct parms_s |
676 | typedef struct parms_s |
606 | { |
677 | { |
607 | int dperms; // directory permissions (e.g. 0755) |
678 | int dperms; // directory permissions (e.g. 0755) |
608 | int perms; // file permissions (e.g. 0644) |
679 | int perms; // file permissions (e.g. 0644) |
609 | int uid; // owner user ID (e.g. 0 = root) |
680 | int uid; // owner user ID (e.g. 0 = root) |
Line 616... | Line 687... | ||
616 | bool should_autosymlink_dylib; // dynamic libraries should be written under their official SONAME and a named symlink be created pointing at them |
687 | bool should_autosymlink_dylib; // dynamic libraries should be written under their official SONAME and a named symlink be created pointing at them |
617 | bool is_compiled_bootscript; // entry has [+script] attribute |
688 | bool is_compiled_bootscript; // entry has [+script] attribute |
618 | int extra_ino_flags; // bitmap of extra inode flags (IFS_INO_xxx) |
689 | int extra_ino_flags; // bitmap of extra inode flags (IFS_INO_xxx) |
619 | char search[10 * MAXPATHLEN]; // binary search path (the default one will be constructed at startup) |
690 | char search[10 * MAXPATHLEN]; // binary search path (the default one will be constructed at startup) |
620 | 691 | ||
621 |
|
692 | buffer_t data; |
622 | size_t datalen; |
- | |
623 | } parms_t; |
693 | } parms_t; |
624 | 694 | ||
625 | 695 | ||
626 | // global variables |
696 | // global variables |
627 | static char line_buffer[4096]; // scrap buffer for the IFS build file parser |
697 | static char line_buffer[4096]; // scrap buffer for the IFS build file parser |
Line 655... | Line 725... | ||
655 | static 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 |
725 | static 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 |
656 | 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) |
726 | 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) |
657 | static void hex_fprintf (FILE *fp, const uint8_t *data, size_t data_size, int howmany_columns, const char *fmt, ...); // hexdump-style formatted output to a file stream (which may be stdout/stderr) |
727 | static void hex_fprintf (FILE *fp, const uint8_t *data, size_t data_size, int howmany_columns, const char *fmt, ...); // hexdump-style formatted output to a file stream (which may be stdout/stderr) |
658 | static char *binary (const uint8_t x, char char_for_zero, char char_for_one); // returns the binary representation of byte 'x' as a string |
728 | static char *binary (const uint8_t x, char char_for_zero, char char_for_one); // returns the binary representation of byte 'x' as a string |
659 | static char *describe_uint8 (const uint8_t x, const char *bitwise_stringdescs[8]); // returns the ORed description of byte 'x' according to the description strings for each bit |
729 | static char *describe_uint8 (const uint8_t x, const char *bitwise_stringdescs[8]); // returns the ORed description of byte 'x' according to the description strings for each bit |
660 | static char *read_filecontents (const char *pathname, const char *search_path, |
730 | static char *read_filecontents (const char *pathname, const char *search_path, buffer_t *outbuf); // locates pathname among MKIFS_PATH, reads it, places its contents in a buffer (caller frees) and returns a pointer to the resolved pathname (static string) |
661 | static int fwrite_filecontents (const char *pathname, FILE *fp); // dumps the contents of pathname into fp |
731 | static int fwrite_filecontents (const char *pathname, FILE *fp); // dumps the contents of pathname into fp |
662 | static int relative_offset_of_in (const char *name, const |
732 | static int relative_offset_of_in (const char *name, const buffer_t *stringbuf); // returns the relative offset of a particular string in a string table |
663 | 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 |
733 | 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 |
664 | static size_t fwrite_fsentry (const fsentry_t *fsentry, FILE *fp); // writes the given filesystem entry into fp (without its contents) |
734 | static size_t fwrite_fsentry (const fsentry_t *fsentry, FILE *fp); // writes the given filesystem entry into fp (without its contents) |
665 | static size_t 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 |
735 | static size_t 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 |
666 | static int fsentry_compare_pathnames_cb (const void *a, const void *b); // qsort() comparison callback that sorts filesystem entries by pathnames |
736 | static int fsentry_compare_pathnames_cb (const void *a, const void *b); // qsort() comparison callback that sorts filesystem entries by pathnames |
667 | static void update_MKIFS_PATH (const char *processor); |
737 | static void update_MKIFS_PATH (const char *processor); |
Line 1020... | Line 1090... | ||
1020 | } |
1090 | } |
1021 | return (outstr); |
1091 | return (outstr); |
1022 | } |
1092 | } |
1023 | 1093 | ||
1024 | 1094 | ||
1025 | static char *read_filecontents (const char *pathname, const char *search_path, |
1095 | static char *read_filecontents (const char *pathname, const char *search_path, buffer_t *outbuf) |
1026 | { |
1096 | { |
1027 | // locates pathname among MKIFS_PATH, and places its contents in a buffer (caller frees). Returns resolved pathname (static buffer) or NULL. |
1097 | // locates pathname among MKIFS_PATH, and places its contents in a buffer (caller frees). Returns resolved pathname (static buffer) or NULL. |
1028 | 1098 | ||
1029 | static thread_local char final_pathname[MAXPATHLEN]; |
1099 | static thread_local char final_pathname[MAXPATHLEN]; |
1030 | 1100 | ||
Line 1062... | Line 1132... | ||
1062 | fp = fopen (final_pathname, "rb"); |
1132 | fp = fopen (final_pathname, "rb"); |
1063 | if (fp == NULL) |
1133 | if (fp == NULL) |
1064 | return (NULL); // unexistent file (errno is set to ENOENT) |
1134 | return (NULL); // unexistent file (errno is set to ENOENT) |
1065 | 1135 | ||
1066 | fseek (fp, 0, SEEK_END); |
1136 | fseek (fp, 0, SEEK_END); |
1067 |
|
1137 | outbuf->len = ftell (fp); // measure file length |
1068 | fseek (fp, 0, SEEK_SET); |
1138 | fseek (fp, 0, SEEK_SET); |
1069 |
|
1139 | outbuf->bytes = malloc (outbuf->len); |
1070 | if ( |
1140 | if (outbuf->bytes == NULL) |
1071 | { |
1141 | { |
1072 | fclose (fp); |
1142 | fclose (fp); |
1073 |
|
1143 | outbuf->len = 0; |
1074 | return (NULL); // out of memory (errno is set to ENOMEM) |
1144 | return (NULL); // out of memory (errno is set to ENOMEM) |
1075 | } |
1145 | } |
1076 | if (fread ( |
1146 | if (fread (outbuf->bytes, 1, outbuf->len, fp) != outbuf->len) // read the file in whole |
1077 | { |
1147 | { |
1078 | fclose (fp); |
1148 | fclose (fp); |
1079 |
|
1149 | outbuf->len = 0; |
1080 | return (NULL); // short read (errno is set) |
1150 | return (NULL); // short read (errno is set) |
1081 | } |
1151 | } |
1082 | fclose (fp); // close the file |
1152 | fclose (fp); // close the file |
1083 | 1153 | ||
1084 | return (final_pathname); // file was read successfully and its content put in databuf with size datalen |
1154 | return (final_pathname); // file was read successfully and its content put in databuf with size datalen |
Line 1115... | Line 1185... | ||
1115 | free (blob_buffer); |
1185 | free (blob_buffer); |
1116 | return (ret); |
1186 | return (ret); |
1117 | } |
1187 | } |
1118 | 1188 | ||
1119 | 1189 | ||
1120 | static int relative_offset_of_in (const char *name, const |
1190 | static int relative_offset_of_in (const char *name, const buffer_t *stringbuf) |
1121 | { |
1191 | { |
1122 | int name_len = (int) strlen (name) + 1; |
1192 | int name_len = (int) strlen (name) + 1; |
1123 | WELLMANNERED_ASSERT (name_len < |
1193 | WELLMANNERED_ASSERT (name_len < stringbuf->len, "bad call (name longer than string table)"); |
1124 | for (int idx = 0; idx <= |
1194 | for (int idx = 0; idx <= stringbuf->len - name_len; idx++) |
1125 | if (memcmp (& |
1195 | if (memcmp (&stringbuf->bytes[idx], name, name_len) == 0) |
1126 | return (idx); |
1196 | return (idx); |
1127 | WELLMANNERED_ASSERT (false, "bad call (name '%s' not found in string table)", name); |
1197 | WELLMANNERED_ASSERT (false, "bad call (name '%s' not found in string table)", name); |
1128 | return (0); |
1198 | return (0); |
1129 | } |
1199 | } |
1130 | 1200 | ||
Line 1236... | Line 1306... | ||
1236 | } |
1306 | } |
1237 | 1307 | ||
1238 | 1308 | ||
1239 | static size_t add_fsentry (fsentry_t **fsentries, size_t *fsentry_count, parms_t *entry_parms, const char *stored_pathname, const char *buildhost_pathname) |
1309 | static size_t add_fsentry (fsentry_t **fsentries, size_t *fsentry_count, parms_t *entry_parms, const char *stored_pathname, const char *buildhost_pathname) |
1240 | { |
1310 | { |
1241 | #define ADD_NAME_TO_STRINGTABLE( |
1311 | #define ADD_NAME_TO_STRINGTABLE(name,strtab) do { \ |
1242 | name_len = strlen ((name)) + 1; \ |
1312 | name_len = strlen ((name)) + 1; \ |
1243 | reallocated_ptr = realloc ( |
1313 | reallocated_ptr = realloc ((strtab).bytes, (strtab).len + name_len); \ |
1244 | WELLMANNERED_ASSERT (reallocated_ptr, "out of memory"); \ |
1314 | WELLMANNERED_ASSERT (reallocated_ptr, "out of memory"); \ |
1245 | |
1315 | (strtab).bytes = reallocated_ptr; \ |
1246 | memcpy (&( |
1316 | memcpy (&(strtab).bytes[(strtab).len], (name), name_len); \ |
1247 | |
1317 | (strtab).len += name_len; \ |
- | 1318 | } while (0) |
|
- | 1319 | #define APPEND_SECTION_DATA(section,sectionhdr_offset) do { \ |
|
- | 1320 | memcpy (&entry_parms->data.bytes[entry_parms->data.len], (section).bytes, (section).len); /* write section in place */ \ |
|
- | 1321 | free ((section).bytes); /* free it */ \ |
|
- | 1322 | new_shdr = (elf_section_header_t *) &new_shtab.bytes[(sectionhdr_offset)]; /* now fix this section header */ \ |
|
- | 1323 | ELF_SET_NUMERIC (elf, new_shdr, file_offset, entry_parms->data.len); /* fix section offset in the new section headers table */ \ |
|
- | 1324 | entry_parms->data.len += (section).len; /* update new ELF file length */ \ |
|
1248 | } while (0) |
1325 | } while (0) |
1249 | 1326 | ||
1250 | static thread_local char candidate_pathname[1024]; |
1327 | static thread_local char candidate_pathname[1024]; |
1251 | static int inode_count = 0; // will be preincremented each time this function is called |
1328 | static int inode_count = 0; // will be preincremented each time this function is called |
1252 | 1329 | ||
Line 1264... | Line 1341... | ||
1264 | elf_program_header_t *phdr; |
1341 | elf_program_header_t *phdr; |
1265 | const char *canonical_dylib_name; |
1342 | const char *canonical_dylib_name; |
1266 | const char *dynamic_strings; // strings table of the ".dynamic" section |
1343 | const char *dynamic_strings; // strings table of the ".dynamic" section |
1267 | const char *last_dirsep; |
1344 | const char *last_dirsep; |
1268 | elf_header_t *elf; |
1345 | elf_header_t *elf; |
1269 | uint8_t *new_shdr_table = NULL; // mallocated |
- | |
1270 |
|
1346 | buffer_t new_shtab = { NULL, 0 }; |
1271 | uint8_t *elfsection_qnxinfo_data = NULL; // mallocated |
- | |
1272 |
|
1347 | buffer_t elfsection_qnxinfo = { NULL, 0 }; |
1273 | uint8_t *elfsection_qnxusage_data = NULL; // mallocated |
- | |
1274 |
|
1348 | buffer_t elfsection_qnxusage = { NULL, 0 }; |
1275 | uint8_t *elfsection_debuglink_data = NULL; // mallocated |
- | |
1276 |
|
1349 | buffer_t elfsection_debuglink = { NULL, 0 }; |
1277 | uint8_t *elfsection_buildid_data = NULL; // mallocated |
- | |
1278 |
|
1350 | buffer_t elfsection_buildid = { NULL, 0 }; |
1279 | uint8_t *elfsection_shstrtab_data = NULL; // mallocated |
- | |
1280 |
|
1351 | buffer_t elfsection_shstrtab = { NULL, 0 }; |
1281 | char *resolved_pathname; |
1352 | char *resolved_pathname; |
1282 | void *reallocated_ptr; |
1353 | void *reallocated_ptr; |
1283 | void *old_data; |
1354 | void *old_data; |
1284 | struct stat stat_buf; |
1355 | struct stat stat_buf; |
1285 | size_t new_shdrtable_offset; |
1356 | size_t new_shdrtable_offset; |
Line 1307... | Line 1378... | ||
1307 | } |
1378 | } |
1308 | else if (entry_parms->is_compiled_bootscript) // else is it a startup script ? |
1379 | else if (entry_parms->is_compiled_bootscript) // else is it a startup script ? |
1309 | image_bootscript_ino = inode_count + 1; // save boot script inode number for image header |
1380 | image_bootscript_ino = inode_count + 1; // save boot script inode number for image header |
1310 | 1381 | ||
1311 | // do we already know the data for this data blob ? |
1382 | // do we already know the data for this data blob ? |
1312 | if (entry_parms->data != NULL) |
1383 | if (entry_parms->data.bytes != NULL) |
1313 | { |
1384 | { |
1314 | entry_parms->mtime = entry_parms->mtime_for_inline_files; |
1385 | entry_parms->mtime = entry_parms->mtime_for_inline_files; |
1315 | fprintf (stderr, "file: ino 0x%x uid %d gid %d mode 0%o path \"%s\" blob (len %zd)\n", entry_parms->extra_ino_flags | (inode_count + 1), entry_parms->uid, entry_parms->gid, entry_parms->st_mode, stored_pathname, entry_parms-> |
1386 | fprintf (stderr, "file: ino 0x%x uid %d gid %d mode 0%o path \"%s\" blob (len %zd)\n", entry_parms->extra_ino_flags | (inode_count + 1), entry_parms->uid, entry_parms->gid, entry_parms->st_mode, stored_pathname, entry_parms->data.len); |
1316 | } |
1387 | } |
1317 | else if (buildhost_pathname != NULL) // else was a source file pathname supplied ? |
1388 | else if (buildhost_pathname != NULL) // else was a source file pathname supplied ? |
1318 | { |
1389 | { |
1319 | resolved_pathname = read_filecontents (buildhost_pathname, (entry_parms->search[0] != 0 ? entry_parms->search : MKIFS_PATH), &entry_parms->data |
1390 | resolved_pathname = read_filecontents (buildhost_pathname, (entry_parms->search[0] != 0 ? entry_parms->search : MKIFS_PATH), &entry_parms->data); // locate the file |
1320 | if (resolved_pathname == NULL) |
1391 | if (resolved_pathname == NULL) |
1321 | { |
1392 | { |
1322 | fprintf (stderr, "fatal error: filesystem entry \"%s\" specified in \"%s\" line %d not found on build host: %s\n", buildhost_pathname, buildfile_pathname, lineno, strerror (errno)); |
1393 | fprintf (stderr, "fatal error: filesystem entry \"%s\" specified in \"%s\" line %d not found on build host: %s\n", buildhost_pathname, buildfile_pathname, lineno, strerror (errno)); |
1323 | exit (1); |
1394 | exit (1); |
1324 | } |
1395 | } |
1325 | stat (resolved_pathname, &stat_buf); // can't fail |
1396 | stat (resolved_pathname, &stat_buf); // can't fail |
1326 | if (entry_parms->mtime == UINT32_MAX) |
1397 | if (entry_parms->mtime == UINT32_MAX) |
1327 | entry_parms->mtime = (uint32_t) stat_buf.st_mtime; |
1398 | entry_parms->mtime = (uint32_t) stat_buf.st_mtime; |
1328 | fprintf (stderr, "file: ino 0x%x uid %d gid %d mode 0%o path \"%s\" buildhost_file \"%s\" (len %zd)\n", inode_count + 1, entry_parms->uid, entry_parms->gid, entry_parms->st_mode, stored_pathname, buildhost_pathname, entry_parms-> |
1399 | fprintf (stderr, "file: ino 0x%x uid %d gid %d mode 0%o path \"%s\" buildhost_file \"%s\" (len %zd)\n", inode_count + 1, entry_parms->uid, entry_parms->gid, entry_parms->st_mode, stored_pathname, buildhost_pathname, entry_parms->data.len); |
1329 | } |
1400 | } |
1330 | 1401 | ||
1331 | // is the file we're storing an ELF file ? |
1402 | // is the file we're storing an ELF file ? |
1332 | if ((entry_parms-> |
1403 | if ((entry_parms->data.len > 52) // file is big enough to contain an ELF header |
1333 | && ((elf = (elf_header_t *) entry_parms->data) != NULL) // cast (necessary true) |
1404 | && ((elf = (elf_header_t *) entry_parms->data.bytes) != NULL) // cast (necessary true) |
1334 | && (memcmp (ELF_GET_STRING (elf, elf, magic), ELF_MAGIC_STR, 4) == 0)) // file starts with the ELF magic |
1405 | && (memcmp (ELF_GET_STRING (elf, elf, magic), ELF_MAGIC_STR, 4) == 0)) // file starts with the ELF magic |
1335 | { |
1406 | { |
1336 | // is the file we're storing a relocatable executable (i.e. a dynamic library) and should we check for its canonical name ? |
1407 | // is the file we're storing a relocatable executable (i.e. a dynamic library) and should we check for its canonical name ? |
1337 | if ((ELF_GET_NUMERIC (elf, elf, type) == 3) && entry_parms->should_autosymlink_dylib) |
1408 | if ((ELF_GET_NUMERIC (elf, elf, type) == 3) && entry_parms->should_autosymlink_dylib) |
1338 | { |
1409 | { |
Line 1344... | Line 1415... | ||
1344 | shdr_dynstr = elf_get_section_header_by_name (elf, ".dynstr"); |
1415 | shdr_dynstr = elf_get_section_header_by_name (elf, ".dynstr"); |
1345 | 1416 | ||
1346 | // make sure we have both the dynamic section header and its own strings table header |
1417 | // make sure we have both the dynamic section header and its own strings table header |
1347 | if ((shdr_dynamic != NULL) && (shdr_dynstr != NULL)) |
1418 | if ((shdr_dynamic != NULL) && (shdr_dynstr != NULL)) |
1348 | { |
1419 | { |
1349 | dynamic_strings = (char *) &entry_parms->data[ELF_GET_NUMERIC (elf, shdr_dynstr, file_offset)]; // quick access to dynamic sections strings table |
1420 | dynamic_strings = (char *) &entry_parms->data.bytes[ELF_GET_NUMERIC (elf, shdr_dynstr, file_offset)]; // quick access to dynamic sections strings table |
1350 | 1421 | ||
1351 | // walk through the dynamic section, look for the DT_SONAME entry |
1422 | // walk through the dynamic section, look for the DT_SONAME entry |
1352 | for (dynamic_entry = (elf_dynamic_section_entry_t *) &entry_parms->data[ELF_GET_NUMERIC (elf, shdr_dynamic, file_offset)]; |
1423 | for (dynamic_entry = (elf_dynamic_section_entry_t *) &entry_parms->data.bytes[ELF_GET_NUMERIC (elf, shdr_dynamic, file_offset)]; |
1353 | (ELF_GET_NUMERIC (elf, dynamic_entry, tag) != ELF_DT_NULL); |
1424 | (ELF_GET_NUMERIC (elf, dynamic_entry, tag) != ELF_DT_NULL); |
1354 | dynamic_entry = (elf_dynamic_section_entry_t *) ((uint8_t *) dynamic_entry + ELF_STRUCT_SIZE (elf, dynamic_entry))) |
1425 | dynamic_entry = (elf_dynamic_section_entry_t *) ((uint8_t *) dynamic_entry + ELF_STRUCT_SIZE (elf, dynamic_entry))) |
1355 | if (ELF_GET_NUMERIC (elf, dynamic_entry, tag) == ELF_DT_SONAME) |
1426 | if (ELF_GET_NUMERIC (elf, dynamic_entry, tag) == ELF_DT_SONAME) |
1356 | { |
1427 | { |
1357 | canonical_dylib_name = dynamic_strings + ELF_GET_NUMERIC (elf, dynamic_entry, value |
1428 | canonical_dylib_name = dynamic_strings + ELF_GET_NUMERIC (elf, dynamic_entry, value); |
1358 | break; |
1429 | break; |
1359 | } |
1430 | } |
1360 | 1431 | ||
1361 | // do we have it ? |
1432 | // do we have it ? |
1362 | if ((canonical_dylib_name != NULL) && (canonical_dylib_name[0] != 0)) |
1433 | if ((canonical_dylib_name != NULL) && (canonical_dylib_name[0] != 0)) |
Line 1375... | Line 1446... | ||
1375 | if (!(entry_parms->extra_ino_flags & IFS_INO_PROCESSED_ELF)) |
1446 | if (!(entry_parms->extra_ino_flags & IFS_INO_PROCESSED_ELF)) |
1376 | { |
1447 | { |
1377 | // NOTE: for each ELF file, mkifs |
1448 | // NOTE: for each ELF file, mkifs |
1378 | // -> alters the program header table and offsets each p_addr (physical address) member by 0x1400000 plus the current file offset (this cannot be done right now, will need to be done once they are known) |
1449 | // -> alters the program header table and offsets each p_addr (physical address) member by 0x1400000 plus the current file offset (this cannot be done right now, will need to be done once they are known) |
1379 | // -> 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 |
1450 | // -> 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 |
1380 | // FIXME: what if a |
1451 | // FIXME: what if a thrown away section is located between two program segments ? are they collapsed, moving the segments beyond it one slot down ? |
1381 | 1452 | ||
1382 | // reconstructed ELF: |
1453 | // reconstructed ELF: |
1383 | // ==== START OF FILE ==== |
1454 | // ==== START OF FILE ==== |
1384 | // ELF header |
1455 | // ELF header |
1385 | // program header table |
1456 | // program header table |
1386 | // (same sections, just p_addr offset |
1457 | // (same sections, just p_addr offset changed) |
1387 | // section data 5 (named ".note.gnu.build-id") |
1458 | // section data 5 (named ".note.gnu.build-id") |
1388 | // "............GNU....ZY.....c.o..l" |
1459 | // "............GNU....ZY.....c.o..l" |
1389 | // PROGRAM |
1460 | // PROGRAM |
1390 | // sections table |
1461 | // sections table |
1391 | // + section 1: ALL ZEROES |
1462 | // + section 1: ALL ZEROES |
Line 1407... | Line 1478... | ||
1407 | // ".gnu_debuglink\0" |
1478 | // ".gnu_debuglink\0" |
1408 | // "QNX_usage\0" |
1479 | // "QNX_usage\0" |
1409 | // ".note.gnu.build-id\0" |
1480 | // ".note.gnu.build-id\0" |
1410 | // ==== END OF FILE ==== |
1481 | // ==== END OF FILE ==== |
1411 | 1482 | ||
1412 | // |
1483 | // parse the program header table, and measure the farthest offset known by this table where we'll write the reconstructed section headers table |
1413 | 1484 | ||
1414 | //first_offset = SIZE_MAX; |
- | |
1415 | new_shdrtable_offset = 0; |
1485 | new_shdrtable_offset = 0; |
1416 | table_count = ELF_GET_NUMERIC (elf, elf, program_header_table_len); |
1486 | table_count = ELF_GET_NUMERIC (elf, elf, program_header_table_len); |
1417 | for (table_index = 0; table_index < table_count; table_index++) |
1487 | for (table_index = 0; table_index < table_count; table_index++) |
1418 | { |
1488 | { |
1419 | phdr = (elf_program_header_t *) &entry_parms->data[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 |
1489 | phdr = (elf_program_header_t *) &entry_parms->data.bytes[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 |
1420 | //if (first_offset == SIZE_MAX) |
- | |
1421 | // first_offset = ELF_GET_NUMERIC (elf, phdr, physical_addr); |
- | |
1422 | if (ELF_GET_NUMERIC (elf, phdr, file_offset) + ELF_GET_NUMERIC (elf, phdr, size_in_file) > new_shdrtable_offset) |
1490 | if (ELF_GET_NUMERIC (elf, phdr, file_offset) + ELF_GET_NUMERIC (elf, phdr, size_in_file) > new_shdrtable_offset) |
1423 | new_shdrtable_offset = ELF_GET_NUMERIC (elf, phdr, file_offset) + ELF_GET_NUMERIC (elf, phdr, size_in_file); |
1491 | new_shdrtable_offset = ELF_GET_NUMERIC (elf, phdr, file_offset) + ELF_GET_NUMERIC (elf, phdr, size_in_file); |
1424 | // ELF_SET_NUMERIC (elf, phdr, physical_addr, ELF_GET_NUMERIC (elf, phdr, physical_addr) + (0x1400000 + )); |
- | |
1425 | } |
1492 | } |
1426 | 1493 | ||
1427 | // |
1494 | // re-create the section header table |
1428 | 1495 | ||
1429 |
|
1496 | elfsection_shstrtab.bytes = malloc (1); // initialize an empty section headers strings table |
1430 | WELLMANNERED_ASSERT ( |
1497 | WELLMANNERED_ASSERT (elfsection_shstrtab.bytes, "out of memory"); |
1431 |
|
1498 | elfsection_shstrtab.bytes[0] = 0; |
1432 |
|
1499 | elfsection_shstrtab.len = 1; |
1433 | ADD_NAME_TO_STRINGTABLE (".shstrtab", |
1500 | ADD_NAME_TO_STRINGTABLE (".shstrtab", elfsection_shstrtab); |
1434 | 1501 | ||
1435 |
|
1502 | new_shtab.bytes = malloc (ELF_STRUCT_SIZE (elf, shdr)); // prepare a section headers table with just the default entry |
1436 | WELLMANNERED_ASSERT ( |
1503 | WELLMANNERED_ASSERT (new_shtab.bytes, "out of memory"); |
1437 | new_shdr_table = reallocated_ptr; // reallocation succeeded, save the new pointer |
- | |
1438 | memset ( |
1504 | memset (new_shtab.bytes, 0, ELF_STRUCT_SIZE (elf, shdr)); // the first section header is always zerofilled |
1439 |
|
1505 | new_shtab.len = ELF_STRUCT_SIZE (elf, shdr); // and remember how big the section headers table is now |
1440 | if ((shdr = elf_get_section_header_by_name (elf, "QNX_info")) != NULL) |
1506 | if ((shdr = elf_get_section_header_by_name (elf, "QNX_info")) != NULL) |
1441 | { |
1507 | { |
1442 | if (ELF_GET_NUMERIC (elf, shdr, file_offset) > new_shdrtable_offset) // if this section needs to be moved around, have a copy of it |
1508 | if (ELF_GET_NUMERIC (elf, shdr, file_offset) > new_shdrtable_offset) // if this section needs to be moved around, have a copy of it |
1443 | { |
1509 | { |
1444 |
|
1510 | elfsection_qnxinfo.len = ELF_GET_NUMERIC (elf, shdr, size); |
1445 |
|
1511 | elfsection_qnxinfo.bytes = malloc (elfsection_qnxinfo.len); |
1446 | WELLMANNERED_ASSERT ( |
1512 | WELLMANNERED_ASSERT (elfsection_qnxinfo.bytes, "out of memory"); |
1447 | memcpy ( |
1513 | memcpy (elfsection_qnxinfo.bytes, &entry_parms->data.bytes[ELF_GET_NUMERIC (elf, shdr, file_offset)], elfsection_qnxinfo.len); |
1448 | } |
1514 | } |
1449 | reallocated_ptr = realloc ( |
1515 | reallocated_ptr = realloc (new_shtab.bytes, new_shtab.len + ELF_STRUCT_SIZE (elf, shdr)); // grow our section headers table to have one entry more |
1450 | WELLMANNERED_ASSERT (reallocated_ptr, "out of memory"); |
1516 | WELLMANNERED_ASSERT (reallocated_ptr, "out of memory"); |
1451 |
|
1517 | new_shtab.bytes = reallocated_ptr; // reallocation succeeded, save the new pointer |
1452 | new_qnxinfo_shdr_offset = |
1518 | new_qnxinfo_shdr_offset = new_shtab.len; // remember the new offset of this section header |
1453 |
|
1519 | new_shtab.len += ELF_STRUCT_SIZE (elf, shdr); // and remember how bigger the section headers table is now |
1454 | 1520 | ||
1455 | new_shdr = (elf_section_header_t *) & |
1521 | new_shdr = (elf_section_header_t *) &new_shtab.bytes[new_qnxinfo_shdr_offset]; // now populate this section header |
1456 | ADD_NAME_TO_STRINGTABLE ("QNX_info", |
1522 | ADD_NAME_TO_STRINGTABLE ("QNX_info", elfsection_shstrtab); |
1457 | ELF_SET_NUMERIC (elf, new_shdr, name_offset, relative_offset_of_in ("QNX_info", |
1523 | ELF_SET_NUMERIC (elf, new_shdr, name_offset, relative_offset_of_in ("QNX_info", &elfsection_shstrtab)); // update the relative offset of the section name |
1458 | ELF_SET_NUMERIC (elf, new_shdr, type, ELF_GET_NUMERIC (elf, shdr, type)); // duplicate section type |
1524 | ELF_SET_NUMERIC (elf, new_shdr, type, ELF_GET_NUMERIC (elf, shdr, type)); // duplicate section type |
1459 | ELF_SET_NUMERIC (elf, new_shdr, flags, ELF_GET_NUMERIC (elf, shdr, flags)); // duplicate section flags |
1525 | ELF_SET_NUMERIC (elf, new_shdr, flags, ELF_GET_NUMERIC (elf, shdr, flags)); // duplicate section flags |
1460 | ELF_SET_NUMERIC (elf, new_shdr, virtual_addr, ELF_GET_NUMERIC (elf, shdr, virtual_addr)); // duplicate section virtual address |
1526 | ELF_SET_NUMERIC (elf, new_shdr, virtual_addr, ELF_GET_NUMERIC (elf, shdr, virtual_addr)); // duplicate section virtual address |
1461 | ELF_SET_NUMERIC (elf, new_shdr, file_offset, (ELF_GET_NUMERIC (elf, shdr, file_offset) > new_shdrtable_offset ? WILL_BE_FILLED_LATER : ELF_GET_NUMERIC (elf, shdr, file_offset))); // duplicate section offset only if it doesn't move |
1527 | ELF_SET_NUMERIC (elf, new_shdr, file_offset, (ELF_GET_NUMERIC (elf, shdr, file_offset) > new_shdrtable_offset ? WILL_BE_FILLED_LATER : ELF_GET_NUMERIC (elf, shdr, file_offset))); // duplicate section offset only if it doesn't move |
1462 | ELF_SET_NUMERIC (elf, new_shdr, size, ELF_GET_NUMERIC (elf, shdr, size)); // duplicate section size |
1528 | ELF_SET_NUMERIC (elf, new_shdr, size, ELF_GET_NUMERIC (elf, shdr, size)); // duplicate section size |
Line 1467... | Line 1533... | ||
1467 | } |
1533 | } |
1468 | if ((shdr = elf_get_section_header_by_name (elf, ".gnu_debuglink")) != NULL) |
1534 | if ((shdr = elf_get_section_header_by_name (elf, ".gnu_debuglink")) != NULL) |
1469 | { |
1535 | { |
1470 | if (ELF_GET_NUMERIC (elf, shdr, file_offset) > new_shdrtable_offset) // if this section needs to be moved around, have a copy of it |
1536 | if (ELF_GET_NUMERIC (elf, shdr, file_offset) > new_shdrtable_offset) // if this section needs to be moved around, have a copy of it |
1471 | { |
1537 | { |
1472 |
|
1538 | elfsection_debuglink.len = ELF_GET_NUMERIC (elf, shdr, size); |
1473 |
|
1539 | elfsection_debuglink.bytes = malloc (elfsection_debuglink.len); |
1474 | WELLMANNERED_ASSERT ( |
1540 | WELLMANNERED_ASSERT (elfsection_debuglink.bytes, "out of memory"); |
1475 | memcpy ( |
1541 | memcpy (elfsection_debuglink.bytes, &entry_parms->data.bytes[ELF_GET_NUMERIC (elf, shdr, file_offset)], elfsection_debuglink.len); |
1476 | } |
1542 | } |
1477 | reallocated_ptr = realloc ( |
1543 | reallocated_ptr = realloc (new_shtab.bytes, new_shtab.len + ELF_STRUCT_SIZE (elf, shdr)); // grow our section headers table to have one entry more |
1478 | WELLMANNERED_ASSERT (reallocated_ptr, "out of memory"); |
1544 | WELLMANNERED_ASSERT (reallocated_ptr, "out of memory"); |
1479 |
|
1545 | new_shtab.bytes = reallocated_ptr; // reallocation succeeded, save the new pointer |
1480 | new_debuglink_shdr_offset = |
1546 | new_debuglink_shdr_offset = new_shtab.len; // remember the new offset of this section header |
1481 |
|
1547 | new_shtab.len += ELF_STRUCT_SIZE (elf, shdr); // and remember how bigger the section headers table is now |
1482 | 1548 | ||
1483 | new_shdr = (elf_section_header_t *) & |
1549 | new_shdr = (elf_section_header_t *) &new_shtab.bytes[new_debuglink_shdr_offset]; // now populate this section header |
1484 | ADD_NAME_TO_STRINGTABLE (".gnu_debuglink", |
1550 | ADD_NAME_TO_STRINGTABLE (".gnu_debuglink", elfsection_shstrtab); |
1485 | ELF_SET_NUMERIC (elf, new_shdr, name_offset, relative_offset_of_in (".gnu_debuglink", |
1551 | ELF_SET_NUMERIC (elf, new_shdr, name_offset, relative_offset_of_in (".gnu_debuglink", &elfsection_shstrtab)); // update the relative offset of the section name |
1486 | ELF_SET_NUMERIC (elf, new_shdr, type, ELF_GET_NUMERIC (elf, shdr, type)); // duplicate section type |
1552 | ELF_SET_NUMERIC (elf, new_shdr, type, ELF_GET_NUMERIC (elf, shdr, type)); // duplicate section type |
1487 | ELF_SET_NUMERIC (elf, new_shdr, flags, ELF_GET_NUMERIC (elf, shdr, flags)); // duplicate section flags |
1553 | ELF_SET_NUMERIC (elf, new_shdr, flags, ELF_GET_NUMERIC (elf, shdr, flags)); // duplicate section flags |
1488 | ELF_SET_NUMERIC (elf, new_shdr, virtual_addr, ELF_GET_NUMERIC (elf, shdr, virtual_addr)); // duplicate section virtual address |
1554 | ELF_SET_NUMERIC (elf, new_shdr, virtual_addr, ELF_GET_NUMERIC (elf, shdr, virtual_addr)); // duplicate section virtual address |
1489 | ELF_SET_NUMERIC (elf, new_shdr, file_offset, (ELF_GET_NUMERIC (elf, shdr, file_offset) > new_shdrtable_offset ? WILL_BE_FILLED_LATER : ELF_GET_NUMERIC (elf, shdr, file_offset))); // duplicate section offset only if it doesn't move |
1555 | ELF_SET_NUMERIC (elf, new_shdr, file_offset, (ELF_GET_NUMERIC (elf, shdr, file_offset) > new_shdrtable_offset ? WILL_BE_FILLED_LATER : ELF_GET_NUMERIC (elf, shdr, file_offset))); // duplicate section offset only if it doesn't move |
1490 | ELF_SET_NUMERIC (elf, new_shdr, size, ELF_GET_NUMERIC (elf, shdr, size)); // duplicate section size |
1556 | ELF_SET_NUMERIC (elf, new_shdr, size, ELF_GET_NUMERIC (elf, shdr, size)); // duplicate section size |
Line 1495... | Line 1561... | ||
1495 | } |
1561 | } |
1496 | if ((shdr = elf_get_section_header_by_name (elf, "QNX_usage")) != NULL) |
1562 | if ((shdr = elf_get_section_header_by_name (elf, "QNX_usage")) != NULL) |
1497 | { |
1563 | { |
1498 | if (ELF_GET_NUMERIC (elf, shdr, file_offset) > new_shdrtable_offset) // if this section needs to be moved around, have a copy of it |
1564 | if (ELF_GET_NUMERIC (elf, shdr, file_offset) > new_shdrtable_offset) // if this section needs to be moved around, have a copy of it |
1499 | { |
1565 | { |
1500 |
|
1566 | elfsection_qnxusage.len = ELF_GET_NUMERIC (elf, shdr, size); |
1501 |
|
1567 | elfsection_qnxusage.bytes = malloc (elfsection_qnxusage.len); |
1502 | WELLMANNERED_ASSERT ( |
1568 | WELLMANNERED_ASSERT (elfsection_qnxusage.bytes, "out of memory"); |
1503 | memcpy ( |
1569 | memcpy (elfsection_qnxusage.bytes, &entry_parms->data.bytes[ELF_GET_NUMERIC (elf, shdr, file_offset)], elfsection_qnxusage.len); |
1504 | } |
1570 | } |
1505 | reallocated_ptr = realloc ( |
1571 | reallocated_ptr = realloc (new_shtab.bytes, new_shtab.len + ELF_STRUCT_SIZE (elf, shdr)); // grow our section headers table to have one entry more |
1506 | WELLMANNERED_ASSERT (reallocated_ptr, "out of memory"); |
1572 | WELLMANNERED_ASSERT (reallocated_ptr, "out of memory"); |
1507 |
|
1573 | new_shtab.bytes = reallocated_ptr; // reallocation succeeded, save the new pointer |
1508 | new_qnxusage_shdr_offset = |
1574 | new_qnxusage_shdr_offset = new_shtab.len; // remember the new offset of this section header |
1509 |
|
1575 | new_shtab.len += ELF_STRUCT_SIZE (elf, shdr); // and remember how bigger the section headers table is now |
1510 | 1576 | ||
1511 | new_shdr = (elf_section_header_t *) & |
1577 | new_shdr = (elf_section_header_t *) &new_shtab.bytes[new_qnxusage_shdr_offset]; // now populate this section header |
1512 | ADD_NAME_TO_STRINGTABLE ("QNX_usage", |
1578 | ADD_NAME_TO_STRINGTABLE ("QNX_usage", elfsection_shstrtab); |
1513 | ELF_SET_NUMERIC (elf, new_shdr, name_offset, relative_offset_of_in ("QNX_usage", |
1579 | ELF_SET_NUMERIC (elf, new_shdr, name_offset, relative_offset_of_in ("QNX_usage", &elfsection_shstrtab)); // update the relative offset of the section name |
1514 | ELF_SET_NUMERIC (elf, new_shdr, type, ELF_GET_NUMERIC (elf, shdr, type)); // duplicate section type |
1580 | ELF_SET_NUMERIC (elf, new_shdr, type, ELF_GET_NUMERIC (elf, shdr, type)); // duplicate section type |
1515 | ELF_SET_NUMERIC (elf, new_shdr, flags, ELF_GET_NUMERIC (elf, shdr, flags)); // duplicate section flags |
1581 | ELF_SET_NUMERIC (elf, new_shdr, flags, ELF_GET_NUMERIC (elf, shdr, flags)); // duplicate section flags |
1516 | ELF_SET_NUMERIC (elf, new_shdr, virtual_addr, ELF_GET_NUMERIC (elf, shdr, virtual_addr)); // duplicate section virtual address |
1582 | ELF_SET_NUMERIC (elf, new_shdr, virtual_addr, ELF_GET_NUMERIC (elf, shdr, virtual_addr)); // duplicate section virtual address |
1517 | ELF_SET_NUMERIC (elf, new_shdr, file_offset, (ELF_GET_NUMERIC (elf, shdr, file_offset) > new_shdrtable_offset ? WILL_BE_FILLED_LATER : ELF_GET_NUMERIC (elf, shdr, file_offset))); // duplicate section offset only if it doesn't move |
1583 | ELF_SET_NUMERIC (elf, new_shdr, file_offset, (ELF_GET_NUMERIC (elf, shdr, file_offset) > new_shdrtable_offset ? WILL_BE_FILLED_LATER : ELF_GET_NUMERIC (elf, shdr, file_offset))); // duplicate section offset only if it doesn't move |
1518 | ELF_SET_NUMERIC (elf, new_shdr, size, ELF_GET_NUMERIC (elf, shdr, size)); // duplicate section size |
1584 | ELF_SET_NUMERIC (elf, new_shdr, size, ELF_GET_NUMERIC (elf, shdr, size)); // duplicate section size |
Line 1523... | Line 1589... | ||
1523 | } |
1589 | } |
1524 | if ((shdr = elf_get_section_header_by_name (elf, ".note.gnu.build-id")) != NULL) |
1590 | if ((shdr = elf_get_section_header_by_name (elf, ".note.gnu.build-id")) != NULL) |
1525 | { |
1591 | { |
1526 | if (ELF_GET_NUMERIC (elf, shdr, file_offset) > new_shdrtable_offset) // if this section needs to be moved around, have a copy of it |
1592 | if (ELF_GET_NUMERIC (elf, shdr, file_offset) > new_shdrtable_offset) // if this section needs to be moved around, have a copy of it |
1527 | { |
1593 | { |
1528 |
|
1594 | elfsection_buildid.len = ELF_GET_NUMERIC (elf, shdr, size); |
1529 |
|
1595 | elfsection_buildid.bytes = malloc (elfsection_buildid.len); |
1530 | WELLMANNERED_ASSERT ( |
1596 | WELLMANNERED_ASSERT (elfsection_buildid.bytes, "out of memory"); |
1531 | memcpy ( |
1597 | memcpy (elfsection_buildid.bytes, &entry_parms->data.bytes[ELF_GET_NUMERIC (elf, shdr, file_offset)], elfsection_buildid.len); |
1532 | } |
1598 | } |
1533 | reallocated_ptr = realloc ( |
1599 | reallocated_ptr = realloc (new_shtab.bytes, new_shtab.len + ELF_STRUCT_SIZE (elf, shdr)); // grow our section headers table to have one entry more |
1534 | WELLMANNERED_ASSERT (reallocated_ptr, "out of memory"); |
1600 | WELLMANNERED_ASSERT (reallocated_ptr, "out of memory"); |
1535 |
|
1601 | new_shtab.bytes = reallocated_ptr; // reallocation succeeded, save the new pointer |
1536 | new_buildid_shdr_offset = |
1602 | new_buildid_shdr_offset = new_shtab.len; // remember the new offset of this section header |
1537 |
|
1603 | new_shtab.len += ELF_STRUCT_SIZE (elf, shdr); // and remember how bigger the section headers table is now |
1538 | 1604 | ||
1539 | new_shdr = (elf_section_header_t *) & |
1605 | new_shdr = (elf_section_header_t *) &new_shtab.bytes[new_buildid_shdr_offset]; // now populate this section header |
1540 | ADD_NAME_TO_STRINGTABLE (".note.gnu.build-id", |
1606 | ADD_NAME_TO_STRINGTABLE (".note.gnu.build-id", elfsection_shstrtab); |
1541 | ELF_SET_NUMERIC (elf, new_shdr, name_offset, relative_offset_of_in (".note.gnu.build-id", |
1607 | ELF_SET_NUMERIC (elf, new_shdr, name_offset, relative_offset_of_in (".note.gnu.build-id", &elfsection_shstrtab)); // update the relative offset of the section name |
1542 | ELF_SET_NUMERIC (elf, new_shdr, type, ELF_GET_NUMERIC (elf, shdr, type)); // duplicate section type |
1608 | ELF_SET_NUMERIC (elf, new_shdr, type, ELF_GET_NUMERIC (elf, shdr, type)); // duplicate section type |
1543 | ELF_SET_NUMERIC (elf, new_shdr, flags, ELF_GET_NUMERIC (elf, shdr, flags)); // duplicate section flags |
1609 | ELF_SET_NUMERIC (elf, new_shdr, flags, ELF_GET_NUMERIC (elf, shdr, flags)); // duplicate section flags |
1544 | ELF_SET_NUMERIC (elf, new_shdr, virtual_addr, ELF_GET_NUMERIC (elf, shdr, virtual_addr)); // duplicate section virtual address |
1610 | ELF_SET_NUMERIC (elf, new_shdr, virtual_addr, ELF_GET_NUMERIC (elf, shdr, virtual_addr)); // duplicate section virtual address |
1545 | ELF_SET_NUMERIC (elf, new_shdr, file_offset, (ELF_GET_NUMERIC (elf, shdr, file_offset) > new_shdrtable_offset ? WILL_BE_FILLED_LATER : ELF_GET_NUMERIC (elf, shdr, file_offset))); // duplicate section offset only if it doesn't move |
1611 | ELF_SET_NUMERIC (elf, new_shdr, file_offset, (ELF_GET_NUMERIC (elf, shdr, file_offset) > new_shdrtable_offset ? WILL_BE_FILLED_LATER : ELF_GET_NUMERIC (elf, shdr, file_offset))); // duplicate section offset only if it doesn't move |
1546 | ELF_SET_NUMERIC (elf, new_shdr, size, ELF_GET_NUMERIC (elf, shdr, size)); // duplicate section size |
1612 | ELF_SET_NUMERIC (elf, new_shdr, size, ELF_GET_NUMERIC (elf, shdr, size)); // duplicate section size |
1547 | ELF_SET_NUMERIC (elf, new_shdr, linked_index, ELF_GET_NUMERIC (elf, shdr, linked_index)); // duplicate section linked index (FIXME: may be wrong now!) |
1613 | ELF_SET_NUMERIC (elf, new_shdr, linked_index, ELF_GET_NUMERIC (elf, shdr, linked_index)); // duplicate section linked index (FIXME: may be wrong now!) |
1548 | ELF_SET_NUMERIC (elf, new_shdr, info, ELF_GET_NUMERIC (elf, shdr, info)); // duplicate section info |
1614 | ELF_SET_NUMERIC (elf, new_shdr, info, ELF_GET_NUMERIC (elf, shdr, info)); // duplicate section info |
1549 | ELF_SET_NUMERIC (elf, new_shdr, alignment, ELF_GET_NUMERIC (elf, shdr, alignment)); // duplicate section alignment |
1615 | ELF_SET_NUMERIC (elf, new_shdr, alignment, ELF_GET_NUMERIC (elf, shdr, alignment)); // duplicate section alignment |
1550 | ELF_SET_NUMERIC (elf, new_shdr, entry_size, ELF_GET_NUMERIC (elf, shdr, entry_size)); // duplicate section entry size |
1616 | ELF_SET_NUMERIC (elf, new_shdr, entry_size, ELF_GET_NUMERIC (elf, shdr, entry_size)); // duplicate section entry size |
1551 | } |
1617 | } |
1552 | reallocated_ptr = realloc ( |
1618 | reallocated_ptr = realloc (new_shtab.bytes, new_shtab.len + ELF_STRUCT_SIZE (elf, shdr)); // grow our section headers table to have one entry more |
1553 | WELLMANNERED_ASSERT (reallocated_ptr, "out of memory"); |
1619 | WELLMANNERED_ASSERT (reallocated_ptr, "out of memory"); |
1554 |
|
1620 | new_shtab.bytes = reallocated_ptr; // reallocation succeeded, save the new pointer |
1555 | new_shstrtab_shdr_offset = |
1621 | new_shstrtab_shdr_offset = new_shtab.len; // remember the new offset of this section header |
1556 |
|
1622 | new_shtab.len += ELF_STRUCT_SIZE (elf, shdr); // and remember how bigger the section headers table is now |
1557 | 1623 | ||
1558 | new_shdr = (elf_section_header_t *) & |
1624 | new_shdr = (elf_section_header_t *) &new_shtab.bytes[new_shstrtab_shdr_offset]; // now populate this section header |
1559 | ELF_SET_NUMERIC (elf, new_shdr, name_offset, relative_offset_of_in (".shstrtab", |
1625 | ELF_SET_NUMERIC (elf, new_shdr, name_offset, relative_offset_of_in (".shstrtab", &elfsection_shstrtab)); // update the relative offset of the section name |
1560 | ELF_SET_NUMERIC (elf, new_shdr, type, ELF_SECTIONTYPE_STRINGTABLE); // section type (SHT_STRTAB) |
1626 | ELF_SET_NUMERIC (elf, new_shdr, type, ELF_SECTIONTYPE_STRINGTABLE); // section type (SHT_STRTAB) |
1561 | ELF_SET_NUMERIC (elf, new_shdr, flags, 0); // section flags (we could set SHF_STRINGS i.e. 0x20 here, but mkifs does not, so mimic that) |
1627 | ELF_SET_NUMERIC (elf, new_shdr, flags, 0); // section flags (we could set SHF_STRINGS i.e. 0x20 here, but mkifs does not, so mimic that) |
1562 | ELF_SET_NUMERIC (elf, new_shdr, virtual_addr, 0); // this section does not need to be mapped |
1628 | ELF_SET_NUMERIC (elf, new_shdr, virtual_addr, 0); // this section does not need to be mapped |
1563 | ELF_SET_NUMERIC (elf, new_shdr, file_offset, WILL_BE_FILLED_LATER); // |
1629 | ELF_SET_NUMERIC (elf, new_shdr, file_offset, WILL_BE_FILLED_LATER); // will be filled once we know it |
1564 | ELF_SET_NUMERIC (elf, new_shdr, size, |
1630 | ELF_SET_NUMERIC (elf, new_shdr, size, elfsection_shstrtab.len); // section size |
1565 | ELF_SET_NUMERIC (elf, new_shdr, linked_index, 0); // this section is not linked to any other |
1631 | ELF_SET_NUMERIC (elf, new_shdr, linked_index, 0); // this section is not linked to any other |
1566 | ELF_SET_NUMERIC (elf, new_shdr, info, 0); // this section has no additional info |
1632 | ELF_SET_NUMERIC (elf, new_shdr, info, 0); // this section has no additional info |
1567 | ELF_SET_NUMERIC (elf, new_shdr, alignment, 1); // this section is byte-aligned |
1633 | ELF_SET_NUMERIC (elf, new_shdr, alignment, 1); // this section is byte-aligned |
1568 | ELF_SET_NUMERIC (elf, new_shdr, entry_size, 0); // this section is not a table, so entry_size is zero |
1634 | ELF_SET_NUMERIC (elf, new_shdr, entry_size, 0); // this section is not a table, so entry_size is zero |
1569 | 1635 | ||
1570 | // jump over the new section headers table and write the sections that need to be relocated after the section headers table |
1636 | // jump over the new section headers table and write the sections that need to be relocated after the section headers table |
1571 | entry_parms-> |
1637 | entry_parms->data.len = new_shdrtable_offset + new_shtab.len; // assume there are no sections beyond the section headers table until known otherwise |
1572 | if ( |
1638 | if (elfsection_qnxinfo.bytes != NULL) |
1573 | { |
- | |
1574 | memcpy (&entry_parms->data[entry_parms->datalen], elfsection_qnxinfo_data, elfsection_qnxinfo_size); // write section in place |
- | |
1575 | free (elfsection_qnxinfo_data); // free it |
- | |
1576 |
|
1639 | APPEND_SECTION_DATA (elfsection_qnxinfo, new_qnxinfo_shdr_offset); // write "QNX_info" section data if we have such a section |
1577 | ELF_SET_NUMERIC (elf, new_shdr, file_offset, entry_parms->datalen); // fix section offset in the new section headers table |
- | |
1578 | entry_parms->datalen += elfsection_qnxinfo_size; // update new ELF file length |
- | |
1579 | } |
- | |
1580 | if ( |
1640 | if (elfsection_debuglink.bytes != NULL) |
1581 | { |
- | |
1582 | memcpy (&entry_parms->data[entry_parms->datalen], elfsection_debuglink_data, elfsection_debuglink_size); // write section in place |
- | |
1583 | free (elfsection_debuglink_data); // free it |
- | |
1584 |
|
1641 | APPEND_SECTION_DATA (elfsection_debuglink, new_debuglink_shdr_offset); // write ".gnu_debuglink" section data if we have such a section |
1585 | ELF_SET_NUMERIC (elf, new_shdr, file_offset, entry_parms->datalen); // fix section offset in the new section headers table |
- | |
1586 | entry_parms->datalen += elfsection_debuglink_size; // update new ELF file length |
- | |
1587 | } |
- | |
1588 | if ( |
1642 | if (elfsection_qnxusage.bytes != NULL) |
1589 | { |
- | |
1590 | memcpy (&entry_parms->data[entry_parms->datalen], elfsection_qnxusage_data, elfsection_qnxusage_size); // write section in place |
- | |
1591 | free (elfsection_qnxusage_data); // free it |
- | |
1592 |
|
1643 | APPEND_SECTION_DATA (elfsection_qnxusage, new_qnxusage_shdr_offset); // write "QNX_usage" section data if we have such a section |
1593 | ELF_SET_NUMERIC (elf, new_shdr, file_offset, entry_parms->datalen); // fix section offset in the new section headers table |
- | |
1594 | entry_parms->datalen += elfsection_qnxusage_size; // update new ELF file length |
- | |
1595 | } |
- | |
1596 | if ( |
1644 | if (elfsection_buildid.bytes != NULL) |
1597 | { |
- | |
1598 | memcpy (&entry_parms->data[entry_parms->datalen], elfsection_buildid_data, elfsection_buildid_size); // write section in place |
- | |
1599 | free (elfsection_buildid_data); // free it |
- | |
1600 | new_shdr = (elf_section_header_t *) &new_shdr_table[new_buildid_shdr_offset]; // now fix this section header |
- | |
1601 |
|
1645 | APPEND_SECTION_DATA (elfsection_buildid, new_buildid_shdr_offset); // write ".note.gnu.build-id" section data if we have such a section |
1602 | entry_parms->datalen += elfsection_buildid_size; // update new ELF file length |
- | |
1603 | } |
- | |
1604 | if (elfsection_shstrtab_data != NULL) |
- | |
1605 | { |
- | |
1606 |
|
1646 | APPEND_SECTION_DATA (elfsection_shstrtab, new_shstrtab_shdr_offset); // write the section header strings table as the last section |
1607 | free (elfsection_shstrtab_data); |
- | |
1608 | new_shdr = (elf_section_header_t *) &new_shdr_table[new_shstrtab_shdr_offset]; // now fix this section header |
- | |
1609 | ELF_SET_NUMERIC (elf, new_shdr, file_offset, entry_parms->datalen); // fix section offset in the new section headers table |
- | |
1610 | entry_parms->datalen += elfsection_shstrtab_size; // update new ELF file length |
- | |
1611 | } |
- | |
1612 | 1647 | ||
1613 | // now write the section headers table |
1648 | // now write the section headers table |
1614 | fprintf (stderr, "rewriting section headers table at offset 0x%zd\n", new_shdrtable_offset); |
- | |
1615 | memcpy (&entry_parms->data[new_shdrtable_offset], |
1649 | memcpy (&entry_parms->data.bytes[new_shdrtable_offset], new_shtab.bytes, new_shtab.len); |
1616 | free ( |
1650 | free (new_shtab.bytes); // free it |
1617 | 1651 | ||
1618 | // and finally fix the ELF header |
1652 | // and finally fix the ELF header |
1619 | ELF_SET_NUMERIC (elf, elf, section_header_table_offset, new_shdrtable_offset); |
1653 | ELF_SET_NUMERIC (elf, elf, section_header_table_offset, new_shdrtable_offset); |
1620 | ELF_SET_NUMERIC (elf, elf, section_header_table_len, |
1654 | ELF_SET_NUMERIC (elf, elf, section_header_table_len, new_shtab.len / ELF_STRUCT_SIZE (elf, shdr)); |
1621 | ELF_SET_NUMERIC (elf, elf, section_header_names_idx, |
1655 | ELF_SET_NUMERIC (elf, elf, section_header_names_idx, new_shtab.len / ELF_STRUCT_SIZE (elf, shdr) - 1); // the section headers strings table is the last section |
1622 | 1656 | ||
1623 | // align size with page size (4096 on x86, 16k on ARM) |
1657 | // align size with page size (4096 on x86, 16k on ARM) |
1624 | end_padding_offset = entry_parms-> |
1658 | end_padding_offset = entry_parms->data.len; |
1625 | if (ELF_GET_NUMERIC (elf, elf, instruction_set) == ELF_MACHINE_X86_64) |
1659 | if (ELF_GET_NUMERIC (elf, elf, instruction_set) == ELF_MACHINE_X86_64) |
1626 | entry_parms-> |
1660 | entry_parms->data.len = ROUND_TO_UPPER_MULTIPLE (end_padding_offset, 4 * 1024); // 4 kb pages on Intel processors |
1627 | else if (ELF_GET_NUMERIC (elf, elf, instruction_set) == ELF_MACHINE_AARCH64) |
1661 | else if (ELF_GET_NUMERIC (elf, elf, instruction_set) == ELF_MACHINE_AARCH64) |
1628 | entry_parms-> |
1662 | entry_parms->data.len = ROUND_TO_UPPER_MULTIPLE (end_padding_offset, 16 * 1024); // 16 kb pages on ARM64 |
1629 | else |
1663 | else |
1630 | { |
1664 | { |
1631 | fprintf (stderr, "fatal error: this ELF file \"%s\" does not belong to an architecture supported by ifstool (neither x86_64, nor aarch64)\n", stored_pathname); |
1665 | fprintf (stderr, "fatal error: this ELF file \"%s\" does not belong to an architecture supported by ifstool (neither x86_64, nor aarch64)\n", stored_pathname); |
1632 | exit (1); |
1666 | exit (1); |
1633 | } |
1667 | } |
1634 | memset (&entry_parms->data[end_padding_offset], 0, entry_parms-> |
1668 | memset (&entry_parms->data.bytes[end_padding_offset], 0, entry_parms->data.len - end_padding_offset); // zerofill |
1635 | 1669 | ||
1636 | entry_parms->extra_ino_flags |= IFS_INO_PROCESSED_ELF; // mark this inode as a preprocessed ELF file |
1670 | entry_parms->extra_ino_flags |= IFS_INO_PROCESSED_ELF; // mark this inode as a preprocessed ELF file |
1637 | } // end if the file is not yet a processed ELF |
1671 | } // end if the file is not yet a processed ELF |
1638 | } // end if the file we're storing is an ELF file |
1672 | } // end if the file we're storing is an ELF file |
1639 | } |
1673 | } |
1640 | else if (S_ISLNK (entry_parms->st_mode)) // else are we storing a symbolic link ? |
1674 | else if (S_ISLNK (entry_parms->st_mode)) // else are we storing a symbolic link ? |
1641 | fprintf (stderr, "symlink: ino 0x%x uid %d gid %d mode 0%o path \"%s\" -> \"%s\"\n", inode_count + 1, entry_parms->uid, entry_parms->gid, entry_parms->st_mode, stored_pathname, entry_parms->data); |
1675 | fprintf (stderr, "symlink: ino 0x%x uid %d gid %d mode 0%o path \"%s\" -> \"%s\"\n", inode_count + 1, entry_parms->uid, entry_parms->gid, entry_parms->st_mode, stored_pathname, entry_parms->data.bytes); |
1642 | else // we must be storing a FIFO |
1676 | else // we must be storing a FIFO |
1643 | { |
1677 | { |
1644 | if (strchr (entry_parms->data, ':') == NULL) |
1678 | if (strchr (entry_parms->data.bytes, ':') == NULL) |
1645 | { |
1679 | { |
1646 | fprintf (stderr, "fatal error: device entry \"%s\" malformed (no 'dev:rdev' pair)\n", stored_pathname); |
1680 | fprintf (stderr, "fatal error: device entry \"%s\" malformed (no 'dev:rdev' pair)\n", stored_pathname); |
1647 | exit (1); |
1681 | exit (1); |
1648 | } |
1682 | } |
1649 | fprintf (stderr, "fifo: ino 0x%x uid %d gid %d mode 0%o path \"%s\" dev rdev %s)\n", inode_count + 1, entry_parms->uid, entry_parms->gid, entry_parms->st_mode, stored_pathname, entry_parms->data); |
1683 | fprintf (stderr, "fifo: ino 0x%x uid %d gid %d mode 0%o path \"%s\" dev rdev %s)\n", inode_count + 1, entry_parms->uid, entry_parms->gid, entry_parms->st_mode, stored_pathname, entry_parms->data.bytes); |
1650 | } |
1684 | } |
1651 | 1685 | ||
1652 | // grow filesystem entries array to hold one more slot |
1686 | // grow filesystem entries array to hold one more slot |
1653 | reallocated_ptr = realloc (*fsentries, (*fsentry_count + 1) * sizeof (fsentry_t)); // attempt to reallocate |
1687 | reallocated_ptr = realloc (*fsentries, (*fsentry_count + 1) * sizeof (fsentry_t)); // attempt to reallocate |
1654 | if (reallocated_ptr == NULL) |
1688 | if (reallocated_ptr == NULL) |
Line 1672... | Line 1706... | ||
1672 | fsentry->UNSAVED_was_data_written = true; // no data to save |
1706 | fsentry->UNSAVED_was_data_written = true; // no data to save |
1673 | } |
1707 | } |
1674 | else if (S_ISREG (entry_parms->st_mode)) |
1708 | else if (S_ISREG (entry_parms->st_mode)) |
1675 | { |
1709 | { |
1676 | fsentry->u.file.offset = WILL_BE_FILLED_LATER; // will be filled later in main() when the file's data blob will be written to the output file |
1710 | fsentry->u.file.offset = WILL_BE_FILLED_LATER; // will be filled later in main() when the file's data blob will be written to the output file |
1677 | fsentry->u.file.size = (uint32_t) entry_parms-> |
1711 | fsentry->u.file.size = (uint32_t) entry_parms->data.len; |
1678 | fsentry->u.file.path = strdup (stored_pathname[0] == '/' ? &stored_pathname[1] : stored_pathname); |
1712 | fsentry->u.file.path = strdup (stored_pathname[0] == '/' ? &stored_pathname[1] : stored_pathname); |
1679 | fsentry->u.file.UNSAVED_databuf = malloc (entry_parms-> |
1713 | fsentry->u.file.UNSAVED_databuf = malloc (entry_parms->data.len); |
1680 | WELLMANNERED_ASSERT (fsentry->u.file.UNSAVED_databuf, "out of memory"); |
1714 | WELLMANNERED_ASSERT (fsentry->u.file.UNSAVED_databuf, "out of memory"); |
1681 | memcpy (fsentry->u.file.UNSAVED_databuf, entry_parms->data, entry_parms-> |
1715 | memcpy (fsentry->u.file.UNSAVED_databuf, entry_parms->data.bytes, entry_parms->data.len); |
1682 | fsentry->header.size = (uint16_t) ROUND_TO_UPPER_MULTIPLE (sizeof (fsentry->header) + sizeof (uint32_t) + sizeof (uint32_t) + strlen (fsentry->u.file.path) + 1, image_align); // now we can set the size |
1716 | fsentry->header.size = (uint16_t) ROUND_TO_UPPER_MULTIPLE (sizeof (fsentry->header) + sizeof (uint32_t) + sizeof (uint32_t) + strlen (fsentry->u.file.path) + 1, image_align); // now we can set the size |
1683 | fsentry->UNSAVED_was_data_written = false; // there *IS* data to save |
1717 | fsentry->UNSAVED_was_data_written = false; // there *IS* data to save |
1684 | } |
1718 | } |
1685 | else if (S_ISLNK (entry_parms->st_mode)) |
1719 | else if (S_ISLNK (entry_parms->st_mode)) |
1686 | { |
1720 | { |
1687 | fsentry->u.symlink.sym_offset = (uint16_t) (strlen (stored_pathname[0] == '/' ? &stored_pathname[1] : stored_pathname) + 1); |
1721 | fsentry->u.symlink.sym_offset = (uint16_t) (strlen (stored_pathname[0] == '/' ? &stored_pathname[1] : stored_pathname) + 1); |
1688 | fsentry->u.symlink.sym_size = (uint16_t) entry_parms-> |
1722 | fsentry->u.symlink.sym_size = (uint16_t) entry_parms->data.len; |
1689 | fsentry->u.symlink.path = strdup (stored_pathname[0] == '/' ? &stored_pathname[1] : stored_pathname); |
1723 | fsentry->u.symlink.path = strdup (stored_pathname[0] == '/' ? &stored_pathname[1] : stored_pathname); |
1690 | fsentry->u.symlink.contents = strdup (entry_parms->data); |
1724 | fsentry->u.symlink.contents = strdup (entry_parms->data.bytes); |
1691 | WELLMANNERED_ASSERT (fsentry->u.symlink.contents, "out of memory"); |
1725 | WELLMANNERED_ASSERT (fsentry->u.symlink.contents, "out of memory"); |
1692 | fsentry->header.size = (uint16_t) ROUND_TO_UPPER_MULTIPLE (sizeof (fsentry->header) + sizeof (uint16_t) + sizeof (uint16_t) + (size_t) fsentry->u.symlink.sym_offset + fsentry->u.symlink.sym_size + 1, image_align); // now we can set the size |
1726 | fsentry->header.size = (uint16_t) ROUND_TO_UPPER_MULTIPLE (sizeof (fsentry->header) + sizeof (uint16_t) + sizeof (uint16_t) + (size_t) fsentry->u.symlink.sym_offset + fsentry->u.symlink.sym_size + 1, image_align); // now we can set the size |
1693 | fsentry->UNSAVED_was_data_written = true; // no data to save |
1727 | fsentry->UNSAVED_was_data_written = true; // no data to save |
1694 | } |
1728 | } |
1695 | else // necessarily a device node |
1729 | else // necessarily a device node |
1696 | { |
1730 | { |
1697 | fsentry->u.device.dev = strtol (entry_parms->data, NULL, 0); // use strtol() to parse decimal (...), hexadecimal (0x...) and octal (0...) numbers |
1731 | fsentry->u.device.dev = strtol (entry_parms->data.bytes, NULL, 0); // use strtol() to parse decimal (...), hexadecimal (0x...) and octal (0...) numbers |
1698 | fsentry->u.device.rdev = strtol (strchr (entry_parms->data, ':') + 1, NULL, 0); // use strtol() to parse decimal (...), hexadecimal (0x...) and octal (0...) numbers |
1732 | fsentry->u.device.rdev = strtol (strchr (entry_parms->data.bytes, ':') + 1, NULL, 0); // use strtol() to parse decimal (...), hexadecimal (0x...) and octal (0...) numbers |
1699 | fsentry->u.device.path = strdup (stored_pathname[0] == '/' ? &stored_pathname[1] : stored_pathname); |
1733 | fsentry->u.device.path = strdup (stored_pathname[0] == '/' ? &stored_pathname[1] : stored_pathname); |
1700 | fsentry->header.size = (uint16_t) ROUND_TO_UPPER_MULTIPLE (sizeof (fsentry->header) + sizeof (uint32_t) + sizeof (uint32_t) + strlen (fsentry->u.device.path), image_align); // now we can set the size |
1734 | fsentry->header.size = (uint16_t) ROUND_TO_UPPER_MULTIPLE (sizeof (fsentry->header) + sizeof (uint32_t) + sizeof (uint32_t) + strlen (fsentry->u.device.path), image_align); // now we can set the size |
1701 | fsentry->UNSAVED_was_data_written = true; // no data to save |
1735 | fsentry->UNSAVED_was_data_written = true; // no data to save |
1702 | } |
1736 | } |
1703 | (*fsentry_count)++; |
1737 | (*fsentry_count)++; |
Line 1709... | Line 1743... | ||
1709 | entry_parms->should_autosymlink_dylib = false; |
1743 | entry_parms->should_autosymlink_dylib = false; |
1710 | entry_parms->should_follow_symlinks = false; |
1744 | entry_parms->should_follow_symlinks = false; |
1711 | entry_parms->st_mode = S_IFLNK | 0777; // NOTE: mkifs stores symlink permissions as rwxrwxrwx ! |
1745 | entry_parms->st_mode = S_IFLNK | 0777; // NOTE: mkifs stores symlink permissions as rwxrwxrwx ! |
1712 | entry_parms->extra_ino_flags = (fsentry->header.ino & (IFS_INO_PROCESSED_ELF | IFS_INO_RUNONCE_ELF | IFS_INO_BOOTSTRAP_EXE)); // preserve target's inode flags |
1746 | entry_parms->extra_ino_flags = (fsentry->header.ino & (IFS_INO_PROCESSED_ELF | IFS_INO_RUNONCE_ELF | IFS_INO_BOOTSTRAP_EXE)); // preserve target's inode flags |
1713 | last_dirsep = strrchr (stored_pathname, '/'); |
1747 | last_dirsep = strrchr (stored_pathname, '/'); |
1714 | old_data = entry_parms->data; // backup previous data pointer |
1748 | old_data = entry_parms->data.bytes; // backup previous data pointer |
1715 | entry_parms->data = (uint8_t *) (last_dirsep == NULL ? stored_pathname : last_dirsep + 1); // store symlink target in dirent data |
1749 | entry_parms->data.bytes = (uint8_t *) (last_dirsep == NULL ? stored_pathname : last_dirsep + 1); // store symlink target in dirent data |
1716 | entry_parms-> |
1750 | entry_parms->data.len = strlen (entry_parms->data.bytes); |
1717 | add_fsentry (fsentries, fsentry_count, entry_parms, original_stored_pathname, NULL); |
1751 | add_fsentry (fsentries, fsentry_count, entry_parms, original_stored_pathname, NULL); |
1718 | entry_parms->data = old_data; // restore previous data pointer so that it can be freed normally |
1752 | entry_parms->data.bytes = old_data; // restore previous data pointer so that it can be freed normally |
1719 | } |
1753 | } |
1720 | 1754 | ||
1721 | return (*fsentry_count); |
1755 | return (*fsentry_count); |
1722 | } |
1756 | } |
1723 | 1757 | ||
Line 1801... | Line 1835... | ||
1801 | .should_follow_symlinks = true, // [+|-followlink] |
1835 | .should_follow_symlinks = true, // [+|-followlink] |
1802 | .should_autosymlink_dylib = true, // [+|-autolink] |
1836 | .should_autosymlink_dylib = true, // [+|-autolink] |
1803 | .is_compiled_bootscript = false, // [+|-script] |
1837 | .is_compiled_bootscript = false, // [+|-script] |
1804 | .extra_ino_flags = 0, |
1838 | .extra_ino_flags = 0, |
1805 | .search = "", |
1839 | .search = "", |
1806 | .data = NULL, |
1840 | .data = { NULL, 0 } |
1807 | .datalen = 0 |
- | |
1808 | }; |
1841 | }; |
1809 | static parms_t entry_parms = { 0 }; // current parameters for a filesystem entry (will be initialized to default_parms each time a new entry is parsed in the build file) |
1842 | static parms_t entry_parms = { 0 }; // current parameters for a filesystem entry (will be initialized to default_parms each time a new entry is parsed in the build file) |
1810 | 1843 | ||
1811 | // bootable IFS support |
1844 | // bootable IFS support |
1812 | char *bootfile_pathname = NULL; // HACK: pathname to bootcode binary blob file to put at the start of a bootable IFS |
1845 | char *bootfile_pathname = NULL; // HACK: pathname to bootcode binary blob file to put at the start of a bootable IFS |
Line 1826... | Line 1859... | ||
1826 | struct stat stat_buf; |
1859 | struct stat stat_buf; |
1827 | size_t startuptrailer_offset; |
1860 | size_t startuptrailer_offset; |
1828 | size_t startupheader_offset; |
1861 | size_t startupheader_offset; |
1829 | size_t imagetrailer_offset; |
1862 | size_t imagetrailer_offset; |
1830 | size_t imageheader_offset; |
1863 | size_t imageheader_offset; |
- | 1864 | size_t corrective_offset; |
|
1831 | size_t imgdir_offset; |
1865 | size_t imgdir_offset; |
1832 | size_t imgdir_size; |
1866 | size_t imgdir_size; |
1833 | size_t final_size; |
1867 | size_t final_size; |
1834 | size_t blob_size; |
- | |
1835 | size_t available_space; |
1868 | size_t available_space; |
1836 | size_t allocated_size; |
1869 | size_t allocated_size; |
1837 | size_t fsentry_index; |
1870 | size_t fsentry_index; |
1838 | size_t largest_index; |
1871 | size_t largest_index; |
1839 | size_t largest_size; |
1872 | size_t largest_size; |
1840 | size_t curr_offset; |
1873 | size_t curr_offset; |
1841 | size_t table_index; |
1874 | size_t table_index; |
1842 | size_t table_count; |
1875 | size_t table_count; |
1843 |
|
1876 | buffer_t blob; |
1844 | int32_t checksum; |
1877 | int32_t checksum; |
1845 | char *specifiedpathname_start; |
1878 | char *specifiedpathname_start; |
1846 | char *directiveblock_start; |
1879 | char *directiveblock_start; |
1847 | char *write_ptr; |
1880 | char *write_ptr; |
1848 | char *line_ptr; |
1881 | char *line_ptr; |
Line 1851... | Line 1884... | ||
1851 | char *sep; |
1884 | char *sep; |
1852 | //char *ctx; |
1885 | //char *ctx; |
1853 | int arg_index; |
1886 | int arg_index; |
1854 | bool is_quoted_context = false; |
1887 | bool is_quoted_context = false; |
1855 | bool is_escaped_char = false; |
1888 | bool is_escaped_char = false; |
1856 | bool |
1889 | bool should_discard_inline_contents = false; |
1857 | bool want_info = false; |
1890 | bool want_info = false; |
1858 | bool want_everything = false; |
1891 | bool want_everything = false; |
1859 | bool want_help = false; |
1892 | bool want_help = false; |
1860 | bool is_foreign_endianness; |
1893 | bool is_foreign_endianness; |
1861 | int string_len; |
1894 | int string_len; |
Line 1894... | Line 1927... | ||
1894 | } |
1927 | } |
1895 | else if (strcmp (argv[arg_index], "-n") == 0) |
1928 | else if (strcmp (argv[arg_index], "-n") == 0) |
1896 | default_parms.mtime_for_inline_files = 0; // inline files should have a mtime set to zero |
1929 | default_parms.mtime_for_inline_files = 0; // inline files should have a mtime set to zero |
1897 | else if (strcmp (argv[arg_index], "-nn") == 0) |
1930 | else if (strcmp (argv[arg_index], "-nn") == 0) |
1898 | { |
1931 | { |
1899 | default_parms.mtime = 0; // all files should have a mtime set to zero |
1932 | default_parms.mtime = 0; // *all* files should have a mtime set to zero |
1900 | default_parms.mtime_for_inline_files = 0; |
1933 | default_parms.mtime_for_inline_files = 0; |
1901 | } |
1934 | } |
1902 | else if (strcmp (argv[arg_index], "--info") == 0) |
1935 | else if (strcmp (argv[arg_index], "--info") == 0) |
1903 | want_info = true; |
1936 | want_info = true; |
1904 | else if (strcmp (argv[arg_index], "--everything") == 0) |
1937 | else if (strcmp (argv[arg_index], "--everything") == 0) |
Line 1920... | Line 1953... | ||
1920 | fprintf (stderr, "error: missing parameters\n"); |
1953 | fprintf (stderr, "error: missing parameters\n"); |
1921 | fprintf ((want_help ? stdout : stderr), "usage:\n"); |
1954 | fprintf ((want_help ? stdout : stderr), "usage:\n"); |
1922 | fprintf ((want_help ? stdout : stderr), " ifstool [--bootfile <pathname>] [--startupfile <pathname>@<EP_from_imgbase>] [--kernelfile <pathname>@<fileoffs>] [-n[n]] <buildfile> <outfile>\n"); |
1955 | fprintf ((want_help ? stdout : stderr), " ifstool [--bootfile <pathname>] [--startupfile <pathname>@<EP_from_imgbase>] [--kernelfile <pathname>@<fileoffs>] [-n[n]] <buildfile> <outfile>\n"); |
1923 | fprintf ((want_help ? stdout : stderr), " ifstool --info [--everything] <ifs file>\n"); |
1956 | fprintf ((want_help ? stdout : stderr), " ifstool --info [--everything] <ifs file>\n"); |
1924 | fprintf ((want_help ? stdout : stderr), " ifstool --help\n"); |
1957 | fprintf ((want_help ? stdout : stderr), " ifstool --help\n"); |
1925 | fprintf ((want_help ? stdout : stderr), " |
1958 | fprintf ((want_help ? stdout : stderr), "NOTE: the compilation feature requires predigested boot, startup and kernel files produced by mkifs.\n"); |
1926 | exit (want_help ? 0 : 1); |
1959 | exit (want_help ? 0 : 1); |
1927 | } |
1960 | } |
1928 | 1961 | ||
1929 | // do we want info about a particular IFS ? if so, dump it |
1962 | // do we want info about a particular IFS ? if so, dump it |
1930 | if (want_info) |
1963 | if (want_info) |
Line 1957... | Line 1990... | ||
1957 | // stack up filesystem entries |
1990 | // stack up filesystem entries |
1958 | memcpy (&entry_parms, &default_parms, sizeof (default_parms)); |
1991 | memcpy (&entry_parms, &default_parms, sizeof (default_parms)); |
1959 | entry_parms.st_mode = S_IFDIR | default_parms.dperms; |
1992 | entry_parms.st_mode = S_IFDIR | default_parms.dperms; |
1960 | add_fsentry (&fsentries, &fsentry_count, &entry_parms, "", NULL); // add the root dir first |
1993 | add_fsentry (&fsentries, &fsentry_count, &entry_parms, "", NULL); // add the root dir first |
1961 | 1994 | ||
- | 1995 | // parse the IFS build file line per line |
|
1962 | while (fgets (line_buffer, sizeof (line_buffer), buildfile_fp) != NULL) |
1996 | while (fgets (line_buffer, sizeof (line_buffer), buildfile_fp) != NULL) |
1963 | { |
1997 | { |
1964 | if (current_line != NULL) |
1998 | if (current_line != NULL) |
1965 | free (current_line); |
1999 | free (current_line); |
1966 | current_line = strdup (line_buffer); |
2000 | current_line = strdup (line_buffer); |
1967 | WELLMANNERED_ASSERT (current_line, "out of memory"); |
2001 | WELLMANNERED_ASSERT (current_line, "out of memory"); |
1968 | lineno++; // keep track of current line number |
2002 | lineno++; // keep track of current line number |
1969 | //fprintf (stderr, "read buildfile line %d: {%s}\n", lineno, line_buffer); |
- | |
1970 | 2003 | ||
1971 | line_ptr = line_buffer; |
2004 | line_ptr = line_buffer; |
1972 | while ((*line_ptr != 0) && isspace (*line_ptr)) |
2005 | while ((*line_ptr != 0) && isspace (*line_ptr)) |
1973 | line_ptr++; // skip leading spaces |
2006 | line_ptr++; // skip leading spaces |
1974 | 2007 | ||
Line 1981... | Line 2014... | ||
1981 | 2014 | ||
1982 | // reset entry values |
2015 | // reset entry values |
1983 | memcpy (&entry_parms, &default_parms, sizeof (default_parms)); |
2016 | memcpy (&entry_parms, &default_parms, sizeof (default_parms)); |
1984 | path_in_ifs[0] = 0; |
2017 | path_in_ifs[0] = 0; |
1985 | path_on_buildhost[0] = 0; |
2018 | path_on_buildhost[0] = 0; |
1986 |
|
2019 | should_discard_inline_contents = false; |
1987 | - | ||
1988 | //fprintf (stderr, "parsing buildfile line %d: [%s]\n", lineno, line_ptr); |
- | |
1989 | 2020 | ||
1990 | // does this line start with an attribute block ? |
2021 | // does this line start with an attribute block ? |
1991 | if (*line_ptr == '[') |
2022 | if (*line_ptr == '[') |
1992 | { |
2023 | { |
1993 | line_ptr++; // skip the leading square bracket |
2024 | line_ptr++; // skip the leading square bracket |
Line 2049... | Line 2080... | ||
2049 | fprintf (stderr, "error: unable to stat the boot file \"%s\" specified in \"%s\" line %d: %s\n", bootfile_pathname, buildfile_pathname, lineno, strerror (errno)); |
2080 | fprintf (stderr, "error: unable to stat the boot file \"%s\" specified in \"%s\" line %d: %s\n", bootfile_pathname, buildfile_pathname, lineno, strerror (errno)); |
2050 | exit (1); |
2081 | exit (1); |
2051 | } |
2082 | } |
2052 | bootfile_size = stat_buf.st_size; // save preboot file size |
2083 | bootfile_size = stat_buf.st_size; // save preboot file size |
2053 | fprintf (stderr, "info: processor \"%s\" bootfile \"%s\"\n", image_processor, bootfile_pathname); |
2084 | fprintf (stderr, "info: processor \"%s\" bootfile \"%s\"\n", image_processor, bootfile_pathname); |
- | 2085 | #if 1 |
|
- | 2086 | // ###################################################################################################################################################################################################################################### |
|
- | 2087 | // # FIXME: figure out how to re-create it: linker call involved |
|
- | 2088 | // # $ 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 |
|
- | 2089 | // ###################################################################################################################################################################################################################################### |
|
2054 | if (read_filecontents (kernelfile_pathname, ".", &entry_parms.data |
2090 | if (read_filecontents (kernelfile_pathname, ".", &entry_parms.data) == NULL) |
2055 | { |
2091 | { |
2056 | fprintf (stderr, "fatal error: unable to read precompiled kernel file \"%s\" specified in --kernelfile argument\n", kernelfile_pathname); |
2092 | fprintf (stderr, "fatal error: unable to read precompiled kernel file \"%s\" specified in --kernelfile argument\n", kernelfile_pathname); |
2057 | exit (1); |
2093 | exit (1); |
2058 | } |
2094 | } |
- | 2095 | #else // nonworking |
|
- | 2096 | strcpy (path_on_buildhost, "procnto-smp-instr"); |
|
- | 2097 | #endif // nonworking |
|
- | 2098 | ||
2059 |
|
2099 | should_discard_inline_contents = true; // remember we already have data (so as to discard the inline block's contents) |
2060 | } |
2100 | } |
2061 | else if (strncmp (token, "mtime=", 6) == 0) { REACH_TOKEN_VALUE (); if (strcmp (value, "*") == 0) entry_parms.mtime = UINT32_MAX; else { |
2101 | else if (strncmp (token, "mtime=", 6) == 0) { REACH_TOKEN_VALUE (); if (strcmp (value, "*") == 0) entry_parms.mtime = UINT32_MAX; else { |
2062 | // value *must* be "YYYY-MM-DD-HH:MM:SS" by specification |
2102 | // value *must* be "YYYY-MM-DD-HH:MM:SS" by specification |
2063 | memset (&utc_time, 0, sizeof (utc_time)); |
2103 | memset (&utc_time, 0, sizeof (utc_time)); |
2064 | if (sscanf (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) |
2104 | if (sscanf (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 2070... | Line 2110... | ||
2070 | entry_parms.mtime = (uint32_t) mktime (&utc_time); |
2110 | entry_parms.mtime = (uint32_t) mktime (&utc_time); |
2071 | } |
2111 | } |
2072 | } |
2112 | } |
2073 | else if (strcmp (token, "+script") == 0) { |
2113 | else if (strcmp (token, "+script") == 0) { |
2074 | entry_parms.is_compiled_bootscript = true; |
2114 | entry_parms.is_compiled_bootscript = true; |
2075 | entry_parms.data = malloc (sizeof (INITIAL_STARTUP_SCRIPT) - 1); |
2115 | entry_parms.data.bytes = malloc (sizeof (INITIAL_STARTUP_SCRIPT) - 1); |
2076 | WELLMANNERED_ASSERT (entry_parms.data, "out of memory"); |
2116 | WELLMANNERED_ASSERT (entry_parms.data.bytes, "out of memory"); |
2077 | memcpy (entry_parms.data, INITIAL_STARTUP_SCRIPT, sizeof (INITIAL_STARTUP_SCRIPT) - 1); // FIXME: HACK until the script compiler is implemented |
2117 | memcpy (entry_parms.data.bytes, INITIAL_STARTUP_SCRIPT, sizeof (INITIAL_STARTUP_SCRIPT) - 1); // FIXME: HACK until the script compiler is implemented |
2078 | entry_parms. |
2118 | entry_parms.data.len = sizeof (INITIAL_STARTUP_SCRIPT) - 1; |
2079 |
|
2119 | should_discard_inline_contents = true; // remember we already have data (so as to discard the inline block's contents) |
2080 | } |
2120 | } |
2081 | else if (strcmp (token, "-script") == 0) entry_parms.is_compiled_bootscript = false; |
2121 | else if (strcmp (token, "-script") == 0) entry_parms.is_compiled_bootscript = false; |
2082 | else if (strcmp (token, "+followlink") == 0) entry_parms.should_follow_symlinks = true; |
2122 | else if (strcmp (token, "+followlink") == 0) entry_parms.should_follow_symlinks = true; |
2083 | else if (strcmp (token, "-followlink") == 0) entry_parms.should_follow_symlinks = false; |
2123 | else if (strcmp (token, "-followlink") == 0) entry_parms.should_follow_symlinks = false; |
2084 | else if (strcmp (token, "+autolink") == 0) entry_parms.should_autosymlink_dylib = true; |
2124 | else if (strcmp (token, "+autolink") == 0) entry_parms.should_autosymlink_dylib = true; |
Line 2168... | Line 2208... | ||
2168 | } |
2208 | } |
2169 | 2209 | ||
2170 | // read the host system's path, it may be either a path or a contents definition. Is it a content definition ? |
2210 | // read the host system's path, it may be either a path or a contents definition. Is it a content definition ? |
2171 | if (*line_ptr == '{') |
2211 | if (*line_ptr == '{') |
2172 | { |
2212 | { |
2173 | path_on_buildhost[0] = 0; // this is an inline fine, which means it doesn't exist on the build host |
- | |
2174 | allocated_size = 0; |
2213 | allocated_size = 0; |
2175 | 2214 | ||
2176 | line_ptr++; // skip the leading content definition |
2215 | line_ptr++; // skip the leading content definition |
2177 | is_escaped_char = false; |
2216 | is_escaped_char = false; |
2178 | for (;;) |
2217 | for (;;) |
Line 2188... | Line 2227... | ||
2188 | else if ((read_char == '}') && !is_escaped_char) |
2227 | else if ((read_char == '}') && !is_escaped_char) |
2189 | break; // found an unescaped closing bracked, stop parsing |
2228 | break; // found an unescaped closing bracked, stop parsing |
2190 | else |
2229 | else |
2191 | { |
2230 | { |
2192 | is_escaped_char = false; // any other char, meaning the next one will not be escaped |
2231 | is_escaped_char = false; // any other char, meaning the next one will not be escaped |
2193 | if (! |
2232 | if (!should_discard_inline_contents) // only store the contents if we do NOT know the data yet |
2194 | { |
2233 | { |
2195 | if (entry_parms. |
2234 | if (entry_parms.data.len == allocated_size) // reallocate in 4 kb blocks |
2196 | { |
2235 | { |
2197 | reallocated_ptr = realloc (entry_parms.data, allocated_size + 4096); |
2236 | reallocated_ptr = realloc (entry_parms.data.bytes, allocated_size + 4096); |
2198 | WELLMANNERED_ASSERT (reallocated_ptr, "out of memory"); |
2237 | WELLMANNERED_ASSERT (reallocated_ptr != NULL, "out of memory"); |
2199 | entry_parms.data = reallocated_ptr; |
2238 | entry_parms.data.bytes = reallocated_ptr; |
2200 | allocated_size += 4096; |
2239 | allocated_size += 4096; |
2201 | } |
2240 | } |
2202 | entry_parms.data[entry_parms. |
2241 | entry_parms.data.bytes[entry_parms.data.len++] = read_char; |
2203 | } |
2242 | } |
2204 | if (read_char == '\n') |
2243 | if (read_char == '\n') |
2205 | lineno++; // update line counter as we parse the inline content |
2244 | lineno++; // update line counter as we parse the inline content |
2206 | } |
2245 | } |
2207 | } // end for |
2246 | } // end for |
2208 | has_data_already = true; // remember we have data now |
- | |
2209 | } |
2247 | } |
2210 | else // not a content definition between { brackets }, must be either a pathname on the build host, or the target of a symlink |
2248 | else // not a content definition between { brackets }, must be either a pathname on the build host, or the target of a symlink |
2211 | { |
2249 | { |
2212 | is_quoted_context = (*line_ptr == '"'); |
2250 | is_quoted_context = (*line_ptr == '"'); |
2213 | if (is_quoted_context) |
2251 | if (is_quoted_context) |
Line 2229... | Line 2267... | ||
2229 | if (is_quoted_context && (*line_ptr == '"')) |
2267 | if (is_quoted_context && (*line_ptr == '"')) |
2230 | line_ptr++; // skip a possible final quote |
2268 | line_ptr++; // skip a possible final quote |
2231 | 2269 | ||
2232 | if (S_ISLNK (entry_parms.st_mode)) // are we storing a symlink ? |
2270 | if (S_ISLNK (entry_parms.st_mode)) // are we storing a symlink ? |
2233 | { |
2271 | { |
2234 | entry_parms.data = strdup (specifiedpathname_start); // if so, store the symlink target as the dirent's blob data |
2272 | entry_parms.data.bytes = strdup (specifiedpathname_start); // if so, store the symlink target as the dirent's blob data |
2235 | WELLMANNERED_ASSERT (entry_parms.data, "out of memory"); |
2273 | WELLMANNERED_ASSERT (entry_parms.data.bytes != NULL, "out of memory"); |
2236 | entry_parms. |
2274 | entry_parms.data.len = strlen (specifiedpathname_start); |
2237 | has_data_already = true; // remember we have data now |
- | |
2238 | } |
2275 | } |
2239 | else // it's a build host filesystem path |
2276 | else // it's a build host filesystem path |
2240 | strcpy (path_on_buildhost, line_ptr); // the path on the build host is given after the equal sign |
2277 | strcpy (path_on_buildhost, line_ptr); // the path on the build host is given after the equal sign |
2241 | } |
2278 | } |
2242 | } |
2279 | } |
Line 2263... | Line 2300... | ||
2263 | else // file or device node |
2300 | else // file or device node |
2264 | entry_parms.st_mode |= entry_parms.perms; |
2301 | entry_parms.st_mode |= entry_parms.perms; |
2265 | 2302 | ||
2266 | add_fsentry (&fsentries, &fsentry_count, &entry_parms, path_in_ifs, path_on_buildhost); // and add filesystem entry |
2303 | add_fsentry (&fsentries, &fsentry_count, &entry_parms, path_in_ifs, path_on_buildhost); // and add filesystem entry |
2267 | 2304 | ||
2268 | if (entry_parms.data != NULL) |
2305 | if (entry_parms.data.bytes != NULL) |
2269 | free (entry_parms.data); // if blob data was allocated, free it |
2306 | free (entry_parms.data.bytes); // if blob data was allocated, free it |
2270 | } |
2307 | } |
2271 | 2308 | ||
2272 | // write IFS file |
2309 | // write IFS file |
2273 | fp = fopen (ifs_pathname, "w+b"); |
2310 | fp = fopen (ifs_pathname, "w+b"); |
2274 | if (fp == NULL) |
2311 | if (fp == NULL) |
Line 2279... | Line 2316... | ||
2279 | 2316 | ||
2280 | // do we have a startup file ? if so, this is a bootable image |
2317 | // do we have a startup file ? if so, this is a bootable image |
2281 | if (startupfile_pathname != NULL) |
2318 | if (startupfile_pathname != NULL) |
2282 | { |
2319 | { |
2283 | // write boot prefix |
2320 | // write boot prefix |
- | 2321 | // ###################################################################################################################################################################################################################################### |
|
- | 2322 | // # FIXME: figure out how to re-create it |
|
- | 2323 | // ###################################################################################################################################################################################################################################### |
|
2284 | fwrite_filecontents (bootfile_pathname, fp); |
2324 | fwrite_filecontents (bootfile_pathname, fp); |
2285 | PAD_OUTFILE_TO (ROUND_TO_UPPER_MULTIPLE (ftell (fp), image_align)); // pad as necessary |
2325 | PAD_OUTFILE_TO (ROUND_TO_UPPER_MULTIPLE (ftell (fp), image_align)); // pad as necessary |
2286 | 2326 | ||
2287 | startupheader_offset = ftell (fp); // save startup header offset |
2327 | startupheader_offset = ftell (fp); // save startup header offset |
2288 | memset (&startup_header, 0, sizeof (startup_header)); // prepare startup header |
2328 | memset (&startup_header, 0, sizeof (startup_header)); // prepare startup header |
Line 2309... | Line 2349... | ||
2309 | startup_header.preboot_size = (uint16_t) bootfile_size; // [I ] Size of loaded before header, here 0xf30 or 3888 bytes (size of "bios.boot" file)) |
2349 | startup_header.preboot_size = (uint16_t) bootfile_size; // [I ] Size of loaded before header, here 0xf30 or 3888 bytes (size of "bios.boot" file)) |
2310 | fwrite_or_die (&startup_header, 1, sizeof (startup_header), fp); // write startup header |
2350 | fwrite_or_die (&startup_header, 1, sizeof (startup_header), fp); // write startup header |
2311 | PAD_OUTFILE_TO (ROUND_TO_UPPER_MULTIPLE (ftell (fp), image_align)); // pad as necessary |
2351 | PAD_OUTFILE_TO (ROUND_TO_UPPER_MULTIPLE (ftell (fp), image_align)); // pad as necessary |
2312 | 2352 | ||
2313 | // ###################################################################################################################################################################################################################################### |
2353 | // ###################################################################################################################################################################################################################################### |
2314 | // # FIXME: figure out how to re-create it: |
2354 | // # FIXME: figure out how to re-create it: |
- | 2355 | // first: open "startup-x86" ELF file, |
|
- | 2356 | // lookup section headers table (there is no program headers table in this one) |
|
- | 2357 | // FIXME: figure out something in there where the result is 0x1401030 !!! |
|
2315 | // |
2358 | // then: call the linker: ld --sysroot=${QNX_TARGET}/x86_64/ -T${QNX_TARGET}/x86_64/lib/nto.link --section-start .text=0x1401030 --no-relax ${QNX_TARGET}/x86_64/boot/sys/startup-x86 -o startup.bin.UNSTRIPPED |
- | 2359 | // then: parse resulting ELF file, take all program segments and concatenate them --> this is the blob (FIXME: wrong?) |
|
2316 | // ###################################################################################################################################################################################################################################### |
2360 | // ###################################################################################################################################################################################################################################### |
- | 2361 | #if 0 // nonworking |
|
- | 2362 | { |
|
- | 2363 | buffer_t startupfile; |
|
- | 2364 | elf_section_header_t *shdr_text; |
|
- | 2365 | size_t segment_len; |
|
- | 2366 | FILE *control_fp = fopen ("startup.bin.MYSTRIPPED", "wb"); |
|
- | 2367 | ||
- | 2368 | if (read_filecontents ("startup.bin.UNSTRIPPED", MKIFS_PATH, &startupfile) == NULL) |
|
- | 2369 | { |
|
- | 2370 | fprintf (stderr, "fatal error: couldn't read startup-x86\n"); |
|
- | 2371 | exit (1); |
|
- | 2372 | } |
|
- | 2373 | elf = (elf_header_t *) startupfile.bytes; // quick access to ELF header |
|
- | 2374 | table_count = ELF_GET_NUMERIC (elf, elf, program_header_table_len); // get the number of program headers |
|
- | 2375 | for (table_index = 0; table_index < table_count; table_index++) // cycle through program headers |
|
- | 2376 | { |
|
- | 2377 | phdr = (elf_program_header_t *) &startupfile.bytes[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 |
|
- | 2378 | segment_len = ELF_GET_NUMERIC (elf, phdr, size_in_file); |
|
- | 2379 | fwrite_or_die (&startupfile.bytes[ELF_GET_NUMERIC (elf, phdr, file_offset)], 1, segment_len, fp); // dump program segment |
|
- | 2380 | fwrite_or_die (&startupfile.bytes[ELF_GET_NUMERIC (elf, phdr, file_offset)], 1, segment_len, control_fp); // dump program segment |
|
- | 2381 | while (segment_len % 4096 > 0) |
|
- | 2382 | { |
|
- | 2383 | fputc (0, control_fp); |
|
- | 2384 | segment_len++; |
|
- | 2385 | } |
|
- | 2386 | } |
|
- | 2387 | ||
- | 2388 | fclose (control_fp); |
|
- | 2389 | free (startupfile.bytes); |
|
- | 2390 | } |
|
- | 2391 | #else // working |
|
2317 | fwrite_filecontents (startupfile_pathname, fp); // write startup code from blob file |
2392 | fwrite_filecontents (startupfile_pathname, fp); // write startup code from blob file |
- | 2393 | #endif // working |
|
2318 | PAD_OUTFILE_TO (ROUND_TO_UPPER_MULTIPLE (ftell (fp), image_align)); // pad as necessary |
2394 | PAD_OUTFILE_TO (ROUND_TO_UPPER_MULTIPLE (ftell (fp), image_align)); // pad as necessary |
2319 | 2395 | ||
2320 | startuptrailer_offset = ftell (fp); // save startup trailer offset |
2396 | startuptrailer_offset = ftell (fp); // save startup trailer offset |
2321 | fwrite_or_die (&startup_trailer, 1, sizeof (startup_trailer), fp); // write startup trailer |
2397 | fwrite_or_die (&startup_trailer, 1, sizeof (startup_trailer), fp); // write startup trailer |
2322 | PAD_OUTFILE_TO (ROUND_TO_UPPER_MULTIPLE (ftell (fp), image_align)); // pad as necessary |
2398 | PAD_OUTFILE_TO (ROUND_TO_UPPER_MULTIPLE (ftell (fp), image_align)); // pad as necessary |
Line 2383... | Line 2459... | ||
2383 | largest_index = fsentry_index; |
2459 | largest_index = fsentry_index; |
2384 | } |
2460 | } |
2385 | } |
2461 | } |
2386 | if (largest_size == 0) |
2462 | if (largest_size == 0) |
2387 | break; // found none ? if so, stop searching |
2463 | break; // found none ? if so, stop searching |
- | 2464 | ||
- | 2465 | fsentries[largest_index].u.file.offset = (uint32_t) (curr_offset - imageheader_offset); // save file data blob offset in file structure |
|
2388 | 2466 | ||
2389 | // is the file we're storing a preprocessed ELF file ? |
2467 | // is the file we're storing a preprocessed ELF file ? |
2390 | if (fsentries[ |
2468 | if (fsentries[largest_index].header.ino & IFS_INO_PROCESSED_ELF) |
2391 | { |
2469 | { |
2392 | elf = (elf_header_t *) fsentries[ |
2470 | elf = (elf_header_t *) fsentries[largest_index].u.file.UNSAVED_databuf; // quick access to ELF header |
2393 | table_count = ELF_GET_NUMERIC (elf, elf, program_header_table_len); // get the number of program headers |
2471 | table_count = ELF_GET_NUMERIC (elf, elf, program_header_table_len); // get the number of program headers |
2394 | for (table_index = 0; table_index < table_count; table_index++) |
2472 | for (table_index = 0; table_index < table_count; table_index++) |
2395 | { |
2473 | { |
2396 | phdr = (elf_program_header_t *) &fsentries[ |
2474 | phdr = (elf_program_header_t *) &fsentries[largest_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 |
- | 2475 | corrective_offset = ELF_GET_NUMERIC (elf, phdr, virtual_addr) - ELF_GET_NUMERIC (elf, phdr, file_offset); |
|
- | 2476 | if (ELF_GET_NUMERIC (elf, phdr, size_in_memory) != 0) // only patch the physical address of segments that have an actual size in memory |
|
2397 | ELF_SET_NUMERIC (elf, phdr, physical_addr, ELF_GET_NUMERIC (elf, phdr, physical_addr) + |
2477 | ELF_SET_NUMERIC (elf, phdr, physical_addr, ELF_GET_NUMERIC (elf, phdr, physical_addr) + 0x1400000 + curr_offset - corrective_offset); // patch the physical address member of the program header table |
2398 | } |
2478 | } |
2399 | } |
2479 | } |
2400 | 2480 | ||
2401 | fsentries[largest_index].u.file.offset = (uint32_t) (curr_offset - imageheader_offset); // save file data blob offset in file structure |
- | |
2402 | fwrite_or_die (fsentries[largest_index].u.file.UNSAVED_databuf, 1, fsentries[largest_index].u.file.size, fp); // write file data blob |
2481 | fwrite_or_die (fsentries[largest_index].u.file.UNSAVED_databuf, 1, fsentries[largest_index].u.file.size, fp); // write file data blob |
2403 | fsentries[largest_index].UNSAVED_was_data_written = true; // and remember this file's data was written |
2482 | fsentries[largest_index].UNSAVED_was_data_written = true; // and remember this file's data was written |
2404 | } |
2483 | } |
2405 | fprintf (stderr, "Current offset: 0x%zx\n", curr_offset); |
2484 | fprintf (stderr, "Current offset: 0x%zx\n", curr_offset); |
2406 | fprintf (stderr, "Kernel file offset: 0x%zx\n", kernelfile_offset); |
2485 | fprintf (stderr, "Kernel file offset: 0x%zx\n", kernelfile_offset); |
Line 2410... | Line 2489... | ||
2410 | for (fsentry_index = 1; fsentry_index < fsentry_count; fsentry_index++) |
2489 | for (fsentry_index = 1; fsentry_index < fsentry_count; fsentry_index++) |
2411 | if (fsentries[fsentry_index].header.ino == image_kernel_ino) |
2490 | if (fsentries[fsentry_index].header.ino == image_kernel_ino) |
2412 | break; // locate the kernel directory entry (can't fail) |
2491 | break; // locate the kernel directory entry (can't fail) |
2413 | curr_offset = ftell (fp); // see where we are |
2492 | curr_offset = ftell (fp); // see where we are |
2414 | fsentries[fsentry_index].u.file.offset = (uint32_t) (curr_offset - imageheader_offset); // save file data blob offset in file structure |
2493 | fsentries[fsentry_index].u.file.offset = (uint32_t) (curr_offset - imageheader_offset); // save file data blob offset in file structure |
2415 | // ###################################################################################################################################################################################################################################### |
- | |
2416 | // # FIXME: figure out how to re-create it: linker call involved |
- | |
2417 | // # $ 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 |
- | |
2418 | // ###################################################################################################################################################################################################################################### |
- | |
2419 |
|
2494 | fwrite_or_die (fsentries[fsentry_index].u.file.UNSAVED_databuf, 1, fsentries[fsentry_index].u.file.size, fp); // write kernel file data blob |
2420 | PAD_OUTFILE_TO (ROUND_TO_UPPER_MULTIPLE (ftell (fp), image_align)); // pad as necessary |
2495 | PAD_OUTFILE_TO (ROUND_TO_UPPER_MULTIPLE (ftell (fp), image_align)); // pad as necessary |
2421 | fsentries[fsentry_index].UNSAVED_was_data_written = true; // and remember this file's data was written |
2496 | fsentries[fsentry_index].UNSAVED_was_data_written = true; // and remember this file's data was written |
2422 | } |
2497 | } |
2423 | 2498 | ||
2424 | // then write all the other files by increasing inode number: ELF files first |
2499 | // then write all the other files by increasing inode number: ELF files first |
Line 2436... | Line 2511... | ||
2436 | elf = (elf_header_t *) fsentries[fsentry_index].u.file.UNSAVED_databuf; // quick access to ELF header |
2511 | elf = (elf_header_t *) fsentries[fsentry_index].u.file.UNSAVED_databuf; // quick access to ELF header |
2437 | table_count = ELF_GET_NUMERIC (elf, elf, program_header_table_len); // get the number of program headers |
2512 | table_count = ELF_GET_NUMERIC (elf, elf, program_header_table_len); // get the number of program headers |
2438 | for (table_index = 0; table_index < table_count; table_index++) |
2513 | for (table_index = 0; table_index < table_count; table_index++) |
2439 | { |
2514 | { |
2440 | 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 |
2515 | 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 |
- | 2516 | corrective_offset = ELF_GET_NUMERIC (elf, phdr, virtual_addr) - ELF_GET_NUMERIC (elf, phdr, file_offset); |
|
- | 2517 | if (ELF_GET_NUMERIC (elf, phdr, size_in_memory) != 0) // only patch the physical address of segments that have an actual size in memory |
|
2441 | ELF_SET_NUMERIC (elf, phdr, physical_addr, ELF_GET_NUMERIC (elf, phdr, physical_addr) + |
2518 | ELF_SET_NUMERIC (elf, phdr, physical_addr, ELF_GET_NUMERIC (elf, phdr, physical_addr) + 0x1400000 + curr_offset - corrective_offset); // patch the physical address member of the program header table |
2442 | } |
2519 | } |
2443 | } |
2520 | } |
2444 | 2521 | ||
2445 | fwrite_or_die (fsentries[fsentry_index].u.file.UNSAVED_databuf, 1, fsentries[fsentry_index].u.file.size, fp); // write file data blob |
2522 | fwrite_or_die (fsentries[fsentry_index].u.file.UNSAVED_databuf, 1, fsentries[fsentry_index].u.file.size, fp); // write file data blob |
2446 | fsentries[fsentry_index].UNSAVED_was_data_written = true; // and remember this file's data was written |
2523 | fsentries[fsentry_index].UNSAVED_was_data_written = true; // and remember this file's data was written |
Line 2477... | Line 2554... | ||
2477 | { |
2554 | { |
2478 | // rewrite startup header with final values |
2555 | // rewrite startup header with final values |
2479 | fseek_or_die (fp, startupheader_offset, SEEK_SET); |
2556 | fseek_or_die (fp, startupheader_offset, SEEK_SET); |
2480 | startup_header.startup_size = (uint32_t) (imageheader_offset - startupheader_offset); // size of startup header up to image header |
2557 | startup_header.startup_size = (uint32_t) (imageheader_offset - startupheader_offset); // size of startup header up to image header |
2481 | startup_header.imagefs_size = (uint32_t) (final_size - imageheader_offset); // size of uncompressed imagefs |
2558 | startup_header.imagefs_size = (uint32_t) (final_size - imageheader_offset); // size of uncompressed imagefs |
2482 | startup_header.ram_size = (uint32_t) final_size |
2559 | startup_header.ram_size = (uint32_t) (final_size - startupheader_offset); |
2483 | startup_header.stored_size = (uint32_t) final_size; |
2560 | startup_header.stored_size = (uint32_t) (final_size - startupheader_offset); |
2484 | fwrite_or_die (&startup_header, 1, sizeof (startup_header), fp); // write startup header |
2561 | fwrite_or_die (&startup_header, 1, sizeof (startup_header), fp); // write startup header |
2485 | } |
2562 | } |
2486 | 2563 | ||
2487 | // rewrite image header with final values |
2564 | // rewrite image header with final values |
2488 | fseek_or_die (fp, imageheader_offset, SEEK_SET); |
2565 | fseek_or_die (fp, imageheader_offset, SEEK_SET); |
Line 2499... | Line 2576... | ||
2499 | 2576 | ||
2500 | fclose (fp); // ensure everything is flushed |
2577 | fclose (fp); // ensure everything is flushed |
2501 | 2578 | ||
2502 | // ALL CHECKSUMS AT THE VERY END |
2579 | // ALL CHECKSUMS AT THE VERY END |
2503 | 2580 | ||
2504 | blob_data = NULL; |
- | |
2505 | read_filecontents (ifs_pathname, ".", & |
2581 | read_filecontents (ifs_pathname, ".", &blob); |
2506 | WELLMANNERED_ASSERT ( |
2582 | WELLMANNERED_ASSERT (blob.bytes != NULL, "failed to open IFS file for checksumming: %s", strerror (errno)); |
2507 | 2583 | ||
2508 | // do we have a startup file ? if so, this is a bootable image |
2584 | // do we have a startup file ? if so, this is a bootable image |
2509 | if (startupfile_pathname != NULL) |
2585 | if (startupfile_pathname != NULL) |
2510 | { |
2586 | { |
2511 | // compute SHA-512 checksum and V1 checksum of startup block |
2587 | // compute SHA-512 checksum and V1 checksum of startup block |
Line 2513... | Line 2589... | ||
2513 | || (!(startup_header.flags1 & STARTUP_HDR_FLAGS1_BIGENDIAN) && (__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__))) |
2589 | || (!(startup_header.flags1 & STARTUP_HDR_FLAGS1_BIGENDIAN) && (__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__))) |
2514 | is_foreign_endianness = true; // if the header is big endian and we're on a little endian machine, or the other way around, it's a foreign endianness |
2590 | is_foreign_endianness = true; // if the header is big endian and we're on a little endian machine, or the other way around, it's a foreign endianness |
2515 | else |
2591 | else |
2516 | is_foreign_endianness = false; // else this header is for the same endianness as us |
2592 | is_foreign_endianness = false; // else this header is for the same endianness as us |
2517 | 2593 | ||
2518 | SHA512 (& |
2594 | SHA512 (&blob.bytes[startupheader_offset], startuptrailer_offset - startupheader_offset, &blob.bytes[startuptrailer_offset]); // compute SHA512 checksum and write it in place in blob data |
2519 | checksum = update_checksum (& |
2595 | checksum = update_checksum (&blob.bytes[startupheader_offset], startuptrailer_offset + SHA512_DIGEST_LENGTH - startupheader_offset, is_foreign_endianness); // compute old checksum |
2520 | memcpy (& |
2596 | memcpy (&blob.bytes[startuptrailer_offset + SHA512_DIGEST_LENGTH], &checksum, 4); // and write it in place |
2521 | } |
2597 | } |
2522 | 2598 | ||
2523 | // compute SHA-512 checksum and V1 checksum of image block |
2599 | // compute SHA-512 checksum and V1 checksum of image block |
2524 | if ( ( (image_header.flags & IMAGE_FLAGS_BIGENDIAN) && (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__)) |
2600 | if ( ( (image_header.flags & IMAGE_FLAGS_BIGENDIAN) && (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__)) |
2525 | || (!(image_header.flags & IMAGE_FLAGS_BIGENDIAN) && (__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__))) |
2601 | || (!(image_header.flags & IMAGE_FLAGS_BIGENDIAN) && (__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__))) |
2526 | is_foreign_endianness = true; // if the header is big endian and we're on a little endian machine, or the other way around, it's a foreign endianness |
2602 | is_foreign_endianness = true; // if the header is big endian and we're on a little endian machine, or the other way around, it's a foreign endianness |
2527 | else |
2603 | else |
2528 | is_foreign_endianness = false; // else this header is for the same endianness as us |
2604 | is_foreign_endianness = false; // else this header is for the same endianness as us |
2529 | 2605 | ||
2530 | SHA512 (& |
2606 | SHA512 (&blob.bytes[imageheader_offset], imagetrailer_offset - imageheader_offset, &blob.bytes[imagetrailer_offset]); // compute SHA512 checksum and write it in place in blob data |
2531 | checksum = update_checksum (& |
2607 | checksum = update_checksum (&blob.bytes[imageheader_offset], imagetrailer_offset + SHA512_DIGEST_LENGTH - imageheader_offset, is_foreign_endianness); // compute old checksum |
2532 | memcpy (& |
2608 | memcpy (&blob.bytes[imagetrailer_offset + SHA512_DIGEST_LENGTH], &checksum, 4); // and write it in place |
2533 | 2609 | ||
2534 | // now rewrite IFS with the correct checksums |
2610 | // now rewrite IFS with the correct checksums |
2535 | fp = fopen (ifs_pathname, "wb"); |
2611 | fp = fopen (ifs_pathname, "wb"); |
2536 | WELLMANNERED_ASSERT (fp, "failed to reopen IFS file for checksumming: %s", strerror (errno)); |
2612 | WELLMANNERED_ASSERT (fp, "failed to reopen IFS file for checksumming: %s", strerror (errno)); |
2537 | fwrite_or_die ( |
2613 | fwrite_or_die (blob.bytes, 1, blob.len, fp); |
2538 | fclose (fp); |
2614 | fclose (fp); |
2539 | free ( |
2615 | free (blob.bytes); |
2540 | 2616 | ||
2541 | // finished, exit with a success code |
2617 | // finished, exit with a success code |
2542 | fprintf (stdout, "Success\n"); |
2618 | fprintf (stdout, "Success\n"); |
2543 | exit (0); |
2619 | exit (0); |
2544 | } |
2620 | } |
Line 2601... | Line 2677... | ||
2601 | size_t nearest_distance; |
2677 | size_t nearest_distance; |
2602 | size_t nearest_index; |
2678 | size_t nearest_index; |
2603 | size_t byte_index; |
2679 | size_t byte_index; |
2604 | uint32_t recorded_checksum; |
2680 | uint32_t recorded_checksum; |
2605 | uint32_t computed_checksum; |
2681 | uint32_t computed_checksum; |
2606 | uint8_t *filedata; |
- | |
2607 |
|
2682 | buffer_t file; |
2608 | time_t mtime; |
2683 | time_t mtime; |
2609 | 2684 | ||
2610 | // open and read IFS file |
2685 | // open and read IFS file |
2611 | if (read_filecontents (ifs_pathname, ".", & |
2686 | if (read_filecontents (ifs_pathname, ".", &file) == NULL) |
2612 | { |
2687 | { |
2613 | fprintf (stderr, "error: can't open \"%s\" for reading: %s\n", ifs_pathname, strerror (errno)); |
2688 | fprintf (stderr, "error: can't open \"%s\" for reading: %s\n", ifs_pathname, strerror (errno)); |
2614 | return (1); |
2689 | return (1); |
2615 | } |
2690 | } |
2616 | 2691 | ||
2617 | printf ("QNX In-kernel Filesystem analysis produced by ifstool version " VERSION_FMT_YYYYMMDD "\n", VERSION_ARG_YYYYMMDD); |
2692 | printf ("QNX In-kernel Filesystem analysis produced by ifstool version " VERSION_FMT_YYYYMMDD "\n", VERSION_ARG_YYYYMMDD); |
2618 | printf ("IFS file \"%s\" - size 0x%zx (%zd) bytes\n", ifs_pathname, |
2693 | printf ("IFS file \"%s\" - size 0x%zx (%zd) bytes\n", ifs_pathname, file.len, file.len); |
2619 | 2694 | ||
2620 | // parse file from start to end |
2695 | // parse file from start to end |
2621 | current_offset = 0; |
2696 | current_offset = 0; |
2622 | for (;;) |
2697 | for (;;) |
2623 | { |
2698 | { |
2624 | // does a startup header start here ? |
2699 | // does a startup header start here ? |
2625 | if ((current_offset + sizeof (startup_header_t) < |
2700 | if ((current_offset + sizeof (startup_header_t) < file.len) && (memcmp (&file.bytes[current_offset], "\xeb\x7e\xff\x00", 4) == 0)) |
2626 | { |
2701 | { |
2627 | startupheader_offset = current_offset; |
2702 | startupheader_offset = current_offset; |
2628 | startup_header = (startup_header_t *) & |
2703 | startup_header = (startup_header_t *) &file.bytes[startupheader_offset]; |
2629 | 2704 | ||
2630 | // layout: |
2705 | // layout: |
2631 | // [STARTUP HEADER] |
2706 | // [STARTUP HEADER] |
2632 | // (startup file blob) |
2707 | // (startup file blob) |
2633 | // [STARTUP TRAILER v1 or v2] |
2708 | // [STARTUP TRAILER v1 or v2] |
Line 2643... | Line 2718... | ||
2643 | printf (" startup_vaddr = 0x%08x (%d) - virtual address to transfer to after IPL is done\n", startup_header->startup_vaddr, startup_header->startup_vaddr); |
2718 | printf (" startup_vaddr = 0x%08x (%d) - virtual address to transfer to after IPL is done\n", startup_header->startup_vaddr, startup_header->startup_vaddr); |
2644 | printf (" paddr_bias = 0x%08x (%d) - value to add to physical addresses to get an indirectable pointer value\n", startup_header->paddr_bias, startup_header->paddr_bias); |
2719 | printf (" paddr_bias = 0x%08x (%d) - value to add to physical addresses to get an indirectable pointer value\n", startup_header->paddr_bias, startup_header->paddr_bias); |
2645 | printf (" image_paddr = 0x%08x (%d) - physical address of image\n", startup_header->image_paddr, startup_header->image_paddr); |
2720 | printf (" image_paddr = 0x%08x (%d) - physical address of image\n", startup_header->image_paddr, startup_header->image_paddr); |
2646 | printf (" ram_paddr = 0x%08x (%d) - physical address of RAM to copy image to (startup_size bytes copied)\n", startup_header->ram_paddr, startup_header->ram_paddr); |
2721 | printf (" ram_paddr = 0x%08x (%d) - physical address of RAM to copy image to (startup_size bytes copied)\n", startup_header->ram_paddr, startup_header->ram_paddr); |
2647 | printf (" ram_size = 0x%08x (%d) - amount of RAM used by the startup program and executables in the fs\n", startup_header->ram_size, startup_header->ram_size); |
2722 | printf (" ram_size = 0x%08x (%d) - amount of RAM used by the startup program and executables in the fs\n", startup_header->ram_size, startup_header->ram_size); |
2648 | printf (" startup_size = 0x%08x (%d) - size of startup (never compressed) - %s\n", startup_header->startup_size, startup_header->startup_size, (current_offset + sizeof (image_header_t) + startup_header->startup_size + (startup_header->flags1 & STARTUP_HDR_FLAGS1_TRAILER_V2 ? sizeof (image_trailer_v2_t) : sizeof (image_trailer_v1_t)) < |
2723 | printf (" startup_size = 0x%08x (%d) - size of startup (never compressed) - %s\n", startup_header->startup_size, startup_header->startup_size, (current_offset + sizeof (image_header_t) + startup_header->startup_size + (startup_header->flags1 & STARTUP_HDR_FLAGS1_TRAILER_V2 ? sizeof (image_trailer_v2_t) : sizeof (image_trailer_v1_t)) < file.len ? "looks good" : "BAD (IFS file too short)")); |
2649 | printf (" stored_size = 0x%08x (%d) - size of entire image - %s\n", startup_header->stored_size, startup_header->stored_size, (startup_header->stored_size == startup_header->ram_size ? "looks good" : "???")); |
2724 | printf (" stored_size = 0x%08x (%d) - size of entire image - %s\n", startup_header->stored_size, startup_header->stored_size, (startup_header->stored_size == startup_header->ram_size ? "looks good" : "???")); |
2650 | printf (" imagefs_paddr = 0x%08x (%d) - set by IPL when startup runs - %s\n", startup_header->imagefs_paddr, startup_header->imagefs_paddr, (startup_header->imagefs_paddr == 0 ? "looks good" : "??? should be zero")); |
2725 | printf (" imagefs_paddr = 0x%08x (%d) - set by IPL when startup runs - %s\n", startup_header->imagefs_paddr, startup_header->imagefs_paddr, (startup_header->imagefs_paddr == 0 ? "looks good" : "??? should be zero")); |
2651 | printf (" imagefs_size = 0x%08x (%d) - size of uncompressed imagefs\n", startup_header->imagefs_size, startup_header->imagefs_size); |
2726 | printf (" imagefs_size = 0x%08x (%d) - size of uncompressed imagefs\n", startup_header->imagefs_size, startup_header->imagefs_size); |
2652 | printf (" preboot_size = 0x%04x (%d) - size of loaded before header - %s\n", startup_header->preboot_size, startup_header->preboot_size, (startup_header->preboot_size == current_offset ? "looks good" : "???")); |
2727 | printf (" preboot_size = 0x%04x (%d) - size of loaded before header - %s\n", startup_header->preboot_size, startup_header->preboot_size, (startup_header->preboot_size == current_offset ? "looks good" : "???")); |
2653 | printf (" zero0 = 0x%04x (%d) - zeros - %s\n", startup_header->zero0, startup_header->zero0, (startup_header->zero0 == 0 ? "looks good" : "??? should be zero")); |
2728 | printf (" zero0 = 0x%04x (%d) - zeros - %s\n", startup_header->zero0, startup_header->zero0, (startup_header->zero0 == 0 ? "looks good" : "??? should be zero")); |
2654 | printf (" zero[0] = 0x%08x (%d) - zeros - %s\n", startup_header->zero[0], startup_header->zero[0], (startup_header->zero[0] == 0 ? "looks good" : "??? should be zero")); |
2729 | printf (" zero[0] = 0x%08x (%d) - zeros - %s\n", startup_header->zero[0], startup_header->zero[0], (startup_header->zero[0] == 0 ? "looks good" : "??? should be zero")); |
2655 | printf (" addr_off = 0x%016llx (%lld) - offset for startup_vaddr and [image|ram|imagefs]_paddr - %s\n", startup_header->addr_off, startup_header->addr_off, (startup_header->addr_off == 0 ? "looks good" : "??? should be zero")); |
2730 | printf (" addr_off = 0x%016llx (%lld) - offset for startup_vaddr and [image|ram|imagefs]_paddr - %s\n", startup_header->addr_off, startup_header->addr_off, (startup_header->addr_off == 0 ? "looks good" : "??? should be zero")); |
2656 | hex_printf ((uint8_t *) &startup_header->info[0], sizeof (startup_header->info), " info[48] =\n"); |
2731 | hex_printf ((uint8_t *) &startup_header->info[0], sizeof (startup_header->info), " info[48] =\n"); |
2657 | 2732 | ||
2658 | // validate that the file can contain up to the startup trailer |
2733 | // validate that the file can contain up to the startup trailer |
2659 | if (current_offset + startup_header->startup_size > |
2734 | if (current_offset + startup_header->startup_size > file.len) |
2660 | { |
2735 | { |
2661 | printf ("WARNING: this IFS file is corrupted (startup trailer extends past end of file)\n"); |
2736 | printf ("WARNING: this IFS file is corrupted (startup trailer extends past end of file)\n"); |
2662 | goto endofdata; |
2737 | goto endofdata; |
2663 | } |
2738 | } |
2664 | 2739 | ||
Line 2671... | Line 2746... | ||
2671 | 2746 | ||
2672 | // locate the right startup trailer at the right offset |
2747 | // locate the right startup trailer at the right offset |
2673 | if (startup_header->flags1 & STARTUP_HDR_FLAGS1_TRAILER_V2) |
2748 | if (startup_header->flags1 & STARTUP_HDR_FLAGS1_TRAILER_V2) |
2674 | { |
2749 | { |
2675 | startuptrailer_offset = current_offset + startup_header->startup_size - sizeof (startup_trailer_v2_t); |
2750 | startuptrailer_offset = current_offset + startup_header->startup_size - sizeof (startup_trailer_v2_t); |
2676 | startup_trailer_v2 = (startup_trailer_v2_t *) & |
2751 | startup_trailer_v2 = (startup_trailer_v2_t *) &file.bytes[startuptrailer_offset]; |
2677 | startupfile_blobsize = startup_header->startup_size - sizeof (startup_header_t) - sizeof (startup_trailer_v2_t); |
2752 | startupfile_blobsize = startup_header->startup_size - sizeof (startup_header_t) - sizeof (startup_trailer_v2_t); |
2678 | } |
2753 | } |
2679 | else // old V1 trailer |
2754 | else // old V1 trailer |
2680 | { |
2755 | { |
2681 | startuptrailer_offset = current_offset + startup_header->startup_size - sizeof (startup_trailer_v1_t); |
2756 | startuptrailer_offset = current_offset + startup_header->startup_size - sizeof (startup_trailer_v1_t); |
2682 | startup_trailer_v1 = (startup_trailer_v1_t *) & |
2757 | startup_trailer_v1 = (startup_trailer_v1_t *) &file.bytes[startuptrailer_offset]; |
2683 | startupfile_blobsize = startup_header->startup_size - sizeof (startup_header_t) - sizeof (startup_trailer_v1_t); |
2758 | startupfile_blobsize = startup_header->startup_size - sizeof (startup_header_t) - sizeof (startup_trailer_v1_t); |
2684 | } |
2759 | } |
2685 | 2760 | ||
2686 | current_offset += sizeof (startup_header_t); // jump over the startup header and reach the startup blob |
2761 | current_offset += sizeof (startup_header_t); // jump over the startup header and reach the startup blob |
2687 | printf ("\n"); |
2762 | printf ("\n"); |
2688 | printf ("Startup blob at offset 0x%zx (%zd):\n", current_offset, current_offset); |
2763 | printf ("Startup blob at offset 0x%zx (%zd):\n", current_offset, current_offset); |
2689 | printf (" size 0x%zx (%zd) bytes\n", startupfile_blobsize, startupfile_blobsize); |
2764 | printf (" size 0x%zx (%zd) bytes\n", startupfile_blobsize, startupfile_blobsize); |
2690 | printf (" checksum %d\n", update_checksum (& |
2765 | printf (" checksum %d\n", update_checksum (&file.bytes[current_offset], startupfile_blobsize, is_foreign_endianness)); |
2691 | 2766 | ||
2692 | current_offset += startupfile_blobsize; // jump over the startup blob and reach the startup trailer |
2767 | current_offset += startupfile_blobsize; // jump over the startup blob and reach the startup trailer |
2693 | printf ("\n"); |
2768 | printf ("\n"); |
2694 | printf ("Startup trailer at offset 0x%zx (%zd) - version %d:\n", current_offset, current_offset, (startup_header->flags1 & STARTUP_HDR_FLAGS1_TRAILER_V2 ? 2 : 1)); |
2769 | printf ("Startup trailer at offset 0x%zx (%zd) - version %d:\n", current_offset, current_offset, (startup_header->flags1 & STARTUP_HDR_FLAGS1_TRAILER_V2 ? 2 : 1)); |
2695 | if (startup_header->flags1 & STARTUP_HDR_FLAGS1_TRAILER_V2) |
2770 | if (startup_header->flags1 & STARTUP_HDR_FLAGS1_TRAILER_V2) |
Line 2717... | Line 2792... | ||
2717 | 2792 | ||
2718 | current_offset += (startup_header->flags1 & STARTUP_HDR_FLAGS1_TRAILER_V2 ? sizeof (startup_trailer_v2_t) : sizeof (startup_trailer_v1_t)); // now reach the next segment |
2793 | current_offset += (startup_header->flags1 & STARTUP_HDR_FLAGS1_TRAILER_V2 ? sizeof (startup_trailer_v2_t) : sizeof (startup_trailer_v1_t)); // now reach the next segment |
2719 | } |
2794 | } |
2720 | 2795 | ||
2721 | // else does an image header start here ? |
2796 | // else does an image header start here ? |
2722 | else if ((current_offset + sizeof (image_header_t) < |
2797 | else if ((current_offset + sizeof (image_header_t) < file.len) && (memcmp (&file.bytes[current_offset], "imagefs", 7) == 0)) |
2723 | { |
2798 | { |
2724 | imageheader_offset = current_offset; |
2799 | imageheader_offset = current_offset; |
2725 | image_header = (image_header_t *) & |
2800 | image_header = (image_header_t *) &file.bytes[imageheader_offset]; |
2726 | 2801 | ||
2727 | // layout: |
2802 | // layout: |
2728 | // [IMAGE HEADER] |
2803 | // [IMAGE HEADER] |
2729 | // [image directory entries] |
2804 | // [image directory entries] |
2730 | // [smallest file blobs up to KERNEL] |
2805 | // [smallest file blobs up to KERNEL] |
Line 2735... | Line 2810... | ||
2735 | 2810 | ||
2736 | printf ("\n"); |
2811 | printf ("\n"); |
2737 | printf ("Image header at offset %zx (%zd):\n", current_offset, current_offset); |
2812 | printf ("Image header at offset %zx (%zd):\n", current_offset, current_offset); |
2738 | printf (" signature = %02x %02x %02x %02x %02x %02x %02x (\"%.7s\") - good\n", image_header->signature[0], image_header->signature[1], image_header->signature[2], image_header->signature[3], image_header->signature[4], image_header->signature[5], image_header->signature[6], image_header->signature); |
2813 | printf (" signature = %02x %02x %02x %02x %02x %02x %02x (\"%.7s\") - good\n", image_header->signature[0], image_header->signature[1], image_header->signature[2], image_header->signature[3], image_header->signature[4], image_header->signature[5], image_header->signature[6], image_header->signature); |
2739 | printf (" flags = 0x%02x (%s)\n", image_header->flags, describe_uint8 (image_header->flags, imageheader_flags_strings)); |
2814 | printf (" flags = 0x%02x (%s)\n", image_header->flags, describe_uint8 (image_header->flags, imageheader_flags_strings)); |
2740 | printf (" image_size = 0x%08x (%d) - size from header to end of trailer - %s\n", image_header->image_size, image_header->image_size, (current_offset + image_header->image_size <= |
2815 | printf (" image_size = 0x%08x (%d) - size from header to end of trailer - %s\n", image_header->image_size, image_header->image_size, (current_offset + image_header->image_size <= file.len ? "looks good" : "BAD (IFS file too short)")); |
2741 | printf (" hdr_dir_size = 0x%08x (%d) - size from header to last dirent - %s\n", image_header->hdr_dir_size, image_header->hdr_dir_size, (current_offset + image_header->hdr_dir_size < |
2816 | printf (" hdr_dir_size = 0x%08x (%d) - size from header to last dirent - %s\n", image_header->hdr_dir_size, image_header->hdr_dir_size, (current_offset + image_header->hdr_dir_size < file.len ? "looks good" : "BAD (IFS file too short)")); |
2742 | printf (" dir_offset = 0x%08x (%d) - offset from header to first dirent - %s\n", image_header->dir_offset, image_header->dir_offset, (current_offset + image_header->dir_offset >= |
2817 | printf (" dir_offset = 0x%08x (%d) - offset from header to first dirent - %s\n", image_header->dir_offset, image_header->dir_offset, (current_offset + image_header->dir_offset >= file.len ? "BAD (IFS file too short)" : (image_header->dir_offset > image_header->hdr_dir_size ? "BAD" : "looks good"))); |
2743 | printf (" boot_ino[4] = { 0x%08x, 0x%08x, 0x%08x, 0x%08x }\n", image_header->boot_ino[0], image_header->boot_ino[1], image_header->boot_ino[2], image_header->boot_ino[3]); |
2818 | printf (" boot_ino[4] = { 0x%08x, 0x%08x, 0x%08x, 0x%08x }\n", image_header->boot_ino[0], image_header->boot_ino[1], image_header->boot_ino[2], image_header->boot_ino[3]); |
2744 | printf (" script_ino = 0x%08x (%d) - inode of compiled bootscript\n", image_header->script_ino, image_header->script_ino); |
2819 | printf (" script_ino = 0x%08x (%d) - inode of compiled bootscript\n", image_header->script_ino, image_header->script_ino); |
2745 | printf (" chain_paddr = 0x%08x (%d) - offset to next fs signature\n", image_header->chain_paddr, image_header->chain_paddr); |
2820 | printf (" chain_paddr = 0x%08x (%d) - offset to next fs signature\n", image_header->chain_paddr, image_header->chain_paddr); |
2746 | hex_printf ((uint8_t *) &image_header->spare[0], sizeof (image_header->spare), " spare[10] =\n"); |
2821 | hex_printf ((uint8_t *) &image_header->spare[0], sizeof (image_header->spare), " spare[10] =\n"); |
2747 | printf (" mountflags = 0x%08x (%s %s %s %s)\n", image_header->mountflags, BINARY (((uint8_t *) &image_header->mountflags)[0]), BINARY (((uint8_t *) &image_header->mountflags)[1]), BINARY (((uint8_t *) &image_header->mountflags)[2]), BINARY (((uint8_t *) &image_header->mountflags)[3])); |
2822 | printf (" mountflags = 0x%08x (%s %s %s %s)\n", image_header->mountflags, BINARY (((uint8_t *) &image_header->mountflags)[0]), BINARY (((uint8_t *) &image_header->mountflags)[1]), BINARY (((uint8_t *) &image_header->mountflags)[2]), BINARY (((uint8_t *) &image_header->mountflags)[3])); |
2748 | printf (" mountpoint = \"%s\"\n", image_header->mountpoint); |
2823 | printf (" mountpoint = \"%s\"\n", image_header->mountpoint); |
2749 | 2824 | ||
2750 | // validate that the file can contain up to the image trailer |
2825 | // validate that the file can contain up to the image trailer |
2751 | if (current_offset + image_header->image_size > |
2826 | if (current_offset + image_header->image_size > file.len) |
2752 | { |
2827 | { |
2753 | printf ("WARNING: this IFS file is corrupted (image trailer extends past end of file)\n"); |
2828 | printf ("WARNING: this IFS file is corrupted (image trailer extends past end of file)\n"); |
2754 | goto endofdata; |
2829 | goto endofdata; |
2755 | } |
2830 | } |
2756 | 2831 | ||
Line 2763... | Line 2838... | ||
2763 | 2838 | ||
2764 | // locate the image trailer at the right offset |
2839 | // locate the image trailer at the right offset |
2765 | if (image_header->flags & IMAGE_FLAGS_TRAILER_V2) |
2840 | if (image_header->flags & IMAGE_FLAGS_TRAILER_V2) |
2766 | { |
2841 | { |
2767 | imagetrailer_offset = current_offset + image_header->image_size - sizeof (image_trailer_v2_t); |
2842 | imagetrailer_offset = current_offset + image_header->image_size - sizeof (image_trailer_v2_t); |
2768 | image_trailer_v2 = (image_trailer_v2_t *) & |
2843 | image_trailer_v2 = (image_trailer_v2_t *) &file.bytes[imagetrailer_offset]; |
2769 | } |
2844 | } |
2770 | else // old V1 trailer |
2845 | else // old V1 trailer |
2771 | { |
2846 | { |
2772 | imagetrailer_offset = current_offset + image_header->image_size - sizeof (image_trailer_v1_t); |
2847 | imagetrailer_offset = current_offset + image_header->image_size - sizeof (image_trailer_v1_t); |
2773 | image_trailer_v1 = (image_trailer_v1_t *) & |
2848 | image_trailer_v1 = (image_trailer_v1_t *) &file.bytes[imagetrailer_offset]; |
2774 | } |
2849 | } |
2775 | 2850 | ||
2776 | current_offset += sizeof (image_header_t); // jump over the image header and reach the first directory entry |
2851 | current_offset += sizeof (image_header_t); // jump over the image header and reach the first directory entry |
2777 | 2852 | ||
2778 | // there may be padding before the first directory entry |
2853 | // there may be padding before the first directory entry |
2779 | if (image_header->dir_offset - sizeof (image_header_t) > 0) |
2854 | if (image_header->dir_offset - sizeof (image_header_t) > 0) |
2780 | hex_printf (& |
2855 | hex_printf (&file.bytes[current_offset], image_header->dir_offset - sizeof (image_header_t), "\n" "%zd padding bytes at offset 0x%zd (%zd):\n", image_header->dir_offset - sizeof (image_header_t), current_offset, current_offset); |
2781 | current_offset += image_header->dir_offset - sizeof (image_header_t); // padding was processed, jump over it |
2856 | current_offset += image_header->dir_offset - sizeof (image_header_t); // padding was processed, jump over it |
2782 | 2857 | ||
2783 | // dump all directory entries until the last one included |
2858 | // dump all directory entries until the last one included |
2784 | fsentries = NULL; |
2859 | fsentries = NULL; |
2785 | fsentry_count = 0; |
2860 | fsentry_count = 0; |
2786 | while (current_offset < imageheader_offset + image_header->hdr_dir_size) |
2861 | while (current_offset < imageheader_offset + image_header->hdr_dir_size) |
2787 | { |
2862 | { |
2788 | current_fsentry = (fsentry_t *) & |
2863 | current_fsentry = (fsentry_t *) &file.bytes[current_offset]; |
2789 | 2864 | ||
2790 | if (imageheader_offset + image_header->hdr_dir_size - current_offset < sizeof (current_fsentry->header)) |
2865 | if (imageheader_offset + image_header->hdr_dir_size - current_offset < sizeof (current_fsentry->header)) |
2791 | break; // end padding reached |
2866 | break; // end padding reached |
2792 | 2867 | ||
2793 | // stack up the filesystem entry pointers in an array while we read them |
2868 | // stack up the filesystem entry pointers in an array while we read them |
Line 2797... | Line 2872... | ||
2797 | fsentries[fsentry_count] = current_fsentry; |
2872 | fsentries[fsentry_count] = current_fsentry; |
2798 | fsentry_count++; |
2873 | fsentry_count++; |
2799 | 2874 | ||
2800 | printf ("\n"); |
2875 | printf ("\n"); |
2801 | printf ("Filesystem entry at offset 0x%zx (%zd) - last one at 0x%zd (%zd):\n", current_offset, current_offset, imageheader_offset + image_header->hdr_dir_size, imageheader_offset + image_header->hdr_dir_size); |
2876 | printf ("Filesystem entry at offset 0x%zx (%zd) - last one at 0x%zd (%zd):\n", current_offset, current_offset, imageheader_offset + image_header->hdr_dir_size, imageheader_offset + image_header->hdr_dir_size); |
2802 | printf (" size = 0x%04x (%d) - size of dirent - %s\n", current_fsentry->header.size, current_fsentry->header.size, ((current_fsentry->header.size > 0) && (current_offset + current_fsentry->header.size < |
2877 | printf (" size = 0x%04x (%d) - size of dirent - %s\n", current_fsentry->header.size, current_fsentry->header.size, ((current_fsentry->header.size > 0) && (current_offset + current_fsentry->header.size < file.len) ? "looks good" : "BAD")); |
2803 | printf (" extattr_offset = 0x%04x (%d) - %s\n", current_fsentry->header.extattr_offset, current_fsentry->header.extattr_offset, (current_fsentry->header.extattr_offset == 0 ? "no extattr" : "has extattr")); |
2878 | printf (" extattr_offset = 0x%04x (%d) - %s\n", current_fsentry->header.extattr_offset, current_fsentry->header.extattr_offset, (current_fsentry->header.extattr_offset == 0 ? "no extattr" : "has extattr")); |
2804 | printf (" ino = 0x%08x (%d) - inode number (%s%s%s%s)\n", current_fsentry->header.ino, current_fsentry->header.ino, (current_fsentry->header.ino & 0xE0000000 ? "is" : "nothing special"), (current_fsentry->header.ino & IFS_INO_PROCESSED_ELF ? " PROCESSED_ELF" : ""), (current_fsentry->header.ino & IFS_INO_RUNONCE_ELF ? " RUNONCE_ELF" : ""), (current_fsentry->header.ino & IFS_INO_BOOTSTRAP_EXE ? " BOOTSTRAP_EXE" : "")); |
2879 | printf (" ino = 0x%08x (%d) - inode number (%s%s%s%s)\n", current_fsentry->header.ino, current_fsentry->header.ino, (current_fsentry->header.ino & 0xE0000000 ? "is" : "nothing special"), (current_fsentry->header.ino & IFS_INO_PROCESSED_ELF ? " PROCESSED_ELF" : ""), (current_fsentry->header.ino & IFS_INO_RUNONCE_ELF ? " RUNONCE_ELF" : ""), (current_fsentry->header.ino & IFS_INO_BOOTSTRAP_EXE ? " BOOTSTRAP_EXE" : "")); |
2805 | printf (" mode = 0x%08x (%d) - %s (0%o), POSIX permissions 0%o\n", current_fsentry->header.mode, current_fsentry->header.mode, (S_ISDIR (current_fsentry->header.mode) ? "directory" : (S_ISREG (current_fsentry->header.mode) ? "file" : (S_ISLNK (current_fsentry->header.mode) ? "symlink" : "device"))), (current_fsentry->header.mode & 0xF000) >> 12, current_fsentry->header.mode & 0xFFF); |
2880 | printf (" mode = 0x%08x (%d) - %s (0%o), POSIX permissions 0%o\n", current_fsentry->header.mode, current_fsentry->header.mode, (S_ISDIR (current_fsentry->header.mode) ? "directory" : (S_ISREG (current_fsentry->header.mode) ? "file" : (S_ISLNK (current_fsentry->header.mode) ? "symlink" : "device"))), (current_fsentry->header.mode & 0xF000) >> 12, current_fsentry->header.mode & 0xFFF); |
2806 | printf (" gid = 0x%08x (%d) - owner group ID%s\n", current_fsentry->header.gid, current_fsentry->header.gid, (current_fsentry->header.gid == 0 ? " (root)" : "")); |
2881 | printf (" gid = 0x%08x (%d) - owner group ID%s\n", current_fsentry->header.gid, current_fsentry->header.gid, (current_fsentry->header.gid == 0 ? " (root)" : "")); |
2807 | printf (" uid = 0x%08x (%d) - owner user ID%s\n", current_fsentry->header.uid, current_fsentry->header.uid, (current_fsentry->header.uid == 0 ? " (root)" : "")); |
2882 | printf (" uid = 0x%08x (%d) - owner user ID%s\n", current_fsentry->header.uid, current_fsentry->header.uid, (current_fsentry->header.uid == 0 ? " (root)" : "")); |
Line 2809... | Line 2884... | ||
2809 | printf (" mtime = 0x%08x (%d) - POSIX timestamp: %s", current_fsentry->header.mtime, current_fsentry->header.mtime, asctime (localtime (&mtime))); // NOTE: asctime() provides the newline |
2884 | printf (" mtime = 0x%08x (%d) - POSIX timestamp: %s", current_fsentry->header.mtime, current_fsentry->header.mtime, asctime (localtime (&mtime))); // NOTE: asctime() provides the newline |
2810 | if (S_ISDIR (current_fsentry->header.mode)) |
2885 | if (S_ISDIR (current_fsentry->header.mode)) |
2811 | printf (" [DIRECTORY] path = \"%s\"\n", (char *) ¤t_fsentry->u.dir.path); // convert from pointer to char array |
2886 | printf (" [DIRECTORY] path = \"%s\"\n", (char *) ¤t_fsentry->u.dir.path); // convert from pointer to char array |
2812 | else if (S_ISREG (current_fsentry->header.mode)) |
2887 | else if (S_ISREG (current_fsentry->header.mode)) |
2813 | { |
2888 | { |
2814 | printf (" [FILE] offset = 0x%08x (%d) - %s\n", current_fsentry->u.file.offset, current_fsentry->u.file.offset, (imageheader_offset + current_fsentry->u.file.offset < |
2889 | printf (" [FILE] offset = 0x%08x (%d) - %s\n", current_fsentry->u.file.offset, current_fsentry->u.file.offset, (imageheader_offset + current_fsentry->u.file.offset < file.len ? "looks good" : "BAD (IFS file too short)")); |
2815 | printf (" [FILE] size = 0x%08x (%d) - %s\n", current_fsentry->u.file.size, current_fsentry->u.file.size, (imageheader_offset + current_fsentry->u.file.offset + current_fsentry->u.file.size < |
2890 | printf (" [FILE] size = 0x%08x (%d) - %s\n", current_fsentry->u.file.size, current_fsentry->u.file.size, (imageheader_offset + current_fsentry->u.file.offset + current_fsentry->u.file.size < file.len ? "looks good" : "BAD (IFS file too short)")); |
2816 | printf (" [FILE] path = \"%s\"\n", (char *) ¤t_fsentry->u.file.path); // convert from pointer to char array |
2891 | printf (" [FILE] path = \"%s\"\n", (char *) ¤t_fsentry->u.file.path); // convert from pointer to char array |
2817 | } |
2892 | } |
2818 | else if (S_ISLNK (current_fsentry->header.mode)) |
2893 | else if (S_ISLNK (current_fsentry->header.mode)) |
2819 | { |
2894 | { |
2820 | printf (" [SYMLINK] sym_offset = 0x%04x (%d) - %s\n", current_fsentry->u.symlink.sym_offset, current_fsentry->u.symlink.sym_offset, (sizeof (current_fsentry->header) + 2 * sizeof (uint16_t) + current_fsentry->u.symlink.sym_offset <= current_fsentry->header.size ? "looks good" : "BAD (dirent too short)")); |
2895 | printf (" [SYMLINK] sym_offset = 0x%04x (%d) - %s\n", current_fsentry->u.symlink.sym_offset, current_fsentry->u.symlink.sym_offset, (sizeof (current_fsentry->header) + 2 * sizeof (uint16_t) + current_fsentry->u.symlink.sym_offset <= current_fsentry->header.size ? "looks good" : "BAD (dirent too short)")); |
Line 2827... | Line 2902... | ||
2827 | printf (" [DEVICE] dev = 0x%08x (%d)\n", current_fsentry->u.device.dev, current_fsentry->u.device.dev); |
2902 | printf (" [DEVICE] dev = 0x%08x (%d)\n", current_fsentry->u.device.dev, current_fsentry->u.device.dev); |
2828 | printf (" [DEVICE] rdev = 0x%08x (%d)\n", current_fsentry->u.device.rdev, current_fsentry->u.device.rdev); |
2903 | printf (" [DEVICE] rdev = 0x%08x (%d)\n", current_fsentry->u.device.rdev, current_fsentry->u.device.rdev); |
2829 | printf (" [DEVICE] path = \"%s\"\n", (char *) ¤t_fsentry->u.device.path); // convert from pointer to char array |
2904 | printf (" [DEVICE] path = \"%s\"\n", (char *) ¤t_fsentry->u.device.path); // convert from pointer to char array |
2830 | } |
2905 | } |
2831 | 2906 | ||
2832 | if ((current_fsentry->header.size == 0) || (current_offset + current_fsentry->header.size >= |
2907 | if ((current_fsentry->header.size == 0) || (current_offset + current_fsentry->header.size >= file.len)) |
2833 | { |
2908 | { |
2834 | printf ("WARNING: this IFS file is corrupted (the size of this directory entry is invalid)\n"); |
2909 | printf ("WARNING: this IFS file is corrupted (the size of this directory entry is invalid)\n"); |
2835 | goto endofdata; |
2910 | goto endofdata; |
2836 | } |
2911 | } |
2837 | 2912 | ||
2838 | current_offset += current_fsentry->header.size; |
2913 | current_offset += current_fsentry->header.size; |
2839 | } |
2914 | } |
2840 | if (imageheader_offset + image_header->hdr_dir_size < current_offset + sizeof (current_fsentry->header)) |
2915 | if (imageheader_offset + image_header->hdr_dir_size < current_offset + sizeof (current_fsentry->header)) |
2841 | hex_printf (& |
2916 | hex_printf (&file.bytes[current_offset], imageheader_offset + image_header->hdr_dir_size - current_offset, "\n" "%zd padding bytes at offset 0x%zx (%zd):\n", imageheader_offset + image_header->hdr_dir_size - current_offset, current_offset, current_offset); |
2842 | current_offset += imageheader_offset + image_header->hdr_dir_size - current_offset; // padding was processed, jump over it |
2917 | current_offset += imageheader_offset + image_header->hdr_dir_size - current_offset; // padding was processed, jump over it |
2843 | 2918 | ||
2844 | // at this point we are past the directory entries; what is stored now, up to and until the image trailer, is the files' data |
2919 | // at this point we are past the directory entries; what is stored now, up to and until the image trailer, is the files' data |
2845 | if (fsentry_count > 0) |
2920 | if (fsentry_count > 0) |
2846 | { |
2921 | { |
Line 2862... | Line 2937... | ||
2862 | fsentry_index = nearest_index; |
2937 | fsentry_index = nearest_index; |
2863 | current_fsentry = fsentries[fsentry_index]; // quick access to closest fsentry |
2938 | current_fsentry = fsentries[fsentry_index]; // quick access to closest fsentry |
2864 | 2939 | ||
2865 | // there may be padding before the file data |
2940 | // there may be padding before the file data |
2866 | if (imageheader_offset + (size_t) current_fsentry->u.file.offset - current_offset > 0) |
2941 | if (imageheader_offset + (size_t) current_fsentry->u.file.offset - current_offset > 0) |
2867 | hex_printf (& |
2942 | hex_printf (&file.bytes[current_offset], imageheader_offset + (size_t) current_fsentry->u.file.offset - current_offset, "\n" "%zd padding bytes at offset 0x%zx (%zd):\n", imageheader_offset + (size_t) current_fsentry->u.file.offset - current_offset, current_offset, current_offset); |
2868 | current_offset += imageheader_offset + (size_t) current_fsentry->u.file.offset - current_offset; // padding was processed, jump over it |
2943 | current_offset += imageheader_offset + (size_t) current_fsentry->u.file.offset - current_offset; // padding was processed, jump over it |
2869 | 2944 | ||
2870 | printf ("\n"); |
2945 | printf ("\n"); |
2871 | printf ("File data blob at offset 0x%zx (%zd):\n", current_offset, current_offset); |
2946 | printf ("File data blob at offset 0x%zx (%zd):\n", current_offset, current_offset); |
2872 | printf (" corresponding dirent index: %zd/%zd\n", fsentry_index, fsentry_count); |
2947 | printf (" corresponding dirent index: %zd/%zd\n", fsentry_index, fsentry_count); |
2873 | printf (" corresponding inode 0x%08x (%d) -%s%s%s%s\n", current_fsentry->header.ino, current_fsentry->header.ino, (current_fsentry->header.ino & 0xE0000000 ? "" : " nothing special"), (current_fsentry->header.ino & IFS_INO_PROCESSED_ELF ? " PROCESSED_ELF" : ""), (current_fsentry->header.ino & IFS_INO_RUNONCE_ELF ? " RUNONCE_ELF" : ""), (current_fsentry->header.ino & IFS_INO_BOOTSTRAP_EXE ? " BOOTSTRAP_EXE" : "")); |
2948 | printf (" corresponding inode 0x%08x (%d) -%s%s%s%s\n", current_fsentry->header.ino, current_fsentry->header.ino, (current_fsentry->header.ino & 0xE0000000 ? "" : " nothing special"), (current_fsentry->header.ino & IFS_INO_PROCESSED_ELF ? " PROCESSED_ELF" : ""), (current_fsentry->header.ino & IFS_INO_RUNONCE_ELF ? " RUNONCE_ELF" : ""), (current_fsentry->header.ino & IFS_INO_BOOTSTRAP_EXE ? " BOOTSTRAP_EXE" : "")); |
2874 | printf (" corresponding path: \"%s\"\n", (char *) ¤t_fsentry->u.file.path); // convert from pointer to char array |
2949 | printf (" corresponding path: \"%s\"\n", (char *) ¤t_fsentry->u.file.path); // convert from pointer to char array |
2875 | printf (" size 0x%zx (%zd) bytes\n", (size_t) current_fsentry->u.file.size, (size_t) current_fsentry->u.file.size); |
2950 | printf (" size 0x%zx (%zd) bytes\n", (size_t) current_fsentry->u.file.size, (size_t) current_fsentry->u.file.size); |
2876 | if (current_offset + 4 < |
2951 | if (current_offset + 4 < file.len) |
2877 | hex_printf (& |
2952 | hex_printf (&file.bytes[current_offset], current_fsentry->u.file.size, " data:\n"); |
2878 | if (current_offset + current_fsentry->u.file.size < |
2953 | if (current_offset + current_fsentry->u.file.size < file.len) |
2879 | printf (" checksum %d\n", update_checksum (& |
2954 | printf (" checksum %d\n", update_checksum (&file.bytes[current_offset], current_fsentry->u.file.size, is_foreign_endianness)); |
2880 | else |
2955 | else |
2881 | { |
2956 | { |
2882 | printf ("WARNING: this IFS file is corrupted (the size of this file data extends past the IFS size)\n"); |
2957 | printf ("WARNING: this IFS file is corrupted (the size of this file data extends past the IFS size)\n"); |
2883 | goto endofdata; |
2958 | goto endofdata; |
2884 | } |
2959 | } |
Line 2887... | Line 2962... | ||
2887 | } |
2962 | } |
2888 | } |
2963 | } |
2889 | 2964 | ||
2890 | // ad this point we're past the last file data, there may be padding before the image trailer |
2965 | // ad this point we're past the last file data, there may be padding before the image trailer |
2891 | if (imagetrailer_offset - current_offset > 0) |
2966 | if (imagetrailer_offset - current_offset > 0) |
2892 | hex_printf (& |
2967 | hex_printf (&file.bytes[current_offset], imagetrailer_offset - current_offset, "\n" "%zd padding bytes at offset %zx (%zd):\n", imagetrailer_offset - current_offset, current_offset, current_offset); |
2893 | current_offset += imagetrailer_offset - current_offset; // padding was processed, jump over it |
2968 | current_offset += imagetrailer_offset - current_offset; // padding was processed, jump over it |
2894 | 2969 | ||
2895 | printf ("\n"); |
2970 | printf ("\n"); |
2896 | printf ("Image trailer at offset 0x%zx (%zd) - version %d:\n", current_offset, current_offset, (image_header->flags & IMAGE_FLAGS_TRAILER_V2 ? 2 : 1)); |
2971 | printf ("Image trailer at offset 0x%zx (%zd) - version %d:\n", current_offset, current_offset, (image_header->flags & IMAGE_FLAGS_TRAILER_V2 ? 2 : 1)); |
2897 | if (image_header->flags & IMAGE_FLAGS_TRAILER_V2) |
2972 | if (image_header->flags & IMAGE_FLAGS_TRAILER_V2) |
Line 2922... | Line 2997... | ||
2922 | 2997 | ||
2923 | // else it has to be a boot blob, of which we don't know the size, except that it has to fit in 0xffff bytes and be immediately followed by a startup header |
2998 | // else it has to be a boot blob, of which we don't know the size, except that it has to fit in 0xffff bytes and be immediately followed by a startup header |
2924 | else |
2999 | else |
2925 | { |
3000 | { |
2926 | // so scan for the first startup header magic and version (which makes us 6 bytes to scan for, i.e. "\xeb\x7e\xff\x00" for the magic and "\x01\x00" (LSB) for the version 1) |
3001 | // so scan for the first startup header magic and version (which makes us 6 bytes to scan for, i.e. "\xeb\x7e\xff\x00" for the magic and "\x01\x00" (LSB) for the version 1) |
2927 | for (byte_index = current_offset; byte_index < |
3002 | for (byte_index = current_offset; byte_index < file.len - 6; byte_index++) |
2928 | if (memcmp (& |
3003 | if (memcmp (&file.bytes[byte_index], "\xeb\x7e\xff\x00" "\x01\x00", 4 + 2) == 0) |
2929 | break; // stop as soon as we find it |
3004 | break; // stop as soon as we find it |
2930 | 3005 | ||
2931 | if (byte_index >= |
3006 | if (byte_index >= file.len - 6) |
2932 | break; // if not found, stop scanning |
3007 | break; // if not found, stop scanning |
2933 | 3008 | ||
2934 | bootfile_blobsize = byte_index - current_offset; |
3009 | bootfile_blobsize = byte_index - current_offset; |
2935 | printf ("Boot blob at offset 0x%zx (%zd):\n", current_offset, current_offset); |
3010 | printf ("Boot blob at offset 0x%zx (%zd):\n", current_offset, current_offset); |
2936 | printf (" size 0x%zx (%zd) bytes\n", bootfile_blobsize, bootfile_blobsize); |
3011 | printf (" size 0x%zx (%zd) bytes\n", bootfile_blobsize, bootfile_blobsize); |
2937 | printf (" checksum 0x%08x\n", update_checksum (& |
3012 | printf (" checksum 0x%08x\n", update_checksum (&file.bytes[current_offset], bootfile_blobsize, false)); // NOTE: endianness is not known yet -- assume same |
2938 | 3013 | ||
2939 | current_offset = byte_index; // now reach the next segment |
3014 | current_offset = byte_index; // now reach the next segment |
2940 | } |
3015 | } |
2941 | } |
3016 | } |
2942 | 3017 | ||
2943 | endofdata: |
3018 | endofdata: |
2944 | // at this point there's nothing left we're able to parse |
3019 | // at this point there's nothing left we're able to parse |
2945 | if (current_offset < |
3020 | if (current_offset < file.len) |
2946 | { |
3021 | { |
2947 | printf ("End of identifiable data reached.\n"); |
3022 | printf ("End of identifiable data reached.\n"); |
2948 | hex_printf (& |
3023 | hex_printf (&file.bytes[current_offset], file.len - current_offset, "\n" "%zd extra bytes at offset %zx (%zd):\n", file.len - current_offset, current_offset, current_offset); |
2949 | } |
3024 | } |
2950 | 3025 | ||
2951 | printf ("End of file reached at offset 0x%zx (%zd)\n", |
3026 | printf ("End of file reached at offset 0x%zx (%zd)\n", file.len, file.len); |
2952 | printf ("IFS dissecation complete.\n"); |
3027 | printf ("IFS dissecation complete.\n"); |
2953 | return (0); |
3028 | return (0); |
2954 | } |
3029 | } |