GCC 4.8之后的调试问题

gdb无法调试4.8或者更新版本gcc编译的程序,这个问题比较常见。原因很简单,参见 https://gcc.gnu.org/gcc-4.8/changes.html

DWARF4 is now the default when generating DWARF debug information. When -g is used on a platform that uses DWARF debugging information, GCC will now default to -gdwarf-4 -fno-debug-types-section.
GDB 7.5, Valgrind 3.8.0 and elfutils 0.154 debug information consumers support DWARF4 by default. Before GCC 4.8 the default version used was DWARF2. To make GCC 4.8 generate an older DWARF version use -g together with -gdwarf-2 or -gdwarf-3. The default for Darwin and VxWorks is still -gdwarf-2 -gstrict-dwarf.

这是因为,gcc 4.8缺省生成dwarf4版本的调试信息,旧版本的gdb无法识别。所以,要么升级gdb,要么通过选项-g -gdwarf-2或者-gdwarf-3来生成低版本的dwarf调试信息。

注:查看ELF文件的dwarf版本信息,可以使用如下命令

readelf -wi a.out | grep Version

为gcc源代码生成tags

LLVM的td文件使用的是tablegen语言,所以,它可以增加一个tablegen后端,来输出td文件的tags。

gcc的def文件使用的是宏定义,格式比较随意,很难通过类似llvm这样的方式,来为def文件生成tags。好在,大多def文件都是这样的一个格式:

DEF (ENUM, NAME, ...)

例如:

DEF_GOMP_BUILTIN (BUILT_IN_OMP_GET_NUM_THREADS, "omp_get_num_threads",
                  BT_FN_INT, ATTR_CONST_NOTHROW_LEAF_LIST)

通过如下的ctags命令,可以粗略的为这些def文件生成tags索引:

$ ctags --langdef=def --langmap=def:.def --regex-def="/^[ \t]*[a-zA-Z0-9_]+[ \t]*\([ \t]*([a-zA-Z0-9_]+)/\1/d,definition/" -R .

可以看到tags文件里生成了如下内容:

BUILT_IN_OMP_GET_NUM_THREADS    omp-builtins.def        /^DEF_GOMP_BUILTIN (BUILT_IN_OMP_GET_NUM_THREADS, "omp_get_num_threads",$/;"    d

目前gcc的代码虽然是c++实现,但是后缀名还是“.c”。所以,需要加上一个额外选项告诉ctags:

--langmap=c++:+.c

去掉testsuite目录:

--exclude=testsuite

过滤掉代码中一些宏的干扰:

-I GTY+ -I VEC+ -I DEF_VEC_P+

把build目录加进来,合起来的命令如下:

$ ctags --langdef=def --langmap=def:.def --regex-def="/^[ \t]*[a-zA-Z0-9_]+[ \t]*\([ \t]*([a-zA-Z0-9_]+)/\1/d,definition/" --langmap=c++:+.c --exclude=testsuite -I GTY+ -I VEC+ -I DEF_VEC_P+ -R . ~/build/build-gcc-trunk/gcc

使用gcc-6.1.0编译SPEC2006错误参考

一堆错误,还好逐个都解决了,其中:

400.perlbench,编译出错,一堆重定义,是inline的不同实现标准造成的,需要加上一个选项-std=gnu90。gnu90和c99的对extern函数的inline实现方式不同。
416.gamess 运行出错,需要加上一个选项-funconstrained-commons,参考https://gcc.gnu.org/ml/gcc-patches/2016-03/msg00465.html,gfortran文档中没有提到这个选项。
其它还有一些是strcat,memcp之类的函数,没有显式的include相应的头文件。还有的,是不在std namespace中,代码中竟然有std::。

为td文件生成tags

LLVM的TableGen可以用来为td文件生成tags,方便在vim中查看。该功能的svn信息如下:

------------------------------------------------------------------------
r177682 | silvas | 2013-03-22 07:40:38 +0800 (Fri, 22 Mar 2013) | 18 lines
Changed paths:
   M /llvm/trunk/utils/TableGen/CMakeLists.txt
   A /llvm/trunk/utils/TableGen/CTagsEmitter.cpp
   M /llvm/trunk/utils/TableGen/TableGen.cpp
   M /llvm/trunk/utils/TableGen/TableGenBackends.h
   A /llvm/trunk/utils/TableGen/tdtags

Add TableGen ctags(1) emitter and helper script.

To use this in conjunction with exuberant ctags to generate a single
combined tags file, run tblgen first and then
  $ ctags --append [...]

Since some identifiers have corresponding definitions in C++ code,
it can be useful (if using vim) to also use cscope, and
  :set cscopetagorder=1
so that
  :tag X
will preferentially select the tablegen symbol, while
  :cscope find g X
will always find the C++ symbol.

Patch by Kevin Schoedel!

(a couple small formatting changes courtesy of clang-format)
------------------------------------------------------------------------

使用方法如下:

xmj@xmj-OptiPlex-9020:~/project/llvm-trunk$ bash utils/TableGen/tdtags -q -x all

生成的tags文件:

xmj@xmj-OptiPlex-9020:~/project/llvm-trunk$ find ./ -name tags
./unittests/Option/tags
./lib/IR/tags
./lib/LibDriver/tags
./lib/Target/AVR/tags
./lib/Target/XCore/tags
./lib/Target/WebAssembly/tags
./lib/Target/BPF/tags
./lib/Target/Sparc/tags
./lib/Target/Mips/tags
./lib/Target/NVPTX/tags
./lib/Target/SystemZ/tags
./lib/Target/PowerPC/tags
./lib/Target/Lanai/tags
./lib/Target/MSP430/tags
./lib/Target/X86/tags
./lib/Target/AArch64/tags
./lib/Target/Hexagon/tags
./lib/Target/ARM/tags
./lib/Target/AMDGPU/tags
./test/TableGen/tags
./include/llvm/IR/tags
./include/llvm/Option/tags
./include/llvm/Target/tags
./include/llvm/CodeGen/tags
./tools/clang/tags
./tools/clang/lib/StaticAnalyzer/Checkers/tags
./tools/clang/test/TableGen/tags
./tools/clang/include/clang/AST/tags
./tools/clang/include/clang/Driver/tags
./tools/clang/include/clang/Basic/tags
./tools/clang/include/clang/StaticAnalyzer/Checkers/tags

回路搜索算法

Gcc和LLVM中的软流水优化,都是基于Swing Modulo Scheduling算法(翻译成摆动模调度?)实现的,参见[1]。其中,需要在依赖图(dependency graph)上搜索所有的简单回路(elementary circuits)。

LLVM中的软流水代码里,提到了“Identify all the elementary circuits in the dependence graph using Johnson’s circuit algorithm.”,这个算法源自论文[2]。

为了更好的理解回路搜索算法,我也基于论文[2]做个实现,放在了github上,参见[3]。

[1] Josep Llosa, Antonio Gonzalez, Eduard Ayguade, and Mateo Valero. Swing Modulo Scheduling: A Lifetime Sensitive Approach. In Pact96 , pages 80-87, October 1996 (Boston – Massachusetts – USA).
[2] Donald B. Johnson, Finding all the elementary circuits of a directed graph, SIAM Journal on Computing, 1975.
[3] https://github.com/hellogcc/circuit-finding-algorithm