readelfのシンボルテーブルをデマングルして読みやすくする (c++filtを使う)

c++での名前マングリングされたシンボル名を人が読むのはけっこうつらい。
社内勉強会で `c++filt` で簡単にデマングルできるよ、との情報があったので試してみる。

# c++filtのインストール
おそらくデフォルトでは入っていないため、debian系では以下のようにダウンロードします。

```bash
sudo apt-get install c++filt
```

# 検証対象のソース

```cpp:test.cpp
#include <iostream>
#include <boost/optional.hpp>

int main(int argc, char const* argv[])
{
    boost::optional<int> opt;
    return 0;
}
```

おもむろに `g++ test.cpp` でビルドする (=> a.out ができる)

# まずはそのままシンボルテーブルを見てみる(マングリングされている状態)

以下は `readelf -s -W a.out` の実行結果

```txt:デフォルトの状態
Symbol table '.dynsym' contains 10 entries:
   Num:    Value          Size Type    Bind   Vis      Ndx Name
     0: 0000000000000000     0 NOTYPE  LOCAL  DEFAULT  UND 
     1: 0000000000000000     0 NOTYPE  WEAK   DEFAULT  UND __gmon_start__
     2: 0000000000000000     0 NOTYPE  WEAK   DEFAULT  UND _Jv_RegisterClasses
     3: 0000000000000000     0 FUNC    GLOBAL DEFAULT  UND _ZNSt8ios_base4InitC1Ev@GLIBCXX_3.4 (2)
     4: 0000000000000000     0 FUNC    GLOBAL DEFAULT  UND __libc_start_main@GLIBC_2.2.5 (3)
     5: 0000000000000000     0 FUNC    GLOBAL DEFAULT  UND __cxa_atexit@GLIBC_2.2.5 (3)
     6: 0000000000000000     0 NOTYPE  WEAK   DEFAULT  UND _ITM_deregisterTMCloneTable
     7: 0000000000000000     0 NOTYPE  WEAK   DEFAULT  UND _ITM_registerTMCloneTable
     8: 0000000000000000     0 FUNC    GLOBAL DEFAULT  UND __stack_chk_fail@GLIBC_2.4 (4)
     9: 0000000000400630     0 FUNC    GLOBAL DEFAULT  UND _ZNSt8ios_base4InitD1Ev@GLIBCXX_3.4 (2)

Symbol table '.symtab' contains 88 entries:
   Num:    Value          Size Type    Bind   Vis      Ndx Name
     0: 0000000000000000     0 NOTYPE  LOCAL  DEFAULT  UND 
     1: 0000000000400238     0 SECTION LOCAL  DEFAULT    1 
     2: 0000000000400254     0 SECTION LOCAL  DEFAULT    2 
     3: 0000000000400274     0 SECTION LOCAL  DEFAULT    3 
     4: 0000000000400298     0 SECTION LOCAL  DEFAULT    4 
     5: 00000000004002c0     0 SECTION LOCAL  DEFAULT    5 
     6: 00000000004003b0     0 SECTION LOCAL  DEFAULT    6 
     7: 00000000004004a6     0 SECTION LOCAL  DEFAULT    7 
     8: 00000000004004c0     0 SECTION LOCAL  DEFAULT    8 
     9: 0000000000400510     0 SECTION LOCAL  DEFAULT    9 
    10: 0000000000400528     0 SECTION LOCAL  DEFAULT   10 
    11: 00000000004005b8     0 SECTION LOCAL  DEFAULT   11 
    12: 00000000004005e0     0 SECTION LOCAL  DEFAULT   12 
    13: 0000000000400650     0 SECTION LOCAL  DEFAULT   13 
    14: 00000000004009a4     0 SECTION LOCAL  DEFAULT   14 
    15: 00000000004009b0     0 SECTION LOCAL  DEFAULT   15 
    16: 00000000004009c0     0 SECTION LOCAL  DEFAULT   16 
    17: 0000000000400a60     0 SECTION LOCAL  DEFAULT   17 
    18: 0000000000600df8     0 SECTION LOCAL  DEFAULT   18 
    19: 0000000000600e08     0 SECTION LOCAL  DEFAULT   19 
    20: 0000000000600e10     0 SECTION LOCAL  DEFAULT   20 
    21: 0000000000600e18     0 SECTION LOCAL  DEFAULT   21 
    22: 0000000000600ff8     0 SECTION LOCAL  DEFAULT   22 
    23: 0000000000601000     0 SECTION LOCAL  DEFAULT   23 
    24: 0000000000601048     0 SECTION LOCAL  DEFAULT   24 
    25: 0000000000601058     0 SECTION LOCAL  DEFAULT   25 
    26: 0000000000000000     0 SECTION LOCAL  DEFAULT   26 
    27: 0000000000000000     0 FILE    LOCAL  DEFAULT  ABS crtstuff.c
    28: 0000000000600e10     0 OBJECT  LOCAL  DEFAULT   20 __JCR_LIST__
    29: 0000000000400680     0 FUNC    LOCAL  DEFAULT   13 deregister_tm_clones
    30: 00000000004006b0     0 FUNC    LOCAL  DEFAULT   13 register_tm_clones
    31: 00000000004006f0     0 FUNC    LOCAL  DEFAULT   13 __do_global_dtors_aux
    32: 0000000000601058     1 OBJECT  LOCAL  DEFAULT   25 completed.6972
    33: 0000000000600e08     0 OBJECT  LOCAL  DEFAULT   19 __do_global_dtors_aux_fini_array_entry
    34: 0000000000400710     0 FUNC    LOCAL  DEFAULT   13 frame_dummy
    35: 0000000000600df8     0 OBJECT  LOCAL  DEFAULT   18 __frame_dummy_init_array_entry
    36: 0000000000000000     0 FILE    LOCAL  DEFAULT  ABS test.cpp
    37: 0000000000601059     1 OBJECT  LOCAL  DEFAULT   25 _ZStL8__ioinit
    38: 0000000000400796    61 FUNC    LOCAL  DEFAULT   13 _Z41__static_initialization_and_destruction_0ii
    39: 00000000004009b8     8 OBJECT  LOCAL  DEFAULT   15 _ZN5boostL4noneE
    40: 00000000004007d3    21 FUNC    LOCAL  DEFAULT   13 _GLOBAL__sub_I_main
    41: 0000000000000000     0 FILE    LOCAL  DEFAULT  ABS crtstuff.c
    42: 0000000000400cf8     0 OBJECT  LOCAL  DEFAULT   17 __FRAME_END__
    43: 0000000000600e10     0 OBJECT  LOCAL  DEFAULT   20 __JCR_END__
    44: 0000000000000000     0 FILE    LOCAL  DEFAULT  ABS 
    45: 0000000000601000     0 OBJECT  LOCAL  DEFAULT   23 _GLOBAL_OFFSET_TABLE_
    46: 0000000000600e08     0 NOTYPE  LOCAL  DEFAULT   18 __init_array_end
    47: 0000000000600df8     0 NOTYPE  LOCAL  DEFAULT   18 __init_array_start
    48: 0000000000600e18     0 OBJECT  LOCAL  DEFAULT   21 _DYNAMIC
    49: 0000000000601048     0 NOTYPE  WEAK   DEFAULT   24 data_start
    50: 00000000004009a0     2 FUNC    GLOBAL DEFAULT   13 __libc_csu_fini
    51: 0000000000400650     0 FUNC    GLOBAL DEFAULT   13 _start
    52: 0000000000000000     0 NOTYPE  WEAK   DEFAULT  UND __gmon_start__
    53: 0000000000000000     0 NOTYPE  WEAK   DEFAULT  UND _Jv_RegisterClasses
    54: 00000000004009a4     0 FUNC    GLOBAL DEFAULT   14 _fini
    55: 0000000000000000     0 FUNC    GLOBAL DEFAULT  UND _ZNSt8ios_base4InitC1Ev@@GLIBCXX_3.4
    56: 0000000000000000     0 FUNC    GLOBAL DEFAULT  UND __libc_start_main@@GLIBC_2.2.5
    57: 00000000004007e8    26 FUNC    WEAK   DEFAULT   13 _ZN5boost8optionalIiEC2Ev
    58: 0000000000000000     0 FUNC    GLOBAL DEFAULT  UND __cxa_atexit@@GLIBC_2.2.5
    59: 000000000040091a    14 FUNC    WEAK   DEFAULT   13 _ZN5boost15optional_detail15aligned_storageIiE7addressEv
    60: 0000000000400802    26 FUNC    WEAK   DEFAULT   13 _ZN5boost8optionalIiED2Ev
    61: 0000000000400630     0 FUNC    GLOBAL DEFAULT  UND _ZNSt8ios_base4InitD1Ev@@GLIBCXX_3.4
    62: 0000000000000000     0 NOTYPE  WEAK   DEFAULT  UND _ITM_deregisterTMCloneTable
    63: 00000000004009b0     4 OBJECT  GLOBAL DEFAULT   15 _IO_stdin_used
    64: 00000000004008ac    53 FUNC    WEAK   DEFAULT   13 _ZN5boost15optional_detail13optional_baseIiE12get_ptr_implEv
    65: 0000000000400826    33 FUNC    WEAK   DEFAULT   13 _ZN5boost15optional_detail13optional_baseIiEC2Ev
    66: 0000000000400848    26 FUNC    WEAK   DEFAULT   13 _ZN5boost15optional_detail13optional_baseIiED1Ev
    67: 00000000004007e8    26 FUNC    WEAK   DEFAULT   13 _ZN5boost8optionalIiEC1Ev
    68: 0000000000000000     0 NOTYPE  WEAK   DEFAULT  UND _ITM_registerTMCloneTable
    69: 0000000000601048     0 NOTYPE  GLOBAL DEFAULT   24 __data_start
    70: 000000000040088a    33 FUNC    WEAK   DEFAULT   13 _ZN5boost15optional_detail13optional_baseIiE12destroy_implEN4mpl_5bool_ILb0EEE
    71: 000000000040081c    10 FUNC    WEAK   DEFAULT   13 _ZN5boost15optional_detail12optional_tagC1Ev
    72: 0000000000601058     0 OBJECT  GLOBAL HIDDEN    24 __TMC_END__
    73: 0000000000601050     0 OBJECT  GLOBAL HIDDEN    24 __dso_handle
    74: 0000000000400930   101 FUNC    GLOBAL DEFAULT   13 __libc_csu_init
    75: 00000000004008e2    38 FUNC    WEAK   DEFAULT   13 _ZN5boost15optional_detail13optional_baseIiE10get_objectEv
    76: 0000000000400908    18 FUNC    WEAK   DEFAULT   13 _ZN5boost15optional_detail13optional_baseIiE8cast_ptrEPiN4mpl_5bool_ILb0EEE
    77: 0000000000601058     0 NOTYPE  GLOBAL DEFAULT   25 __bss_start
    78: 0000000000400802    26 FUNC    WEAK   DEFAULT   13 _ZN5boost8optionalIiED1Ev
    79: 0000000000400848    26 FUNC    WEAK   DEFAULT   13 _ZN5boost15optional_detail13optional_baseIiED2Ev
    80: 0000000000000000     0 FUNC    GLOBAL DEFAULT  UND __stack_chk_fail@@GLIBC_2.4
    81: 0000000000400862    40 FUNC    WEAK   DEFAULT   13 _ZN5boost15optional_detail13optional_baseIiE7destroyEv
    82: 0000000000400826    33 FUNC    WEAK   DEFAULT   13 _ZN5boost15optional_detail13optional_baseIiEC1Ev
    83: 0000000000601060     0 NOTYPE  GLOBAL DEFAULT   25 _end
    84: 0000000000601058     0 NOTYPE  GLOBAL DEFAULT   24 _edata
    85: 000000000040081c    10 FUNC    WEAK   DEFAULT   13 _ZN5boost15optional_detail12optional_tagC2Ev
    86: 000000000040073d    89 FUNC    GLOBAL DEFAULT   13 main
    87: 00000000004005b8     0 FUNC    GLOBAL DEFAULT   11 _init
```

