1

GDB version: GNU gdb (Ubuntu 8.1.1-0ubuntu1) 8.1.1

I can't define a command with arbitrary number of arguments in gdb.

I have found some workaround, for example a command with up to three arguments support:

define test_1

if $argc == 1
    python args = "$arg0"
end
if $argc == 2
    python args = "$arg0 $arg1"
end
if $argc == 3
    python args = "$arg0 $arg1 $arg2"
end

python print(gdb.execute(args, to_string=True))

end

Usage

test_1 info breakpoints

I have tried another approach but it doesn't work, because gdb parses $arg<n> arguments before python execution, so "$arg0 $arg1 $arg2" in the args variable are not replaced by their values:

define test_1

python args = ' '.join(f"$arg{i}" for i in range($argc))
python print(gdb.execute(args, to_string=True))

end

Question: How to do it right? Python is not mandatory, other solutions (like pure gdb script) are allowable.

2
  • 1
    Have you tried gdb python commands? Commented Mar 11, 2021 at 11:16
  • @ssbssa I have glanced this page several times, but I have not read it carefully... It turned out, this is exactly what I need. Thanks for the link. Commented Mar 11, 2021 at 21:13

1 Answer 1

3

The easiest and most robust way to do this is to use GDB's Python extensions. Making a subclass of gdb.Command will give you access to the unsplit argument string, as the 2nd argument to invoke. In your example use case, this string can be passed as-is to gdb.execute.

You can also split it into arguments using gdb.string_to_argv. And if you’re going to pass just a part of the argument string to gdb.execute, you can use string.split, as in this example:

class Repeat(gdb.Command):
  """repeat count command - run the given command count times"""

  def __init__(self):
    super (Repeat, self).__init__ ("repeat", gdb.COMMAND_USER, gdb.COMPLETE_COMMAND)

  def invoke(self, argstr, from_tty):
      try:
        (count, command) = argstr.split(maxsplit = 1)
      except ValueError:
        raise Exception("Usage: repeat count command")
      if not count.isdigit():
        raise Exception("missing or garbled repeat count: " + count)
      for _ in range(0, int(count)):
        gdb.execute(command, from_tty = False)

Repeat()

Example:

(gdb) repeat 3 run $(expr $RANDOM % 20)
16! = 20922789888000
[Inferior 1 (process 259) exited normally]
9! = 362880
[Inferior 1 (process 262) exited normally]
13! = 6227020800
[Inferior 1 (process 265) exited normally]

If you can't use Python, a user-defined command can still concatenate its arguments, using eval, but it's not nearly as robust (see note at the end.)

(This requires GDB 9.1 or later; its C-like expression evaluator will concatenate adjacent string literals. )

define repeat
  if $argc < 2
    printf "Usage: repeat count command\n"
  else
    # first arg goes in $count, rest are concatenated and put in $command
    set $count=$arg0
    set $i=1
    set $command=""
    while $i < $argc
      eval "set $command = \"%s\" \"$arg%d\"", $command, $i
      # add one blank space after every arg except for the last
      if $i < $argc - 1
        eval "set $command = \"%s\" \" \"", $command
      end
      set $i++
    end
    printf "About to run `%s' %d times.\n", $command, $count
    set $i=0
    while $i < $count
      eval "%s", $command
      set $i++
    end
  end
end

Using eval to surround strings in double quotes when those strings contain double quotes is problematic, though.

(gdb) repeat 3 set $a="foo"
A syntax error in expression, near `foo""'.
Sign up to request clarification or add additional context in comments.

1 Comment

Thanks. This approach allowed me to do what I wanted - Using less as gdb pager.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.