简体   繁体   中英

Crystal debugging with GDB

I am trying to learn to debug programs written in Crystal with GDB. Here is a sample:

class Demo
  @array = [] of String

  def bar(url)
    ret = url.downcase * 2
    if ret == "alsj"
      return false
    else
      return ret
    end
  end

  def do(foo)
    @array.push(foo)
    html = bar(foo)
    puts "HI" # GDB breakpoint here
    return html
  end
end

a = Demo.new
puts a.do("HI")

I compiled the sample above with the --debug flag and loaded it into GDB. Then I let it run and stopped at the marked line ( GDB breakpoint here ). Now I have three four questions:

  1. Printing string values (eg foo ): When I inspect a string variable, I often see something like $1 = (struct String *) 0x4b9f18 . When I say printf "%s", foo , I get nothing back. How can I display the current value of a string variable?
  2. optimized out. Other times I just see $1 = <optimized out> when inspecting a variable. What does that mean and how can I see the value in that case?
  3. Accessing object variables How can I see the value of @array in the given situation? p array says no symbol in current context and p @array returns unknown address space modifier. Edit: I found a way: use p self.array
  4. Vanished variables In the given situation (breaking at the line puts "HI" ) I can't see the variable html at all: p html returns no symbol in current context. Why is that and how do I solve it?

Crystal debugging capabilities are still on development so you can't see some symbols or symbols data is optimized by LLVM. About optimized output , sometimes crystal algorithms are optimized too much, even on --debug builds. By example:

Currently yield methods are inlined and optimized, so this isn't very debuggable.

3.times do |i|
  pp i
end

However, you can use pp keyword to print name => value .

pp i
i => 1
i => 2
i => 3

Also you can set breakpoints using debugger keyword and inspect macro output using {% debug() %} or $ crystal tool expand command.

On the other hand compound statement are easy to debug using tools like GDB.

i = 0
while i < 3
  debugger
  i += 1 # i variable is listed by GDB
end

Finally you can try some tricks I found in my debugging daily tasks.

  1. Printing string values: try @[NoInline] and p &foo.c this will enable args data and you will be able to print all struct string value

Using @[NoInline] attribute:

@[NoInline]
def do(foo)
  debugger
end

On GDB:

(gdb) p &foo.c
$1 = (UInt8 *) 0x10008e6c4 "HI"
  1. optimized out: maybe because LLVM optimizes some method calls. if you see <optimized out> use @[NoInline] and try assigning instance vars to local vars array = @array

  2. Accessing object variables: use self.var for instance vars.

Also use p array.buffer[0]@size to print array values.

(gdb) p &array.buffer[0].c
$19 = (UInt8 *) 0x10008e7f4 "HI"
  1. Vanished variables: this happens because debugging info is not complete enough.

Try adding debug info manually converting or casting values:

@[NoInline]
def do(foo)
  html = bar(foo).as(String)
  html = bar(foo).to_s
  debugger
end

Now html var is visible on GDB thanks to .as or .to_s methods

(gdb) p &html.c
$1 = (UInt8 *) 0x1002fcfec "hihi"

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM