//////////////////////////////////////////////////////////////////////////////// // // メモリ管理モジュール // @copyright 2003 - 2023 Nomura Kei // #include <stdio.h> #include <stdbool.h> #include <errno.h> #include <string.h> #include <threads.h> // 常に本来の malloc, free を利用するため、KC_MEMORY_ENABLED を無効化する。 #ifdef KC_MEMORY_ENABLED #undef KC_MEMORY_ENABLED #endif // KC_MEMORY_DUMP_LEAK が未定義の場合 0:無効 を定義する。 #ifndef KC_MEMORY_DUMP_LEAK #define KC_MEMORY_DUMP_LEAK (0) #endif #include <kc_memory.h> //////////////////////////////////////////////////////////////////////////////// // // 定数定義 // /** パディング */ #define KC_MEMORY_PADDING (sizeof(void*) * 2) //////////////////////////////////////////////////////////////////////////////// // // 内部変数 // static KcMemoryHandler kc_memory_ahandler = NULL; //<! メモリ確保時に呼び出されるハンドラ static KcMemoryHandler kc_memory_fhandler = NULL; //<! メモリ解放時に呼び出されるハンドラ static KcMemoryHandler kc_memory_ehandler = NULL; //<! メモリ確保/解放エラー発生時に呼び出されるハンドラ static KcMemoryEntry kc_memory_head; //<! 管理メモリの先頭 static KcMemoryEntry kc_memory_tail; //<! 管理メモリの末尾 static KcMemoryEntry kc_memory_error; //<! 一時エラー出力用 static mtx_t kc_memory_mutex; //<! 同期実行のための mutex //////////////////////////////////////////////////////////////////////////////// // // 内部関数 プロトタイプ宣言 // // ============================================================================= // ユーティリティで利用されるハンドラ関数 static bool kc_memory_entries_handler(KcMemoryEntry* entry, const char* msg); static bool kc_memory_freeif_handler(KcMemoryEntry* entry, const char* msg); static bool kc_memory_dump_entry(KcMemoryEntry* entry, const char* msg); // ============================================================================= // メモリ確保/解放 static void* kc_memory_allocate(size_t size, KcMemoryMark mark, const char* file, const char* func, int line); static void* kc_memory_reallocate(void* ptr, size_t size, KcMemoryMark mark, const char* file, const char* func, int line); static void* kc_memory_reallocate_managed_ptr(void* ptr, size_t size, KcMemoryMark mark, const char* file, const char* func, int line); static void* kc_memory_reallocate_unmanaged_ptr(void* ptr, size_t size, KcMemoryMark mark, const char* file, const char* func, int line); static void* kc_memory_reallocate_invalid_ptr(void* ptr, size_t size, KcMemoryMark mark, const char* file, const char* func, int line); static void kc_memory_deallocate(void* ptr); static void kc_memory_deallocate_entry(KcMemoryEntry* entry); // ============================================================================= // メモリエントリ管理 static void kc_memory_init_entry(void); static void kc_memory_set_entry(KcMemoryEntry* entry, size_t size, KcMemoryMark mark, const char* file, const char* func, int line); static void kc_memory_add_entry(KcMemoryEntry* entry); static bool kc_memory_add_entry_handler(KcMemoryEntry* entry, const char* msg); static void kc_memory_remove_entry(KcMemoryEntry* entry); static bool kc_memory_remove_entry_handler(KcMemoryEntry* entry, const char* msg); // ============================================================================= // ハンドラ実行 static void kc_memory_execute_ahandler(KcMemoryEntry* entry, const char* msg); static void kc_memory_execute_fhandler(KcMemoryEntry* entry, const char* msg); static void kc_memory_execute_ehandler(KcMemoryEntry* entry, const char* msg); // ============================================================================ // 同期実行 static bool kc_memory_mutex_init(void); static bool kc_memory_locked_execute(KcMemoryHandler handler, KcMemoryEntry* entry, const char* msg); // ============================================================================ // データダンプ static const char* kc_memory_strmark(int mark); static void kc_memory_dump_data_ascii(KcMemoryEntry* entry, int dump_size); static void kc_memory_dump_data(KcMemoryEntry* entry, int dump_size); //////////////////////////////////////////////////////////////////////////////// // // 公開関数群 // /** * メモリ確保/解放/エラー発生時に呼び出されるハンドラ関数a登録します。 * * @param ahandler メモリ確保時に呼び出されるハンドラ * @param fhandler メモリ解放時に呼び出されるハンドラ * @param ehandler メモリ確保/解放エラー発生時に呼び出されるハンドラ */ void kc_memory_set_handlers(KcMemoryHandler ahandler, KcMemoryHandler fhandler, KcMemoryHandler ehandler) { kc_memory_ahandler = ahandler; kc_memory_fhandler = fhandler; kc_memory_ehandler = ehandler; } /** * 指定されたサイズのメモリを確保します。 * * @param size 確保するメモリサイズ * @param file メモリ確保ファイル名 * @param func メモリ確保関数名 * @param line メモリ確保行番号 * @return 確保したメモリへのポインタ */ void* kc_memory_malloc(size_t size, const char* file, const char* func, int line) { void* ptr = kc_memory_allocate(size, KC_MEMORY_ALLOCATED, file, func, line); return ptr; } /** * 指定されたサイズ要素が nmemb 個からなるメモリを確保します。 * * @param nmemb 確保する要素数 * @param size 1要素のメモリサイズ * @param file メモリ確保ファイル名 * @param func メモリ確保関数名 * @param line メモリ確保行番号 * @return 確保したメモリへのポインタ */ void* kc_memory_calloc (size_t nmemb, size_t size, const char* file, const char* func, int line) { size_t n = nmemb * size; void* ptr = kc_memory_allocate(n, KC_MEMORY_ALLOCATED, file, func, line); if (ptr != NULL) { memset(ptr, 0x00, n); } return ptr; } /** * ポインタが示すメモリブロックのサイズを size バイトに変更します。 * * @param ptr ポインタ * @param size 変更後のメモリサイズ * @param file メモリ確保ファイル名 * @param func メモリ確保関数名 * @param line メモリ確保行番号 * @return 確保したメモリへのポインタ */ void* kc_memory_realloc(void* ptr, size_t size, const char* file, const char* func, int line) { void* nptr = kc_memory_reallocate(ptr, size, KC_MEMORY_ALLOCATED, file, func, line); return nptr; } /** * 指定されたメモリを解放します。 * * @param ptr 解放するメモリへのポインタ */ void kc_memory_free(void* ptr) { kc_memory_deallocate(ptr); } // entries /** * 指定された handler に現在管理しているメモリエントリが順次渡されます。 * handler の中では、メモリエントリの情報を操作しないでください。 * * @param handler ハンドラ * @return true/false (処理成功/処理失敗[ロック獲得失敗]) */ bool kc_memory_entries(KcMemoryHandler handler) { kc_memory_init_entry(); // KcMemoryEntry のデータに handler を設定 size_t size = sizeof(KcMemoryHandler); KcMemoryEntry* entry = (KcMemoryEntry*) malloc(size + sizeof(KcMemoryEntry) + KC_MEMORY_PADDING); entry->data = handler; bool is_executed = kc_memory_locked_execute(kc_memory_entries_handler, entry, NULL); return is_executed; } /** * kc_memory_entries で使用されるハンドラ。 * * @param entry エントリ(使用しない) * @param msg メッセージ(使用しない) * @return true(固定) */ static bool kc_memory_entries_handler(KcMemoryEntry* entry, const char* msg) { KcMemoryHandler handler = (KcMemoryHandler) entry->data; KcMemoryEntry* next_entry = kc_memory_head._next; while (next_entry != &kc_memory_tail) { handler(next_entry, msg); next_entry = next_entry->_next; } return true; } // freeif /** * 指定された handler に現在管理しているメモリエントリが順次渡されます。 * handler にて、true を返したメモリが解放されます。 * * @param handler ハンドラ * @return true/false (処理成功/処理失敗[ロック獲得失敗]) */ bool kc_memory_freeif(KcMemoryHandler handler) { kc_memory_init_entry(); // KcMemoryEntry のデータに handler を設定 size_t size = sizeof(KcMemoryHandler); KcMemoryEntry* entry = (KcMemoryEntry*) malloc(size + sizeof(KcMemoryEntry) + KC_MEMORY_PADDING); entry->data = handler; bool is_executed = kc_memory_locked_execute(kc_memory_freeif_handler, entry, NULL); return is_executed; } /** * kc_memory_freeif で使用されるハンドラ。 * * @param entry エントリ(使用しない) * @param msg メッセージ(使用しない) * @return true(固定) */ static bool kc_memory_freeif_handler(KcMemoryEntry* entry, const char* msg) { KcMemoryHandler handler = (KcMemoryHandler) entry->data; KcMemoryEntry* next_entry = kc_memory_head._next; while (next_entry != &kc_memory_tail) { bool exec_free = handler(next_entry, msg); next_entry = next_entry->_next; if (exec_free) { // メモリ解放 kc_memory_free(next_entry->_prev->data); } } return true; } /** * 現在管理しているメモリ情報をダンプします。 */ void kc_memory_dump(void) { (void) kc_memory_entries(kc_memory_dump_entry); } /** * 指定されたメモリエントリの情報をダンプ出力します。 * * @param entry 出力するエントリ * @param msg メッセージ * @return true(固定) */ static bool kc_memory_dump_entry(KcMemoryEntry* entry, const char* msg) { UNUSED_VARIABLE(msg); printf("%-15s:%05d:%-15s (%5d) %s ", entry->file, entry->line, entry->func, entry->size, kc_memory_strmark(entry->_mark)); // dump kc_memory_dump_data(entry, KC_MEMORY_DUMP_SIZE); // ascii printf(" | "); kc_memory_dump_data_ascii(entry, KC_MEMORY_DUMP_SIZE); printf("\n"); return true; } //////////////////////////////////////////////////////////////////////////////// // // 内部関数群 // // ============================================================================= // メモリ確保解放 // ============================================================================= /** * 指定されたサイズのメモリを確保します。 * * @param size 確保するメモリサイズ * @param mark メモリ確保情報を示すマーク * @param file メモリ確保ファイル名 * @param func メモリ確保関数名 * @param line メモリ確保行番号 * @return 確保したメモリへのポインタ */ static void* kc_memory_allocate(size_t size, KcMemoryMark mark, const char* file, const char* func, int line) { KcMemoryEntry* entry = (KcMemoryEntry*) malloc(size + sizeof(KcMemoryEntry) + KC_MEMORY_PADDING); if (entry == NULL) { // メモリ確保失敗 kc_memory_set_entry(&kc_memory_error, size, mark, file, func, line); kc_memory_ehandler(&kc_memory_error, "kc memory : can't allocate"); return NULL; } kc_memory_set_entry(entry, size, mark, file, func, line); kc_memory_add_entry(entry); return (entry->data); } /** * 指定されたポインタがさすメモリサイズを変更します。 * ポインタ ptr が NULL の場合、kc_memory_allocate を呼び出します。 * * @param ptr メモリサイズを変更するメモリへのポインタ * @param size 確保するメモリサイズ * @param mark メモリ確保情報を示すマーク * @param file メモリ確保ファイル名 * @param func メモリ確保関数名 * @param line メモリ確保行番号 * @return 確保したメモリへのポインタ */ static void* kc_memory_reallocate(void* ptr, size_t size, KcMemoryMark mark, const char* file, const char* func, int line) { if (ptr == NULL) { return kc_memory_allocate(size, mark, file, func, line); } KcMemoryEntry* old_entry = (KcMemoryEntry*) ptr; old_entry--; switch (old_entry->_mark) { case KC_MEMORY_ALLOCATED: // 管理されたメモリの realloc return kc_memory_reallocate_managed_ptr(ptr, size, mark, file, func, line); case KC_MEMORY_ALLOCATED_NEW: // 不正 (new で確保されたメモリへの realloc) return kc_memory_reallocate_invalid_ptr(ptr, size, mark, file, func, line); case KC_MEMORY_ALLOCATED_NEW_ARRAY: // 不正 (new[] で確保されたメモリへの realloc) return kc_memory_reallocate_invalid_ptr(ptr, size, mark, file, func, line); case KC_MEMORY_DELETED: // 削除済みメモリ => 通常の allocate と同様とする return kc_memory_allocate(size, mark, file, func, line); default: // 管理外メモリの realloc return kc_memory_reallocate_unmanaged_ptr(ptr, size, mark, file, func, line); } } /** * 管理されたメモリ領域に対する realloc を実施します。 * * @param ptr メモリサイズを変更するメモリへのポインタ (使用しない) * @param size 確保するメモリサイズ * @param mark メモリ確保情報を示すマーク * @param file メモリ確保ファイル名 * @param func メモリ確保関数名 * @param line メモリ確保行番号 * @return 確保したメモリへのポインタ */ static void* kc_memory_reallocate_managed_ptr( void* ptr, size_t size, KcMemoryMark mark, const char* file, const char* func, int line) { UNUSED_VARIABLE(ptr); KcMemoryEntry* old_entry = (KcMemoryEntry*) ptr; old_entry--; kc_memory_remove_entry(old_entry); KcMemoryEntry* entry = (KcMemoryEntry*) realloc(old_entry, size + sizeof(KcMemoryEntry) + KC_MEMORY_PADDING); if (entry != NULL) { // メモリ確保成功 // メモリ管理リストに加えてポインタを返す。 kc_memory_set_entry(entry, size, mark, file, func, line); kc_memory_add_entry(entry); return (entry->data); } else { // メモリ確保失敗 // エラーハンドラを実行し、NULL を返す。 kc_memory_set_entry(&kc_memory_error, size, mark, file, func, line); kc_memory_ehandler(&kc_memory_error, "kc memory : can't reallocate"); // 古いメモリ領域は残っているため、管理対象に戻す。 kc_memory_add_entry(old_entry); return NULL; } } /** * 管理外メモリ領域に対する realloc を実施します。 * * @param ptr メモリサイズを変更するメモリへのポインタ (使用しない) * @param size 確保するメモリサイズ * @param mark メモリ確保情報を示すマーク * @param file メモリ確保ファイル名 * @param func メモリ確保関数名 * @param line メモリ確保行番号 * @return 確保したメモリへのポインタ */ static void* kc_memory_reallocate_unmanaged_ptr( void* ptr, size_t size, KcMemoryMark mark, const char* file, const char* func, int line) { // |<-- 新たな領域 ---------------->| // +------------+-------------------+ // | 元々の領域 | 追加分 + 管理領域 | // +------------+-------------------+ // ↓ // ↓memmove で元々の領域+追加分を、管理領域分を確保した先にコピー // ↓ // +----------+------------+--------+ // | 管理領域 | 元々の領域 | 追加分 | // +----------+------------+--------+ KcMemoryEntry* entry = (KcMemoryEntry*) realloc(ptr, size + sizeof(KcMemoryEntry) + KC_MEMORY_PADDING); if (entry != NULL) { // メモリ確保成功 // memmove で元々の領域+追加分を、管理領域分を確保した先にコピー // メモリ管理リストに加えてポインタを返す。 memmove((entry + 1), entry, size); kc_memory_set_entry(entry, size, mark, file, func, line); kc_memory_add_entry(entry); return (entry->data); } else { // メモリ確保失敗 // エラーハンドラを実行し、NULL を返す。 kc_memory_set_entry(&kc_memory_error, size, mark, file, func, line); kc_memory_ehandler(&kc_memory_error, "kc memory : can't reallocate"); return NULL; } } /** * 不正なメモリ領域に対する realloc のエラー処理を実施します。 * * @param ptr メモリサイズを変更するメモリへのポインタ (使用しない) * @param size 確保するメモリサイズ * @param mark メモリ確保情報を示すマーク * @param file メモリ確保ファイル名 * @param func メモリ確保関数名 * @param line メモリ確保行番号 * @return 確保したメモリへのポインタ */ static void* kc_memory_reallocate_invalid_ptr( void* ptr, size_t size, KcMemoryMark mark, const char* file, const char* func, int line) { UNUSED_VARIABLE(ptr); errno = EINVAL; kc_memory_set_entry(&kc_memory_error, size, mark, file, func, line); kc_memory_ehandler(&kc_memory_error, "kc memory : can't reallocate (invalid pointer)"); return NULL; } /** * 指定されたポインタの指すメモリ領域を解放します。 * NULL が指定された場合なにもしません。 * 管理されたメモリの場合、管理領域を合わせて解放します。 * 管理外メモリの場合、free を実行します。 * * @param ptr 解放するメモリへのポインタ */ static void kc_memory_deallocate(void* ptr) { if (ptr == NULL) { // NULL ポインタに対してはなにもしない return; } KcMemoryEntry* entry = (KcMemoryEntry*) ptr; entry--; switch (entry->_mark) { case KC_MEMORY_ALLOCATED: // 管理メモリ kc_memory_deallocate_entry(entry); break; case KC_MEMORY_ALLOCATED_NEW: // new により確保されたメモリ kc_memory_deallocate_entry(entry); perror("kc memory : warning : please use delete"); kc_memory_execute_ehandler(entry, "warning : please use delete"); break; case KC_MEMORY_ALLOCATED_NEW_ARRAY: // new[] により確保されたメモリ kc_memory_deallocate_entry(entry); perror("kc memory : warning : please use delete[]"); kc_memory_execute_ehandler(entry, "warning : please use delete[]"); break; case KC_MEMORY_DELETED: // 削除済みメモリ // Nothing to do. break; default: free(ptr); break; } } /** * 指定されたメモリ管理およびデータ領域を解放します。 * * @param entry 解放するメモリ管理領域へのポインタ */ static void kc_memory_deallocate_entry(KcMemoryEntry* entry) { (void) kc_memory_remove_entry(entry); entry->_mark = KC_MEMORY_DELETED; entry->size = 0; free(entry); } // ============================================================================= // メモリエントリ管理 // ============================================================================= /** * メモリ管理エントリ全体を初期化します。 */ static void kc_memory_init_entry(void) { static bool kc_memory_entry_initialized = false; if (!kc_memory_entry_initialized) { // メモリ管理エントリ初期化 kc_memory_set_entry(&kc_memory_head , 0, KC_MEMORY_DELETED, NULL, NULL, 0); kc_memory_set_entry(&kc_memory_tail , 0, KC_MEMORY_DELETED, NULL, NULL, 0); kc_memory_set_entry(&kc_memory_error, 0, KC_MEMORY_DELETED, NULL, NULL, 0); kc_memory_head._prev = kc_memory_head._next = &kc_memory_tail; kc_memory_tail._prev = kc_memory_tail._next = &kc_memory_head; kc_memory_entry_initialized = true; } } /** * 指定された entry を指定された各パラメータで初期化します。 * * @param entry 初期化するエントリ * @param size 確保するメモリサイズ * @param mark メモリ確保情報を示すマーク * @param file メモリ確保ファイル名 * @param func メモリ確保関数名 * @param line メモリ確保行番号 */ static void kc_memory_set_entry(KcMemoryEntry* entry, size_t size, KcMemoryMark mark, const char* file, const char* func, int line) { entry->file = file; entry->func = func; entry->line = line; entry->size = size; entry->_mark = mark; entry->data = (entry + 1); entry->_prev = NULL; entry->_next = NULL; } /** * 指定されたエントリをメモリ管理のリストに追加します。 * メモリがリストに追加された際、予め登録されたメモリ確保のハンドラが実行されます。 * * @param entry 追加するエントリ */ static void kc_memory_add_entry(KcMemoryEntry* entry) { kc_memory_init_entry(); bool is_executed = kc_memory_locked_execute(kc_memory_add_entry_handler, entry, NULL); if (is_executed) { kc_memory_execute_ahandler(entry, "allocate memory"); } else { perror("kc memory : can't add entry"); kc_memory_execute_ehandler(entry, "can't add entry"); } } /** * 指定されたエントリをメモリ管理のリストに追加します。 * * @param entry 追加するエントリ * @param msg メッセージ (使用されません) * @return true (固定) */ static bool kc_memory_add_entry_handler(KcMemoryEntry* entry, const char* msg) { UNUSED_VARIABLE(msg); // [tail] の一つ前に挿入する。 entry->_next = &kc_memory_tail; entry->_prev = kc_memory_tail._prev; kc_memory_tail._prev->_next = entry; kc_memory_tail._prev = entry; return true; } /** * 指定されたエントリをメモリ管理のリストから削除します。 * メモリがリストに追加された際、予め登録されたメモリ解放のハンドラが実行されます。 * * @param entry 削除するエントリ */ static void kc_memory_remove_entry(KcMemoryEntry* entry) { kc_memory_init_entry(); bool is_executed = kc_memory_locked_execute(kc_memory_remove_entry_handler, entry, NULL); if (is_executed) { kc_memory_execute_fhandler(entry, "free memory"); } else { perror("kc memory : can't remove entry"); kc_memory_execute_ehandler(entry, "can't remove entry"); } } /** * 指定されたエントリをメモリ管理のリストより削除します。 * * @param entry 削除するエントリ * @param msg メッセージ (使用されません) * @return true (固定) */ static bool kc_memory_remove_entry_handler(KcMemoryEntry* entry, const char* msg) { UNUSED_VARIABLE(msg); entry->_prev->_next = entry->_next; entry->_next->_prev = entry->_prev; return true; } // ============================================================================= // ハンドラ実行 // ============================================================================= /** * メモリ確保時のハンドラを実行します。 * ハンドラが未登録の場合何もしません。 * * @param entry 確保したメモリエントリ * @param msg メッセージ */ static void kc_memory_execute_ahandler(KcMemoryEntry* entry, const char* msg) { if (kc_memory_ahandler != NULL) { kc_memory_ahandler(entry, msg); } } /** * メモリ解放時のハンドラを実行します。 * ハンドラが未登録の場合何もしません。 * * @param entry 解放するメモリエントリ * @param msg メッセージ */ static void kc_memory_execute_fhandler(KcMemoryEntry* entry, const char* msg) { if (kc_memory_fhandler != NULL) { kc_memory_fhandler(entry, msg); } } /** * エラー発生時のハンドラを実行します。 * ハンドラが未登録の場合何もしません。 * * @param entry 関連するメモリエントリ * @param msg メッセージ */ static void kc_memory_execute_ehandler(KcMemoryEntry* entry, const char* msg) { if (kc_memory_ehandler != NULL) { kc_memory_ehandler(entry, msg); } } // ============================================================================ // 同期実行 // ============================================================================= /** * 同期化実現のための mutex を初期化します。 * * @return true/false (初期化成功/失敗) */ static bool kc_memory_mutex_init(void) { static bool kc_memory_mutex_initialized = false; if (!kc_memory_mutex_initialized) { // 未初期化の場合のみ実施する。 // kc_memory_mutex は、kc_memory_locked_execute 内でのみ利用する。 // mtx_recursive を使用し、同関数内での再帰呼び出し // (handler内でのkc_memory_locked_execute)を許容する。 int result = mtx_init(&kc_memory_mutex, mtx_plain | mtx_recursive); if (result == thrd_success) { kc_memory_mutex_initialized = true; } else { perror("kc memory : can't init mutex"); kc_memory_execute_ehandler(NULL, "can't init mutex"); } } return kc_memory_mutex_initialized; } /** * 指定された handler の実行を同期化します。 * mutex によるロック失敗により、handler を実行できなかった場合、false を返します。 * * @param handler 同期化して実行する関数 * @param entry handler へ渡される第一引数 (操作するメモリエントリ) * @param msg handler へ渡される第二引数 * @return true/false (handler を実行した/handler を実行できなかった) */ static bool kc_memory_locked_execute(KcMemoryHandler handler, KcMemoryEntry* entry, const char* msg) { (void) kc_memory_mutex_init(); int is_locked = mtx_lock(&kc_memory_mutex); if (is_locked == thrd_success) { // ハンドラの戻り値は Don't Care (void) handler(entry, msg); bool is_unlocked = mtx_unlock(&kc_memory_mutex); if (is_unlocked != thrd_success) { perror("memory : can't unlock"); kc_memory_execute_ehandler(NULL, "can't unlock"); } // アンロックに失敗しても handler 自体は実行しているため true を返す。 return true; } return false; } // ============================================================================ // データダンプ // ============================================================================= /** * 指定されたバイトを ASCII 文字に変換します。 * * @param c バイト */ #define KC_MEMORY_TO_ASCII(c) (((0x20 <= c) && (c < 0x7F)) ? c : '.') /** * 指定された確保メモリ状態(mark)に対応する文字列表現を返します。 * * @param mark 確保メモリ状態 * @return 確保メモリ状態に対応する文字列表現 */ static const char* kc_memory_strmark(int mark) { switch (mark) { case KC_MEMORY_DELETED: return "del "; case KC_MEMORY_ALLOCATED: return "alloc"; case KC_MEMORY_ALLOCATED_NEW: return "new "; case KC_MEMORY_ALLOCATED_NEW_ARRAY: return "new[]"; default: return "other"; } } /** * 指定されたメモリエントリのデータをダンプします。 * * @param entry エントリ * @param dump_size ダンプするサイズ(バイト数) */ static void kc_memory_dump_data(KcMemoryEntry* entry, int dump_size) { const unsigned char* data_ptr = (const unsigned char*) entry->data; int data_len = ((int) entry->size < dump_size) ? (int) entry->size : dump_size; int idx = 0; for (; idx < data_len; idx++) { printf("%02X ", data_ptr[idx]); } for (; idx < dump_size; idx++) { printf("-- "); } } /** * 指定されたメモリエントリのデータを ASCII 形式でダンプします。 * * @param entry エントリ * @param dump_size ダンプするサイズ(バイト数) */ static void kc_memory_dump_data_ascii(KcMemoryEntry* entry, int dump_size) { const unsigned char* data_ptr = (const unsigned char*) entry->data; int data_len = ((int) entry->size < dump_size) ? (int) entry->size : dump_size; int idx = 0; for (; idx < data_len; idx++) { printf("%c", KC_MEMORY_TO_ASCII(data_ptr[idx])); } for (; idx < dump_size; idx++) { printf(" "); } }