Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve debugging support #8538

Merged
merged 48 commits into from
Apr 16, 2020
Merged
Show file tree
Hide file tree
Changes from 36 commits
Commits
Show all changes
48 commits
Select commit Hold shift + click to select a range
6346c1c
Rudimentary debug support is here. It allows LLDB to show Crystal var…
Nov 30, 2019
401de7a
Rolled back enforced NoInline in debug mode.
Nov 30, 2019
b3105f4
Added comment to explain why we have to use C++ Language ID
Dec 5, 2019
574eb32
Added debug information for union and nullable types.
Jan 20, 2020
65cc438
Fixed some of the debug type glitches (MixedUnionType notoriously) as…
Jan 30, 2020
94a7e1c
Refactored debug information logging as per bcardiff comments
Jan 31, 2020
f0e82d4
Added array types debugging with DWARF support.
Feb 2, 2020
1f70c61
Some extra features was added to llvm module so now it is possible to…
Feb 6, 2020
9df1511
Added debug support for Tuples, NamedTuples, TypeDefs and partial sup…
Feb 8, 2020
82fd67e
Removed unnecessary debug logs and did some format tidy up.
Feb 10, 2020
75bf4c8
More of code tidy up.
Feb 10, 2020
3020b31
Moving LLVM functions to the class they belong to.
Feb 10, 2020
79de0c7
Neating up the code as per comments of reviewers.
Feb 10, 2020
c2a608c
Code cleanup as per Sija's comments.
Feb 11, 2020
0a75f31
Moved lldb crystal formatter into etc/lldb
Feb 17, 2020
436979e
Merge branch 'master' into debug
Feb 17, 2020
3be118a
Merge branch 'master' into debug
Feb 23, 2020
1576156
Rolled back previously set_current_debug_location as they are breaki…
Feb 23, 2020
5a60d9a
Fixes as per Sija's suggestions as well as fix for failed unit test d…
Feb 24, 2020
a163b74
Merge branch 'master' into debug
Feb 24, 2020
71f1dbc
autoformated source code
Feb 24, 2020
d779e17
Removed location code that is not needed and was redundant and also w…
Feb 25, 2020
599a555
Code clean up as per Sija's comments.
Feb 25, 2020
06f25e7
Typo fix! Thanks a lot, Sija!
Feb 25, 2020
84e8280
Some clean up to trigger the build to re-test Alpine Linux.
Feb 25, 2020
64e1316
Re-trigger build wth comment commit.
Feb 25, 2020
17a56a0
Fixed formatting issues (who knew that ### is not allowed! )
Feb 25, 2020
411f85a
initial refactor to use proper debug alloca
Feb 28, 2020
dc54cc8
fixing of alloca to be on alloca block
Feb 29, 2020
8c32552
formatted code
Feb 29, 2020
9785609
Merge branch 'master' of https://github.com/crystal-lang/crystal into…
Mar 4, 2020
910f742
Bug fixing for proper debug implementation. It should work properly n…
Mar 7, 2020
6efdf2f
Fix of code formatting.
Mar 7, 2020
a8bf28f
Code fixes and avoid generating debug info for naked functions
Mar 11, 2020
ab00367
Fixed function name typo that @Sija found
Mar 11, 2020
859734c
Addressed PR comments and refactored back to Type for debug_type_hash.
Mar 14, 2020
b01085a
changed the order of 'if' branch execution for setup_fun when --debug…
Mar 21, 2020
a8d0f41
Removed method attributes irrelevant for debugging as per @RX14
Mar 24, 2020
5229b4c
Refactored code as per suggestions from @asterlite and @Sija
Mar 27, 2020
7e78afc
Code refactoring as per @Sija suggestions
Mar 28, 2020
ce1d00c
Removed all unused methods that were implemented during debug support…
Mar 28, 2020
f81e506
Merge branch 'master' of https://github.com/crystal-lang/crystal into…
Apr 4, 2020
7324863
Merge branch 'master' into debug
bcardiff Apr 8, 2020
3291ec8
Initial debug specs
bcardiff Apr 9, 2020
4024e52
Merge commit '3291ec8533c4bb505ac122c9e6bd3e17b6502032' into debug
Apr 9, 2020
3811814
Cherrypicked debug driver from @bcardiff
Apr 9, 2020
83d3e8c
Merge branch 'master' of https://github.com/crystal-lang/crystal into…
Apr 14, 2020
c0e2417
Merge branch 'master' of https://github.com/crystal-lang/crystal into…
Apr 14, 2020
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
62 changes: 62 additions & 0 deletions etc/lldb/crystal_formatters.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
import lldb

class CrystalArraySyntheticProvider:
def __init__(self, valobj, internal_dict):
self.valobj = valobj
self.buffer = None
self.size = 0

def update(self):
if self.valobj.type.is_pointer:
self.valobj = self.valobj.Dereference()
self.size = int(self.valobj.child[0].value)
self.type = self.valobj.type
self.buffer = self.valobj.child[2]

def num_children(self):
size = 0 if self.size is None else self.size
return size

def get_child_index(self, name):
try:
return int(name.lstrip('[').rstrip(']'))
except:
return -1

def get_child_at_index(self,index):
if index >= self.size:
return None
try:
elementType = self.buffer.type.GetPointeeType()
offset = elementType.size * index
return self.buffer.CreateChildAtOffset('[' + str(index) + ']', offset, elementType)
except Exception as e:
print('Got exception %s' % (str(e)))
return None

def findType(name, module):
cachedTypes = module.GetTypes()
for idx in range(cachedTypes.GetSize()):
type = cachedTypes.GetTypeAtIndex(idx)
if type.name == name:
return type
return None


def CrystalString_SummaryProvider(value, dict):
error = lldb.SBError()
if value.TypeIsPointerType():
value = value.Dereference()
process = value.GetTarget().GetProcess()
byteSize = int(value.child[0].value)
len = int(value.child[1].value)
len = byteSize or len
strAddr = value.child[2].load_addr
val = process.ReadCStringFromMemory(strAddr, len + 1, error)
return '"%s"' % val


def __lldb_init_module(debugger, dict):
debugger.HandleCommand('type synthetic add -l crystal_formatters.CrystalArraySyntheticProvider -x "^Array\(.+\)(\s*\**)?" -w Crystal')
debugger.HandleCommand('type summary add -F crystal_formatters.CrystalString_SummaryProvider -x "^(String|\(String \| Nil\))(\s*\**)?$" -w Crystal')
debugger.HandleCommand('type category enable Crystal')
8 changes: 6 additions & 2 deletions spec/spec_helper.cr
Original file line number Diff line number Diff line change
Expand Up @@ -156,9 +156,13 @@ def assert_macro_internal(program, sub_node, macro_args, macro_body, expected, e
result_pragmas.should eq(expected_pragmas) if expected_pragmas
end

def codegen(code, inject_primitives = true, debug = Crystal::Debug::None)
def codegen(code, inject_primitives = true, debug = Crystal::Debug::None, filename = __FILE__)
code = inject_primitives(code) if inject_primitives
node = parse code
parser = Parser.new(code)
parser.filename = filename
parser.wants_doc = false
node = parser.parse

result = semantic node
result.program.codegen(result.node, single_module: false, debug: debug)[""].mod
end
Expand Down
31 changes: 27 additions & 4 deletions src/compiler/crystal/codegen/codegen.cr
Original file line number Diff line number Diff line change
Expand Up @@ -135,8 +135,9 @@ module Crystal
# llvm value, so in a way it's "already loaded".
# This field is true if that's the case.
getter already_loaded : Bool
getter debug_variable_created : Bool

def initialize(@pointer, @type, @already_loaded = false)
def initialize(@pointer, @type, @already_loaded = false, @debug_variable_created = false)
end
end

Expand Down Expand Up @@ -361,6 +362,13 @@ module Crystal
mod = info.mod
push_debug_info_metadata(mod) unless @debug.none?

if ENV["CRYSTAL_DEBUG_LL_DUMP"]?
puts "Module #{name}:"
mod.functions.each do |func|
puts func.body_to_ll_string
end
end

skuznetsov marked this conversation as resolved.
Show resolved Hide resolved
mod.dump if dump_all_llvm || name =~ dump_llvm_regex

# Always run verifications so we can catch bugs earlier and more often.
Expand Down Expand Up @@ -1345,7 +1353,12 @@ module Crystal
end

def declare_var(var)
context.vars[var.name] ||= LLVMVar.new(var.no_returns? ? llvm_nil : alloca(llvm_type(var.type), var.name), var.type)
context.vars[var.name] ||= begin
pointer = var.no_returns? ? llvm_nil : alloca(llvm_type(var.type), var.name)
debug_variable_created = false
debug_variable_created = declare_variable(var.name, var.type, pointer, var.location) unless context.fun.naked?
skuznetsov marked this conversation as resolved.
Show resolved Hide resolved
LLVMVar.new(pointer, var.type, debug_variable_created: debug_variable_created)
end
end

def declare_lib_var(name, type, thread_local)
Expand Down Expand Up @@ -1712,8 +1725,18 @@ module Crystal
is_arg = args.try &.any? { |arg| arg.name == var.name }
next if is_arg

ptr = builder.alloca llvm_type(var_type), name
context.vars[name] = LLVMVar.new(ptr, var_type)
ptr = alloca llvm_type(var_type), name

location = var.location
if location.nil? && obj.is_a?(ASTNode)
location = obj.location
end

debug_variable_created = false
if location && !context.fun.naked?
debug_variable_created = declare_variable name, var_type, ptr, location, alloca_block
end
skuznetsov marked this conversation as resolved.
Show resolved Hide resolved
context.vars[name] = LLVMVar.new(ptr, var_type, debug_variable_created: debug_variable_created)

# Assign default nil for variables that are bound to the nil variable
if bound_to_mod_nil?(var)
Expand Down
4 changes: 4 additions & 0 deletions src/compiler/crystal/codegen/crystal_llvm_builder.cr
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,10 @@ module Crystal
@builder.build_operand_bundle_def(name, values)
end

def current_debug_location_metadata
@builder.current_debug_location_metadata
end

skuznetsov marked this conversation as resolved.
Show resolved Hide resolved
def to_unsafe
@builder.to_unsafe
end
Expand Down
Loading