malloc hook: mbuddy

cinsk의 이미지

오늘은 상당히 재미있는 것을 배워봅시다. :lol:

GNU C 라이브러리의 malloc/realloc/free 함수는 다양한 디버깅 기능과 hook 기능을 제공합니다. 이번에 다룰 것은 hook 기능인데, 이 기능을 이용하면 다양한 malloc utility를 만들 수 있습니다. 아이디어는 간단합니다. 프로그램이 malloc을 부르게 되면 C 라이브러리 malloc이 사용자가 등록한 hook 함수가 있는지 조사하고 hook가 있을 경우, 그 hook 함수를 대신 부릅니다. 물론 이 hook 함수는 원래의 malloc을 호출할 수 있습니다.

void *(*__malloc_hook)(size_t SIZE, const void *CALLER);
void *(*__realloc_hook)(void *PTR, size_t SIZE, const void *CALLER);
void (*__free_hook) (void *PTR, const void *CALLER);

이 세 후크는 각각 malloc/realloc/free 함수와 비슷한 함수 포인터를 받습니다. 대신 각각 CALLER라는 인자를 추가로 받는다는 것만 다릅니다. 따라서 사용자는 다음과 같이 hook 함수를 만들 수 있습니다.

void *
malloc_hook(size_t SIZE, const void *CALLER)
{
}

void *
realloc_hook(void *PTR, size_t SIZE, const void *CALLER)
{
}

void *
free_hook(void *PTR, const void *CALLER)
{
}

그리고 각각의 함수를 앞에서 소개한 hook 변수에 등록해 줍니다. 이 때, 이 초기화 함수를 GNU C 라이브러리가 메모리 관련 함수를 호출하기 전 항상 불러주는 __malloc_initialize_hook 변수에 등록해주면 사용자가 따로 불러줄 필요가 없습니다:

void (*__malloc_initialize_hook)(void) = malloc_init;

static void
malloc_init(void)
{
  old_malloc_hook = __malloc_hook;
  old_realloc_hook = __realloc_hook;
  old_free_hook = __free_hook;

  __malloc_hook = mb_malloc;
  __realloc_hook = mb_realloc;
  __free_hook = mb_free;
}

위에서 old_로 시작하는 변수는 기존에 등록된 hook 함수들이 있을 경우, 필요하다면 다시 복귀시켜주기 위한 것입니다. 이 작업은 우리가 만든 malloc 함수인 mb_malloc()에서 진짜 malloc()을 부르기 위해 필요합니다. 즉 hook의 값을 원래대로 복원하는 기능과 제가 만든 함수로 등록하는 기능이 필요한데, 다음 매크로가 그 기능을 합니다:

#define RESTORE_HOOK()  do { \
                          __malloc_hook = old_malloc_hook; \
                          __realloc_hook = old_realloc_hook; \
                          __free_hook = old_free_hook; \
                        } while (0)

#define SAVE_HOOK()     do { \
                          __malloc_hook = mb_malloc; \
                          __realloc_hook = mb_realloc; \
                          __free_hook = mb_free; \
                        } while (0)

그러면 mb_malloc()은 쉽게 만들 수 있습니다.

static void *
mb_malloc(size_t size, const void *caller)
{
  void *p;
  RESTORE_HOOK();

  p = malloc(size);

  SAVE_HOOK();
  return p;
}

이런 식으로 mb_realloc()과 mb_free()를 만듭니다. 그리고 각 함수에서 (여기서 보이지는 않았지만) 호출된 시간과, 할당 또는 해제하는 메모리 크기 등을 로그 파일에 기록하도록 합니다. 제가 사용한 방식은, 먼저 millisecond 단위로 시간 기록, 전체 동적 할당 메모리 크기 기록, 그리고 현재 할당인지 해제인지 +-로 표시 기록, 그리고 메시지 기록입니다:

1142552430.940313:     29576:     -5663: realloc(0x804ccc8, 1753) from 0x8049aa9 => 0x804ccc8
1142552430.940339:     27597:     -1979: free(0x80515c0) from 0x8049885
1142552430.940372:     33625:      6028: malloc(6028) from 0x8049815 => 0x8055078