`_ZN5boost15optional_detail12optional_tagC2Ev` とか訳の分からない文字列になってますね・・・。

# `c++filt` を通す

以下は `readelf -s -W a.out | c++filt` の実行結果
※wide指定をしないと80文字で切れでデマングルできないため、必ず `-W` または `--wide` をつけること

```txt:c++filtを使う
Symbol table '.dynsym' contains 10 entries:
   Num:    Value          Size Type    Bind   Vis      Ndx Name
     0: 0000000000000000     0 NOTYPE  LOCAL  DEFAULT  UND 
     1: 0000000000000000     0 NOTYPE  WEAK   DEFAULT  UND __gmon_start__
     2: 0000000000000000     0 NOTYPE  WEAK   DEFAULT  UND _Jv_RegisterClasses
     3: 0000000000000000     0 FUNC    GLOBAL DEFAULT  UND std::ios_base::Init::Init()@GLIBCXX_3.4 (2)
     4: 0000000000000000     0 FUNC    GLOBAL DEFAULT  UND __libc_start_main@GLIBC_2.2.5 (3)
     5: 0000000000000000     0 FUNC    GLOBAL DEFAULT  UND __cxa_atexit@GLIBC_2.2.5 (3)
     6: 0000000000000000     0 NOTYPE  WEAK   DEFAULT  UND _ITM_deregisterTMCloneTable
     7: 0000000000000000     0 NOTYPE  WEAK   DEFAULT  UND _ITM_registerTMCloneTable
     8: 0000000000000000     0 FUNC    GLOBAL DEFAULT  UND __stack_chk_fail@GLIBC_2.4 (4)
     9: 0000000000400630     0 FUNC    GLOBAL DEFAULT  UND std::ios_base::Init::~Init()@GLIBCXX_3.4 (2)

Symbol table '.symtab' contains 88 entries:
   Num:    Value          Size Type    Bind   Vis      Ndx Name
     0: 0000000000000000     0 NOTYPE  LOCAL  DEFAULT  UND 
     1: 0000000000400238     0 SECTION LOCAL  DEFAULT    1 
     2: 0000000000400254     0 SECTION LOCAL  DEFAULT    2 
     3: 0000000000400274     0 SECTION LOCAL  DEFAULT    3 
     4: 0000000000400298     0 SECTION LOCAL  DEFAULT    4 
     5: 00000000004002c0     0 SECTION LOCAL  DEFAULT    5 
     6: 00000000004003b0     0 SECTION LOCAL  DEFAULT    6 
     7: 00000000004004a6     0 SECTION LOCAL  DEFAULT    7 
     8: 00000000004004c0     0 SECTION LOCAL  DEFAULT    8 
     9: 0000000000400510     0 SECTION LOCAL  DEFAULT    9 
    10: 0000000000400528     0 SECTION LOCAL  DEFAULT   10 
    11: 00000000004005b8     0 SECTION LOCAL  DEFAULT   11 
    12: 00000000004005e0     0 SECTION LOCAL  DEFAULT   12 
    13: 0000000000400650     0 SECTION LOCAL  DEFAULT   13 
    14: 00000000004009a4     0 SECTION LOCAL  DEFAULT   14 
    15: 00000000004009b0     0 SECTION LOCAL  DEFAULT   15 
    16: 00000000004009c0     0 SECTION LOCAL  DEFAULT   16 
    17: 0000000000400a60     0 SECTION LOCAL  DEFAULT   17 
    18: 0000000000600df8     0 SECTION LOCAL  DEFAULT   18 
    19: 0000000000600e08     0 SECTION LOCAL  DEFAULT   19 
    20: 0000000000600e10     0 SECTION LOCAL  DEFAULT   20 
    21: 0000000000600e18     0 SECTION LOCAL  DEFAULT   21 
    22: 0000000000600ff8     0 SECTION LOCAL  DEFAULT   22 
    23: 0000000000601000     0 SECTION LOCAL  DEFAULT   23 
    24: 0000000000601048     0 SECTION LOCAL  DEFAULT   24 
    25: 0000000000601058     0 SECTION LOCAL  DEFAULT   25 
    26: 0000000000000000     0 SECTION LOCAL  DEFAULT   26 
    27: 0000000000000000     0 FILE    LOCAL  DEFAULT  ABS crtstuff.c
    28: 0000000000600e10     0 OBJECT  LOCAL  DEFAULT   20 __JCR_LIST__
    29: 0000000000400680     0 FUNC    LOCAL  DEFAULT   13 deregister_tm_clones
    30: 00000000004006b0     0 FUNC    LOCAL  DEFAULT   13 register_tm_clones
    31: 00000000004006f0     0 FUNC    LOCAL  DEFAULT   13 __do_global_dtors_aux
    32: 0000000000601058     1 OBJECT  LOCAL  DEFAULT   25 completed.6972
    33: 0000000000600e08     0 OBJECT  LOCAL  DEFAULT   19 __do_global_dtors_aux_fini_array_entry
    34: 0000000000400710     0 FUNC    LOCAL  DEFAULT   13 frame_dummy
    35: 0000000000600df8     0 OBJECT  LOCAL  DEFAULT   18 __frame_dummy_init_array_entry
    36: 0000000000000000     0 FILE    LOCAL  DEFAULT  ABS test.cpp
    37: 0000000000601059     1 OBJECT  LOCAL  DEFAULT   25 std::__ioinit
    38: 0000000000400796    61 FUNC    LOCAL  DEFAULT   13 __static_initialization_and_destruction_0(int, int)
    39: 00000000004009b8     8 OBJECT  LOCAL  DEFAULT   15 boost::none
    40: 00000000004007d3    21 FUNC    LOCAL  DEFAULT   13 _GLOBAL__sub_I_main
    41: 0000000000000000     0 FILE    LOCAL  DEFAULT  ABS crtstuff.c
    42: 0000000000400cf8     0 OBJECT  LOCAL  DEFAULT   17 __FRAME_END__
    43: 0000000000600e10     0 OBJECT  LOCAL  DEFAULT   20 __JCR_END__
    44: 0000000000000000     0 FILE    LOCAL  DEFAULT  ABS 
    45: 0000000000601000     0 OBJECT  LOCAL  DEFAULT   23 _GLOBAL_OFFSET_TABLE_
    46: 0000000000600e08     0 NOTYPE  LOCAL  DEFAULT   18 __init_array_end
    47: 0000000000600df8     0 NOTYPE  LOCAL  DEFAULT   18 __init_array_start
    48: 0000000000600e18     0 OBJECT  LOCAL  DEFAULT   21 _DYNAMIC
    49: 0000000000601048     0 NOTYPE  WEAK   DEFAULT   24 data_start
    50: 00000000004009a0     2 FUNC    GLOBAL DEFAULT   13 __libc_csu_fini
    51: 0000000000400650     0 FUNC    GLOBAL DEFAULT   13 _start
    52: 0000000000000000     0 NOTYPE  WEAK   DEFAULT  UND __gmon_start__
    53: 0000000000000000     0 NOTYPE  WEAK   DEFAULT  UND _Jv_RegisterClasses
    54: 00000000004009a4     0 FUNC    GLOBAL DEFAULT   14 _fini
    55: 0000000000000000     0 FUNC    GLOBAL DEFAULT  UND std::ios_base::Init::Init()@@GLIBCXX_3.4
    56: 0000000000000000     0 FUNC    GLOBAL DEFAULT  UND __libc_start_main@@GLIBC_2.2.5
    57: 00000000004007e8    26 FUNC    WEAK   DEFAULT   13 boost::optional<int>::optional()
    58: 0000000000000000     0 FUNC    GLOBAL DEFAULT  UND __cxa_atexit@@GLIBC_2.2.5
    59: 000000000040091a    14 FUNC    WEAK   DEFAULT   13 boost::optional_detail::aligned_storage<int>::address()
    60: 0000000000400802    26 FUNC    WEAK   DEFAULT   13 boost::optional<int>::~optional()
    61: 0000000000400630     0 FUNC    GLOBAL DEFAULT  UND std::ios_base::Init::~Init()@@GLIBCXX_3.4
    62: 0000000000000000     0 NOTYPE  WEAK   DEFAULT  UND _ITM_deregisterTMCloneTable
    63: 00000000004009b0     4 OBJECT  GLOBAL DEFAULT   15 _IO_stdin_used
    64: 00000000004008ac    53 FUNC    WEAK   DEFAULT   13 boost::optional_detail::optional_base<int>::get_ptr_impl()
    65: 0000000000400826    33 FUNC    WEAK   DEFAULT   13 boost::optional_detail::optional_base<int>::optional_base()
    66: 0000000000400848    26 FUNC    WEAK   DEFAULT   13 boost::optional_detail::optional_base<int>::~optional_base()
    67: 00000000004007e8    26 FUNC    WEAK   DEFAULT   13 boost::optional<int>::optional()
    68: 0000000000000000     0 NOTYPE  WEAK   DEFAULT  UND _ITM_registerTMCloneTable
    69: 0000000000601048     0 NOTYPE  GLOBAL DEFAULT   24 __data_start
    70: 000000000040088a    33 FUNC    WEAK   DEFAULT   13 boost::optional_detail::optional_base<int>::destroy_impl(mpl_::bool_<false>)
    71: 000000000040081c    10 FUNC    WEAK   DEFAULT   13 boost::optional_detail::optional_tag::optional_tag()
    72: 0000000000601058     0 OBJECT  GLOBAL HIDDEN    24 __TMC_END__
    73: 0000000000601050     0 OBJECT  GLOBAL HIDDEN    24 __dso_handle
    74: 0000000000400930   101 FUNC    GLOBAL DEFAULT   13 __libc_csu_init
    75: 00000000004008e2    38 FUNC    WEAK   DEFAULT   13 boost::optional_detail::optional_base<int>::get_object()
    76: 0000000000400908    18 FUNC    WEAK   DEFAULT   13 boost::optional_detail::optional_base<int>::cast_ptr(int*, mpl_::bool_<false>)
    77: 0000000000601058     0 NOTYPE  GLOBAL DEFAULT   25 __bss_start
    78: 0000000000400802    26 FUNC    WEAK   DEFAULT   13 boost::optional<int>::~optional()
    79: 0000000000400848    26 FUNC    WEAK   DEFAULT   13 boost::optional_detail::optional_base<int>::~optional_base()
    80: 0000000000000000     0 FUNC    GLOBAL DEFAULT  UND __stack_chk_fail@@GLIBC_2.4
    81: 0000000000400862    40 FUNC    WEAK   DEFAULT   13 boost::optional_detail::optional_base<int>::destroy()
    82: 0000000000400826    33 FUNC    WEAK   DEFAULT   13 boost::optional_detail::optional_base<int>::optional_base()
    83: 0000000000601060     0 NOTYPE  GLOBAL DEFAULT   25 _end
    84: 0000000000601058     0 NOTYPE  GLOBAL DEFAULT   24 _edata
    85: 000000000040081c    10 FUNC    WEAK   DEFAULT   13 boost::optional_detail::optional_tag::optional_tag()
    86: 000000000040073d    89 FUNC    GLOBAL DEFAULT   13 main
    87: 00000000004005b8     0 FUNC    GLOBAL DEFAULT   11 _init
```

