25 |
* SUCH DAMAGE. |
* SUCH DAMAGE. |
26 |
* |
* |
27 |
* |
* |
28 |
* $Id: file.c,v 1.88 2005/04/17 00:15:24 debug Exp $ |
* $Id: file.c,v 1.105 2005/08/11 16:11:33 debug Exp $ |
29 |
* |
* |
30 |
* This file contains functions which load executable images into (emulated) |
* This file contains functions which load executable images into (emulated) |
31 |
* memory. File formats recognized so far: |
* memory. File formats recognized so far: |
123 |
} |
} |
124 |
|
|
125 |
|
|
126 |
|
#define AOUT_FLAG_DECOSF1 1 |
127 |
|
#define AOUT_FLAG_FROM_BEGINNING 2 |
128 |
|
#define AOUT_FLAG_VADDR_ZERO_HACK 4 |
129 |
/* |
/* |
130 |
* file_load_aout(): |
* file_load_aout(): |
131 |
* |
* |
136 |
* formats, where text/data are aligned differently. |
* formats, where text/data are aligned differently. |
137 |
*/ |
*/ |
138 |
static void file_load_aout(struct machine *m, struct memory *mem, |
static void file_load_aout(struct machine *m, struct memory *mem, |
139 |
char *filename, int osf1_hack, |
char *filename, int flags, |
140 |
uint64_t *entrypointp, int arch, int *byte_orderp) |
uint64_t *entrypointp, int arch, int *byte_orderp) |
141 |
{ |
{ |
142 |
struct exec aout_header; |
struct exec aout_header; |
146 |
uint32_t entry, datasize, textsize; |
uint32_t entry, datasize, textsize; |
147 |
int32_t symbsize = 0; |
int32_t symbsize = 0; |
148 |
uint32_t vaddr, total_len; |
uint32_t vaddr, total_len; |
149 |
unsigned char buf[4096]; |
unsigned char buf[65536]; |
150 |
unsigned char *syms; |
unsigned char *syms; |
151 |
|
|
152 |
|
if (m->cpus[0]->byte_order == EMUL_BIG_ENDIAN) |
153 |
|
encoding = ELFDATA2MSB; |
154 |
|
|
155 |
f = fopen(filename, "r"); |
f = fopen(filename, "r"); |
156 |
if (f == NULL) { |
if (f == NULL) { |
157 |
perror(filename); |
perror(filename); |
158 |
exit(1); |
exit(1); |
159 |
} |
} |
160 |
|
|
161 |
if (osf1_hack) { |
if (flags & AOUT_FLAG_DECOSF1) { |
162 |
fread(&buf, 1, 32, f); |
fread(&buf, 1, 32, f); |
163 |
vaddr = buf[16] + (buf[17] << 8) + |
vaddr = buf[16] + (buf[17] << 8) + |
164 |
(buf[18] << 16) + (buf[19] << 24); |
(buf[18] << 16) + (buf[19] << 24); |
169 |
symbsize = 0; |
symbsize = 0; |
170 |
fseek(f, 0, SEEK_END); |
fseek(f, 0, SEEK_END); |
171 |
/* This is of course wrong, but should work anyway: */ |
/* This is of course wrong, but should work anyway: */ |
172 |
textsize = ftell(f) - 512; |
textsize = ftello(f) - 512; |
173 |
datasize = 0; |
datasize = 0; |
174 |
fseek(f, 512, SEEK_SET); |
fseek(f, 512, SEEK_SET); |
175 |
} else { |
} else { |
181 |
} |
} |
182 |
|
|
183 |
unencode(entry, &aout_header.a_entry, uint32_t); |
unencode(entry, &aout_header.a_entry, uint32_t); |
|
vaddr = entry; |
|
184 |
debug("a.out, entry point 0x%08lx\n", (long)entry); |
debug("a.out, entry point 0x%08lx\n", (long)entry); |
185 |
|
vaddr = entry; |
186 |
|
|
187 |
|
if (flags & AOUT_FLAG_VADDR_ZERO_HACK) |
188 |
|
vaddr = 0; |
189 |
|
|
190 |
unencode(textsize, &aout_header.a_text, uint32_t); |
unencode(textsize, &aout_header.a_text, uint32_t); |
191 |
unencode(datasize, &aout_header.a_data, uint32_t); |
unencode(datasize, &aout_header.a_data, uint32_t); |
194 |
unencode(symbsize, &aout_header.a_syms, uint32_t); |
unencode(symbsize, &aout_header.a_syms, uint32_t); |
195 |
} |
} |
196 |
|
|
197 |
|
if (flags & AOUT_FLAG_FROM_BEGINNING) { |
198 |
|
fseek(f, 0, SEEK_SET); |
199 |
|
vaddr &= ~0xfff; |
200 |
|
} |
201 |
|
|
202 |
/* Load text and data: */ |
/* Load text and data: */ |
203 |
total_len = textsize + datasize; |
total_len = textsize + datasize; |
204 |
while (total_len != 0) { |
while (total_len != 0) { |
208 |
/* printf("fread len=%i vaddr=%x buf[0..]=%02x %02x %02x\n", |
/* printf("fread len=%i vaddr=%x buf[0..]=%02x %02x %02x\n", |
209 |
len, (int)vaddr, buf[0], buf[1], buf[2]); */ |
len, (int)vaddr, buf[0], buf[1], buf[2]); */ |
210 |
|
|
211 |
if (len > 0) |
if (len > 0) { |
212 |
m->cpus[0]->memory_rw(m->cpus[0], mem, vaddr, |
int len2 = 0; |
213 |
&buf[0], len, MEM_WRITE, NO_EXCEPTIONS); |
uint64_t vaddr1 = vaddr & |
214 |
else { |
((1 << BITS_PER_MEMBLOCK) - 1); |
215 |
if (osf1_hack) |
uint64_t vaddr2 = (vaddr + |
216 |
|
len) & ((1 << BITS_PER_MEMBLOCK) - 1); |
217 |
|
if (vaddr2 < vaddr1) { |
218 |
|
len2 = len - vaddr2; |
219 |
|
m->cpus[0]->memory_rw(m->cpus[0], mem, vaddr, |
220 |
|
&buf[0], len2, MEM_WRITE, NO_EXCEPTIONS); |
221 |
|
} |
222 |
|
m->cpus[0]->memory_rw(m->cpus[0], mem, vaddr + len2, |
223 |
|
&buf[len2], len-len2, MEM_WRITE, NO_EXCEPTIONS); |
224 |
|
} else { |
225 |
|
if (flags & AOUT_FLAG_DECOSF1) |
226 |
break; |
break; |
227 |
else { |
else { |
228 |
fprintf(stderr, "could not read from %s\n", |
fprintf(stderr, "could not read from %s\n", |
243 |
char *string_symbols; |
char *string_symbols; |
244 |
off_t oldpos; |
off_t oldpos; |
245 |
|
|
246 |
debug("symbols: %i bytes @ 0x%x\n", symbsize, (int)ftell(f)); |
debug("symbols: %i bytes @ 0x%x\n", symbsize, (int)ftello(f)); |
247 |
syms = malloc(symbsize); |
syms = malloc(symbsize); |
248 |
if (syms == NULL) { |
if (syms == NULL) { |
249 |
fprintf(stderr, "out of memory\n"); |
fprintf(stderr, "out of memory\n"); |
256 |
exit(1); |
exit(1); |
257 |
} |
} |
258 |
|
|
259 |
oldpos = ftell(f); |
oldpos = ftello(f); |
260 |
fseek(f, 0, SEEK_END); |
fseek(f, 0, SEEK_END); |
261 |
strings_len = ftell(f) - oldpos; |
strings_len = ftello(f) - oldpos; |
262 |
fseek(f, oldpos, SEEK_SET); |
fseek(f, oldpos, SEEK_SET); |
263 |
debug("strings: %i bytes @ 0x%x\n", strings_len, (int)ftell(f)); |
debug("strings: %i bytes @ 0x%x\n", strings_len,(int)ftello(f)); |
264 |
string_symbols = malloc(strings_len); |
string_symbols = malloc(strings_len); |
265 |
if (string_symbols == NULL) { |
if (string_symbols == NULL) { |
266 |
fprintf(stderr, "out of memory\n"); |
fprintf(stderr, "out of memory\n"); |
282 |
|
|
283 |
if (type != 0 && addr != 0) |
if (type != 0 && addr != 0) |
284 |
add_symbol_name(&m->symbol_context, |
add_symbol_name(&m->symbol_context, |
285 |
addr, 0, string_symbols + str_index, 0); |
addr, 0, string_symbols + str_index, 0, -1); |
286 |
i++; |
i++; |
287 |
} |
} |
288 |
|
|
292 |
|
|
293 |
fclose(f); |
fclose(f); |
294 |
|
|
295 |
*entrypointp = entry; |
*entrypointp = (int32_t)entry; |
296 |
|
|
297 |
if (encoding == ELFDATA2LSB) |
if (encoding == ELFDATA2LSB) |
298 |
*byte_orderp = EMUL_LITTLE_ENDIAN; |
*byte_orderp = EMUL_LITTLE_ENDIAN; |
491 |
if (s_scnptr != 0 && s_size != 0 && |
if (s_scnptr != 0 && s_size != 0 && |
492 |
s_vaddr != 0 && !(s_flags & 0x02)) { |
s_vaddr != 0 && !(s_flags & 0x02)) { |
493 |
/* Remember the current file offset: */ |
/* Remember the current file offset: */ |
494 |
oldpos = ftell(f); |
oldpos = ftello(f); |
495 |
|
|
496 |
/* Load the section into emulated memory: */ |
/* Load the section into emulated memory: */ |
497 |
fseek(f, s_scnptr, SEEK_SET); |
fseek(f, s_scnptr, SEEK_SET); |
592 |
memcpy(name, sym->name, 8); |
memcpy(name, sym->name, 8); |
593 |
name[8] = '\0'; |
name[8] = '\0'; |
594 |
add_symbol_name(&m->symbol_context, |
add_symbol_name(&m->symbol_context, |
595 |
v, 0, name, 0); |
v, 0, name, 0, -1); |
596 |
n_real_symbols ++; |
n_real_symbols ++; |
597 |
} else if (t == 0x20 && !sym->name[0]) { |
} else if (t == 0x20 && !sym->name[0]) { |
598 |
off_t ofs; |
off_t ofs; |
604 |
/* debug(" [altname=0x%x '%s']", |
/* debug(" [altname=0x%x '%s']", |
605 |
altname, name); */ |
altname, name); */ |
606 |
add_symbol_name(&m->symbol_context, |
add_symbol_name(&m->symbol_context, |
607 |
v, 0, name, 0); |
v, 0, name, 0, -1); |
608 |
n_real_symbols ++; |
n_real_symbols ++; |
609 |
} |
} |
610 |
|
|
675 |
|
|
676 |
add_symbol_name(&m->symbol_context, |
add_symbol_name(&m->symbol_context, |
677 |
extsyms[sym_nr].es_value, 0, |
extsyms[sym_nr].es_value, 0, |
678 |
symbol_data + extsyms[sym_nr].es_strindex, 0); |
symbol_data + extsyms[sym_nr].es_strindex, 0, -1); |
679 |
} |
} |
680 |
|
|
681 |
free(extsyms); |
free(extsyms); |
917 |
} |
} |
918 |
|
|
919 |
debug("RAW: 0x%llx bytes @ 0x%08llx", |
debug("RAW: 0x%llx bytes @ 0x%08llx", |
920 |
(long long) (ftell(f) - skip), (long long)loadaddr); |
(long long) (ftello(f) - skip), (long long)loadaddr); |
921 |
if (skip != 0) |
if (skip != 0) |
922 |
debug(" (0x%llx bytes of header skipped)", (long long)skip); |
debug(" (0x%llx bytes of header skipped)", (long long)skip); |
923 |
debug("\n"); |
debug("\n"); |
1023 |
unencode(eshoff, &hdr64.e_shoff, Elf64_Off); |
unencode(eshoff, &hdr64.e_shoff, Elf64_Off); |
1024 |
if (ephentsize != sizeof(Elf64_Phdr)) { |
if (ephentsize != sizeof(Elf64_Phdr)) { |
1025 |
fprintf(stderr, "%s: incorrect phentsize? %i, should " |
fprintf(stderr, "%s: incorrect phentsize? %i, should " |
1026 |
"be %i\n", filename, (int)ephentsize, |
"be %i\nPerhaps this is a dynamically linked " |
1027 |
(int)sizeof(Elf64_Phdr)); |
"binary (which isn't supported yet).\n", filename, |
1028 |
|
(int)ephentsize, (int)sizeof(Elf64_Phdr)); |
1029 |
exit(1); |
exit(1); |
1030 |
} |
} |
1031 |
if (eshentsize != sizeof(Elf64_Shdr)) { |
if (eshentsize != sizeof(Elf64_Shdr)) { |
1032 |
fprintf(stderr, "%s: incorrect phentsize? %i, should " |
fprintf(stderr, "%s: incorrect shentsize? %i, should " |
1033 |
"be %i\n", filename, (int)ephentsize, |
"be %i\nPerhaps this is a dynamically linked " |
1034 |
(int)sizeof(Elf64_Shdr)); |
"binary (which isn't supported yet).\n", filename, |
1035 |
|
(int)eshentsize, (int)sizeof(Elf64_Shdr)); |
1036 |
exit(1); |
exit(1); |
1037 |
} |
} |
1038 |
} else { |
} else { |
1048 |
unencode(eshoff, &hdr32.e_shoff, Elf32_Off); |
unencode(eshoff, &hdr32.e_shoff, Elf32_Off); |
1049 |
if (ephentsize != sizeof(Elf32_Phdr)) { |
if (ephentsize != sizeof(Elf32_Phdr)) { |
1050 |
fprintf(stderr, "%s: incorrect phentsize? %i, should " |
fprintf(stderr, "%s: incorrect phentsize? %i, should " |
1051 |
"be %i\n", filename, (int)ephentsize, |
"be %i\nPerhaps this is a dynamically linked " |
1052 |
(int)sizeof(Elf32_Phdr)); |
"binary (which isn't supported yet).\n", filename, |
1053 |
|
(int)ephentsize, (int)sizeof(Elf32_Phdr)); |
1054 |
exit(1); |
exit(1); |
1055 |
} |
} |
1056 |
if (eshentsize != sizeof(Elf32_Shdr)) { |
if (eshentsize != sizeof(Elf32_Shdr)) { |
1057 |
fprintf(stderr, "%s: incorrect phentsize? %i, should " |
fprintf(stderr, "%s: incorrect shentsize? %i, should " |
1058 |
"be %i\n", filename, (int)ephentsize, |
"be %i\nPerhaps this is a dynamically linked " |
1059 |
(int)sizeof(Elf32_Shdr)); |
"binary (which isn't supported yet).\n", filename, |
1060 |
|
(int)eshentsize, (int)sizeof(Elf32_Shdr)); |
1061 |
exit(1); |
exit(1); |
1062 |
} |
} |
1063 |
} |
} |
1077 |
ok = 1; |
ok = 1; |
1078 |
} |
} |
1079 |
break; |
break; |
|
case ARCH_HPPA: |
|
|
switch (emachine) { |
|
|
case EM_PARISC: |
|
|
ok = 1; |
|
|
} |
|
|
break; |
|
1080 |
case ARCH_MIPS: |
case ARCH_MIPS: |
1081 |
switch (emachine) { |
switch (emachine) { |
1082 |
case EM_MIPS: |
case EM_MIPS: |
1102 |
switch (emachine) { |
switch (emachine) { |
1103 |
case EM_386: |
case EM_386: |
1104 |
case EM_486: |
case EM_486: |
1105 |
|
*tocp = 1; |
1106 |
ok = 1; |
ok = 1; |
1107 |
break; |
break; |
1108 |
case EM_AMD64: |
case EM_AMD64: |
1109 |
*tocp = 1; |
*tocp = 2; |
1110 |
ok = 1; |
ok = 1; |
1111 |
break; |
break; |
1112 |
} |
} |
1113 |
break; |
break; |
1114 |
|
case ARCH_ARM: |
1115 |
|
switch (emachine) { |
1116 |
|
case EM_ARM: |
1117 |
|
ok = 1; |
1118 |
|
} |
1119 |
|
break; |
1120 |
|
case ARCH_IA64: |
1121 |
|
switch (emachine) { |
1122 |
|
case EM_IA_64: |
1123 |
|
ok = 1; |
1124 |
|
} |
1125 |
|
break; |
1126 |
|
case ARCH_M68K: |
1127 |
|
switch (emachine) { |
1128 |
|
case EM_68K: |
1129 |
|
ok = 1; |
1130 |
|
} |
1131 |
|
break; |
1132 |
default: |
default: |
1133 |
fatal("file.c: INTERNAL ERROR: Unimplemented arch!\n"); |
fatal("file.c: INTERNAL ERROR: Unimplemented arch!\n"); |
1134 |
} |
} |
1234 |
|
|
1235 |
debug(" len=0x%llx\n", (long long)p_memsz); |
debug(" len=0x%llx\n", (long long)p_memsz); |
1236 |
|
|
1237 |
if (p_vaddr != p_paddr) { |
if (p_vaddr != p_paddr) |
1238 |
fprintf(stderr, "%s: vaddr != paddr. TODO: " |
fatal("WARNING! vaddr (0x%llx) and paddr " |
1239 |
"how to handle this? vaddr=%016llx paddr" |
"(0x%llx) differ; using vaddr\n", |
1240 |
"=%016llx\n", filename, (long long)p_vaddr, |
(long long)p_vaddr, (long long)p_paddr); |
|
(long long)p_paddr); |
|
|
exit(1); |
|
|
} |
|
1241 |
|
|
1242 |
if (p_memsz < p_filesz) { |
if (p_memsz < p_filesz) { |
1243 |
fprintf(stderr, "%s: memsz < filesz. TODO: how" |
fprintf(stderr, "%s: memsz < filesz. TODO: how" |
1300 |
} |
} |
1301 |
} |
} |
1302 |
|
|
1303 |
/* Read the section headers to find the address of the _gp symbol: */ |
/* |
1304 |
|
* Read the section headers to find the address of the _gp |
1305 |
|
* symbol (for MIPS): |
1306 |
|
*/ |
1307 |
|
|
1308 |
for (i=0; i<eshnum; i++) { |
for (i=0; i<eshnum; i++) { |
1309 |
int sh_name, sh_type, sh_flags, sh_link, sh_info, sh_entsize; |
int sh_name, sh_type, sh_flags, sh_link, sh_info, sh_entsize; |
1462 |
unencode(size, &sym32.st_size, Elf32_Word); |
unencode(size, &sym32.st_size, Elf32_Word); |
1463 |
} |
} |
1464 |
|
|
1465 |
|
/* debug("symbol info=0x%02x addr=0x%016llx" |
1466 |
|
" (%i) '%s'\n", st_info, (long long)addr, |
1467 |
|
st_name, symbol_strings + st_name); */ |
1468 |
|
|
1469 |
if (size == 0) |
if (size == 0) |
1470 |
size ++; |
size ++; |
1471 |
|
|
1472 |
if (addr != 0) { |
if (addr != 0) /* && ((st_info >> 4) & 0xf) |
1473 |
|
>= STB_GLOBAL) */ { |
1474 |
/* debug("symbol info=0x%02x addr=0x%016llx" |
/* debug("symbol info=0x%02x addr=0x%016llx" |
1475 |
" '%s'\n", st_info, (long long)addr, |
" '%s'\n", st_info, (long long)addr, |
1476 |
symbol_strings + st_name); */ |
symbol_strings + st_name); */ |
1477 |
add_symbol_name(&m->symbol_context, |
add_symbol_name(&m->symbol_context, |
1478 |
addr, size, symbol_strings + st_name, 0); |
addr, size, symbol_strings + st_name, |
1479 |
|
0, -1); |
1480 |
} |
} |
1481 |
|
|
1482 |
if (strcmp(symbol_strings + st_name, "_gp") == 0) { |
if (strcmp(symbol_strings + st_name, "_gp") == 0) { |
1575 |
int iadd = 4; |
int iadd = 4; |
1576 |
FILE *f; |
FILE *f; |
1577 |
unsigned char buf[12]; |
unsigned char buf[12]; |
1578 |
int len, i; |
unsigned char buf2[2]; |
1579 |
|
size_t len, len2, i; |
1580 |
off_t size; |
off_t size; |
1581 |
|
|
1582 |
if (byte_orderp == NULL) { |
if (byte_orderp == NULL) { |
1608 |
} |
} |
1609 |
|
|
1610 |
fseek(f, 0, SEEK_END); |
fseek(f, 0, SEEK_END); |
1611 |
size = ftell(f); |
size = ftello(f); |
1612 |
fseek(f, 0, SEEK_SET); |
fseek(f, 0, SEEK_SET); |
1613 |
|
|
1614 |
memset(buf, 0, sizeof(buf)); |
memset(buf, 0, sizeof(buf)); |
1615 |
len = fread(buf, 1, sizeof(buf), f); |
len = fread(buf, 1, sizeof(buf), f); |
1616 |
|
fseek(f, 510, SEEK_SET); |
1617 |
|
len2 = fread(buf2, 1, sizeof(buf2), f); |
1618 |
fclose(f); |
fclose(f); |
1619 |
|
|
1620 |
if (len < (signed int)sizeof(buf)) { |
if (len < (signed int)sizeof(buf)) { |
1630 |
goto ret; |
goto ret; |
1631 |
} |
} |
1632 |
|
|
1633 |
/* Is it an a.out? (Special case for DEC OSF1 kernels.) */ |
/* Is it an a.out? */ |
1634 |
if (buf[0]==0x00 && buf[1]==0x8b && buf[2]==0x01 && buf[3]==0x07) { |
if (buf[0]==0x00 && buf[1]==0x8b && buf[2]==0x01 && buf[3]==0x07) { |
1635 |
|
/* MIPS a.out */ |
1636 |
file_load_aout(machine, mem, filename, 0, |
file_load_aout(machine, mem, filename, 0, |
1637 |
entrypointp, arch, byte_orderp); |
entrypointp, arch, byte_orderp); |
1638 |
goto ret; |
goto ret; |
1639 |
} |
} |
1640 |
|
if (buf[0]==0x00 && buf[1]==0x87 && buf[2]==0x01 && buf[3]==0x08) { |
1641 |
|
/* M68K a.out */ |
1642 |
|
file_load_aout(machine, mem, filename, |
1643 |
|
AOUT_FLAG_VADDR_ZERO_HACK /* for OpenBSD/mac68k */, |
1644 |
|
entrypointp, arch, byte_orderp); |
1645 |
|
goto ret; |
1646 |
|
} |
1647 |
|
if (buf[0]==0x00 && buf[1]==0x86 && buf[2]==0x01 && buf[3]==0x0b) { |
1648 |
|
/* i386 a.out (old OpenBSD and NetBSD etc) */ |
1649 |
|
file_load_aout(machine, mem, filename, AOUT_FLAG_FROM_BEGINNING, |
1650 |
|
entrypointp, arch, byte_orderp); |
1651 |
|
goto ret; |
1652 |
|
} |
1653 |
if (buf[0]==0x00 && buf[2]==0x00 && buf[8]==0x7a && buf[9]==0x75) { |
if (buf[0]==0x00 && buf[2]==0x00 && buf[8]==0x7a && buf[9]==0x75) { |
1654 |
file_load_aout(machine, mem, filename, 1, |
/* DEC OSF1 on MIPS: */ |
1655 |
|
file_load_aout(machine, mem, filename, AOUT_FLAG_DECOSF1, |
1656 |
entrypointp, arch, byte_orderp); |
entrypointp, arch, byte_orderp); |
1657 |
goto ret; |
goto ret; |
1658 |
} |
} |
1697 |
fprintf(stderr, "\nThis file is very large (%lli bytes)\n", |
fprintf(stderr, "\nThis file is very large (%lli bytes)\n", |
1698 |
(long long)size); |
(long long)size); |
1699 |
fprintf(stderr, "Are you sure it is a kernel and not a disk " |
fprintf(stderr, "Are you sure it is a kernel and not a disk " |
1700 |
"image?\n"); |
"image? (Use the -d option.)\n"); |
1701 |
exit(1); |
exit(1); |
1702 |
} |
} |
1703 |
|
|
1720 |
"unknown.\n\n ", filename); |
"unknown.\n\n ", filename); |
1721 |
for (i=0; i<(signed)sizeof(buf); i++) |
for (i=0; i<(signed)sizeof(buf); i++) |
1722 |
fprintf(stderr, " %02x", buf[i]); |
fprintf(stderr, " %02x", buf[i]); |
1723 |
|
|
1724 |
|
if (len2 == 2 && buf2[0] == 0x55 && buf2[1] == 0xaa) |
1725 |
|
fprintf(stderr, "\n\nIt has a PC-style " |
1726 |
|
"bootsector marker."); |
1727 |
|
|
1728 |
fprintf(stderr, "\n\nPossible explanations:\n\n" |
fprintf(stderr, "\n\nPossible explanations:\n\n" |
1729 |
" o) If this is a disk image, you forgot '-d' " |
" o) If this is a disk image, you forgot '-d' " |
1730 |
"on the command line.\n" |
"on the command line.\n" |