1 /*---------------------------------------------------------------------------*
2   Project:  TwlSDK - bin2obj
3   File:     cookargs.c
4 
5   Copyright 2005-2008 Nintendo. All rights reserved.
6 
7   These coded instructions, statements, and computer programs contain
8   proprietary information of Nintendo of America Inc. and/or Nintendo
9   Company Ltd., and are protected by Federal copyright law. They may
10   not be disclosed to third parties or copied or duplicated in any form,
11   in whole or in part, without the prior written consent of Nintendo.
12 
13   $Date:: 2008-09-17#$
14   $Rev: 8556 $
15   $Author: okubata_ryoma $
16  *---------------------------------------------------------------------------*/
17 #include "bin2obj.h"
18 
19 extern const unsigned long SDK_DATE_OF_LATEST_FILE;
20 
21 /*---------------------------------------------------------------------------*
22   Name:         cook_args
23 
24   Description:  bin2obj main.
25  *---------------------------------------------------------------------------*/
cook_args(Bin2ObjArgs * t,int argc,char * argv[])26 void cook_args(Bin2ObjArgs * t, int argc, char *argv[])
27 {
28     u16     default_machine;
29     u8      default_endian;
30     int     c;
31     static struct option long_options[] = {
32         {"begin", 1, 0, 'b'},
33         {"end", 1, 0, 'e'},
34         {"compatible", 0, 0, 'C'},
35         {"section", 1, 0, 's'},
36         {"align", 1, 0, 'a'},
37         {"readonly", 0, 0, 'r'},
38         {"big-endian", 0, 0, 'B'},
39         {"little-endian", 0, 0, 'L'},
40         {"machine", 0, 0, 'm'},
41         {0, 0, 0, 0}
42     };
43 
44     memset(t, 0, sizeof(Bin2ObjArgs));
45     UnpackFileName(argv[0], NULL, &t->app_name, NULL);
46     t->align = DEFAULT_ALIGN;
47     t->writable = DEFALUT_WRITABLE;
48     t->symbol_begin = StrDup(DEFAULT_SYMBOL_BEGIN);
49     t->symbol_end = StrDup(DEFAULT_SYMBOL_END);
50     t->section_rodata = StrDup(DEFAULT_SECTION_RODATA);
51     t->section_rwdata = StrDup(DEFAULT_SECTION_RWDATA);
52 
53     t->machine = 0;
54     t->endian  = ELFDATA2UNDEF;
55 
56     default_machine = EM_ARM;
57     default_endian  = ELFDATA2LSB;
58 
59     while ((c = getopt_long(argc, argv, "b:e:Cs:a:rBLm:", long_options, NULL)) != -1)
60     {
61         switch (c)
62         {
63         case 'b':
64             if (t->symbol_begin)
65                 free(t->symbol_begin);
66             t->symbol_begin = StrDup(optarg);
67             break;
68 
69         case 'e':
70             if (t->symbol_end)
71                 free(t->symbol_end);
72             t->symbol_end = StrDup(optarg);
73             break;
74 
75         case 'C':
76             // For Compatibility with CodeWarrior BinToElf
77             if (t->symbol_begin)
78                 free(t->symbol_begin);
79             if (t->symbol_end)
80                 free(t->symbol_end);
81             t->symbol_begin = StrDup(COMPATIBLE_SYMBOL_BEGIN);
82             t->symbol_end = StrDup(COMPATIBLE_SYMBOL_END);
83             break;
84 
85         case 's':
86             if (t->section_rodata)
87                 free(t->section_rodata);
88             if (t->section_rwdata)
89                 free(t->section_rwdata);
90             t->section_rodata = StrDup(optarg);
91             t->section_rwdata = StrDup(optarg);
92             break;
93 
94         case 'a':
95             t->align = atoi(optarg);
96             if (t->align < 1)
97                 t->align = 1;
98             break;
99 
100         case 'r':
101             t->writable = FALSE;
102             break;
103 
104         case 'B':
105             t->endian       = ELFDATA2MSB;	// Big Endian
106             default_machine = EM_PPC;
107             break;
108 
109         case 'L':
110             t->endian       = ELFDATA2LSB;	// Little Endian
111             default_machine = EM_ARM;
112             break;
113 
114         case 'm':
115             if (!strcmp(optarg, "arm"))
116             {
117                 t->machine     = EM_ARM;
118                 default_endian = ELFDATA2LSB;
119             }
120             else if (!strcmp(optarg, "ppc"))
121             {
122                 t->machine     = EM_PPC;
123                 default_endian = ELFDATA2MSB;
124             }
125             break;
126 
127         case '?':
128         case ':':
129         default:
130             goto usage;
131         }
132     }
133 
134     if (optind + 2 != argc)
135     {
136         goto usage;
137     }
138 
139     t->binary_filename = StrDup(argv[optind + 0]);
140     t->object_filename = StrDup(argv[optind + 1]);
141 
142     // Default endian & machine
143     if (t->machine == 0)
144     {
145         t->machine = default_machine;
146     }
147     if (t->endian == ELFDATA2UNDEF)
148     {
149         t->endian = default_endian;
150     }
151 
152     return;
153 
154   usage:
155     {
156         fprintf(stderr,
157                 "NITRO/RevoEX Software Development Tool - %s - Binary to Object converter \n"
158                 "Build %lu\n\n"
159                 "Usage: %s [-b|--begin SYMBOL_BEGIN]\n"
160                 "               [-e|--end   SYMBOL_END]\n"
161                 "               [-C|--compatible]\n"
162                 "               [-a|--align ALIGNMENT]\n"
163                 "               [-r|--readonly]\n"
164                 "               [-s|--section SECTION]\n"
165                 "               [-m|--machine [arm|ppc]]\n"
166                 "               [-B|--big-endian]\n"
167                 "               [-L|--little-endian] BINARY_FILE OBJECT_FILE\n\n"
168                 " -b or --begin             Set symbol name for top of binary. (*)\n"
169                 " -e or --end               Set symbol name for bottom of binary. (*)\n"
170                 " -C or --compatible        Use compatible symbols with BinToElf.exe.\n"
171                 "                           Same as \"-b _binary_%%f -e _binary_%%f_end\".\n"
172                 " -a or --align             Set binary data alignment in bytes.\n"
173                 " -r or --readonly          Handle binary data as readonly.\n"
174                 " -s or --section           Set section name.\n"
175                 " -m or --machine [arm|ppc] Machine arch [arm|ppc].(default=arm)\n"
176                 " -B or --big-endian        Output in big    endian format.\n"
177                 " -L or --little-endian     Output in little endian format.\n\n"
178                 "  (*) special %% rules for symbols (ex. binary_file = \"filename.dat\")\n"
179                 "       %%f,%%t replaced to file name of binary   (%%f = \"filename.dat\")\n"
180                 "       %%b    replaced to base name of binary   (%%b = \"filename\")\n"
181                 "       %%e    replaced to extension of binary   (%%e = \"dat\")\n\n",
182                 t->app_name, SDK_DATE_OF_LATEST_FILE, t->app_name);
183         free_args(t);
184         exit(-1);
185     }
186 }
187 
188 /*---------------------------------------------------------------------------*
189   Name:         create_symbol_string
190 
191   Description:  Creates the symbol name from the binary file name.
192  *---------------------------------------------------------------------------*/
create_symbol_string(const char * filename,const char * symbol_format)193 char   *create_symbol_string(const char *filename, const char *symbol_format)
194 {
195     char   *symbol;
196     char   *file_base;
197     char   *file_ext;
198     int     i;
199 
200     // Analyze the filename and divide into its elements
201     UnpackFileName(filename, NULL, &file_base, &file_ext);
202 
203     // Determine if %f, %b, %e characters are in the format specification, and replace them with the corresponding filename data (main filename, file extension, etc.)
204     //
205     symbol = StrDup(symbol_format);
206     for (i = 0; symbol[i] != '\0'; i++)
207     {
208         if (symbol[i] == '%')
209         {
210             switch (symbol[i + 1])
211             {
212             case 'b':
213                 i = replace_word(&symbol, i, 2, file_base);
214                 break;
215 
216             case 'e':
217                 i = replace_word(&symbol, i, 2, file_ext);
218                 break;
219 
220             case 'f':
221             case 't':
222                 i = replace_word(&symbol, i, 2, file_base);
223                 i = replace_word(&symbol, i, 0, ".");
224                 i = replace_word(&symbol, i, 0, file_ext);
225                 break;
226             }
227         }
228     }
229 
230     // If characters that cannot be used as symbols are included, change them to "_"
231     for (i = 0; symbol[i] != '\0'; i++)
232     {
233         if (!isalnum(symbol[i]) && symbol[i] != '_')
234         {
235             symbol[i] = '_';
236         }
237     }
238     if (isdigit(symbol[i]))
239     {
240         symbol[i] = '_';               // First character cannot be a numeral, either
241     }
242 
243     free(file_base);
244     free(file_ext);
245 
246     return symbol;
247 }
248 
249 /*---------------------------------------------------------------------------*
250   Name:         replace_word
251 
252   Description:  Replaces string.
253 
254   Arguments:    *symbol: String to be replaced (realloc-ed)
255                 pos: Replacement position
256                 len: String size to be deleted through replacement
257                 str: String to be inserted in the replacement position
258 
259                 Characters from symbol[pos] to symbol[pos+len-1] are replaced by str.
260                 If the size of str is different from len, the length of the entire string will change.
261 
262 
263   Returns:      The end position of the inserted string.
264  *---------------------------------------------------------------------------*/
replace_word(char ** str,int pos,int len,const char * substr)265 int replace_word(char **str, int pos, int len, const char *substr)
266 {
267     int     new_len, str_len, substr_len;
268     char   *new_str;
269 
270     // Calculate the size of the string after replacement
271     str_len = strlen(*str);
272     assert(str_len >= pos + len);
273 
274     if (!substr)
275         substr = "";
276     substr_len = strlen(substr);
277     new_len = str_len - len + substr_len;
278 
279     // Create the string after replacement
280     new_str = Calloc(new_len + 1);     // +1 for '\0'
281     strncpy(new_str, *str, pos);
282     strcat(new_str, substr);
283     strcat(new_str, *str + pos + len);
284 
285     // realloc processing
286     free(*str);
287     *str = new_str;
288 
289     // Return the new position
290     return pos + substr_len;
291 }
292 
293 /*---------------------------------------------------------------------------*
294   Name:         free_args
295 
296   Description:  Clears the Bin2ObjArgs region.
297  *---------------------------------------------------------------------------*/
free_args(Bin2ObjArgs * t)298 void free_args(Bin2ObjArgs * t)
299 {
300     if (t->app_name)
301         free(t->app_name);
302     if (t->binary_filename)
303         free(t->binary_filename);
304     if (t->object_filename)
305         free(t->object_filename);
306     if (t->section_rodata)
307         free(t->section_rodata);
308     if (t->section_rwdata)
309         free(t->section_rwdata);
310     if (t->symbol_begin)
311         free(t->symbol_begin);
312     if (t->symbol_end)
313         free(t->symbol_end);
314     memset(t, 0, sizeof(Bin2ObjArgs));
315 }
316 
317 
318 /*---------------------------------------------------------------------------*
319   Name:         StrDup
320 
321   Description:  Error handling version of strdup
322 
323   Arguments:    str     String to copy
324 
325   Returns:      String that was copied
326  *---------------------------------------------------------------------------*/
StrDup(const char * str)327 char   *StrDup(const char *str)
328 {
329     char   *cp;
330 
331     if (NULL == (cp = strdup(str ? str : "")))
332     {
333         fprintf(stderr, "Error: No memory.");
334         exit(2);
335     }
336     return cp;
337 }
338 
339 /*---------------------------------------------------------------------------*
340   Name:         StrNDup
341 
342   Description:  Error-handling version of strdup with character length specification.
343 
344   Arguments:    str     String to copy
345                 len     String to copy (Not including '\0')
346 
347   Returns:      String that was copied
348  *---------------------------------------------------------------------------*/
StrNDup(const char * str,int len)349 char   *StrNDup(const char *str, int len)
350 {
351     char   *cp;
352 
353     cp = Calloc(len + 1);
354     if (str && len)
355         (void)strncpy(cp, str, len);
356     return cp;
357 
358     // Area having len+1 bytes was allocated with malloc, so there is no need to add  '\0' after strncpy.
359     //
360     // Can also support cases where str is NULL
361 }
362 
363 /*---------------------------------------------------------------------------*
364   Name:         StrCatDup
365 
366   Description:  Allocates room for a concatenated string from the heap area.
367 
368   Arguments:    str1    String 1 (When str1 == NULL, treated as "  ")
369                 str2    String 2 (When str2 == NULL, treated as "  ")
370 
371   Returns:      Concatenated string
372  *---------------------------------------------------------------------------*/
StrCatDup(const char * str1,const char * str2)373 char   *StrCatDup(const char *str1, const char *str2)
374 {
375     int     len1, len2;
376     char   *cp;
377 
378     len1 = str1 ? strlen(str1) : 0;
379     len2 = str2 ? strlen(str2) : 0;
380 
381     cp = Calloc(len1 + len2 + 1);
382 
383     if (str1)
384         (void)strcpy(cp, str1);
385     if (str2)
386         (void)strcat(cp, str2);
387 
388     return cp;
389 }
390 
391 /*---------------------------------------------------------------------------*
392   Name:         Calloc
393 
394   Description:  Error-handling version of calloc (only one argument)
395 
396   Arguments:    size    Length of area to allocate
397 
398   Returns:      Allocated area
399  *---------------------------------------------------------------------------*/
Calloc(int size)400 void   *Calloc(int size)
401 {
402     void   *cp;
403 
404     if (NULL == (cp = calloc(1, size)))
405     {
406         fprintf(stderr, "Error: No memory.");
407         exit(2);
408     }
409     return cp;
410 }
411 
412 /*---------------------------------------------------------------------------*
413   Name:         UnpackFileName
414 
415   Description:  Analyzes the file name and divides it into parts: (directory, file base name, file extension)
416 
417 
418   Arguments:    path   Full path name
419                 dir    Directory
420                 base   File's base name
421                 ext    File extension (not including '.')
422 
423                 * * Because dir, base, and ext are allocated from the heap, they must be freed
424                 * * When dir, base or ext is NULL, no value is assigned
425 
426   Returns:      None.
427  *---------------------------------------------------------------------------*/
UnpackFileName(const char * path,char ** dir,char ** base,char ** ext)428 void UnpackFileName(const char *path, char **dir, char **base, char **ext)
429 {
430     int     i, base_top, ext_top;
431     int     path_len = strlen(path);
432 
433     // Search for the position of the final '.' and the path delimiters
434     ext_top = path_len;
435     for (i = path_len - 1; i >= 0; i--)
436     {
437         if (path[i] == '.' && ext_top == path_len)
438         {
439             ext_top = i + 1;
440         }
441         if (path[i] == '/' || path[i] == '\\' || path[i] == ':')
442         {
443             break;
444         }
445     }
446     base_top = i + 1;
447 
448     // Assign
449     if (dir)
450         *dir = StrNDup(path, base_top);
451     if (base)
452         *base = StrNDup(path + base_top, ext_top - base_top - 1);
453     if (ext)
454         *ext = StrDup(path + ext_top);
455     return;
456 }
457