실제 mb_malloc()/mb_realloc()/mb_free()는 이보다 조금 더 복잡합니다. 원래 realloc()과 free()에서 현재 할당되어 있는 메모리의 크기를 알 수가 없으므로, malloc의 경우, 좀 더 큰 메모리를 할당해서 앞 공간에 할당한 크기, 시간 등을 기록하고, 그 뒤에 빈 공간을 리턴하도록 합니다. 그리고 realloc과 free에서 그 공간을 참고해서 원하는 정보를 얻을 수 있도록 합니다.

이 과정이 끝나면 단순히 링크하는 것만으로 메모리 할당 관련 자료를 얻을 수 있습니다. 지금까지 작업한 내용을 mbuddy.c로 만들고, 컴파일합니다:

$ cc -o mbuddy.o mbuddy.c

그리고 나중에 대상 프로그램에 함께 링크해 줍니다:

$ cc -o my_application a.c b.c c.c mbuddy.o

그리고 나서 이 프로그램을 실행하면, 관련 로그를 (e.g. "mb.out"에 기록한다고 가정) 얻을 수 있고, 이 것을 간단한 gnuplot script를 써서 그래프를 그리면 첨부와 같습니다:

전체 소스는
여기에서 볼 수 있습니다. 맨 위 버전에서 "(view)"를 누르면 소스가 보입니다.

Flash로 만든 gnuplot 그래프 메모도 있습니다.

Forums: 
cinsk의 이미지

파일 첨부가 빠졌네요..

--
C FAQ: http://www.eskimo.com/~scs/C-faq/top.html
Korean Ver: http://www.cinsk.org/cfaqs/

댓글 첨부 파일: 
첨부파일 크기
Image icon 6.77 KB
jenix의 이미지

와~ 좋은 강좌 보고갑니다 :)
감사감사!!

---------------------------------------------------------------------------
http://jinhyung.org -- 방문해 보세요!! Jenix 의 블로그입니다! :D

---------------------------------------------------------------------------
http://jinhyung.org -- 방문해 보세요!! Jenix 의 블로그입니다! :D

cinsk의 이미지

mbuddy로 만든 데이터 mb.out을 ploting하기 위한 스크립트는 여기에 있습니다. (마찬가지로 맨 위에 있는 "(view)"를 누르시면 볼 수 있습니다.)
--
C FAQ: http://www.eskimo.com/~scs/C-faq/top.html
Korean Ver: http://www.cinsk.org/cfaqs/

huricool의 이미지

앗. 고수이십니다.
정말 주옥같은 강좌네요.
감사합니다~~

무인도에 갇힌다면 당신이 가지고 갈 세가지는?

douner의 이미지

정말 계속 되는 좋은 강좌들 정말 고맙습니다! ;)

http://grafix3d.net/douner
인생, 쉬운 것만은 아니네..

인생, 쉬운 것만은 아니네..

사용법의 이미지

전체소스를 보니 필요한 헤더 파일도 있고 한데..
어떻게 사용하는건가요..???

댓글 달기

Filtered HTML

  • 텍스트에 BBCode 태그를 사용할 수 있습니다. URL은 자동으로 링크 됩니다.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>
  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.

BBCode

  • 텍스트에 BBCode 태그를 사용할 수 있습니다. URL은 자동으로 링크 됩니다.
  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param>
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.

Textile

  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • You can use Textile markup to format text.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>

Markdown

  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • Quick Tips:
    • Two or more spaces at a line's end = Line break
    • Double returns = Paragraph
    • *Single asterisks* or _single underscores_ = Emphasis
    • **Double** or __double__ = Strong
    • This is [a link](http://the.link.example.com "The optional title text")
    For complete details on the Markdown syntax, see the Markdown documentation and Markdown Extra documentation for tables, footnotes, and more.
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>

Plain text

  • HTML 태그를 사용할 수 없습니다.
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.
  • 줄과 단락은 자동으로 분리됩니다.
댓글 첨부 파일
이 댓글에 이미지나 파일을 업로드 합니다.
파일 크기는 8 MB보다 작아야 합니다.
허용할 파일 형식: txt pdf doc xls gif jpg jpeg mp3 png rar zip.
CAPTCHA
이것은 자동으로 스팸을 올리는 것을 막기 위해서 제공됩니다.