1
+ import std:: { vec, str, map, option, unsafe} ;
2
+ import std:: vec:: to_ptr;
3
+ import std:: map:: hashmap;
4
+ import lib:: llvm:: llvm;
5
+ import lib:: llvm:: llvm:: { ModuleRef , ValueRef } ;
6
+ import middle:: trans_common:: * ;
7
+ import syntax:: { ast, codemap} ;
8
+
9
+ const LLVMDebugVersion : int = 0x80000 ;
10
+
11
+ const DW_LANG_RUST : int = 0x9000 ;
12
+ const DW_VIRTUALITY_none : int = 0 ;
13
+
14
+ const CompileUnitTag : int = 17 ;
15
+ const FileDescriptorTag : int = 41 ;
16
+ const SubprogramTag : int = 46 ;
17
+
18
+ fn as_buf ( s : str ) -> str:: sbuf {
19
+ str:: as_buf ( s, { |sbuf| sbuf} )
20
+ }
21
+ fn llstr ( s : str ) -> ValueRef {
22
+ llvm:: LLVMMDString ( as_buf ( s) , str:: byte_len ( s) )
23
+ }
24
+
25
+ fn lltag ( lltag : int ) -> ValueRef {
26
+ lli32 ( 0x80000 + lltag)
27
+ }
28
+ fn lli32 ( val : int ) -> ValueRef {
29
+ C_i32 ( val as i32 )
30
+ }
31
+ fn lli1 ( bval : bool ) -> ValueRef {
32
+ C_bool ( bval)
33
+ }
34
+ fn llmdnode ( elems : [ ValueRef ] ) -> ValueRef unsafe {
35
+ llvm:: LLVMMDNode ( vec:: unsafe:: to_ptr ( elems) ,
36
+ vec:: len ( elems) )
37
+ }
38
+ fn llunused ( ) -> ValueRef {
39
+ lli32 ( 0x0 )
40
+ }
41
+
42
+ fn update_cache ( cache : metadata_cache , mdtag : int , val : debug_metadata ) {
43
+ let existing = if cache. contains_key ( mdtag) {
44
+ cache. get ( mdtag)
45
+ } else {
46
+ [ ]
47
+ } ;
48
+ cache. insert ( mdtag, existing + [ val] ) ;
49
+ }
50
+
51
+ ////////////////
52
+
53
+ type metadata < T > = { node : ValueRef , data : T } ;
54
+
55
+ type file_md = { path: str } ;
56
+ type compile_unit_md = { path: str } ;
57
+ type subprogram_md = { name : str , file : str } ;
58
+
59
+ type metadata_cache = hashmap < int , [ debug_metadata ] > ;
60
+
61
+ tag debug_metadata {
62
+ file_metadata( @metadata<file_md>) ;
63
+ compile_unit_metadata ( @metadata<compile_unit_md>) ;
64
+ subprogram_metadata ( @metadata<subprogram_md>) ;
65
+ }
66
+
67
+ fn md_from_metadata < T > ( val : debug_metadata ) -> T unsafe {
68
+ alt val {
69
+ file_metadata( md) { unsafe :: reinterpret_cast ( md) }
70
+ compile_unit_metadata ( md) { unsafe :: reinterpret_cast ( md) }
71
+ subprogram_metadata ( md) { unsafe :: reinterpret_cast ( md) }
72
+ }
73
+ }
74
+
75
+ fn cached_metadata < T > ( cache : metadata_cache , mdtag : int ,
76
+ eq : block ( md : T ) -> bool ) -> option:: t < T > {
77
+ if cache. contains_key ( mdtag) {
78
+ let items = cache. get ( mdtag) ;
79
+ for item in items {
80
+ let md: T = md_from_metadata :: < T > ( item) ;
81
+ if eq ( md) {
82
+ ret option:: some ( md) ;
83
+ }
84
+ }
85
+ }
86
+ ret option:: none;
87
+ }
88
+
89
+ fn get_compile_unit_metadata ( cx : @crate_ctxt , full_path : str )
90
+ -> @metadata < compile_unit_md > {
91
+ let cache = cx. llmetadata ;
92
+ alt cached_metadata :: < @metadata < compile_unit_md > > ( cache, CompileUnitTag ,
93
+ { |md| md. data . path == full_path} ) {
94
+ option:: some ( md) { ret md; }
95
+ option:: none. { }
96
+ }
97
+ let sep = str:: rindex ( full_path, '/' as u8 ) as uint ;
98
+ let fname = str:: slice ( full_path, sep + 1 u,
99
+ str:: byte_len ( full_path) ) ;
100
+ let path = str:: slice ( full_path, 0 u, sep + 1 u) ;
101
+ let unit_metadata = [ lltag ( CompileUnitTag ) ,
102
+ llunused ( ) ,
103
+ lli32 ( DW_LANG_RUST ) ,
104
+ llstr ( fname) ,
105
+ llstr ( path) ,
106
+ llstr ( #env[ "CFG_VERSION" ] ) ,
107
+ lli1 ( false ) , // main compile unit
108
+ lli1 ( cx. sess . get_opts ( ) . optimize != 0 u) ,
109
+ llstr ( "" ) , // flags (???)
110
+ lli32 ( 0 ) // runtime version (???)
111
+ // list of enum types
112
+ // list of retained values
113
+ // list of subprograms
114
+ // list of global variables
115
+ ] ;
116
+ let unit_node = llmdnode ( unit_metadata) ;
117
+ llvm:: LLVMAddNamedMetadataOperand ( cx. llmod , as_buf ( "llvm.dbg.cu" ) ,
118
+ str:: byte_len ( "llvm.dbg.cu" ) ,
119
+ unit_node) ;
120
+ let mdval = @{ node: unit_node, data : { path : full_path} } ;
121
+ update_cache ( cache, CompileUnitTag , compile_unit_metadata ( mdval) ) ;
122
+ ret mdval;
123
+ }
124
+
125
+ // let kind_id = llvm::LLVMGetMDKindID(as_buf("dbg"),
126
+ // str::byte_len("dbg"));
127
+
128
+
129
+ fn get_file_metadata ( cx : @crate_ctxt , full_path : str ) -> @metadata < file_md > {
130
+ let cache = cx. llmetadata ;
131
+ alt cached_metadata :: < @metadata < file_md > > (
132
+ cache, FileDescriptorTag , { |md| md. data . path == full_path} ) {
133
+ option:: some ( md) { ret md; }
134
+ option:: none. { }
135
+ }
136
+ let sep = str:: rindex ( full_path, '/' as u8 ) as uint ;
137
+ let fname = str:: slice ( full_path, sep + 1 u,
138
+ str:: byte_len ( full_path) ) ;
139
+ let path = str:: slice ( full_path, 0 u, sep + 1 u) ;
140
+ let unit_node = get_compile_unit_metadata ( cx, path) . node ;
141
+ let file_md = [ lltag ( FileDescriptorTag ) ,
142
+ llstr ( fname) ,
143
+ llstr ( path) ,
144
+ unit_node] ;
145
+ let val = llmdnode ( file_md) ;
146
+ let mdval = @{ node: val, data : { path : full_path} } ;
147
+ update_cache ( cache, FileDescriptorTag , file_metadata ( mdval) ) ;
148
+ ret mdval;
149
+ }
150
+
151
+ fn get_function_metadata ( cx : @crate_ctxt , item : @ast:: item ,
152
+ llfndecl : ValueRef ) -> @metadata < subprogram_md > {
153
+ let cache = cx. llmetadata ;
154
+ alt cached_metadata :: < @metadata < subprogram_md > > (
155
+ cache, SubprogramTag , { |md| md. data . name == item. ident &&
156
+ /*sub.path == ??*/ true } ) {
157
+ option:: some ( md) { ret md; }
158
+ option:: none. { }
159
+ }
160
+ let loc = codemap:: lookup_char_pos ( cx. sess . get_codemap ( ) ,
161
+ item. span . lo ) ;
162
+ let file_node = get_file_metadata ( cx, loc. filename ) . node ;
163
+ let fn_metadata = [ lltag ( SubprogramTag ) ,
164
+ llunused ( ) ,
165
+ file_node,
166
+ llstr ( item. ident ) ,
167
+ llstr ( item. ident ) , //XXX fully-qualified C++ name
168
+ llstr ( item. ident ) , //XXX MIPS name?????
169
+ file_node,
170
+ lli32 ( loc. line as int ) ,
171
+ C_null ( T_ptr ( T_nil ( ) ) ) , // XXX reference to tydesc
172
+ lli1 ( false ) , //XXX static
173
+ lli1 ( true ) , // not extern
174
+ lli32 ( DW_VIRTUALITY_none ) , // virtual-ness
175
+ lli32 ( 0 i) , //index into virt func
176
+ C_null ( T_ptr ( T_nil ( ) ) ) , // base type with vtbl
177
+ lli1 ( false ) , // artificial
178
+ lli1 ( cx. sess . get_opts ( ) . optimize != 0 u) ,
179
+ llfndecl
180
+ //list of template params
181
+ //func decl descriptor
182
+ //list of func vars
183
+ ] ;
184
+ let val = llmdnode ( fn_metadata) ;
185
+ llvm:: LLVMAddNamedMetadataOperand ( cx. llmod , as_buf ( "llvm.dbg.sp" ) ,
186
+ str:: byte_len ( "llvm.dbg.sp" ) ,
187
+ val) ;
188
+ let mdval = @{ node: val, data : { name : item. ident ,
189
+ file : loc. filename } } ;
190
+ update_cache ( cache, SubprogramTag , subprogram_metadata ( mdval) ) ;
191
+ ret mdval;
192
+ }
0 commit comments