読める。

# 結論

c++filtすごい。

# 細かいところ
C++ の名前修飾に関しては標準化されておらず、どういうシンボル名になるのかはコンパイラ依存のようです。
ヘタすると同じコンパイラでもバージョンやプラットフォームごとにルールが違ったりするとのこと。
※今回使用したコンパイラは `g++ 4.8.2` になります。

[名前修飾 - Wikipedia](https://ja.wikipedia.org/wiki/%E5%90%8D%E5%89%8D%E4%BF%AE%E9%A3%BE)

```
$ c++filt --help
Usage: c++filt [options] [mangled names]
Options are:
  [-_|--strip-underscore]     Ignore first leading underscore
  [-n|--no-strip-underscore]  Do not ignore a leading underscore (default)
  [-p|--no-params]            Do not display function arguments
  [-i|--no-verbose]           Do not show implementation details (if any)
  [-t|--types]                Also attempt to demangle type encodings
  [-s|--format {none,auto,gnu,lucid,arm,hp,edg,gnu-v3,java,gnat}]
  [@<file>]                   Read extra options from <file>
  [-h|--help]                 Display this information
  [-v|--version]              Show the version information
Demangled names are displayed to stdout.
If a name cannot be demangled it is just echoed to stdout.
If no names are provided on the command line, stdin is read.
Report bugs to <http://www.sourceware.org/bugzilla/>.
```

c++filt が自動判別してくれるか不明ですが、いちおう `--format` オプションで明示的に種別を選べるようです。

# その他

nm の場合は c++filt を通してもいいけど、nm自体が`--demangle` オプションを持っているとのこと。

# 参考
[名前修飾 - Wikipedia](https://ja.wikipedia.org/wiki/%E5%90%8D%E5%89%8D%E4%BF%AE%E9%A3%BE)
[C++ のシンボルをデマングルする - bkブログ](http://0xcc.net/blog/archives/000095.html)