authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2022-03-08 14:24:31-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2022-03-08 14:58:54-07:00
log874b51d8d4d80f224e979adba11526a5dcec61da
tree2061c7a0e3481ba500cad589651b880cc5b9eea8
parentfa57335ec64931b2e2b0413fc19cb0b53648cc0b

LLVM: add debug info for opaque, vector, and tuples

Also fix UAF of Type memory in the di_type_map.

1 files changed, 95 insertions(+), 76 deletions(-)

src/codegen/llvm.zig+95-76
...@@ -1909,6 +1909,9 @@ pub const DeclGen = struct {...@@ -1909,6 +1909,9 @@ pub const DeclGen = struct {
1909 const gop = try dg.object.di_type_map.getOrPut(gpa, ty);1909 const gop = try dg.object.di_type_map.getOrPut(gpa, ty);
1910 if (gop.found_existing) return gop.value_ptr.*;1910 if (gop.found_existing) return gop.value_ptr.*;
1911 errdefer assert(dg.object.di_type_map.remove(ty));1911 errdefer assert(dg.object.di_type_map.remove(ty));
1912 // The Type memory is ephemeral; since we want to store a longer-lived
1913 // reference, we need to copy it here.
1914 gop.key_ptr.* = try ty.copy(dg.object.type_map_arena.allocator());
1912 const target = dg.module.getTarget();1915 const target = dg.module.getTarget();
1913 const dib = dg.object.di_builder.?;1916 const dib = dg.object.di_builder.?;
1914 switch (ty.zigTypeTag()) {1917 switch (ty.zigTypeTag()) {
...@@ -2084,7 +2087,7 @@ pub const DeclGen = struct {...@@ -2084,7 +2087,7 @@ pub const DeclGen = struct {
2084 ),2087 ),
2085 };2088 };
20862089
2087 const replacement_di_type = dib.createStructType(2090 const replacement_di_ty = dib.createStructType(
2088 compile_unit_scope,2091 compile_unit_scope,
2089 name.ptr,2092 name.ptr,
2090 di_file,2093 di_file,
...@@ -2099,10 +2102,10 @@ pub const DeclGen = struct {...@@ -2099,10 +2102,10 @@ pub const DeclGen = struct {
2099 null, // vtable holder2102 null, // vtable holder
2100 "", // unique id2103 "", // unique id
2101 );2104 );
2102 dib.replaceTemporary(fwd_decl, replacement_di_type);2105 dib.replaceTemporary(fwd_decl, replacement_di_ty);
2103 // The recursive call to `lowerDebugType` means we can't use `gop` anymore.2106 // The recursive call to `lowerDebugType` means we can't use `gop` anymore.
2104 try dg.object.di_type_map.put(gpa, ty, replacement_di_type);2107 try dg.object.di_type_map.put(gpa, ty, replacement_di_ty);
2105 return replacement_di_type;2108 return replacement_di_ty;
2106 }2109 }
21072110
2108 const elem_di_ty = try lowerDebugType(dg, ptr_info.pointee_type);2111 const elem_di_ty = try lowerDebugType(dg, ptr_info.pointee_type);
...@@ -2118,6 +2121,10 @@ pub const DeclGen = struct {...@@ -2118,6 +2121,10 @@ pub const DeclGen = struct {
2118 return ptr_di_ty;2121 return ptr_di_ty;
2119 },2122 },
2120 .Opaque => {2123 .Opaque => {
2124 if (ty.tag() == .anyopaque) {
2125 gop.value_ptr.* = dib.createBasicType("anyopaque", 0, DW.ATE.signed);
2126 return gop.value_ptr.*;
2127 }
2121 const name = try ty.nameAlloc(gpa); // TODO this is a leak2128 const name = try ty.nameAlloc(gpa); // TODO this is a leak
2122 const owner_decl = ty.getOwnerDecl();2129 const owner_decl = ty.getOwnerDecl();
2123 const opaque_di_ty = dib.createForwardDeclType(2130 const opaque_di_ty = dib.createForwardDeclType(
...@@ -2144,7 +2151,15 @@ pub const DeclGen = struct {...@@ -2144,7 +2151,15 @@ pub const DeclGen = struct {
2144 return array_di_ty;2151 return array_di_ty;
2145 },2152 },
2146 .Vector => {2153 .Vector => {
2147 @panic("TODO debug info type for vector");2154 const vector_di_ty = dib.createVectorType(
2155 ty.abiSize(target) * 8,
2156 ty.abiAlignment(target) * 8,
2157 try lowerDebugType(dg, ty.childType()),
2158 ty.vectorLen(),
2159 );
2160 // The recursive call to `lowerDebugType` means we can't use `gop` anymore.
2161 try dg.object.di_type_map.put(gpa, ty, vector_di_ty);
2162 return vector_di_ty;
2148 },2163 },
2149 .Optional => {2164 .Optional => {
2150 const name = try ty.nameAlloc(gpa); // TODO this is a leak2165 const name = try ty.nameAlloc(gpa); // TODO this is a leak
...@@ -2209,7 +2224,7 @@ pub const DeclGen = struct {...@@ -2209,7 +2224,7 @@ pub const DeclGen = struct {
2209 ),2224 ),
2210 };2225 };
22112226
2212 const replacement_di_type = dib.createStructType(2227 const replacement_di_ty = dib.createStructType(
2213 compile_unit_scope,2228 compile_unit_scope,
2214 name.ptr,2229 name.ptr,
2215 di_file,2230 di_file,
...@@ -2224,10 +2239,10 @@ pub const DeclGen = struct {...@@ -2224,10 +2239,10 @@ pub const DeclGen = struct {
2224 null, // vtable holder2239 null, // vtable holder
2225 "", // unique id2240 "", // unique id
2226 );2241 );
2227 dib.replaceTemporary(fwd_decl, replacement_di_type);2242 dib.replaceTemporary(fwd_decl, replacement_di_ty);
2228 // The recursive call to `lowerDebugType` means we can't use `gop` anymore.2243 // The recursive call to `lowerDebugType` means we can't use `gop` anymore.
2229 try dg.object.di_type_map.put(gpa, ty, replacement_di_type);2244 try dg.object.di_type_map.put(gpa, ty, replacement_di_ty);
2230 return replacement_di_type;2245 return replacement_di_ty;
2231 },2246 },
2232 .ErrorUnion => {2247 .ErrorUnion => {
2233 const err_set_ty = ty.errorUnionSet();2248 const err_set_ty = ty.errorUnionSet();
...@@ -2286,7 +2301,7 @@ pub const DeclGen = struct {...@@ -2286,7 +2301,7 @@ pub const DeclGen = struct {
2286 ),2301 ),
2287 };2302 };
22882303
2289 const replacement_di_type = dib.createStructType(2304 const replacement_di_ty = dib.createStructType(
2290 compile_unit_scope,2305 compile_unit_scope,
2291 name.ptr,2306 name.ptr,
2292 di_file,2307 di_file,
...@@ -2301,10 +2316,10 @@ pub const DeclGen = struct {...@@ -2301,10 +2316,10 @@ pub const DeclGen = struct {
2301 null, // vtable holder2316 null, // vtable holder
2302 "", // unique id2317 "", // unique id
2303 );2318 );
2304 dib.replaceTemporary(fwd_decl, replacement_di_type);2319 dib.replaceTemporary(fwd_decl, replacement_di_ty);
2305 // The recursive call to `lowerDebugType` means we can't use `gop` anymore.2320 // The recursive call to `lowerDebugType` means we can't use `gop` anymore.
2306 try dg.object.di_type_map.put(gpa, ty, replacement_di_type);2321 try dg.object.di_type_map.put(gpa, ty, replacement_di_ty);
2307 return replacement_di_type;2322 return replacement_di_ty;
2308 },2323 },
2309 .ErrorSet => {2324 .ErrorSet => {
2310 // TODO make this a proper enum with all the error codes in it.2325 // TODO make this a proper enum with all the error codes in it.
...@@ -2313,20 +2328,80 @@ pub const DeclGen = struct {...@@ -2313,20 +2328,80 @@ pub const DeclGen = struct {
2313 return gop.value_ptr.*;2328 return gop.value_ptr.*;
2314 },2329 },
2315 .Struct => {2330 .Struct => {
2316 const owner_decl = ty.getOwnerDecl();2331 const compile_unit_scope = dg.object.di_compile_unit.?.toScope();
2317
2318 const name = try ty.nameAlloc(gpa); // TODO this is a leak2332 const name = try ty.nameAlloc(gpa); // TODO this is a leak
2319 const fwd_decl = dib.createReplaceableCompositeType(2333 const fwd_decl = dib.createReplaceableCompositeType(
2320 DW.TAG.structure_type,2334 DW.TAG.structure_type,
2321 name.ptr,2335 name.ptr,
2322 dg.object.di_compile_unit.?.toScope(),2336 compile_unit_scope,
2323 null, // file2337 null, // file
2324 0, // line2338 0, // line
2325 );2339 );
2326 gop.value_ptr.* = fwd_decl;2340 gop.value_ptr.* = fwd_decl;
23272341
2342 if (ty.isTupleOrAnonStruct()) {
2343 const tuple = ty.tupleFields();
2344
2345 var di_fields: std.ArrayListUnmanaged(*llvm.DIType) = .{};
2346 defer di_fields.deinit(gpa);
2347
2348 try di_fields.ensureUnusedCapacity(gpa, tuple.types.len);
2349
2350 comptime assert(struct_layout_version == 2);
2351 var offset: u64 = 0;
2352
2353 for (tuple.types) |field_ty, i| {
2354 const field_val = tuple.values[i];
2355 if (field_val.tag() != .unreachable_value) continue;
2356
2357 const field_size = field_ty.abiSize(target);
2358 const field_align = field_ty.abiAlignment(target);
2359 const field_offset = std.mem.alignForwardGeneric(u64, offset, field_align);
2360 offset = field_offset + field_size;
2361
2362 const field_name = if (ty.castTag(.anon_struct)) |payload|
2363 try gpa.dupeZ(u8, payload.data.names[i])
2364 else
2365 try std.fmt.allocPrintZ(gpa, "{d}", .{i});
2366 defer gpa.free(field_name);
2367
2368 try di_fields.append(gpa, dib.createMemberType(
2369 fwd_decl.toScope(),
2370 field_name,
2371 null, // file
2372 0, // line
2373 field_size * 8, // size in bits
2374 field_align * 8, // align in bits
2375 field_offset * 8, // offset in bits
2376 0, // flags
2377 try dg.lowerDebugType(field_ty),
2378 ));
2379 }
2380
2381 const replacement_di_ty = dib.createStructType(
2382 compile_unit_scope,
2383 name.ptr,
2384 null, // file
2385 0, // line
2386 ty.abiSize(target) * 8, // size in bits
2387 ty.abiAlignment(target) * 8, // align in bits
2388 0, // flags
2389 null, // derived from
2390 di_fields.items.ptr,
2391 @intCast(c_int, di_fields.items.len),
2392 0, // run time lang
2393 null, // vtable holder
2394 "", // unique id
2395 );
2396 dib.replaceTemporary(fwd_decl, replacement_di_ty);
2397 // The recursive call to `lowerDebugType` means we can't use `gop` anymore.
2398 try dg.object.di_type_map.put(gpa, ty, replacement_di_ty);
2399 return replacement_di_ty;
2400 }
2401
2328 const TODO_implement_this = true; // TODO2402 const TODO_implement_this = true; // TODO
2329 if (TODO_implement_this or !ty.hasRuntimeBits()) {2403 if (TODO_implement_this or !ty.hasRuntimeBits()) {
2404 const owner_decl = ty.getOwnerDecl();
2330 const struct_di_ty = try dg.makeEmptyNamespaceDIType(owner_decl);2405 const struct_di_ty = try dg.makeEmptyNamespaceDIType(owner_decl);
2331 dib.replaceTemporary(fwd_decl, struct_di_ty);2406 dib.replaceTemporary(fwd_decl, struct_di_ty);
2332 // The recursive call to `lowerDebugType` via `makeEmptyNamespaceDIType`2407 // The recursive call to `lowerDebugType` via `makeEmptyNamespaceDIType`
...@@ -2336,65 +2411,6 @@ pub const DeclGen = struct {...@@ -2336,65 +2411,6 @@ pub const DeclGen = struct {
2336 }2411 }
2337 @panic("TODO debug info type for struct");2412 @panic("TODO debug info type for struct");
23382413
2339 //const gop = try dg.object.type_map.getOrPut(gpa, ty);
2340 //if (gop.found_existing) return gop.value_ptr.*;
2341
2342 //// The Type memory is ephemeral; since we want to store a longer-lived
2343 //// reference, we need to copy it here.
2344 //gop.key_ptr.* = try ty.copy(dg.object.type_map_arena.allocator());
2345
2346 //if (ty.isTupleOrAnonStruct()) {
2347 // const tuple = ty.tupleFields();
2348 // const llvm_struct_ty = dg.context.structCreateNamed("");
2349 // gop.value_ptr.* = llvm_struct_ty; // must be done before any recursive calls
2350
2351 // var llvm_field_types: std.ArrayListUnmanaged(*const llvm.Type) = .{};
2352 // defer llvm_field_types.deinit(gpa);
2353
2354 // try llvm_field_types.ensureUnusedCapacity(gpa, tuple.types.len);
2355
2356 // comptime assert(struct_layout_version == 2);
2357 // var offset: u64 = 0;
2358 // var big_align: u32 = 0;
2359
2360 // for (tuple.types) |field_ty, i| {
2361 // const field_val = tuple.values[i];
2362 // if (field_val.tag() != .unreachable_value) continue;
2363
2364 // const field_align = field_ty.abiAlignment(target);
2365 // big_align = @maximum(big_align, field_align);
2366 // const prev_offset = offset;
2367 // offset = std.mem.alignForwardGeneric(u64, offset, field_align);
2368
2369 // const padding_len = offset - prev_offset;
2370 // if (padding_len > 0) {
2371 // const llvm_array_ty = dg.context.intType(8).arrayType(@intCast(c_uint, padding_len));
2372 // try llvm_field_types.append(gpa, llvm_array_ty);
2373 // }
2374 // const field_llvm_ty = try dg.llvmType(field_ty);
2375 // try llvm_field_types.append(gpa, field_llvm_ty);
2376
2377 // offset += field_ty.abiSize(target);
2378 // }
2379 // {
2380 // const prev_offset = offset;
2381 // offset = std.mem.alignForwardGeneric(u64, offset, big_align);
2382 // const padding_len = offset - prev_offset;
2383 // if (padding_len > 0) {
2384 // const llvm_array_ty = dg.context.intType(8).arrayType(@intCast(c_uint, padding_len));
2385 // try llvm_field_types.append(gpa, llvm_array_ty);
2386 // }
2387 // }
2388
2389 // llvm_struct_ty.structSetBody(
2390 // llvm_field_types.items.ptr,
2391 // @intCast(c_uint, llvm_field_types.items.len),
2392 // .False,
2393 // );
2394
2395 // return llvm_struct_ty;
2396 //}
2397
2398 //const struct_obj = ty.castTag(.@"struct").?.data;2414 //const struct_obj = ty.castTag(.@"struct").?.data;
23992415
2400 //if (struct_obj.layout == .Packed) {2416 //if (struct_obj.layout == .Packed) {
...@@ -2554,7 +2570,10 @@ pub const DeclGen = struct {...@@ -2554,7 +2570,10 @@ pub const DeclGen = struct {
2554 defer param_di_types.deinit();2570 defer param_di_types.deinit();
25552571
2556 // Return type goes first.2572 // Return type goes first.
2557 const di_ret_ty = if (sret) Type.void else fn_info.return_type;2573 const di_ret_ty = if (sret or !fn_info.return_type.hasRuntimeBits())
2574 Type.void
2575 else
2576 fn_info.return_type;
2558 try param_di_types.append(try dg.lowerDebugType(di_ret_ty));2577 try param_di_types.append(try dg.lowerDebugType(di_ret_ty));
25592578
2560 if (sret) {2579 if (sret) {