プロが教えるわが家の防犯対策術!

以前もここで質問したものです。皆様の解答をヒントに一歩進みました。

C言語のソースコードを扱っています。
デバッグのため(関数がどういう順番で呼び出されているかを知るため)、関数の先頭にprint文をつけようと思っています。
例えば、

int hoge(引数の並び)

関数の中身


なら

int hoge(引数の並び)

printf("hoge");
関数の中身

といった具合です。
関数が膨大なので、手作業で一つずつprintfを書くのは現実的ではありません。

ここで、
open(IN,"$ARGV[0]");
@array = <IN>;
for($i=0;$i<@array;$i++){
if($array[$i] =~ / _*.+\(.*\)/){
$tmp = $&;
if($array[$i+1] =~ "^{\n"){
print $array[$i];
print $array[$i+1];
print "printf(\"FileName:$ARGV[0] FunctionName:";
print $tmp;
print "\");";
print "\n";
$i++;}
else{
print $array[$i];
}
}else{
print $array[$i];
}
}

というコードを書きました。しかしこれでもうまくいかないケースが多々ありました。

int
main(void)
{
intro();

new_game();

/* @@@ exit(0); */ /* causes a warning in C++ */
return(0);
}

のように返り値が横ではなく上についていたり、

void __ast_string_field_index_build(struct ast_string_field_mgr *mgr,
ast_string_field *fields, int num_fields,
int index, const char *format, ...)
{

のように引数が複数行にわたる場合です。
どのようにしたらよいのでしょうか。
どなたか教えてもらえませんか?

A 回答 (4件)

表示がずれるので、空白2文字を全角空白にしていることに注意



#define _GNU_SOURCE
#include <stdio.h>
#include <string.h>

#ifndef __CYGWIN32__
#include <dlfcn.h>
#endif

/* BINARY HACKS P.300 */
/* 関数への enter/exit をフックする */

#ifndef __CYGWIN32__
__attribute__((no_instrument_function))
void addr2name(void *func_address, char *func_name)
{
  Dl_info dli;

  if (0 != dladdr(func_address, &dli)) {
    strcpy(func_name, dli.dli_sname);
  }
  else {
    strcpy(func_name, "");
  }
}
#endif

__attribute__((no_instrument_function))
void __cyg_profile_func_enter(void *func_address, void *call_site)
{
  extern void *__libc_stack_end;
  char     func_name[256];
  int     stack_size;
  void    *frame = __builtin_frame_address(1) + 8;

#ifndef __CYGWIN32__
  addr2name(func_address, func_name);
  stack_size = __libc_stack_end - __builtin_frame_address(0);
#else
  strcpy(func_name, "");
  stack_size = 0;
#endif
  printf("enter %s:%p, from=%p stack size=%d\n",
      func_name, func_address, call_site, stack_size);
}

__attribute__((no_instrument_function))
void __cyg_profile_func_exit(void *func_address, void *call_site)
{
  char func_name[256];
#ifndef __CYGWIN32__
  addr2name(func_address, func_name);
#else
  strcpy(func_name, "");
#endif
  printf("exit %s:%p, from=%p\n", func_name, func_address, call_site);
}

void sub_func(int arg1, char arg2, char *arg3)
{
}

void func(int arg1, char arg2, char *arg3)
{
  sub_func(arg1, arg2, arg3);
}

__attribute__((no_instrument_function))
void func_no_instrument_function(int arg1, char arg2, char *arg3)
{
}

__attribute__((no_instrument_function))
int main(int argc, char *argv[])
{
  int  arg1 = 10;
  char arg2 = 20;
  char *arg3 = "abc";

  printf("sub_func = %p\n", sub_func);
  printf("func = %p\n", func);

  func(arg1, arg2, arg3);
  func_no_instrument_function(arg1, arg2, arg3);

  return 0;
}

/* $ gcc -g -finstrument-functions -rdynamic foo.c -o a.out -ldl && ./a.out */
/* sub_func = 0x804891e */
/* func = 0x8048952 */
/* enter func:0x8048952, from=0x8048a13 stack size=264 */
/* enter sub_func:0x804891e, from=0x804898b stack size=312 */
/* exit sub_func:0x804891e, from=0x804898b */
/* exit func:0x8048952, from=0x8048a13 */
    • good
    • 0
この回答へのお礼

回答ありがとうございました。

お礼日時:2011/09/01 09:52

http://oshiete.goo.ne.jp/qa/6954461.html
のつづきでしょうか?

真面目にやろうとすると、C言語の構文解析プログラムになり、かなり面倒です。
簡潔にしたかったら、整形ツール(astyle, uncrustify等)で書式を整え、一定の規則(引数はかならず開き括弧と別の行、とか、定義の開始の{はかならず行頭、とか)にそろえてから、その規則に従った正規表現にするのがいいと思います。
    • good
    • 0
この回答へのお礼

回答ありがとうございました。

お礼日時:2011/09/01 09:53

GCC なら C99 が使える. あとはコーディングの問題だけど,


・関数の最初の { はインデントせず行頭にある
・それ以外のブロックを始める { は行頭にないかインデントされている
という条件を満たすなら

$/ = undef;
$program = <>;
$program =~ s/\)\s*\n\{/$&printf("FileName: %s FunctionName: %s\\n, __FILE__, __func__);/g;
print $program;

でだいたいいけると思う.

上の条件を満たさないと突然面倒だが.
    • good
    • 0
この回答へのお礼

回答ありがとうございました。

お礼日時:2011/09/01 09:53

一応確認だけど, 使っている C コンパイラはなんですか?

    • good
    • 0
この回答へのお礼

gccです。

お礼日時:2011/08/23 16:31

お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!