3 * Toyohashi Open Platform for Embedded Real-Time Systems/
4 * Just Standard Profile Kernel
6 * Copyright (C) 2003 by Embedded and Real-Time Systems Laboratory
7 * Toyohashi Univ. of Technology, JAPAN
9 * 上記著作権者は,以下の (1)〜(4) の条件か,Free Software Foundation
10 * によって公表されている GNU General Public License の Version 2 に記
11 * 述されている条件を満たす場合に限り,本ソフトウェア(本ソフトウェア
12 * を改変したものを含む.以下同じ)を使用・複製・改変・再配布(以下,
14 * (1) 本ソフトウェアをソースコードの形で利用する場合には,上記の著作
15 * 権表示,この利用条件および下記の無保証規定が,そのままの形でソー
17 * (2) 本ソフトウェアを,ライブラリ形式など,他のソフトウェア開発に使
18 * 用できる形で再配布する場合には,再配布に伴うドキュメント(利用
19 * 者マニュアルなど)に,上記の著作権表示,この利用条件および下記
21 * (3) 本ソフトウェアを,機器に組み込むなど,他のソフトウェア開発に使
22 * 用できない形で再配布する場合には,次のいずれかの条件を満たすこ
24 * (a) 再配布に伴うドキュメント(利用者マニュアルなど)に,上記の著
25 * 作権表示,この利用条件および下記の無保証規定を掲載すること.
26 * (b) 再配布の形態を,別に定める方法によって,TOPPERSプロジェクトに
28 * (4) 本ソフトウェアの利用により直接的または間接的に生じるいかなる損
29 * 害からも,上記著作権者およびTOPPERSプロジェクトを免責すること.
31 * 本ソフトウェアは,無保証で提供されているものである.上記著作権者お
32 * よびTOPPERSプロジェクトは,本ソフトウェアに関して,その適用可能性も
33 * 含めて,いかなる保証も行わない.また,本ソフトウェアの利用により直
34 * 接的または間接的に生じたいかなる損害に関しても,その責任を負わない.
36 * @(#) $Id: fc_binutils.cpp,v 1.2 2009/06/12 13:30:29 suikan Exp $
39 #if defined(FILECONTAINER_BINUTILS) || defined(TESTSUITE)
42 #pragma warning(disable:4786) //デバッグ文字列を255文字に切り詰めた
45 #include "base/filecontainer.h"
55 #define _isspace(x) isspace(x)
56 #define _isprint(x) isprint(x)
58 #define SIZE_LOADPAGE 65536 //バイナリデータを格納するページ単位
60 #define SIZE_TO_CONFIRM_BINARYFILE 128 //ファイルがバイナリを含むかどうかを確認するのに読み出すデータの長さ (バッファを取るのであまり大きくしないこと)
62 #define MAGIC_SYMBOL "_checker_magic_number"
63 #define MAGIC_NUMBER 0x01234567 //4バイトの整数
65 #define CMD_GNUNM "nm"
66 #define CMD_GNUOBJCOPY "objcopy"
68 #define MAKE_BASEADDRESS(x) ((x) & ~(SIZE_LOADPAGE-1))
69 #define MAKE_OFFSETADDRESS(x) ((x) & (SIZE_LOADPAGE-1))
75 class FileContainerBinutilsImpl : public FileContainer
78 typedef void (interceptor_func_t)(fstream &, const string &); //不意に訪れたバイナリファイルの襲撃に対応する関数の型
82 map<string, address_t> symbol_table;
83 map<address_t, char *> contents;
85 address_t last_address; //キャッシュもどき
89 void loadSymbols(fstream & file) throw(Exception);
90 void loadDataContents(fstream & file) throw(Exception);
93 void writeByte(address_t address, unsigned int) throw(Exception);
96 void searchSymbolPrefix(void) throw();
97 void searchByteOrder(void) throw();
100 FileContainerBinutilsImpl(void) throw();
101 virtual ~FileContainerBinutilsImpl(void) throw();
104 virtual void attachModule(const string & filename) throw(Exception);
105 virtual void loadContents(void * dest, address_t address, size_t size) throw(Exception);
106 virtual address_t getSymbolAddress(const string & symbol) throw(Exception);
107 virtual std::string getArchitecture(void) throw();
109 TESTSUITE_PROTOTYPE(main)
113 FileContainerBinutilsImpl instance_of_FileContainerBinutilsImpl;
117 FileContainerBinutilsImpl::FileContainerBinutilsImpl(void) throw()
118 : symbol_prefix(""), symbol_table(), contents(), last_address(0), last_page(0)
121 /* デストラクタ : データバッファの解放 */
122 FileContainerBinutilsImpl::~FileContainerBinutilsImpl(void) throw()
124 map<address_t, char *>::iterator scope;
126 scope = contents.begin();
127 while(scope != contents.end()) {
128 delete [] scope->second;
131 symbol_table.clear();
135 /* ファイル名をカンマで二つに分ける */
136 void splitFilename(const string & src, string & first, string & second) throw(Exception)
139 string::size_type pos;
141 pos = src.find_first_of(',');
142 if(pos != string::npos) {
143 first = src.substr(0, pos);
144 second = src.substr(pos + 1);
153 ExceptionMessage("[FCBI] Empty filename could not be accepted.","[FCBI] ファイル名がありません").throwException();
156 /* ファイルがバイナリデータを持っているかどうかを判定 */
157 bool hasBinaryContents(fstream & file) throw()
159 assert(file.is_open());
162 char buffer[SIZE_TO_CONFIRM_BINARYFILE];
165 file.read(buffer, SIZE_TO_CONFIRM_BINARYFILE);
166 length = file.gcount();
168 for(streamsize i = 0; i < length; ++ i) {
169 if(buffer[i] < 0 || !(_isprint(buffer[i]) || _isspace(buffer[i]))){
177 file.seekg(0, ios::beg); //先頭に戻しておく
183 /* テキストファイルを開く (バイナリだった場合には対処) */
184 void openTextFile(fstream & file, const string & filename, FileContainerBinutilsImpl::interceptor_func_t * interceptor) throw(Exception)
186 assert(!filename.empty());
187 assert(!file.is_open());
189 file.open(filename.c_str(), ios::in|ios::binary);
190 if(!file.is_open()) {
191 ExceptionMessage("File '%' could not be opened.","ファイル '%' は開けません") << filename << throwException;
195 /* バイナリファイルだったら... */
196 while(hasBinaryContents(file)) {
199 if(interceptor != 0) {
200 (*interceptor)(file, filename);
201 interceptor = 0; //対処は一回のみ
204 if(!file.is_open()) {
211 ExceptionMessage("Program failed to convert the binary '%' into suitable style. Please specify a suitable TEXT file.",
212 "プログラムはバイナリファイル'%'の変換に失敗しました。正しいテキストファイルを指定し直してください。")
213 << filename << throwException;
217 const char * makeTemporaryFilename(void) throw()
219 static char filename[10];
221 sprintf(filename, "cfg%06x", (int)(rand() & 0xffffffl));
227 /* バイナリをGNU-NMを使って変換する */
228 void interceptWithGnuNM(fstream & file, const string & filename) throw(Exception)
230 assert(!file.is_open());
235 symfile.assign(makeTemporaryFilename());
236 cmdline = string(CMD_GNUNM) + " " + filename + " > " + symfile;
237 VerboseMessage("[EXEC] %\n") << cmdline;
239 system(cmdline.c_str());
242 file.open(symfile.c_str(), ios::in);
244 remove(symfile.c_str());
248 /* バイナリをGNU-OBJCOPYを使って変換する */
249 void interceptWithGnuObjcopy(fstream & file, const string & filename) throw(Exception)
251 assert(!file.is_open());
256 srecfile.assign(makeTemporaryFilename());
257 cmdline = string(CMD_GNUOBJCOPY) + " -F srec " + filename + " " + srecfile;
258 VerboseMessage("[EXEC] %\n") << cmdline;
260 system(cmdline.c_str());
263 file.open(srecfile.c_str(), ios::in);
265 remove(srecfile.c_str());
269 /* 16進から10進への変換 (ポインタ移動, 長さ指定付き) */
270 unsigned int hextodec(const char * & src, size_t length) throw()
272 assert(length <= sizeof(unsigned int) * 2);
274 unsigned int result = 0;
277 while(length-- > 0) {
278 if(*src >= '0' && *src <= '9')
280 else if(*src >= 'A' && *src <='F')
281 digit = *src - 'A' + 10;
282 else if(*src >= 'a' && *src <='f')
283 digit = *src - 'a' + 10;
288 result = (result << 4) | (digit & 0xf);
295 bool readGnuNmLine(fstream & file, FileContainer::address_t & address, string & attribute, string & symbolname) throw()
297 assert(file.is_open());
301 string::size_type pos1;
302 string::size_type pos2;
306 if(!attribute.empty())
308 if(!symbolname.empty())
311 //次の行を取得 (空行, 未定義シンボルは読み飛ばす)
316 getline(file, src, '\n');
317 } while(src.empty() || src.at(0) == ' ');
320 pos1 = src.find_first_of(' ');
321 addr = src.substr(0, pos1);
323 pos2 = src.find_first_of(' ', pos1 + 1);
324 attribute = src.substr(pos1 + 1, pos2 - pos1 - 1);
325 symbolname = src.substr(pos2 + 1);
327 //アドレスのパース (注 : なんでこんなちまちまやってるかというと、アドレスが32bitを超えるターゲットがいるから)
328 while(!addr.empty()) {
329 size_t length = addr.size();
330 const char * src = addr.c_str();
331 if(length > sizeof(unsigned int) * 2)
332 length = sizeof(unsigned int) * 2;
333 address = (address << (length * 2)) | (hextodec(src, length));
334 addr.erase(0, length);
341 void FileContainerBinutilsImpl::loadSymbols(fstream & file) throw(Exception)
343 assert(file.is_open());
349 while(readGnuNmLine(file, address, attribute, symbolname)) {
350 symbol_table.insert(map<string, address_t>::value_type(symbolname, address));
353 VerboseMessage("% symbols loaded\n") << symbol_table.size() << &throwException;
358 /* contentsに1バイト書き込み */
359 void FileContainerBinutilsImpl::writeByte(address_t address, unsigned int value) throw(Exception)
361 address_t & base = last_address;
362 char * & page = last_page;
364 /* キャッシュもどきが使えないなら、ページを探す */
365 if(MAKE_BASEADDRESS(address) != last_address || last_page == 0) {
366 map<address_t, char *>::iterator scope;
368 base = MAKE_BASEADDRESS(address);
369 scope = contents.find(base);
370 if(scope == contents.end()) {
371 page = new(nothrow) char [SIZE_LOADPAGE];
373 ExceptionMessage("Not enough memory available to store the contents","空きメモリ不足のため、データの格納に失敗しました").throwException();
376 contents.insert(map<address_t,char*>::value_type(base, page));
379 page = scope->second;
382 *(page + (address - base)) = static_cast<char>(value & 0xff);
386 void trimString(string & src) throw()
388 string::size_type pos;
390 pos = src.find_last_not_of(" \t\r\n");
391 if(pos != string::npos && pos != src.size())
395 /* モトローラSレコードを一行読み込む */
397 The general format of an S-record follows:
398 +-------------------//------------------//-----------------------+
399 | type | count | address | data | checksum |
400 +-------------------//------------------//-----------------------+
402 bool readRecord(fstream & file, string & dest) throw(Exception)
411 //getlineがReadFileを呼んでブロックするので、確実にEOFを反応させるためにこうする
416 file.putback(static_cast<char>(ch));
418 } while(dest.empty());
424 if(dest[0] != 'S') //行頭が'S'で始まらない
425 ExceptionMessage("The file is not a Motorola S-Record file.","モトローラSフォーマットで無い行が見つかりました") << throwException;
427 pos = dest.c_str() + 2;
428 count = hextodec(pos, 2);
429 if(dest.size() != (count + 2)*2)
430 ExceptionMessage("Illegal S-Record found (count unmatched).","不正なSレコードがあります (サイズ不一致)") << throwException;
433 for(i = 0; i < count; ++ i)
434 sum += hextodec(pos, 2);
436 if((sum & 0xff) != 0xff)
437 ExceptionMessage("Illegal S-Record found (check-sum unmatched).","不正なSレコードがあります (チェックサム不一致)") << throwException;
443 FileContainer::address_t parseRecordAddress(const string & src, FileContainer::address_t base) throw()
445 const char * record = src.c_str();
446 FileContainer::address_t result = 0;
449 switch(*(record - 3)) {
451 result = hextodec(record, 4);
454 result = hextodec(record, 6);
457 result = hextodec(record, 8);
469 /* データ部分だけを残してチョップ */
470 void chopRecord(string & src) throw()
472 string::size_type start;
475 case '1': start = 4 + 4; break;
476 case '2': start = 4 + 6; break;
477 case '3': start = 4 + 8; break;
478 default: start = 4; break;
481 //先頭4バイト + アドレス部 + 最後のサムを取り除く
482 src = src.substr(start, src.size() - start - 2);
486 void FileContainerBinutilsImpl::loadDataContents(fstream & file) throw(Exception)
488 assert(file.is_open());
494 while(readRecord(file, line)) {
496 address = parseRecordAddress(line, address);
501 const char * pos = line.c_str();
502 while(*pos != '\x0') {
503 unsigned int data = hextodec(pos, 2);
504 writeByte(address, data);
512 /* シンボルプレフィクスの自動判定 */
513 void FileContainerBinutilsImpl::searchSymbolPrefix(void) throw()
515 const char * candidate_list[] = {"", "_", NULL};
516 const char ** candidate;
518 for(candidate = candidate_list; *candidate != NULL; ++ candidate) {
519 map<string, address_t>::const_iterator scope;
522 symbol = string(*candidate) + MAGIC_SYMBOL;
523 scope = symbol_table.find(symbol);
525 if(scope != symbol_table.end())
529 if(*candidate != NULL)
530 symbol_prefix.assign(*candidate);
534 void FileContainerBinutilsImpl::searchByteOrder(void) throw()
544 address = getSymbolAddress(MAGIC_SYMBOL);
545 loadContents(buffer, address, 4);
547 if(value == MAGIC_NUMBER) {
548 byteorder = HOSTORDER;
551 buffer[0] ^= buffer[3], buffer[3] ^= buffer[0], buffer[0] ^= buffer[3]; // swap(buffer[0], buffer[3])
552 buffer[1] ^= buffer[2], buffer[2] ^= buffer[1], buffer[1] ^= buffer[2]; // swap(buffer[1], buffer[2])
554 if(value == MAGIC_NUMBER)
555 byteorder = HOSTORDER == LITTLE ? BIG : LITTLE;
563 /* モジュールのアタッチ -> シンボル読出し, データ格納 */
564 void FileContainerBinutilsImpl::attachModule(const string & filename) throw(Exception)
567 string symbol_filename;
568 string contents_filename;
570 splitFilename(filename, symbol_filename, contents_filename);
572 openTextFile(file, symbol_filename, interceptWithGnuNM);
575 openTextFile(file, contents_filename, interceptWithGnuObjcopy);
576 loadDataContents(file);
578 searchSymbolPrefix();
583 void FileContainerBinutilsImpl::loadContents(void * _dest, address_t address, size_t size) throw(Exception)
585 char * dest = static_cast<char *>(_dest);
588 map<address_t, char *>::const_iterator scope;
590 address_t base = MAKE_BASEADDRESS(address);
591 address_t offset = MAKE_OFFSETADDRESS(address);
592 size_t transfer_size = size;
594 if(transfer_size > SIZE_LOADPAGE - offset)
595 transfer_size = SIZE_LOADPAGE - offset;
597 scope = contents.find(base);
598 if(scope == contents.end())
599 ExceptionMessage("[Internel error] Memory read with unmapped address","[内部エラー] マップされてないアドレスを使ってメモリリードが行われました").throwException();
601 memcpy(dest, scope->second + offset, transfer_size);
603 dest += transfer_size;
604 size -= transfer_size;
609 FileContainer::address_t FileContainerBinutilsImpl::getSymbolAddress(const string & symbol) throw(Exception)
612 map<string, address_t>::const_iterator scope;
614 symbolname = symbol_prefix + symbol;
616 scope = symbol_table.find(symbolname);
617 if(scope == symbol_table.end())
618 ExceptionMessage("Unknown symbol '%'","不明なシンボル名 '%'") << symbol << throwException;
620 return scope->second;
624 string FileContainerBinutilsImpl::getArchitecture(void) throw()
626 if(byteorder == LITTLE)
627 return "Little endian target (with GNU/Binutils)";
629 return "Big endian target (with GNU/Binutils)";
634 //---------------------------------------------
637 #include "base/coverage_undefs.h"
640 fstream * interceptor_file;
641 string interceptor_filename;
642 void interceptor(fstream & file, const string & filename)
644 CHECKPOINT("interceptor");
645 interceptor_file = &file;
646 interceptor_filename = filename;
648 if(filename.compare("textfile") == 0) {
649 remove(filename.c_str());
650 file.open(filename.c_str(), ios::out);
654 file.open(filename.c_str(), ios::in|ios::binary);
656 else if(filename.compare("binaryfile") == 0) {
657 remove(filename.c_str());
658 file.open(filename.c_str(), ios::out|ios::binary);
662 file.open(filename.c_str(), ios::in|ios::binary);
667 TESTSUITE(main, FileContainerBinutilsImpl)
669 PREDECESSOR("TFileContainer");
671 SingletonBase::ContextChain chain;
672 chain.saveContext<RuntimeObjectTable>();
674 BEGIN_CASE("splitFilename","splitFilename") {
675 BEGIN_CASE("1","カンマの前後で切れる") {
676 string first, second;
678 splitFilename("a,b", first, second);
679 TEST_CASE("1","firstの中身は正しい", first.compare("a") == 0);
680 TEST_CASE("2","secondの中身は正しい", second.compare("b") == 0);
683 BEGIN_CASE("2","カンマの無い引数を与えると、両方に同じ中身が入る") {
684 string first, second;
686 splitFilename("abc", first, second);
687 TEST_CASE("1","firstの中身は正しい", first.compare("abc") == 0);
688 TEST_CASE("2","secondの中身は正しい", second.compare("abc") == 0);
691 BEGIN_CASE("3","空文字を与えると例外") {
693 string first, second;
694 try { splitFilename("", first, second); } catch(Exception &) { result = true; }
700 BEGIN_CASE("hasBinaryContents","hasBinaryContents") {
701 BEGIN_CASE("1","テキストファイルを食わせる") {
702 fstream file("test", ios::out);
703 file << "This is a sample text file.";
706 file.open("test",ios::in|ios::binary);
707 TEST_CASE("1","関数はfalseを返す", !hasBinaryContents(file));
708 TEST_CASE("2","fileはeofに達していない", !file.eof());
714 BEGIN_CASE("2","バイナリデータを食わせる") {
715 fstream file("test", ios::out|ios::binary);
716 file << "This is a sample text file.";
717 file.write("\x0\x1\x2\x3", 4);
720 file.open("test",ios::in|ios::binary);
721 TEST_CASE("1","関数はtrueを返す", hasBinaryContents(file));
722 TEST_CASE("2","fileはeofに達していない", !file.eof());
729 BEGIN_CASE("openTextFile","openTextFile") {
730 BEGIN_CASE("1","テキストファイルを指定する") {
731 TestSuite::clearCheckpoints();
732 fstream file("test", ios::out);
733 file << "This is a sample text file.";
737 try { openTextFile(file, "test", interceptor); } catch(Exception &) { result = false; }
739 TEST_CASE("1","例外は起きない", result);
740 TEST_CASE("2","ファイルが開かれている", file.is_open());
741 TEST_CASE("3","interceptorはコールされていない", !TestSuite::isReached("interceptor"));
744 getline(file, work, '\n');
745 TEST_CASE("4","読み出された内容が正しい", work.compare("This is a sample text file.") == 0);
751 BEGIN_CASE("2","バイナリファイルを指定する (interceptorはファイルを開かない)") {
752 TestSuite::clearCheckpoints();
753 fstream file("test", ios::out|ios::binary);
754 file.write("\x1", 1);
758 try { openTextFile(file, "test", interceptor); } catch(Exception &) { result = true; }
760 TEST_CASE("1","例外が起きる", result);
761 TEST_CASE("2","ファイルが開かれている", !file.is_open());
762 TEST_CASE("3","interceptorがコールされている", TestSuite::isReached("interceptor"));
763 TEST_CASE("4","interceptorの引数が正しい (file)", interceptor_file == &file);
764 TEST_CASE("5","interceptorの引数が正しい", interceptor_filename.compare("test") == 0);
770 BEGIN_CASE("3","存在しないファイルを指定する") {
771 TestSuite::clearCheckpoints();
774 try { openTextFile(file, "___unknown___", interceptor); } catch(Exception &) { result = true; }
776 TEST_CASE("1","例外が起きる", result);
777 TEST_CASE("2","ファイルが開かれていない", !file.is_open());
778 TEST_CASE("3","interceptorがコールされていない", !TestSuite::isReached("interceptor"));
781 BEGIN_CASE("4","interceptorがテキストファイルを生成する") {
782 TestSuite::clearCheckpoints();
783 fstream file("textfile", ios::out|ios::binary);
784 file.write("\x1", 1);
788 try { openTextFile(file, "textfile", interceptor); } catch(Exception &) { result = false; }
790 TEST_CASE("1","例外は起きない", result);
791 TEST_CASE("2","ファイルが開かれている", file.is_open());
792 TEST_CASE("3","interceptorがコールされている", TestSuite::isReached("interceptor"));
793 TEST_CASE("4","interceptorの引数が正しい (file)", interceptor_file == &file);
794 TEST_CASE("5","interceptorの引数が正しい", interceptor_filename.compare("textfile") == 0);
797 getline(file, work, '\n');
798 TEST_CASE("4","読み出された内容が正しい", work.compare("text") == 0);
804 BEGIN_CASE("5","interceptorがバイナリファイルを生成する") {
805 TestSuite::clearCheckpoints();
806 fstream file("binaryfile", ios::out|ios::binary);
807 file.write("\x1", 1);
811 try { openTextFile(file, "binaryfile", interceptor); } catch(Exception &) { result = true; }
813 TEST_CASE("1","例外は起きる", result);
814 TEST_CASE("2","ファイルが開かれていない", !file.is_open());
815 TEST_CASE("3","interceptorがコールされている", TestSuite::isReached("interceptor"));
816 TEST_CASE("4","interceptorの引数が正しい (file)", interceptor_file == &file);
817 TEST_CASE("5","interceptorの引数が正しい", interceptor_filename.compare("binaryfile") == 0);
820 remove("binaryfile");
824 BEGIN_CASE("hextodec","hextodec") {
825 const char * letter = "0123456789abcdEFg";
826 const char * work = letter;
828 TEST_CASE("1", "切り出された値が正しい", hextodec(work, 2) == 1);
829 TEST_CASE("2", "workが進んでいる", work == letter + 2);
830 TEST_CASE("3", "切り出された値が正しい", hextodec(work, 4) == 0x2345);
831 TEST_CASE("4", "workが進んでいる", work == letter + 6);
832 TEST_CASE("5", "切り出された値が正しい", hextodec(work, 8) == 0x6789abcd);
833 TEST_CASE("6", "workが進んでいる", work == letter + 14);
834 TEST_CASE("7", "切り出された値が正しい", hextodec(work, 8) == 0xef);
835 TEST_CASE("8", "workが'g'の位置でとまる", *work == 'g');
836 TEST_CASE("9", "切り出された値が正しい", hextodec(work, 8) == 0);
837 TEST_CASE("10", "workが'g'の位置でとまる", *work == 'g');
840 BEGIN_CASE("readGnuNmLine","readGnuNmLine") {
841 fstream file("test", ios::out);
842 file << "0804aab0 T _kernel_task_initialize\n0805d8a0 B _kernel_tcb_table\n\n0804e560 R _kernel_tinib_table\n U getpid@@GLIBC_2.0\n";
849 file.open("test", ios::in);
850 BEGIN_CASE("1","普通のエントリが読める") {
851 TEST_CASE("1","関数は成功する", readGnuNmLine(file, address, attribute, symbolname));
852 TEST_CASE("2","addressは正しい", address == 0x0804aab0);
853 TEST_CASE("3","attributeは正しい", attribute.compare("T") == 0);
854 TEST_CASE("4","symbolnameは正しい", symbolname.compare("_kernel_task_initialize") == 0);
857 BEGIN_CASE("2","普通のエントリが読める (2)") {
858 TEST_CASE("1","関数は成功する", readGnuNmLine(file, address, attribute, symbolname));
859 TEST_CASE("2","addressは正しい", address == 0x0805d8a0);
860 TEST_CASE("3","attributeは正しい", attribute.compare("B") == 0);
861 TEST_CASE("4","symbolnameは正しい", symbolname.compare("_kernel_tcb_table") == 0);
864 BEGIN_CASE("3","空行を読み飛ばして次が読める") {
865 TEST_CASE("1","関数は成功する", readGnuNmLine(file, address, attribute, symbolname));
866 TEST_CASE("2","addressは正しい", address == 0x0804e560);
867 TEST_CASE("3","attributeは正しい", attribute.compare("R") == 0);
868 TEST_CASE("4","symbolnameは正しい", symbolname.compare("_kernel_tinib_table") == 0);
871 BEGIN_CASE("4","アドレスの無いエントリは無視する") {
872 TEST_CASE("1","関数は失敗する", !readGnuNmLine(file, address, attribute, symbolname));
879 BEGIN_CASE("loadSymbols","loadSymbols") {
880 fstream file("test", ios::out);
881 file << "0804aab0 T _kernel_task_initialize\n0805d8a0 B _kernel_tcb_table\n\n0804e560 R _kernel_tinib_table\n U getpid@@GLIBC_2.0\n";
884 file.open("test",ios::in);
886 FileContainerBinutilsImpl fcbi;
887 fcbi.loadSymbols(file);
889 TEST_CASE("1","読み込まれたエントリの数が正しい", fcbi.symbol_table.size() == 3);
890 TEST_CASE("2","ファイルは閉じられている", !file.is_open());
895 BEGIN_CASE("writeByte","writeByte") {
896 FileContainerBinutilsImpl fcbi;
898 BEGIN_CASE("1","存在しないページへの書き込み") {
899 TEST_CASE("0", "[前提] contentsの要素数は0", fcbi.contents.size() == 0);
900 fcbi.writeByte(0x100, 0);
902 TEST_CASE("1","contentsの要素が増えている", fcbi.contents.size() == 1);
904 const char * scope = fcbi.contents.find(MAKE_BASEADDRESS(0x100))->second + MAKE_OFFSETADDRESS(0x100);
905 TEST_CASE("2","書き込まれている内容が正しい", *scope == 0);
908 BEGIN_CASE("2","存在するページへの書き込み (連続アクセス)") {
909 fcbi.writeByte(0x100, 0xff);
911 TEST_CASE("1","contentsの要素が増えていない", fcbi.contents.size() == 1);
913 const char * scope = fcbi.contents.find(MAKE_BASEADDRESS(0x100))->second + MAKE_OFFSETADDRESS(0x100);
914 TEST_CASE("2","書き込まれている内容が正しい", *scope == 0xff);
917 BEGIN_CASE("3","新しいページへの書き込み") {
918 fcbi.writeByte(0x10000000, 0xff);
920 TEST_CASE("1","contentsの要素が増えている", fcbi.contents.size() == 2);
922 const char * scope = fcbi.contents.find(MAKE_BASEADDRESS(0x10000000))->second + MAKE_OFFSETADDRESS(0x10000000);
923 TEST_CASE("2","書き込まれている内容が正しい", *scope == 0xff);
926 BEGIN_CASE("4","既存のページへのアクセス") {
927 fcbi.writeByte(0x100, 0x0);
929 TEST_CASE("1","contentsの要素が増えていない", fcbi.contents.size() == 2);
931 const char * scope = fcbi.contents.find(MAKE_BASEADDRESS(0x100))->second + MAKE_OFFSETADDRESS(0x100);
932 TEST_CASE("2","書き込まれている内容が正しい", *scope == 0x0);
936 BEGIN_CASE("readRecord","readRecord") {
937 fstream file("test",ios::out);
938 file << "S315080480F42F6C69622F6C642D6C696E75782E736F98\n\nS315080480F42F6C69622F6C642D6C696E75782E736F98\nS308080481042E320005\nDUMMY\nS31808048108040000001000000001000000474E550056\nS31008048108040000001000000001000000474E550056\n";
941 file.open("test",ios::in);
942 BEGIN_CASE("1","正常ケース") {
945 bool exception = false;
946 try { result = readRecord(file, work); } catch(Exception &) { exception = true; }
947 TEST_CASE("1","例外は起こらない", !exception);
948 TEST_CASE("2","関数はtrueを返す", result);
949 TEST_CASE("3","読み出された内容が正しい", work.compare("S315080480F42F6C69622F6C642D6C696E75782E736F98") == 0);
952 BEGIN_CASE("2","正常ケース (空行の読み飛ばし)") {
955 bool exception = false;
956 try { result = readRecord(file, work); } catch(Exception &) { exception = true; }
957 TEST_CASE("1","例外は起こらない", !exception);
958 TEST_CASE("2","関数はtrueを返す", result);
959 TEST_CASE("3","読み出された内容が正しい", work.compare("S315080480F42F6C69622F6C642D6C696E75782E736F98") == 0);
962 BEGIN_CASE("3","チェックサムが誤っているエントリ") {
965 bool exception = false;
966 try { result = readRecord(file, work); } catch(Exception &) { exception = true; }
967 TEST_CASE("1","例外をおこす", exception);
970 BEGIN_CASE("4","先頭がSで始まらないエントリ") {
973 bool exception = false;
974 try { result = readRecord(file, work); } catch(Exception &) { exception = true; }
975 TEST_CASE("1","例外をおこす", exception);
978 BEGIN_CASE("5","指定された長さよりも長いエントリ") {
981 bool exception = false;
982 try { result = readRecord(file, work); } catch(Exception &) { exception = true; }
983 TEST_CASE("1","例外をおこす", exception);
986 BEGIN_CASE("6","指定された長さよりも短いエントリ") {
989 bool exception = false;
990 try { result = readRecord(file, work); } catch(Exception &) { exception = true; }
991 TEST_CASE("1","例外をおこす", exception);
994 BEGIN_CASE("7","ファイル終端") {
997 bool exception = false;
998 try { result = readRecord(file, work); } catch(Exception &) { exception = true; }
999 TEST_CASE("1","例外をおこさない", !exception);
1000 TEST_CASE("2","関数はfalseを返す", !result);
1006 BEGIN_CASE("chopRecord","chopRecord") {
1007 BEGIN_CASE("1","S1レコード") {
1008 string src("S106080480F42F4A");
1011 TEST_CASE("1","値が正しい", src.compare("80F42F") == 0);
1014 BEGIN_CASE("2","S2レコード") {
1015 string src("S206080480F42F4A");
1018 TEST_CASE("1","値が正しい", src.compare("F42F") == 0);
1021 BEGIN_CASE("3","S3レコード") {
1022 string src("S306080480F42F4A");
1025 TEST_CASE("1","値が正しい", src.compare("2F") == 0);
1028 BEGIN_CASE("4","S4レコード") {
1029 string src("S406080480F42F4A");
1032 TEST_CASE("1","値が正しい", src.compare("080480F42F") == 0);
1035 BEGIN_CASE("5","S5レコード") {
1036 string src("S506080480F42F4A");
1039 TEST_CASE("1","値が正しい", src.compare("080480F42F") == 0);
1044 BEGIN_CASE("loadDataContents/loadContents","loadDataContents/loadContents") {
1045 fstream file("test", ios::out);
1046 file << "S30D000000000123456789ABCDEF32\nS509FEDCBA9876543210BE";
1049 BEGIN_CASE("1","正常ケース") {
1050 FileContainerBinutilsImpl fcbi;
1052 file.open("test",ios::in);
1053 bool exception = false;
1054 try { fcbi.loadDataContents(file); } catch(...) { exception = true; }
1056 TEST_CASE("1","例外は起こらない", !exception);
1057 TEST_CASE("2","データが確保されている", fcbi.contents.size() == 1);
1058 TEST_CASE("3","ファイルは閉じられている", !file.is_open());
1059 BEGIN_CASE("4","格納した値が正しく読める") {
1062 assert(sizeof(unsigned int) >= 4);
1065 fcbi.loadContents(&i, 0, 4);
1066 TEST_CASE("1","1-4バイト目", i == 0x67452301);
1067 fcbi.loadContents(&i, 4, 4);
1068 TEST_CASE("1","5-8バイト目", i == 0xefcdab89);
1069 fcbi.loadContents(&i, 8, 4);
1070 TEST_CASE("1","9-12バイト目", i == 0x98badcfe);
1071 fcbi.loadContents(&i,12, 4);
1072 TEST_CASE("1","13-16バイト目", i == 0x10325476);
1077 BEGIN_CASE("2","loadContentsで一度にページサイズを超える量を要求する") {
1078 FileContainerBinutilsImpl fcbi;
1081 for(i=0;i<SIZE_LOADPAGE*2;++i)
1082 fcbi.writeByte(i, i);
1084 unsigned char * buffer = new unsigned char [SIZE_LOADPAGE * 2];
1085 fcbi.loadContents(buffer, 0, SIZE_LOADPAGE * 2);
1087 for(i=0;i<SIZE_LOADPAGE*2;++i)
1088 if(*(buffer + i) != (i & 0xff))
1096 BEGIN_CASE("searchSymbolPrefix","searchSymbolPrefix") {
1098 BEGIN_CASE("1","プレフィクスがない") {
1099 FileContainerBinutilsImpl fcbi;
1100 fcbi.symbol_table.insert(pair<string, address_t>(MAGIC_SYMBOL, 0x100));
1102 fcbi.searchSymbolPrefix();
1103 if(!fcbi.symbol_prefix.empty())
1107 BEGIN_CASE("2","変数名に\"_\"がつくタイプ") {
1108 FileContainerBinutilsImpl fcbi;
1109 fcbi.symbol_table.insert(pair<string, address_t>("_" MAGIC_SYMBOL, 0x100));
1111 fcbi.searchSymbolPrefix();
1112 if(fcbi.symbol_prefix.compare("_") != 0)
1116 BEGIN_CASE("3","\"__\"には反応しない") {
1117 FileContainerBinutilsImpl fcbi;
1118 fcbi.symbol_table.insert(pair<string, address_t>("__" MAGIC_SYMBOL, 0x100));
1120 fcbi.searchSymbolPrefix();
1121 if(!fcbi.symbol_prefix.empty())
1125 BEGIN_CASE("4","発見できない場合、変更しない") {
1126 FileContainerBinutilsImpl fcbi;
1127 fcbi.symbol_prefix.assign("test");
1129 fcbi.searchSymbolPrefix();
1130 if(fcbi.symbol_prefix.compare("test") != 0)
1135 BEGIN_CASE("searchByteOrder","searchByteOrder") {
1136 BEGIN_CASE("1","ホストと同じエンディアン") {
1137 FileContainerBinutilsImpl fcbi;
1138 unsigned int value = MAGIC_NUMBER;
1139 fcbi.symbol_table.insert(pair<string, address_t>(MAGIC_SYMBOL, 0x100));
1141 for(int i=0;i<4;i++)
1142 fcbi.writeByte(0x100 + i, *((char *)&value + i));
1144 fcbi.byteorder = UNKNOWN;
1145 fcbi.searchByteOrder();
1147 if(fcbi.byteorder != HOSTORDER)
1151 BEGIN_CASE("2","ホストと違うエンディアン") {
1152 FileContainerBinutilsImpl fcbi;
1153 unsigned int value = MAGIC_NUMBER;
1154 fcbi.symbol_table.insert(pair<string, address_t>(MAGIC_SYMBOL, 0x100));
1156 for(int i=0;i<4;i++)
1157 fcbi.writeByte(0x100 + i, *((char *)&value + (3 - i)));
1159 fcbi.byteorder = UNKNOWN;
1160 fcbi.searchByteOrder();
1162 if(fcbi.byteorder == HOSTORDER)
1166 BEGIN_CASE("3","シンボルが無い") {
1167 FileContainerBinutilsImpl fcbi;
1168 unsigned int value = MAGIC_NUMBER;
1170 for(int i=0;i<4;i++)
1171 fcbi.writeByte(0x100 + i, *((char *)&value + (3 - i)));
1173 fcbi.byteorder = UNKNOWN;
1174 fcbi.searchByteOrder();
1176 if(fcbi.byteorder != UNKNOWN)
1180 BEGIN_CASE("4","データが無い") {
1181 FileContainerBinutilsImpl fcbi;
1182 unsigned int value = MAGIC_NUMBER;
1183 fcbi.symbol_table.insert(pair<string, address_t>(MAGIC_SYMBOL, 0x100));
1185 fcbi.byteorder = UNKNOWN;
1186 fcbi.searchByteOrder();
1188 if(fcbi.byteorder != UNKNOWN)
1193 chain.restoreContext();
1196 #endif /* TESTSUITE */
1198 #endif /* FILECONTAINER_BINUTILS || TESTSUITE */