1

I have a following function and I want to stop for debugging inside of it depending on content of variable arguments passed to it.

int
my_fprintf (const char *format, ...)
{
  va_list arg_list;
  ...
  va_start (arg_list, format);
  result = vfprintf (stream, indent_str, arg_list);
  va_end (arg_list);

  ...
  return result;
}

What I want is to put a breakpoint in it to stop if the call is my_fprintf ("%s", "hello") for example (so breakpoint condition would be as close as possible to a <smth> == "hello").

Is it possible to do that?

Updates:

  • Debugger is gdb.
  • I know how to set conditional breakpoints, I want to know, that the condition should be in this case.
Michael Pankov
  • 3,581
  • 2
  • 23
  • 31

3 Answers3

2

I think there are two parts to the question/answer:

  1. How to get gdb to see parameters passed in the variable part? I don't think it has this ability, so you'll have to do something platform dependent. This answer should work for x86_64. For 32bit it's more simple, because va_list is just an array of longs.
  2. How to make a conditional breakpoint? gdb's condition command (documented here) can help.
Community
  • 1
  • 1
ugoren
  • 16,023
  • 3
  • 35
  • 65
1

gdb can do that. You just need a variable (p in the following snippet) that you can check. To successfully obtain p, you would need more goo, namely, checking that the first argument of arg2 is a char* within reason, done here by checking that format contains %s for example (though %s is not sufficient, as someone may use %.*s or something).

static int my_fprintf(const char *format, ...)
{
        const char *p;
        va_list arg_list, arg2;
        bool have_string = false;

        va_start(arg_list, format);
        va_copy(arg2, arg_list);
        for (p = strchr(format, '%'); p != NULL; p = strchr(p+1, '%')) {
                if (p[1] == '%')
                        continue;
                if (p[1] != 's')
                        break;
                have_string = true;
                break;
        }
        if (have_string)
                p = va_arg(arg2, const char *);
        result = vfprintf(stream, indent_str, arg_list);
        va_end(arg_list);
        return result;
}

(gdb) b 1234 if have_string && strstr(p, "hello")==0

Replace 1234 by the line number of p=va_arg....
Edited: unshadow p and put have_string into the break cond.

jørgensen
  • 10,149
  • 2
  • 20
  • 27
  • You are shadowing p declared on top of function) – Michael Pankov Jan 31 '12 at 16:10
  • And it seems to me that `if (have_string) ...` should have an `else { p = "" }` for example to handle the case when there's no string. Then I use `strcmp` for strict string comparison. Apart from that, works like a charm! Thank you. – Michael Pankov Jan 31 '12 at 16:19
0

You would have to analyse the guts of your implementation's va_list type. E.g. it could be a pointer to an array of pointers, one of them (probably the first) pointing to "hello". Then teach your debugger to break on this condition.

Jens
  • 69,818
  • 15
  • 125
  • 179