source: anotherchoice/tags/jsp-1.4.4-full-UTF8/cfg/base/fc_binutils.cpp@ 26

Last change on this file since 26 was 26, checked in by ykominami, 10 years ago

initial

File size: 44.0 KB
Line 
1/*
2 * TOPPERS/JSP Kernel
3 * Toyohashi Open Platform for Embedded Real-Time Systems/
4 * Just Standard Profile Kernel
5 *
6 * Copyright (C) 2003 by Embedded and Real-Time Systems Laboratory
7 * Toyohashi Univ. of Technology, JAPAN
8 *
9 * 上記著作権者
10は,以下の (1)〜(4) の条件か,Free Software Foundation
11 * によってå…
12¬è¡¨ã•ã‚Œã¦ã„ã‚‹ GNU General Public License の Version 2 に記
13 * 述されている条件を満たす場合に限り,本ソフトウェア(本ソフトウェア
14 * を改変したものを含む.以下同じ)を使用・複製・改変・再é…
15å¸ƒï¼ˆä»¥ä¸‹ï¼Œ
16 * 利用と呼ぶ)することを無償で許諾する.
17 * (1) 本ソフトウェアをソースコードの形で利用する場合には,上記の著作
18 * 権表示,この利用条件および下記の無保証規定が,そのままの形でソー
19 * スコード中に含まれていること.
20 * (2) 本ソフトウェアを,ライブラリ形式など,他のソフトウェア開発に使
21 * 用できる形で再é…
22å¸ƒã™ã‚‹å ´åˆã«ã¯ï¼Œå†é…
23å¸ƒã«ä¼´ã†ãƒ‰ã‚­ãƒ¥ãƒ¡ãƒ³ãƒˆï¼ˆåˆ©ç”¨
24 * 者
25マニュアルなど)に,上記の著作権表示,この利用条件および下記
26 * の無保証規定を掲載すること.
27 * (3) 本ソフトウェアを,機器に組み込むなど,他のソフトウェア開発に使
28 * 用できない形で再é…
29å¸ƒã™ã‚‹å ´åˆã«ã¯ï¼Œæ¬¡ã®ã„ずれかの条件を満たすこ
30 * と.
31 * (a) 再é…
32å¸ƒã«ä¼´ã†ãƒ‰ã‚­ãƒ¥ãƒ¡ãƒ³ãƒˆï¼ˆåˆ©ç”¨è€…
33マニュアルなど)に,上記の著
34 * 作権表示,この利用条件および下記の無保証規定を掲載すること.
35 * (b) 再é…
36å¸ƒã®å½¢æ…
37‹ã‚’,別に定める方法によって,TOPPERSプロジェクトに
38 * 報告すること.
39 * (4) 本ソフトウェアの利用により直接的または間接的に生じるいかなる損
40 * 害からも,上記著作権者
41およびTOPPERSプロジェクトをå…
42è²¬ã™ã‚‹ã“と.
43 *
44 * 本ソフトウェアは,無保証で提供されているものである.上記著作権者
45お
46 * よびTOPPERSプロジェクトは,本ソフトウェアに関して,その適用可能性も
47 * 含めて,いかなる保証も行わない.また,本ソフトウェアの利用により直
48 * 接的または間接的に生じたいかなる損害に関しても,その責任を負わない.
49 *
50 * @(#) $Id: fc_binutils.cpp,v 1.21 2004/09/04 15:50:13 honda Exp $
51 */
52
53#if defined(FILECONTAINER_BINUTILS) || defined(TESTSUITE)
54
55#ifdef _MSC_VER
56#pragma warning(disable:4786) //デバッグ文字列を255文字に切り詰めた
57#endif
58
59#include "base/filecontainer.h"
60#include <string>
61#include <map>
62#include <fstream>
63#include <cassert>
64#include <cctype>
65#include <cstdio>
66#include <cstdlib>
67#include <cstring>
68
69#define _isspace(x) isspace(x)
70#define _isprint(x) isprint(x)
71
72#define SIZE_LOADPAGE 65536 //バイナリデータを格納するページ単位
73
74#define SIZE_TO_CONFIRM_BINARYFILE 128 //ファイルがバイナリを含むかどうかを確認するのに読み出すデータの長さ (バッファを取るのであまり大きくしないこと)
75
76#define MAGIC_SYMBOL "_checker_magic_number"
77#define MAGIC_NUMBER 0x01234567 //4バイトの整数
78
79#define CMD_GNUNM "nm"
80#define CMD_GNUOBJCOPY "objcopy"
81
82#define MAKE_BASEADDRESS(x) ((x) & ~(SIZE_LOADPAGE-1))
83#define MAKE_OFFSETADDRESS(x) ((x) & (SIZE_LOADPAGE-1))
84
85using namespace std;
86
87namespace {
88
89 class FileContainerBinutilsImpl : public FileContainer
90 {
91 public:
92 typedef void (interceptor_func_t)(fstream &, const string &); //不意に訪れたバイナリファイルの襲撃に対応する関数の型
93
94 protected:
95 string symbol_prefix;
96 map<string, address_t> symbol_table;
97 map<address_t, char *> contents;
98
99 address_t last_address; //キャッシュもどき
100 char * last_page;
101
102 //データ取り込み
103 void loadSymbols(fstream & file) throw(Exception);
104 void loadDataContents(fstream & file) throw(Exception);
105
106 //contentsへ1バイト書き込み
107 void writeByte(address_t address, unsigned int) throw(Exception);
108
109 //自動処理
110 void searchSymbolPrefix(void) throw();
111 void searchByteOrder(void) throw();
112
113 public:
114 FileContainerBinutilsImpl(void) throw();
115 virtual ~FileContainerBinutilsImpl(void) throw();
116
117 /* インタフェース部 */
118 virtual void attachModule(const string & filename) throw(Exception);
119 virtual void loadContents(void * dest, address_t address, size_t size) throw(Exception);
120 virtual address_t getSymbolAddress(const string & symbol) throw(Exception);
121 virtual std::string getArchitecture(void) throw();
122
123 TESTSUITE_PROTOTYPE(main)
124 };
125
126 namespace {
127 FileContainerBinutilsImpl instance_of_FileContainerBinutilsImpl;
128 }
129
130 /* コンストラクタ */
131 FileContainerBinutilsImpl::FileContainerBinutilsImpl(void) throw()
132 : symbol_prefix(""), symbol_table(), contents(), last_address(0), last_page(0)
133 {}
134
135 /* デストラクタ : データバッファの解放 */
136 FileContainerBinutilsImpl::~FileContainerBinutilsImpl(void) throw()
137 {
138 map<address_t, char *>::iterator scope;
139
140 scope = contents.begin();
141 while(scope != contents.end()) {
142 delete [] scope->second;
143 ++ scope;
144 }
145 symbol_table.clear();
146 contents.clear();
147 }
148
149 /* ファイル名をカンマで二つに分ける */
150 void splitFilename(const string & src, string & first, string & second) throw(Exception)
151 {
152 if(!src.empty()) {
153 string::size_type pos;
154
155 pos = src.find_first_of(',');
156 if(pos != string::npos) {
157 first = src.substr(0, pos);
158 second = src.substr(pos + 1);
159 }
160 else {
161 //ファイル名が一つしか指定されていない
162 first = src;
163 second = src;
164 }
165 }
166 else
167 ExceptionMessage("[FCBI] Empty filename could not be accepted.","[FCBI] ファイル名がありません").throwException();
168 }
169
170 /* ファイルがバイナリデータを持っているかどうかを判定 */
171 bool hasBinaryContents(fstream & file) throw()
172 {
173 assert(file.is_open());
174
175 bool result = false;
176 char buffer[SIZE_TO_CONFIRM_BINARYFILE];
177 streamsize length;
178
179 file.read(buffer, SIZE_TO_CONFIRM_BINARYFILE);
180 length = file.gcount();
181
182 for(streamsize i = 0; i < length; ++ i) {
183 if(buffer[i] < 0 || !(_isprint(buffer[i]) || _isspace(buffer[i]))){
184 result = true;
185 break;
186 }
187 }
188
189 if(!result) {
190 file.clear();
191 file.seekg(0, ios::beg); //å…
192ˆé ­ã«æˆ»ã—ておく
193 }
194
195 return result;
196 }
197
198 /* テキストファイルを開く (バイナリだった場合には対処) */
199 void openTextFile(fstream & file, const string & filename, FileContainerBinutilsImpl::interceptor_func_t * interceptor) throw(Exception)
200 {
201 assert(!filename.empty());
202 assert(!file.is_open());
203
204 file.open(filename.c_str(), ios::in|ios::binary);
205 if(!file.is_open()) {
206 ExceptionMessage("File '%' could not be opened.","ファイル '%' は開けません") << filename << throwException;
207 return;
208 }
209
210 /* バイナリファイルだったら... */
211 while(hasBinaryContents(file)) {
212 file.close();
213
214 if(interceptor != 0) {
215 (*interceptor)(file, filename);
216 interceptor = 0; //対処は一回のみ
217 }
218
219 if(!file.is_open()) {
220 break;
221 }
222 }
223
224 /* ファイルが開けなかったら例外 */
225 if(!file.is_open())
226 ExceptionMessage("Program failed to convert the binary '%' into suitable style. Please specify a suitable TEXT file.",
227 "プログラムはバイナリファイル'%'の変換に失敗しました。正しいテキストファイルを指定し直してください。")
228 << filename << throwException;
229 }
230
231 /* 一時的なファイル名の生成 */
232 const char * makeTemporaryFilename(void) throw()
233 {
234 static char filename[10];
235
236 sprintf(filename, "cfg%06x", (int)(rand() & 0xffffffl));
237
238 return filename;
239 }
240
241
242 /* バイナリをGNU-NMを使って変換する */
243 void interceptWithGnuNM(fstream & file, const string & filename) throw(Exception)
244 {
245 assert(!file.is_open());
246
247 string cmdline;
248 string symfile;
249
250 symfile.assign(makeTemporaryFilename());
251 cmdline = string(CMD_GNUNM) + " " + filename + " > " + symfile;
252 VerboseMessage("[EXEC] %\n") << cmdline;
253
254 system(cmdline.c_str());
255
256 /* 正しく開けたらファイルを削除 */
257 file.open(symfile.c_str(), ios::in);
258 if(file.is_open()) {
259 remove(symfile.c_str());
260 }
261 }
262
263 /* バイナリをGNU-OBJCOPYを使って変換する */
264 void interceptWithGnuObjcopy(fstream & file, const string & filename) throw(Exception)
265 {
266 assert(!file.is_open());
267
268 string cmdline;
269 string srecfile;
270
271 srecfile.assign(makeTemporaryFilename());
272 cmdline = string(CMD_GNUOBJCOPY) + " -F srec " + filename + " " + srecfile;
273 VerboseMessage("[EXEC] %\n") << cmdline;
274
275 system(cmdline.c_str());
276
277 /* 正しく開けたらファイルを削除 */
278 file.open(srecfile.c_str(), ios::in);
279 if(file.is_open()) {
280 remove(srecfile.c_str());
281 }
282 }
283
284 /* 16進から10進への変換 (ポインタ移動, 長さ指定付き) */
285 unsigned int hextodec(const char * & src, size_t length) throw()
286 {
287 assert(length <= sizeof(unsigned int) * 2);
288
289 unsigned int result = 0;
290 unsigned int digit;
291
292 while(length-- > 0) {
293 if(*src >= '0' && *src <= '9')
294 digit = *src - '0';
295 else if(*src >= 'A' && *src <='F')
296 digit = *src - 'A' + 10;
297 else if(*src >= 'a' && *src <='f')
298 digit = *src - 'a' + 10;
299 else
300 break;
301
302 ++ src;
303 result = (result << 4) | (digit & 0xf);
304 }
305
306 return result;
307 }
308
309 /* NMが出力した行をパース */
310 bool readGnuNmLine(fstream & file, FileContainer::address_t & address, string & attribute, string & symbolname) throw()
311 {
312 assert(file.is_open());
313
314 string src;
315 string addr;
316 string::size_type pos1;
317 string::size_type pos2;
318
319 /* 中身を空にしておく */
320 address = 0;
321 if(!attribute.empty())
322 attribute.erase();
323 if(!symbolname.empty())
324 symbolname.erase();
325
326 //次の行を取得 (空行, 未定義シンボルは読み飛ばす)
327 do {
328 if(file.eof())
329 return false;
330
331 getline(file, src, '\n');
332 } while(src.empty() || src.at(0) == ' ');
333
334 //行を分解
335 pos1 = src.find_first_of(' ');
336 addr = src.substr(0, pos1);
337
338 pos2 = src.find_first_of(' ', pos1 + 1);
339 attribute = src.substr(pos1 + 1, pos2 - pos1 - 1);
340 symbolname = src.substr(pos2 + 1);
341
342 //アドレスのパース (注 : なんでこんなちまちまやってるかというと、アドレスが32bitを超
343えるターゲットがいるから)
344 while(!addr.empty()) {
345 size_t length = addr.size();
346 const char * src = addr.c_str();
347 if(length > sizeof(unsigned int) * 2)
348 length = sizeof(unsigned int) * 2;
349 address = (address << (length * 2)) | (hextodec(src, length));
350 addr.erase(0, length);
351 }
352
353 return true;
354 }
355
356 /* シンボルの読み込み */
357 void FileContainerBinutilsImpl::loadSymbols(fstream & file) throw(Exception)
358 {
359 assert(file.is_open());
360
361 address_t address;
362 string attribute;
363 string symbolname;
364
365 while(readGnuNmLine(file, address, attribute, symbolname)) {
366 symbol_table.insert(map<string, address_t>::value_type(symbolname, address));
367 }
368
369 VerboseMessage("% symbols loaded\n") << symbol_table.size() << &throwException;
370
371 file.close();
372 }
373
374 /* contentsに1バイト書き込み */
375 void FileContainerBinutilsImpl::writeByte(address_t address, unsigned int value) throw(Exception)
376 {
377 address_t & base = last_address;
378 char * & page = last_page;
379
380 /* キャッシュもどきが使えないなら、ページを探す */
381 if(MAKE_BASEADDRESS(address) != last_address || last_page == 0) {
382 map<address_t, char *>::iterator scope;
383
384 base = MAKE_BASEADDRESS(address);
385 scope = contents.find(base);
386 if(scope == contents.end()) {
387 page = new(nothrow) char [SIZE_LOADPAGE];
388 if(page == 0) {
389 ExceptionMessage("Not enough memory available to store the contents","空きメモリ不足のため、データの格納に失敗しました").throwException();
390 return;
391 }
392 contents.insert(map<address_t,char*>::value_type(base, page));
393 }
394 else
395 page = scope->second;
396 }
397
398 *(page + (address - base)) = static_cast<char>(value & 0xff);
399 }
400
401 /* 末尾の空白文字を切り取る */
402 void trimString(string & src) throw()
403 {
404 string::size_type pos;
405
406 pos = src.find_last_not_of(" \t\r\n");
407 if(pos != string::npos && pos != src.size())
408 src.erase(pos + 1);
409 }
410
411 /* モトローラSレコードを一行読み込む */
412 /*
413 The general format of an S-record follows:
414 +-------------------//------------------//-----------------------+
415 | type | count | address | data | checksum |
416 +-------------------//------------------//-----------------------+
417 */
418 bool readRecord(fstream & file, string & dest) throw(Exception)
419 {
420 unsigned int sum;
421 unsigned int count;
422 unsigned int i;
423 const char * pos;
424
425 /* 次の行を読み込む */
426 do {
427 //getlineがReadFileを呼んでブロックするので、確実にEOFを反応させるためにこうする
428 int ch = file.get();
429 if(ch == EOF)
430 return false;
431
432 file.putback(static_cast<char>(ch));
433 getline(file, dest);
434 } while(dest.empty());
435
436 trimString(dest);
437
438 /* 正当性の判定 */
439
440 if(dest[0] != 'S') //行頭が'S'で始まらない
441 ExceptionMessage("The file is not a Motorola S-Record file.","モトローラSフォーマットで無い行が見つかりました") << throwException;
442
443 pos = dest.c_str() + 2;
444 count = hextodec(pos, 2);
445 if(dest.size() != (count + 2)*2)
446 ExceptionMessage("Illegal S-Record found (count unmatched).","不正なSレコードがあります (サイズ不一致)") << throwException;
447
448 sum = count;
449 for(i = 0; i < count; ++ i)
450 sum += hextodec(pos, 2);
451
452 if((sum & 0xff) != 0xff)
453 ExceptionMessage("Illegal S-Record found (check-sum unmatched).","不正なSレコードがあります (チェックサム不一致)") << throwException;
454
455 return true;
456 }
457
458 /* 次の開始アドレスを得る */
459 FileContainer::address_t parseRecordAddress(const string & src, FileContainer::address_t base) throw()
460 {
461 const char * record = src.c_str();
462 FileContainer::address_t result = 0;
463
464 record += 4;
465 switch(*(record - 3)) {
466 case '1':
467 result = hextodec(record, 4);
468 break;
469 case '2':
470 result = hextodec(record, 6);
471 break;
472 case '3':
473 result = hextodec(record, 8);
474 break;
475 case '5':
476 result = base;
477 break;
478 default:
479 break;
480 }
481
482 return result;
483 }
484
485 /* データ部分だけを残してチョップ */
486 void chopRecord(string & src) throw()
487 {
488 string::size_type start;
489
490 switch(src[1]) {
491 case '1': start = 4 + 4; break;
492 case '2': start = 4 + 6; break;
493 case '3': start = 4 + 8; break;
494 default: start = 4; break;
495 }
496
497 //å…
498ˆé ­4バイト + アドレス部 + 最後のサムを取り除く
499 src = src.substr(start, src.size() - start - 2);
500 }
501
502 /* プログラムデータの読み込み */
503 void FileContainerBinutilsImpl::loadDataContents(fstream & file) throw(Exception)
504 {
505 assert(file.is_open());
506
507 address_t address;
508 string line;
509
510 address = 0;
511 while(readRecord(file, line)) {
512
513 address = parseRecordAddress(line, address);
514
515 chopRecord(line);
516
517 /* データの格納 */
518 const char * pos = line.c_str();
519 while(*pos != '\x0') {
520 unsigned int data = hextodec(pos, 2);
521 writeByte(address, data);
522 ++ address;
523 }
524 }
525
526 file.close();
527 }
528
529 /* シンボルプレフィクスの自動判定 */
530 void FileContainerBinutilsImpl::searchSymbolPrefix(void) throw()
531 {
532 const char * candidate_list[] = {"", "_", NULL};
533 const char ** candidate;
534
535 for(candidate = candidate_list; *candidate != NULL; ++ candidate) {
536 map<string, address_t>::const_iterator scope;
537 string symbol;
538
539 symbol = string(*candidate) + MAGIC_SYMBOL;
540 scope = symbol_table.find(symbol);
541
542 if(scope != symbol_table.end())
543 break;
544 }
545
546 if(*candidate != NULL)
547 symbol_prefix.assign(*candidate);
548 }
549
550 /* エンディアンの自動判定 */
551 void FileContainerBinutilsImpl::searchByteOrder(void) throw()
552 {
553 address_t address;
554 union {
555 char buffer[4];
556 unsigned int value;
557 };
558
559 try {
560 value = 0;
561 address = getSymbolAddress(MAGIC_SYMBOL);
562 loadContents(buffer, address, 4);
563
564 if(value == MAGIC_NUMBER) {
565 byteorder = HOSTORDER;
566 }
567 else {
568 buffer[0] ^= buffer[3], buffer[3] ^= buffer[0], buffer[0] ^= buffer[3]; // swap(buffer[0], buffer[3])
569 buffer[1] ^= buffer[2], buffer[2] ^= buffer[1], buffer[1] ^= buffer[2]; // swap(buffer[1], buffer[2])
570
571 if(value == MAGIC_NUMBER)
572 byteorder = HOSTORDER == LITTLE ? BIG : LITTLE;
573 else
574 throw false;
575 }
576 }
577 catch(...) {}
578 }
579
580 /* モジュールのアタッチ -> シンボル読出し, データ格納 */
581 void FileContainerBinutilsImpl::attachModule(const string & filename) throw(Exception)
582 {
583 fstream file;
584 string symbol_filename;
585 string contents_filename;
586
587 splitFilename(filename, symbol_filename, contents_filename);
588
589 openTextFile(file, symbol_filename, interceptWithGnuNM);
590 loadSymbols(file);
591
592 openTextFile(file, contents_filename, interceptWithGnuObjcopy);
593 loadDataContents(file);
594
595 searchSymbolPrefix();
596 searchByteOrder();
597 }
598
599 /* 格納している内
600容の取得 */
601 void FileContainerBinutilsImpl::loadContents(void * _dest, address_t address, size_t size) throw(Exception)
602 {
603 char * dest = static_cast<char *>(_dest);
604
605 while(size > 0) {
606 map<address_t, char *>::const_iterator scope;
607
608 address_t base = MAKE_BASEADDRESS(address);
609 address_t offset = MAKE_OFFSETADDRESS(address);
610 size_t transfer_size = size;
611
612 if(transfer_size > SIZE_LOADPAGE - offset)
613 transfer_size = SIZE_LOADPAGE - offset;
614
615 scope = contents.find(base);
616 if(scope == contents.end())
617 ExceptionMessage("[Internel error] Memory read with unmapped address","[内
618部エラー] マップされてないアドレスを使ってメモリリードが行われました").throwException();
619
620 memcpy(dest, scope->second + offset, transfer_size);
621
622 dest += transfer_size;
623 size -= transfer_size;
624 }
625 }
626
627 /* シンボルのアドレスの取得 */
628 FileContainer::address_t FileContainerBinutilsImpl::getSymbolAddress(const string & symbol) throw(Exception)
629 {
630 string symbolname;
631 map<string, address_t>::const_iterator scope;
632
633 symbolname = symbol_prefix + symbol;
634
635 scope = symbol_table.find(symbolname);
636 if(scope == symbol_table.end())
637 ExceptionMessage("Unknown symbol '%'","不明なシンボル名 '%'") << symbol << throwException;
638
639 return scope->second;
640 }
641
642 /* アーキテクチャ名の取得 */
643 string FileContainerBinutilsImpl::getArchitecture(void) throw()
644 {
645 if(byteorder == LITTLE)
646 return "Little endian target (with GNU/Binutils)";
647 else
648 return "Big endian target (with GNU/Binutils)";
649 }
650
651}
652
653//---------------------------------------------
654
655#ifdef TESTSUITE
656#include "base/coverage_undefs.h"
657
658namespace {
659 fstream * interceptor_file;
660 string interceptor_filename;
661 void interceptor(fstream & file, const string & filename)
662 {
663 CHECKPOINT("interceptor");
664 interceptor_file = &file;
665 interceptor_filename = filename;
666
667 if(filename.compare("textfile") == 0) {
668 remove(filename.c_str());
669 file.open(filename.c_str(), ios::out);
670 file << "text";
671 file.close();
672
673 file.open(filename.c_str(), ios::in|ios::binary);
674 }
675 else if(filename.compare("binaryfile") == 0) {
676 remove(filename.c_str());
677 file.open(filename.c_str(), ios::out|ios::binary);
678 file.write("\x1",1);
679 file.close();
680
681 file.open(filename.c_str(), ios::in|ios::binary);
682 }
683 }
684}
685
686TESTSUITE(main, FileContainerBinutilsImpl)
687{
688 PREDECESSOR("TFileContainer");
689
690 SingletonBase::ContextChain chain;
691 chain.saveContext<RuntimeObjectTable>();
692
693 BEGIN_CASE("splitFilename","splitFilename") {
694 BEGIN_CASE("1","カンマの前後で切れる") {
695 string first, second;
696
697 splitFilename("a,b", first, second);
698 TEST_CASE("1","firstの中身は正しい", first.compare("a") == 0);
699 TEST_CASE("2","secondの中身は正しい", second.compare("b") == 0);
700 } END_CASE;
701
702 BEGIN_CASE("2","カンマの無い引数を与えると、両方に同じ中身がå…
703¥ã‚‹") {
704 string first, second;
705
706 splitFilename("abc", first, second);
707 TEST_CASE("1","firstの中身は正しい", first.compare("abc") == 0);
708 TEST_CASE("2","secondの中身は正しい", second.compare("abc") == 0);
709 } END_CASE;
710
711 BEGIN_CASE("3","空文字を与えると例外") {
712 bool result = false;
713 string first, second;
714 try { splitFilename("", first, second); } catch(Exception &) { result = true; }
715 if(!result)
716 TEST_FAIL;
717 } END_CASE;
718 } END_CASE;
719
720 BEGIN_CASE("hasBinaryContents","hasBinaryContents") {
721 BEGIN_CASE("1","テキストファイルを食わせる") {
722 fstream file("test", ios::out);
723 file << "This is a sample text file.";
724 file.close();
725
726 file.open("test",ios::in|ios::binary);
727 TEST_CASE("1","関数はfalseを返す", !hasBinaryContents(file));
728 TEST_CASE("2","fileはeofに達していない", !file.eof());
729 file.close();
730
731 remove("test");
732 } END_CASE;
733
734 BEGIN_CASE("2","バイナリデータを食わせる") {
735 fstream file("test", ios::out|ios::binary);
736 file << "This is a sample text file.";
737 file.write("\x0\x1\x2\x3", 4);
738 file.close();
739
740 file.open("test",ios::in|ios::binary);
741 TEST_CASE("1","関数はtrueを返す", hasBinaryContents(file));
742 TEST_CASE("2","fileはeofに達していない", !file.eof());
743 file.close();
744
745 remove("test");
746 } END_CASE;
747 } END_CASE;
748
749 BEGIN_CASE("openTextFile","openTextFile") {
750 BEGIN_CASE("1","テキストファイルを指定する") {
751 TestSuite::clearCheckpoints();
752 fstream file("test", ios::out);
753 file << "This is a sample text file.";
754 file.close();
755
756 bool result = true;
757 try { openTextFile(file, "test", interceptor); } catch(Exception &) { result = false; }
758
759 TEST_CASE("1","例外は起きない", result);
760 TEST_CASE("2","ファイルが開かれている", file.is_open());
761 TEST_CASE("3","interceptorはコールされていない", !TestSuite::isReached("interceptor"));
762
763 string work;
764 getline(file, work, '\n');
765 TEST_CASE("4","読み出された内
766容が正しい", work.compare("This is a sample text file.") == 0);
767
768 file.close();
769 remove("test");
770 } END_CASE;
771
772 BEGIN_CASE("2","バイナリファイルを指定する (interceptorはファイルを開かない)") {
773 TestSuite::clearCheckpoints();
774 fstream file("test", ios::out|ios::binary);
775 file.write("\x1", 1);
776 file.close();
777
778 bool result = false;
779 try { openTextFile(file, "test", interceptor); } catch(Exception &) { result = true; }
780
781 TEST_CASE("1","例外が起きる", result);
782 TEST_CASE("2","ファイルが開かれている", !file.is_open());
783 TEST_CASE("3","interceptorがコールされている", TestSuite::isReached("interceptor"));
784 TEST_CASE("4","interceptorの引数が正しい (file)", interceptor_file == &file);
785 TEST_CASE("5","interceptorの引数が正しい", interceptor_filename.compare("test") == 0);
786
787 file.close();
788 remove("test");
789 } END_CASE;
790
791 BEGIN_CASE("3","存在しないファイルを指定する") {
792 TestSuite::clearCheckpoints();
793 fstream file;
794 bool result = false;
795 try { openTextFile(file, "___unknown___", interceptor); } catch(Exception &) { result = true; }
796
797 TEST_CASE("1","例外が起きる", result);
798 TEST_CASE("2","ファイルが開かれていない", !file.is_open());
799 TEST_CASE("3","interceptorがコールされていない", !TestSuite::isReached("interceptor"));
800 } END_CASE;
801
802 BEGIN_CASE("4","interceptorがテキストファイルを生成する") {
803 TestSuite::clearCheckpoints();
804 fstream file("textfile", ios::out|ios::binary);
805 file.write("\x1", 1);
806 file.close();
807
808 bool result = true;
809 try { openTextFile(file, "textfile", interceptor); } catch(Exception &) { result = false; }
810
811 TEST_CASE("1","例外は起きない", result);
812 TEST_CASE("2","ファイルが開かれている", file.is_open());
813 TEST_CASE("3","interceptorがコールされている", TestSuite::isReached("interceptor"));
814 TEST_CASE("4","interceptorの引数が正しい (file)", interceptor_file == &file);
815 TEST_CASE("5","interceptorの引数が正しい", interceptor_filename.compare("textfile") == 0);
816
817 string work;
818 getline(file, work, '\n');
819 TEST_CASE("4","読み出された内
820容が正しい", work.compare("text") == 0);
821
822 file.close();
823 remove("textfile");
824 } END_CASE;
825
826 BEGIN_CASE("5","interceptorがバイナリファイルを生成する") {
827 TestSuite::clearCheckpoints();
828 fstream file("binaryfile", ios::out|ios::binary);
829 file.write("\x1", 1);
830 file.close();
831
832 bool result = false;
833 try { openTextFile(file, "binaryfile", interceptor); } catch(Exception &) { result = true; }
834
835 TEST_CASE("1","例外は起きる", result);
836 TEST_CASE("2","ファイルが開かれていない", !file.is_open());
837 TEST_CASE("3","interceptorがコールされている", TestSuite::isReached("interceptor"));
838 TEST_CASE("4","interceptorの引数が正しい (file)", interceptor_file == &file);
839 TEST_CASE("5","interceptorの引数が正しい", interceptor_filename.compare("binaryfile") == 0);
840
841 file.close();
842 remove("binaryfile");
843 } END_CASE;
844 } END_CASE;
845
846 BEGIN_CASE("hextodec","hextodec") {
847 const char * letter = "0123456789abcdEFg";
848 const char * work = letter;
849
850 TEST_CASE("1", "切り出された値が正しい", hextodec(work, 2) == 1);
851 TEST_CASE("2", "workが進んでいる", work == letter + 2);
852 TEST_CASE("3", "切り出された値が正しい", hextodec(work, 4) == 0x2345);
853 TEST_CASE("4", "workが進んでいる", work == letter + 6);
854 TEST_CASE("5", "切り出された値が正しい", hextodec(work, 8) == 0x6789abcd);
855 TEST_CASE("6", "workが進んでいる", work == letter + 14);
856 TEST_CASE("7", "切り出された値が正しい", hextodec(work, 8) == 0xef);
857 TEST_CASE("8", "workが'g'の位置でとまる", *work == 'g');
858 TEST_CASE("9", "切り出された値が正しい", hextodec(work, 8) == 0);
859 TEST_CASE("10", "workが'g'の位置でとまる", *work == 'g');
860 } END_CASE;
861
862 BEGIN_CASE("readGnuNmLine","readGnuNmLine") {
863 fstream file("test", ios::out);
864 file << "0804aab0 T _kernel_task_initialize\n0805d8a0 B _kernel_tcb_table\n\n0804e560 R _kernel_tinib_table\n U getpid@@GLIBC_2.0\n";
865 file.close();
866
867 address_t address;
868 string attribute;
869 string symbolname;
870
871 file.open("test", ios::in);
872 BEGIN_CASE("1","普通のエントリが読める") {
873 TEST_CASE("1","関数は成功する", readGnuNmLine(file, address, attribute, symbolname));
874 TEST_CASE("2","addressは正しい", address == 0x0804aab0);
875 TEST_CASE("3","attributeは正しい", attribute.compare("T") == 0);
876 TEST_CASE("4","symbolnameは正しい", symbolname.compare("_kernel_task_initialize") == 0);
877 } END_CASE;
878
879 BEGIN_CASE("2","普通のエントリが読める (2)") {
880 TEST_CASE("1","関数は成功する", readGnuNmLine(file, address, attribute, symbolname));
881 TEST_CASE("2","addressは正しい", address == 0x0805d8a0);
882 TEST_CASE("3","attributeは正しい", attribute.compare("B") == 0);
883 TEST_CASE("4","symbolnameは正しい", symbolname.compare("_kernel_tcb_table") == 0);
884 } END_CASE;
885
886 BEGIN_CASE("3","空行を読み飛ばして次が読める") {
887 TEST_CASE("1","関数は成功する", readGnuNmLine(file, address, attribute, symbolname));
888 TEST_CASE("2","addressは正しい", address == 0x0804e560);
889 TEST_CASE("3","attributeは正しい", attribute.compare("R") == 0);
890 TEST_CASE("4","symbolnameは正しい", symbolname.compare("_kernel_tinib_table") == 0);
891 } END_CASE;
892
893 BEGIN_CASE("4","アドレスの無いエントリは無視する") {
894 TEST_CASE("1","関数は失敗する", !readGnuNmLine(file, address, attribute, symbolname));
895 } END_CASE;
896
897 file.close();
898 remove("test");
899 } END_CASE;
900
901 BEGIN_CASE("loadSymbols","loadSymbols") {
902 fstream file("test", ios::out);
903 file << "0804aab0 T _kernel_task_initialize\n0805d8a0 B _kernel_tcb_table\n\n0804e560 R _kernel_tinib_table\n U getpid@@GLIBC_2.0\n";
904 file.close();
905
906 file.open("test",ios::in);
907
908 FileContainerBinutilsImpl fcbi;
909 fcbi.loadSymbols(file);
910
911 TEST_CASE("1","読み込まれたエントリの数が正しい", fcbi.symbol_table.size() == 3);
912 TEST_CASE("2","ファイルは閉じられている", !file.is_open());
913
914 remove("test");
915 } END_CASE;
916
917 BEGIN_CASE("writeByte","writeByte") {
918 FileContainerBinutilsImpl fcbi;
919
920 BEGIN_CASE("1","存在しないページへの書き込み") {
921 TEST_CASE("0", "[前提] contentsの要素数は0", fcbi.contents.size() == 0);
922 fcbi.writeByte(0x100, 0);
923
924 TEST_CASE("1","contentsの要素が増えている", fcbi.contents.size() == 1);
925
926 const char * scope = fcbi.contents.find(MAKE_BASEADDRESS(0x100))->second + MAKE_OFFSETADDRESS(0x100);
927 TEST_CASE("2","書き込まれている内
928容が正しい", *scope == 0);
929 } END_CASE;
930
931 BEGIN_CASE("2","存在するページへの書き込み (連続アクセス)") {
932 fcbi.writeByte(0x100, 0xff);
933
934 TEST_CASE("1","contentsの要素が増えていない", fcbi.contents.size() == 1);
935
936 const char * scope = fcbi.contents.find(MAKE_BASEADDRESS(0x100))->second + MAKE_OFFSETADDRESS(0x100);
937 TEST_CASE("2","書き込まれている内
938容が正しい", *scope == 0xff);
939 } END_CASE;
940
941 BEGIN_CASE("3","新しいページへの書き込み") {
942 fcbi.writeByte(0x10000000, 0xff);
943
944 TEST_CASE("1","contentsの要素が増えている", fcbi.contents.size() == 2);
945
946 const char * scope = fcbi.contents.find(MAKE_BASEADDRESS(0x10000000))->second + MAKE_OFFSETADDRESS(0x10000000);
947 TEST_CASE("2","書き込まれている内
948容が正しい", *scope == 0xff);
949 } END_CASE;
950
951 BEGIN_CASE("4","既存のページへのアクセス") {
952 fcbi.writeByte(0x100, 0x0);
953
954 TEST_CASE("1","contentsの要素が増えていない", fcbi.contents.size() == 2);
955
956 const char * scope = fcbi.contents.find(MAKE_BASEADDRESS(0x100))->second + MAKE_OFFSETADDRESS(0x100);
957 TEST_CASE("2","書き込まれている内
958容が正しい", *scope == 0x0);
959 } END_CASE;
960 } END_CASE;
961
962 BEGIN_CASE("readRecord","readRecord") {
963 fstream file("test",ios::out);
964 file << "S315080480F42F6C69622F6C642D6C696E75782E736F98\n\nS315080480F42F6C69622F6C642D6C696E75782E736F98\nS308080481042E320005\nDUMMY\nS31808048108040000001000000001000000474E550056\nS31008048108040000001000000001000000474E550056\n";
965 file.close();
966
967 file.open("test",ios::in);
968 BEGIN_CASE("1","正常ケース") {
969 string work;
970 bool result;
971 bool exception = false;
972 try { result = readRecord(file, work); } catch(Exception &) { exception = true; }
973 TEST_CASE("1","例外は起こらない", !exception);
974 TEST_CASE("2","関数はtrueを返す", result);
975 TEST_CASE("3","読み出された内
976容が正しい", work.compare("S315080480F42F6C69622F6C642D6C696E75782E736F98") == 0);
977 } END_CASE;
978
979 BEGIN_CASE("2","正常ケース (空行の読み飛ばし)") {
980 string work;
981 bool result;
982 bool exception = false;
983 try { result = readRecord(file, work); } catch(Exception &) { exception = true; }
984 TEST_CASE("1","例外は起こらない", !exception);
985 TEST_CASE("2","関数はtrueを返す", result);
986 TEST_CASE("3","読み出された内
987容が正しい", work.compare("S315080480F42F6C69622F6C642D6C696E75782E736F98") == 0);
988 } END_CASE;
989
990 BEGIN_CASE("3","チェックサムが誤っているエントリ") {
991 string work;
992 bool result;
993 bool exception = false;
994 try { result = readRecord(file, work); } catch(Exception &) { exception = true; }
995 TEST_CASE("1","例外をおこす", exception);
996 } END_CASE;
997
998 BEGIN_CASE("4","å…
999ˆé ­ãŒSで始まらないエントリ") {
1000 string work;
1001 bool result;
1002 bool exception = false;
1003 try { result = readRecord(file, work); } catch(Exception &) { exception = true; }
1004 TEST_CASE("1","例外をおこす", exception);
1005 } END_CASE;
1006
1007 BEGIN_CASE("5","指定された長さよりも長いエントリ") {
1008 string work;
1009 bool result;
1010 bool exception = false;
1011 try { result = readRecord(file, work); } catch(Exception &) { exception = true; }
1012 TEST_CASE("1","例外をおこす", exception);
1013 } END_CASE;
1014
1015 BEGIN_CASE("6","指定された長さよりも短いエントリ") {
1016 string work;
1017 bool result;
1018 bool exception = false;
1019 try { result = readRecord(file, work); } catch(Exception &) { exception = true; }
1020 TEST_CASE("1","例外をおこす", exception);
1021 } END_CASE;
1022
1023 BEGIN_CASE("7","ファイル終端") {
1024 string work;
1025 bool result;
1026 bool exception = false;
1027 try { result = readRecord(file, work); } catch(Exception &) { exception = true; }
1028 TEST_CASE("1","例外をおこさない", !exception);
1029 TEST_CASE("2","関数はfalseを返す", !result);
1030 } END_CASE;
1031
1032 remove("test");
1033 } END_CASE;
1034
1035 BEGIN_CASE("chopRecord","chopRecord") {
1036 BEGIN_CASE("1","S1レコード") {
1037 string src("S106080480F42F4A");
1038
1039 chopRecord(src);
1040 TEST_CASE("1","値が正しい", src.compare("80F42F") == 0);
1041 } END_CASE;
1042
1043 BEGIN_CASE("2","S2レコード") {
1044 string src("S206080480F42F4A");
1045
1046 chopRecord(src);
1047 TEST_CASE("1","値が正しい", src.compare("F42F") == 0);
1048 } END_CASE;
1049
1050 BEGIN_CASE("3","S3レコード") {
1051 string src("S306080480F42F4A");
1052
1053 chopRecord(src);
1054 TEST_CASE("1","値が正しい", src.compare("2F") == 0);
1055 } END_CASE;
1056
1057 BEGIN_CASE("4","S4レコード") {
1058 string src("S406080480F42F4A");
1059
1060 chopRecord(src);
1061 TEST_CASE("1","値が正しい", src.compare("080480F42F") == 0);
1062 } END_CASE;
1063
1064 BEGIN_CASE("5","S5レコード") {
1065 string src("S506080480F42F4A");
1066
1067 chopRecord(src);
1068 TEST_CASE("1","値が正しい", src.compare("080480F42F") == 0);
1069 } END_CASE;
1070
1071 } END_CASE;
1072
1073 BEGIN_CASE("loadDataContents/loadContents","loadDataContents/loadContents") {
1074 fstream file("test", ios::out);
1075 file << "S30D000000000123456789ABCDEF32\nS509FEDCBA9876543210BE";
1076 file.close();
1077
1078 BEGIN_CASE("1","正常ケース") {
1079 FileContainerBinutilsImpl fcbi;
1080
1081 file.open("test",ios::in);
1082 bool exception = false;
1083 try { fcbi.loadDataContents(file); } catch(...) { exception = true; }
1084
1085 TEST_CASE("1","例外は起こらない", !exception);
1086 TEST_CASE("2","データが確保されている", fcbi.contents.size() == 1);
1087 TEST_CASE("3","ファイルは閉じられている", !file.is_open());
1088 BEGIN_CASE("4","格納した値が正しく読める") {
1089 unsigned int i;
1090
1091 assert(sizeof(unsigned int) >= 4);
1092 i = 0;
1093
1094 fcbi.loadContents(&i, 0, 4);
1095 TEST_CASE("1","1-4バイト目", i == 0x67452301);
1096 fcbi.loadContents(&i, 4, 4);
1097 TEST_CASE("1","5-8バイト目", i == 0xefcdab89);
1098 fcbi.loadContents(&i, 8, 4);
1099 TEST_CASE("1","9-12バイト目", i == 0x98badcfe);
1100 fcbi.loadContents(&i,12, 4);
1101 TEST_CASE("1","13-16バイト目", i == 0x10325476);
1102 } END_CASE;
1103 } END_CASE;
1104 remove("test");
1105
1106 BEGIN_CASE("2","loadContentsで一度にページサイズを超
1107える量を要求する") {
1108 FileContainerBinutilsImpl fcbi;
1109 unsigned int i;
1110
1111 for(i=0;i<SIZE_LOADPAGE*2;++i)
1112 fcbi.writeByte(i, i);
1113
1114 unsigned char * buffer = new unsigned char [SIZE_LOADPAGE * 2];
1115 fcbi.loadContents(buffer, 0, SIZE_LOADPAGE * 2);
1116
1117 for(i=0;i<SIZE_LOADPAGE*2;++i)
1118 if(*(buffer + i) != (i & 0xff))
1119 TEST_FAIL;
1120
1121 delete [] buffer;
1122 } END_CASE;
1123
1124 } END_CASE;
1125
1126 BEGIN_CASE("searchSymbolPrefix","searchSymbolPrefix") {
1127
1128 BEGIN_CASE("1","プレフィクスがない") {
1129 FileContainerBinutilsImpl fcbi;
1130 fcbi.symbol_table.insert(pair<string, address_t>(MAGIC_SYMBOL, 0x100));
1131
1132 fcbi.searchSymbolPrefix();
1133 if(!fcbi.symbol_prefix.empty())
1134 TEST_FAIL;
1135 } END_CASE;
1136
1137 BEGIN_CASE("2","変数名に\"_\"がつくタイプ") {
1138 FileContainerBinutilsImpl fcbi;
1139 fcbi.symbol_table.insert(pair<string, address_t>("_" MAGIC_SYMBOL, 0x100));
1140
1141 fcbi.searchSymbolPrefix();
1142 if(fcbi.symbol_prefix.compare("_") != 0)
1143 TEST_FAIL;
1144 } END_CASE;
1145
1146 BEGIN_CASE("3","\"__\"には反応しない") {
1147 FileContainerBinutilsImpl fcbi;
1148 fcbi.symbol_table.insert(pair<string, address_t>("__" MAGIC_SYMBOL, 0x100));
1149
1150 fcbi.searchSymbolPrefix();
1151 if(!fcbi.symbol_prefix.empty())
1152 TEST_FAIL;
1153 } END_CASE;
1154
1155 BEGIN_CASE("4","発見できない場合、変更しない") {
1156 FileContainerBinutilsImpl fcbi;
1157 fcbi.symbol_prefix.assign("test");
1158
1159 fcbi.searchSymbolPrefix();
1160 if(fcbi.symbol_prefix.compare("test") != 0)
1161 TEST_FAIL;
1162 } END_CASE;
1163 } END_CASE;
1164
1165 BEGIN_CASE("searchByteOrder","searchByteOrder") {
1166 BEGIN_CASE("1","ホストと同じエンディアン") {
1167 FileContainerBinutilsImpl fcbi;
1168 unsigned int value = MAGIC_NUMBER;
1169 fcbi.symbol_table.insert(pair<string, address_t>(MAGIC_SYMBOL, 0x100));
1170
1171 for(int i=0;i<4;i++)
1172 fcbi.writeByte(0x100 + i, *((char *)&value + i));
1173
1174 fcbi.byteorder = UNKNOWN;
1175 fcbi.searchByteOrder();
1176
1177 if(fcbi.byteorder != HOSTORDER)
1178 TEST_FAIL;
1179 } END_CASE;
1180
1181 BEGIN_CASE("2","ホストと違うエンディアン") {
1182 FileContainerBinutilsImpl fcbi;
1183 unsigned int value = MAGIC_NUMBER;
1184 fcbi.symbol_table.insert(pair<string, address_t>(MAGIC_SYMBOL, 0x100));
1185
1186 for(int i=0;i<4;i++)
1187 fcbi.writeByte(0x100 + i, *((char *)&value + (3 - i)));
1188
1189 fcbi.byteorder = UNKNOWN;
1190 fcbi.searchByteOrder();
1191
1192 if(fcbi.byteorder == HOSTORDER)
1193 TEST_FAIL;
1194 } END_CASE;
1195
1196 BEGIN_CASE("3","シンボルが無い") {
1197 FileContainerBinutilsImpl fcbi;
1198 unsigned int value = MAGIC_NUMBER;
1199
1200 for(int i=0;i<4;i++)
1201 fcbi.writeByte(0x100 + i, *((char *)&value + (3 - i)));
1202
1203 fcbi.byteorder = UNKNOWN;
1204 fcbi.searchByteOrder();
1205
1206 if(fcbi.byteorder != UNKNOWN)
1207 TEST_FAIL;
1208 } END_CASE;
1209
1210 BEGIN_CASE("4","データが無い") {
1211 FileContainerBinutilsImpl fcbi;
1212 unsigned int value = MAGIC_NUMBER;
1213 fcbi.symbol_table.insert(pair<string, address_t>(MAGIC_SYMBOL, 0x100));
1214
1215 fcbi.byteorder = UNKNOWN;
1216 fcbi.searchByteOrder();
1217
1218 if(fcbi.byteorder != UNKNOWN)
1219 TEST_FAIL;
1220 } END_CASE;
1221 } END_CASE;
1222
1223 chain.restoreContext();
1224}
1225
1226#endif /* TESTSUITE */
1227
1228#endif /* FILECONTAINER_BINUTILS || TESTSUITE */
1229
Note: See TracBrowser for help on using the repository browser.