/
debuginfo.rs
3997 lines (3498 loc) · 159 KB
/
debuginfo.rs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
/*!
# Debug Info Module
This module serves the purpose of generating debug symbols. We use LLVM's
[source level debugging](http://llvm.org/docs/SourceLevelDebugging.html)
features for generating the debug information. The general principle is this:
Given the right metadata in the LLVM IR, the LLVM code generator is able to
create DWARF debug symbols for the given code. The
[metadata](http://llvm.org/docs/LangRef.html#metadata-type) is structured much
like DWARF *debugging information entries* (DIE), representing type information
such as datatype layout, function signatures, block layout, variable location
and scope information, etc. It is the purpose of this module to generate correct
metadata and insert it into the LLVM IR.
As the exact format of metadata trees may change between different LLVM
versions, we now use LLVM
[DIBuilder](http://llvm.org/docs/doxygen/html/classllvm_1_1DIBuilder.html) to
create metadata where possible. This will hopefully ease the adaption of this
module to future LLVM versions.
The public API of the module is a set of functions that will insert the correct
metadata into the LLVM IR when called with the right parameters. The module is
thus driven from an outside client with functions like
`debuginfo::create_local_var_metadata(bcx: block, local: &ast::local)`.
Internally the module will try to reuse already created metadata by utilizing a
cache. The way to get a shared metadata node when needed is thus to just call
the corresponding function in this module:
let file_metadata = file_metadata(crate_context, path);
The function will take care of probing the cache for an existing node for that
exact file path.
All private state used by the module is stored within either the
CrateDebugContext struct (owned by the CrateContext) or the FunctionDebugContext
(owned by the FunctionContext).
This file consists of three conceptual sections:
1. The public interface of the module
2. Module-internal metadata creation functions
3. Minor utility functions
## Recursive Types
Some kinds of types, such as structs and enums can be recursive. That means that
the type definition of some type X refers to some other type which in turn
(transitively) refers to X. This introduces cycles into the type referral graph.
A naive algorithm doing an on-demand, depth-first traversal of this graph when
describing types, can get trapped in an endless loop when it reaches such a
cycle.
For example, the following simple type for a singly-linked list...
```
struct List {
value: int,
tail: Option<Box<List>>,
}
```
will generate the following callstack with a naive DFS algorithm:
```
describe(t = List)
describe(t = int)
describe(t = Option<Box<List>>)
describe(t = Box<List>)
describe(t = List) // at the beginning again...
...
```
To break cycles like these, we use "forward declarations". That is, when the
algorithm encounters a possibly recursive type (any struct or enum), it
immediately creates a type description node and inserts it into the cache
*before* describing the members of the type. This type description is just a
stub (as type members are not described and added to it yet) but it allows the
algorithm to already refer to the type. After the stub is inserted into the
cache, the algorithm continues as before. If it now encounters a recursive
reference, it will hit the cache and does not try to describe the type anew.
This behaviour is encapsulated in the 'RecursiveTypeDescription' enum, which
represents a kind of continuation, storing all state needed to continue
traversal at the type members after the type has been registered with the cache.
(This implementation approach might be a tad over-engineered and may change in
the future)
## Source Locations and Line Information
In addition to data type descriptions the debugging information must also allow
to map machine code locations back to source code locations in order to be useful.
This functionality is also handled in this module. The following functions allow
to control source mappings:
+ set_source_location()
+ clear_source_location()
+ start_emitting_source_locations()
`set_source_location()` allows to set the current source location. All IR
instructions created after a call to this function will be linked to the given
source location, until another location is specified with
`set_source_location()` or the source location is cleared with
`clear_source_location()`. In the later case, subsequent IR instruction will not
be linked to any source location. As you can see, this is a stateful API
(mimicking the one in LLVM), so be careful with source locations set by previous
calls. It's probably best to not rely on any specific state being present at a
given point in code.
One topic that deserves some extra attention is *function prologues*. At the
beginning of a function's machine code there are typically a few instructions
for loading argument values into allocas and checking if there's enough stack
space for the function to execute. This *prologue* is not visible in the source
code and LLVM puts a special PROLOGUE END marker into the line table at the
first non-prologue instruction of the function. In order to find out where the
prologue ends, LLVM looks for the first instruction in the function body that is
linked to a source location. So, when generating prologue instructions we have
to make sure that we don't emit source location information until the 'real'
function body begins. For this reason, source location emission is disabled by
default for any new function being translated and is only activated after a call
to the third function from the list above, `start_emitting_source_locations()`.
This function should be called right before regularly starting to translate the
top-level block of the given function.
There is one exception to the above rule: `llvm.dbg.declare` instruction must be
linked to the source location of the variable being declared. For function
parameters these `llvm.dbg.declare` instructions typically occur in the middle
of the prologue, however, they are ignored by LLVM's prologue detection. The
`create_argument_metadata()` and related functions take care of linking the
`llvm.dbg.declare` instructions to the correct source locations even while
source location emission is still disabled, so there is no need to do anything
special with source location handling here.
## Unique Type Identification
In order for link-time optimization to work properly, LLVM needs a unique type
identifier that tells it across compilation units which types are the same as
others. This type identifier is created by TypeMap::get_unique_type_id_of_type()
using the following algorithm:
(1) Primitive types have their name as ID
(2) Structs, enums and traits have a multipart identifier
(1) The first part is the SVH (strict version hash) of the crate they were
originally defined in
(2) The second part is the ast::NodeId of the definition in their original
crate
(3) The final part is a concatenation of the type IDs of their concrete type
arguments if they are generic types.
(3) Tuple-, pointer and function types are structurally identified, which means
that they are equivalent if their component types are equivalent (i.e. (int,
int) is the same regardless in which crate it is used).
This algorithm also provides a stable ID for types that are defined in one crate
but instantiated from metadata within another crate. We just have to take care
to always map crate and node IDs back to the original crate context.
As a side-effect these unique type IDs also help to solve a problem arising from
lifetime parameters. Since lifetime parameters are completely omitted in
debuginfo, more than one `ty::t` instance may map to the same debuginfo type
metadata, that is, some struct `Struct<'a>` may have N instantiations with
different concrete substitutions for `'a`, and thus there will be N `ty::t`
instances for the type `Struct<'a>` even though it is not generic otherwise.
Unfortunately this means that we cannot use `ty::type_id()` as cheap identifier
for type metadata---we have done this in the past, but it led to unnecessary
metadata duplication in the best case and LLVM assertions in the worst. However,
the unique type ID as described above *can* be used as identifier. Since it is
comparatively expensive to construct, though, `ty::type_id()` is still used
additionally as an optimization for cases where the exact same type has been
seen before (which is most of the time). */
use driver::config;
use driver::config::{FullDebugInfo, LimitedDebugInfo, NoDebugInfo};
use llvm;
use llvm::{ModuleRef, ContextRef, ValueRef};
use llvm::debuginfo::*;
use metadata::csearch;
use middle::subst::{mod, Subst};
use middle::trans::adt;
use middle::trans::common::*;
use middle::trans::machine;
use middle::trans::_match::{BindingInfo, TrByCopy, TrByMove, TrByRef};
use middle::trans::type_of;
use middle::trans::type_::Type;
use middle::trans;
use middle::ty;
use middle::pat_util;
use util::ppaux;
use libc::c_uint;
use std::c_str::{CString, ToCStr};
use std::cell::{Cell, RefCell};
use std::collections::HashMap;
use std::collections::HashSet;
use std::ptr;
use std::rc::{Rc, Weak};
use syntax::util::interner::Interner;
use syntax::codemap::{Span, Pos};
use syntax::{abi, ast, codemap, ast_util, ast_map};
use syntax::ast_util::PostExpansionMethod;
use syntax::parse::token;
use syntax::parse::token::special_idents;
static DW_LANG_RUST: c_uint = 0x9000;
#[allow(non_uppercase_statics)]
static DW_TAG_auto_variable: c_uint = 0x100;
#[allow(non_uppercase_statics)]
static DW_TAG_arg_variable: c_uint = 0x101;
#[allow(non_uppercase_statics)]
static DW_ATE_boolean: c_uint = 0x02;
#[allow(non_uppercase_statics)]
static DW_ATE_float: c_uint = 0x04;
#[allow(non_uppercase_statics)]
static DW_ATE_signed: c_uint = 0x05;
#[allow(non_uppercase_statics)]
static DW_ATE_unsigned: c_uint = 0x07;
#[allow(non_uppercase_statics)]
static DW_ATE_unsigned_char: c_uint = 0x08;
static UNKNOWN_LINE_NUMBER: c_uint = 0;
static UNKNOWN_COLUMN_NUMBER: c_uint = 0;
// ptr::null() doesn't work :(
static UNKNOWN_FILE_METADATA: DIFile = (0 as DIFile);
static UNKNOWN_SCOPE_METADATA: DIScope = (0 as DIScope);
static FLAGS_NONE: c_uint = 0;
//=-----------------------------------------------------------------------------
// Public Interface of debuginfo module
//=-----------------------------------------------------------------------------
#[deriving(Show, Hash, Eq, PartialEq, Clone)]
struct UniqueTypeId(ast::Name);
// The TypeMap is where the CrateDebugContext holds the type metadata nodes
// created so far. The metadata nodes are indexed by UniqueTypeId, and, for
// faster lookup, also by ty::t. The TypeMap is responsible for creating
// UniqueTypeIds.
struct TypeMap {
// The UniqueTypeIds created so far
unique_id_interner: Interner<Rc<String>>,
// A map from UniqueTypeId to debuginfo metadata for that type. This is a 1:1 mapping.
unique_id_to_metadata: HashMap<UniqueTypeId, DIType>,
// A map from ty::type_id() to debuginfo metadata. This is a N:1 mapping.
type_to_metadata: HashMap<uint, DIType>,
// A map from ty::type_id() to UniqueTypeId. This is a N:1 mapping.
type_to_unique_id: HashMap<uint, UniqueTypeId>
}
impl TypeMap {
fn new() -> TypeMap {
TypeMap {
unique_id_interner: Interner::new(),
type_to_metadata: HashMap::new(),
unique_id_to_metadata: HashMap::new(),
type_to_unique_id: HashMap::new(),
}
}
// Adds a ty::t to metadata mapping to the TypeMap. The method will fail if
// the mapping already exists.
fn register_type_with_metadata(&mut self,
cx: &CrateContext,
type_: ty::t,
metadata: DIType) {
if !self.type_to_metadata.insert(ty::type_id(type_), metadata) {
cx.sess().bug(format!("Type metadata for ty::t '{}' is already in the TypeMap!",
ppaux::ty_to_string(cx.tcx(), type_)).as_slice());
}
}
// Adds a UniqueTypeId to metadata mapping to the TypeMap. The method will
// fail if the mapping already exists.
fn register_unique_id_with_metadata(&mut self,
cx: &CrateContext,
unique_type_id: UniqueTypeId,
metadata: DIType) {
if !self.unique_id_to_metadata.insert(unique_type_id, metadata) {
let unique_type_id_str = self.get_unique_type_id_as_string(unique_type_id);
cx.sess().bug(format!("Type metadata for unique id '{}' is already in the TypeMap!",
unique_type_id_str.as_slice()).as_slice());
}
}
fn find_metadata_for_type(&self, type_: ty::t) -> Option<DIType> {
self.type_to_metadata.find_copy(&ty::type_id(type_))
}
fn find_metadata_for_unique_id(&self, unique_type_id: UniqueTypeId) -> Option<DIType> {
self.unique_id_to_metadata.find_copy(&unique_type_id)
}
// Get the string representation of a UniqueTypeId. This method will fail if
// the id is unknown.
fn get_unique_type_id_as_string(&self, unique_type_id: UniqueTypeId) -> Rc<String> {
let UniqueTypeId(interner_key) = unique_type_id;
self.unique_id_interner.get(interner_key)
}
// Get the UniqueTypeId for the given type. If the UniqueTypeId for the given
// type has been requested before, this is just a table lookup. Otherwise an
// ID will be generated and stored for later lookup.
fn get_unique_type_id_of_type(&mut self, cx: &CrateContext, type_: ty::t) -> UniqueTypeId {
// basic type -> {:name of the type:}
// tuple -> {tuple_(:param-uid:)*}
// struct -> {struct_:svh: / :node-id:_<(:param-uid:),*> }
// enum -> {enum_:svh: / :node-id:_<(:param-uid:),*> }
// enum variant -> {variant_:variant-name:_:enum-uid:}
// reference (&) -> {& :pointee-uid:}
// mut reference (&mut) -> {&mut :pointee-uid:}
// ptr (*) -> {* :pointee-uid:}
// mut ptr (*mut) -> {*mut :pointee-uid:}
// unique ptr (~) -> {~ :pointee-uid:}
// @-ptr (@) -> {@ :pointee-uid:}
// sized vec ([T, ..x]) -> {[:size:] :element-uid:}
// unsized vec ([T]) -> {[] :element-uid:}
// trait (T) -> {trait_:svh: / :node-id:_<(:param-uid:),*> }
// closure -> {<unsafe_> <once_> :store-sigil: |(:param-uid:),* <,_...>| -> \
// :return-type-uid: : (:bounds:)*}
// function -> {<unsafe_> <abi_> fn( (:param-uid:)* <,_...> ) -> \
// :return-type-uid:}
// unique vec box (~[]) -> {HEAP_VEC_BOX<:pointee-uid:>}
// gc box -> {GC_BOX<:pointee-uid:>}
match self.type_to_unique_id.find_copy(&ty::type_id(type_)) {
Some(unique_type_id) => return unique_type_id,
None => { /* generate one */}
};
let mut unique_type_id = String::with_capacity(256);
unique_type_id.push('{');
match ty::get(type_).sty {
ty::ty_nil |
ty::ty_bot |
ty::ty_bool |
ty::ty_char |
ty::ty_str |
ty::ty_int(_) |
ty::ty_uint(_) |
ty::ty_float(_) => {
push_debuginfo_type_name(cx, type_, false, &mut unique_type_id);
},
ty::ty_enum(def_id, ref substs) => {
unique_type_id.push_str("enum ");
from_def_id_and_substs(self, cx, def_id, substs, &mut unique_type_id);
},
ty::ty_struct(def_id, ref substs) => {
unique_type_id.push_str("struct ");
from_def_id_and_substs(self, cx, def_id, substs, &mut unique_type_id);
},
ty::ty_tup(ref component_types) => {
unique_type_id.push_str("tuple ");
for &component_type in component_types.iter() {
let component_type_id =
self.get_unique_type_id_of_type(cx, component_type);
let component_type_id =
self.get_unique_type_id_as_string(component_type_id);
unique_type_id.push_str(component_type_id.as_slice());
}
},
ty::ty_uniq(inner_type) => {
unique_type_id.push('~');
let inner_type_id = self.get_unique_type_id_of_type(cx, inner_type);
let inner_type_id = self.get_unique_type_id_as_string(inner_type_id);
unique_type_id.push_str(inner_type_id.as_slice());
},
ty::ty_ptr(ty::mt { ty: inner_type, mutbl } ) => {
unique_type_id.push('*');
if mutbl == ast::MutMutable {
unique_type_id.push_str("mut");
}
let inner_type_id = self.get_unique_type_id_of_type(cx, inner_type);
let inner_type_id = self.get_unique_type_id_as_string(inner_type_id);
unique_type_id.push_str(inner_type_id.as_slice());
},
ty::ty_rptr(_, ty::mt { ty: inner_type, mutbl }) => {
unique_type_id.push('&');
if mutbl == ast::MutMutable {
unique_type_id.push_str("mut");
}
let inner_type_id = self.get_unique_type_id_of_type(cx, inner_type);
let inner_type_id = self.get_unique_type_id_as_string(inner_type_id);
unique_type_id.push_str(inner_type_id.as_slice());
},
ty::ty_vec(inner_type, optional_length) => {
match optional_length {
Some(len) => {
unique_type_id.push_str(format!("[{}]", len).as_slice());
}
None => {
unique_type_id.push_str("[]");
}
};
let inner_type_id = self.get_unique_type_id_of_type(cx, inner_type);
let inner_type_id = self.get_unique_type_id_as_string(inner_type_id);
unique_type_id.push_str(inner_type_id.as_slice());
},
ty::ty_trait(ref trait_data) => {
unique_type_id.push_str("trait ");
from_def_id_and_substs(self,
cx,
trait_data.def_id,
&trait_data.substs,
&mut unique_type_id);
},
ty::ty_bare_fn(ty::BareFnTy{ fn_style, abi, ref sig } ) => {
if fn_style == ast::UnsafeFn {
unique_type_id.push_str("unsafe ");
}
unique_type_id.push_str(abi.name());
unique_type_id.push_str(" fn(");
for ¶meter_type in sig.inputs.iter() {
let parameter_type_id =
self.get_unique_type_id_of_type(cx, parameter_type);
let parameter_type_id =
self.get_unique_type_id_as_string(parameter_type_id);
unique_type_id.push_str(parameter_type_id.as_slice());
unique_type_id.push(',');
}
if sig.variadic {
unique_type_id.push_str("...");
}
unique_type_id.push_str(")->");
let return_type_id = self.get_unique_type_id_of_type(cx, sig.output);
let return_type_id = self.get_unique_type_id_as_string(return_type_id);
unique_type_id.push_str(return_type_id.as_slice());
},
ty::ty_closure(box ref closure_ty) => {
self.get_unique_type_id_of_closure_type(cx,
closure_ty.clone(),
&mut unique_type_id);
},
ty::ty_unboxed_closure(ref def_id, _, ref substs) => {
let closure_ty = cx.tcx().unboxed_closures.borrow()
.find(def_id).unwrap().closure_type.subst(cx.tcx(), substs);
self.get_unique_type_id_of_closure_type(cx,
closure_ty,
&mut unique_type_id);
},
_ => {
cx.sess().bug(format!("get_unique_type_id_of_type() - unexpected type: {}, {}",
ppaux::ty_to_string(cx.tcx(), type_).as_slice(),
ty::get(type_).sty).as_slice())
}
};
unique_type_id.push('}');
// Trim to size before storing permanently
unique_type_id.shrink_to_fit();
let key = self.unique_id_interner.intern(Rc::new(unique_type_id));
self.type_to_unique_id.insert(ty::type_id(type_), UniqueTypeId(key));
return UniqueTypeId(key);
fn from_def_id_and_substs(type_map: &mut TypeMap,
cx: &CrateContext,
def_id: ast::DefId,
substs: &subst::Substs,
output: &mut String) {
// First, find out the 'real' def_id of the type. Items inlined from
// other crates have to be mapped back to their source.
let source_def_id = if def_id.krate == ast::LOCAL_CRATE {
match cx.external_srcs().borrow().find_copy(&def_id.node) {
Some(source_def_id) => {
// The given def_id identifies the inlined copy of a
// type definition, let's take the source of the copy.
source_def_id
}
None => def_id
}
} else {
def_id
};
// Get the crate hash as first part of the identifier.
let crate_hash = if source_def_id.krate == ast::LOCAL_CRATE {
cx.link_meta().crate_hash.clone()
} else {
cx.sess().cstore.get_crate_hash(source_def_id.krate)
};
output.push_str(crate_hash.as_str());
output.push_str("/");
output.push_str(format!("{:x}", def_id.node).as_slice());
// Maybe check that there is no self type here.
let tps = substs.types.get_slice(subst::TypeSpace);
if tps.len() > 0 {
output.push('<');
for &type_parameter in tps.iter() {
let param_type_id =
type_map.get_unique_type_id_of_type(cx, type_parameter);
let param_type_id =
type_map.get_unique_type_id_as_string(param_type_id);
output.push_str(param_type_id.as_slice());
output.push(',');
}
output.push('>');
}
}
}
fn get_unique_type_id_of_closure_type(&mut self,
cx: &CrateContext,
closure_ty: ty::ClosureTy,
unique_type_id: &mut String) {
let ty::ClosureTy { fn_style,
onceness,
store,
ref bounds,
ref sig,
abi: _ } = closure_ty;
if fn_style == ast::UnsafeFn {
unique_type_id.push_str("unsafe ");
}
if onceness == ast::Once {
unique_type_id.push_str("once ");
}
match store {
ty::UniqTraitStore => unique_type_id.push_str("~|"),
ty::RegionTraitStore(_, ast::MutMutable) => {
unique_type_id.push_str("&mut|")
}
ty::RegionTraitStore(_, ast::MutImmutable) => {
unique_type_id.push_str("&|")
}
};
for ¶meter_type in sig.inputs.iter() {
let parameter_type_id =
self.get_unique_type_id_of_type(cx, parameter_type);
let parameter_type_id =
self.get_unique_type_id_as_string(parameter_type_id);
unique_type_id.push_str(parameter_type_id.as_slice());
unique_type_id.push(',');
}
if sig.variadic {
unique_type_id.push_str("...");
}
unique_type_id.push_str("|->");
let return_type_id = self.get_unique_type_id_of_type(cx, sig.output);
let return_type_id = self.get_unique_type_id_as_string(return_type_id);
unique_type_id.push_str(return_type_id.as_slice());
unique_type_id.push(':');
for bound in bounds.builtin_bounds.iter() {
match bound {
ty::BoundSend => unique_type_id.push_str("Send"),
ty::BoundSized => unique_type_id.push_str("Sized"),
ty::BoundCopy => unique_type_id.push_str("Copy"),
ty::BoundSync => unique_type_id.push_str("Sync"),
};
unique_type_id.push('+');
}
}
// Get the UniqueTypeId for an enum variant. Enum variants are not really
// types of their own, so they need special handling. We still need a
// UniqueTypeId for them, since to debuginfo they *are* real types.
fn get_unique_type_id_of_enum_variant(&mut self,
cx: &CrateContext,
enum_type: ty::t,
variant_name: &str)
-> UniqueTypeId {
let enum_type_id = self.get_unique_type_id_of_type(cx, enum_type);
let enum_variant_type_id = format!("{}::{}",
self.get_unique_type_id_as_string(enum_type_id)
.as_slice(),
variant_name);
let interner_key = self.unique_id_interner.intern(Rc::new(enum_variant_type_id));
UniqueTypeId(interner_key)
}
}
// Returns from the enclosing function if the type metadata with the given
// unique id can be found in the type map
macro_rules! return_if_metadata_created_in_meantime(
($cx: expr, $unique_type_id: expr) => (
match debug_context($cx).type_map
.borrow()
.find_metadata_for_unique_id($unique_type_id) {
Some(metadata) => return MetadataCreationResult::new(metadata, true),
None => { /* proceed normally */ }
};
)
)
/// A context object for maintaining all state needed by the debuginfo module.
pub struct CrateDebugContext {
llcontext: ContextRef,
builder: DIBuilderRef,
current_debug_location: Cell<DebugLocation>,
created_files: RefCell<HashMap<String, DIFile>>,
created_enum_disr_types: RefCell<HashMap<ast::DefId, DIType>>,
type_map: RefCell<TypeMap>,
namespace_map: RefCell<HashMap<Vec<ast::Name>, Rc<NamespaceTreeNode>>>,
// This collection is used to assert that composite types (structs, enums,
// ...) have their members only set once:
composite_types_completed: RefCell<HashSet<DIType>>,
}
impl CrateDebugContext {
pub fn new(llmod: ModuleRef) -> CrateDebugContext {
debug!("CrateDebugContext::new");
let builder = unsafe { llvm::LLVMDIBuilderCreate(llmod) };
// DIBuilder inherits context from the module, so we'd better use the same one
let llcontext = unsafe { llvm::LLVMGetModuleContext(llmod) };
return CrateDebugContext {
llcontext: llcontext,
builder: builder,
current_debug_location: Cell::new(UnknownLocation),
created_files: RefCell::new(HashMap::new()),
created_enum_disr_types: RefCell::new(HashMap::new()),
type_map: RefCell::new(TypeMap::new()),
namespace_map: RefCell::new(HashMap::new()),
composite_types_completed: RefCell::new(HashSet::new()),
};
}
}
pub struct FunctionDebugContext {
repr: FunctionDebugContextRepr,
}
enum FunctionDebugContextRepr {
DebugInfo(Box<FunctionDebugContextData>),
DebugInfoDisabled,
FunctionWithoutDebugInfo,
}
impl FunctionDebugContext {
fn get_ref<'a>(&'a self,
cx: &CrateContext,
span: Span)
-> &'a FunctionDebugContextData {
match self.repr {
DebugInfo(box ref data) => data,
DebugInfoDisabled => {
cx.sess().span_bug(span,
FunctionDebugContext::debuginfo_disabled_message());
}
FunctionWithoutDebugInfo => {
cx.sess().span_bug(span,
FunctionDebugContext::should_be_ignored_message());
}
}
}
fn debuginfo_disabled_message() -> &'static str {
"debuginfo: Error trying to access FunctionDebugContext although debug info is disabled!"
}
fn should_be_ignored_message() -> &'static str {
"debuginfo: Error trying to access FunctionDebugContext for function that should be \
ignored by debug info!"
}
}
struct FunctionDebugContextData {
scope_map: RefCell<HashMap<ast::NodeId, DIScope>>,
fn_metadata: DISubprogram,
argument_counter: Cell<uint>,
source_locations_enabled: Cell<bool>,
}
enum VariableAccess<'a> {
// The llptr given is an alloca containing the variable's value
DirectVariable { alloca: ValueRef },
// The llptr given is an alloca containing the start of some pointer chain
// leading to the variable's content.
IndirectVariable { alloca: ValueRef, address_operations: &'a [ValueRef] }
}
enum VariableKind {
ArgumentVariable(uint /*index*/),
LocalVariable,
CapturedVariable,
}
/// Create any deferred debug metadata nodes
pub fn finalize(cx: &CrateContext) {
if cx.dbg_cx().is_none() {
return;
}
debug!("finalize");
compile_unit_metadata(cx);
unsafe {
llvm::LLVMDIBuilderFinalize(DIB(cx));
llvm::LLVMDIBuilderDispose(DIB(cx));
// Debuginfo generation in LLVM by default uses a higher
// version of dwarf than OS X currently understands. We can
// instruct LLVM to emit an older version of dwarf, however,
// for OS X to understand. For more info see #11352
// This can be overridden using --llvm-opts -dwarf-version,N.
if cx.sess().targ_cfg.os == abi::OsMacos ||
cx.sess().targ_cfg.os == abi::OsiOS {
"Dwarf Version".with_c_str(
|s| llvm::LLVMRustAddModuleFlag(cx.llmod(), s, 2));
}
// Prevent bitcode readers from deleting the debug info.
"Debug Info Version".with_c_str(
|s| llvm::LLVMRustAddModuleFlag(cx.llmod(), s,
llvm::LLVMRustDebugMetadataVersion));
};
}
/// Creates debug information for the given global variable.
///
/// Adds the created metadata nodes directly to the crate's IR.
pub fn create_global_var_metadata(cx: &CrateContext,
node_id: ast::NodeId,
global: ValueRef) {
if cx.dbg_cx().is_none() {
return;
}
// Don't create debuginfo for globals inlined from other crates. The other
// crate should already contain debuginfo for it. More importantly, the
// global might not even exist in un-inlined form anywhere which would lead
// to a linker errors.
if cx.external_srcs().borrow().contains_key(&node_id) {
return;
}
let var_item = cx.tcx().map.get(node_id);
let (ident, span) = match var_item {
ast_map::NodeItem(item) => {
match item.node {
ast::ItemStatic(..) => (item.ident, item.span),
ast::ItemConst(..) => (item.ident, item.span),
_ => {
cx.sess()
.span_bug(item.span,
format!("debuginfo::\
create_global_var_metadata() -
Captured var-id refers to \
unexpected ast_item variant: {}",
var_item).as_slice())
}
}
},
_ => cx.sess().bug(format!("debuginfo::create_global_var_metadata() \
- Captured var-id refers to unexpected \
ast_map variant: {}",
var_item).as_slice())
};
let (file_metadata, line_number) = if span != codemap::DUMMY_SP {
let loc = span_start(cx, span);
(file_metadata(cx, loc.file.name.as_slice()), loc.line as c_uint)
} else {
(UNKNOWN_FILE_METADATA, UNKNOWN_LINE_NUMBER)
};
let is_local_to_unit = is_node_local_to_unit(cx, node_id);
let variable_type = ty::node_id_to_type(cx.tcx(), node_id);
let type_metadata = type_metadata(cx, variable_type, span);
let namespace_node = namespace_for_item(cx, ast_util::local_def(node_id));
let var_name = token::get_ident(ident).get().to_string();
let linkage_name =
namespace_node.mangled_name_of_contained_item(var_name.as_slice());
let var_scope = namespace_node.scope;
var_name.as_slice().with_c_str(|var_name| {
linkage_name.as_slice().with_c_str(|linkage_name| {
unsafe {
llvm::LLVMDIBuilderCreateStaticVariable(DIB(cx),
var_scope,
var_name,
linkage_name,
file_metadata,
line_number,
type_metadata,
is_local_to_unit,
global,
ptr::null_mut());
}
})
});
}
/// Creates debug information for the given local variable.
///
/// Adds the created metadata nodes directly to the crate's IR.
pub fn create_local_var_metadata(bcx: Block, local: &ast::Local) {
if fn_should_be_ignored(bcx.fcx) {
return;
}
let cx = bcx.ccx();
let def_map = &cx.tcx().def_map;
pat_util::pat_bindings(def_map, &*local.pat, |_, node_id, span, path1| {
let var_ident = path1.node;
let datum = match bcx.fcx.lllocals.borrow().find_copy(&node_id) {
Some(datum) => datum,
None => {
bcx.sess().span_bug(span,
format!("no entry in lllocals table for {}",
node_id).as_slice());
}
};
let scope_metadata = scope_metadata(bcx.fcx, node_id, span);
declare_local(bcx,
var_ident,
datum.ty,
scope_metadata,
DirectVariable { alloca: datum.val },
LocalVariable,
span);
})
}
/// Creates debug information for a variable captured in a closure.
///
/// Adds the created metadata nodes directly to the crate's IR.
pub fn create_captured_var_metadata(bcx: Block,
node_id: ast::NodeId,
env_data_type: ty::t,
env_pointer: ValueRef,
env_index: uint,
closure_store: ty::TraitStore,
span: Span) {
if fn_should_be_ignored(bcx.fcx) {
return;
}
let cx = bcx.ccx();
let ast_item = cx.tcx().map.find(node_id);
let variable_ident = match ast_item {
None => {
cx.sess().span_bug(span, "debuginfo::create_captured_var_metadata: node not found");
}
Some(ast_map::NodeLocal(pat)) | Some(ast_map::NodeArg(pat)) => {
match pat.node {
ast::PatIdent(_, ref path1, _) => {
path1.node
}
_ => {
cx.sess()
.span_bug(span,
format!(
"debuginfo::create_captured_var_metadata() - \
Captured var-id refers to unexpected \
ast_map variant: {}",
ast_item).as_slice());
}
}
}
_ => {
cx.sess()
.span_bug(span,
format!("debuginfo::create_captured_var_metadata() - \
Captured var-id refers to unexpected \
ast_map variant: {}",
ast_item).as_slice());
}
};
let variable_type = node_id_type(bcx, node_id);
let scope_metadata = bcx.fcx.debug_context.get_ref(cx, span).fn_metadata;
let llvm_env_data_type = type_of::type_of(cx, env_data_type);
let byte_offset_of_var_in_env = machine::llelement_offset(cx,
llvm_env_data_type,
env_index);
let address_operations = unsafe {
[llvm::LLVMDIBuilderCreateOpDeref(Type::i64(cx).to_ref()),
llvm::LLVMDIBuilderCreateOpPlus(Type::i64(cx).to_ref()),
C_i64(cx, byte_offset_of_var_in_env as i64),
llvm::LLVMDIBuilderCreateOpDeref(Type::i64(cx).to_ref())]
};
let address_op_count = match closure_store {
ty::RegionTraitStore(..) => {
address_operations.len()
}
ty::UniqTraitStore => {
address_operations.len() - 1
}
};
let variable_access = IndirectVariable {
alloca: env_pointer,
address_operations: address_operations[..address_op_count]
};
declare_local(bcx,
variable_ident,
variable_type,
scope_metadata,
variable_access,
CapturedVariable,
span);
}
/// Creates debug information for a local variable introduced in the head of a
/// match-statement arm.
///
/// Adds the created metadata nodes directly to the crate's IR.
pub fn create_match_binding_metadata(bcx: Block,
variable_ident: ast::Ident,
binding: BindingInfo) {
if fn_should_be_ignored(bcx.fcx) {
return;
}
let scope_metadata = scope_metadata(bcx.fcx, binding.id, binding.span);
let aops = unsafe {
[llvm::LLVMDIBuilderCreateOpDeref(bcx.ccx().int_type().to_ref())]
};
// Regardless of the actual type (`T`) we're always passed the stack slot (alloca)
// for the binding. For ByRef bindings that's a `T*` but for ByMove bindings we
// actually have `T**`. So to get the actual variable we need to dereference once
// more. For ByCopy we just use the stack slot we created for the binding.
let var_type = match binding.trmode {
TrByCopy(llbinding) => DirectVariable {
alloca: llbinding
},
TrByMove => IndirectVariable {
alloca: binding.llmatch,
address_operations: aops
},
TrByRef => DirectVariable {
alloca: binding.llmatch
}
};
declare_local(bcx,
variable_ident,
binding.ty,
scope_metadata,
var_type,
LocalVariable,
binding.span);
}
/// Creates debug information for the given function argument.
///
/// Adds the created metadata nodes directly to the crate's IR.
pub fn create_argument_metadata(bcx: Block, arg: &ast::Arg) {
if fn_should_be_ignored(bcx.fcx) {
return;
}
let fcx = bcx.fcx;
let cx = fcx.ccx;