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 {
19091909 const gop = try dg.object.di_type_map.getOrPut(gpa, ty);
19101910 if (gop.found_existing) return gop.value_ptr.*;
19111911 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());
19121915 const target = dg.module.getTarget();
19131916 const dib = dg.object.di_builder.?;
19141917 switch (ty.zigTypeTag()) {
......@@ -2084,7 +2087,7 @@ pub const DeclGen = struct {
20842087 ),
20852088 };
20862089
2087 const replacement_di_type = dib.createStructType(
2090 const replacement_di_ty = dib.createStructType(
20882091 compile_unit_scope,
20892092 name.ptr,
20902093 di_file,
......@@ -2099,10 +2102,10 @@ pub const DeclGen = struct {
20992102 null, // vtable holder
21002103 "", // unique id
21012104 );
2102 dib.replaceTemporary(fwd_decl, replacement_di_type);
2105 dib.replaceTemporary(fwd_decl, replacement_di_ty);
21032106 // 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);
2105 return replacement_di_type;
2107 try dg.object.di_type_map.put(gpa, ty, replacement_di_ty);
2108 return replacement_di_ty;
21062109 }
21072110
21082111 const elem_di_ty = try lowerDebugType(dg, ptr_info.pointee_type);
......@@ -2118,6 +2121,10 @@ pub const DeclGen = struct {
21182121 return ptr_di_ty;
21192122 },
21202123 .Opaque => {
2124 if (ty.tag() == .anyopaque) {
2125 gop.value_ptr.* = dib.createBasicType("anyopaque", 0, DW.ATE.signed);
2126 return gop.value_ptr.*;
2127 }
21212128 const name = try ty.nameAlloc(gpa); // TODO this is a leak
21222129 const owner_decl = ty.getOwnerDecl();
21232130 const opaque_di_ty = dib.createForwardDeclType(
......@@ -2144,7 +2151,15 @@ pub const DeclGen = struct {
21442151 return array_di_ty;
21452152 },
21462153 .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;
21482163 },
21492164 .Optional => {
21502165 const name = try ty.nameAlloc(gpa); // TODO this is a leak
......@@ -2209,7 +2224,7 @@ pub const DeclGen = struct {
22092224 ),
22102225 };
22112226
2212 const replacement_di_type = dib.createStructType(
2227 const replacement_di_ty = dib.createStructType(
22132228 compile_unit_scope,
22142229 name.ptr,
22152230 di_file,
......@@ -2224,10 +2239,10 @@ pub const DeclGen = struct {
22242239 null, // vtable holder
22252240 "", // unique id
22262241 );
2227 dib.replaceTemporary(fwd_decl, replacement_di_type);
2242 dib.replaceTemporary(fwd_decl, replacement_di_ty);
22282243 // 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);
2230 return replacement_di_type;
2244 try dg.object.di_type_map.put(gpa, ty, replacement_di_ty);
2245 return replacement_di_ty;
22312246 },
22322247 .ErrorUnion => {
22332248 const err_set_ty = ty.errorUnionSet();
......@@ -2286,7 +2301,7 @@ pub const DeclGen = struct {
22862301 ),
22872302 };
22882303
2289 const replacement_di_type = dib.createStructType(
2304 const replacement_di_ty = dib.createStructType(
22902305 compile_unit_scope,
22912306 name.ptr,
22922307 di_file,
......@@ -2301,10 +2316,10 @@ pub const DeclGen = struct {
23012316 null, // vtable holder
23022317 "", // unique id
23032318 );
2304 dib.replaceTemporary(fwd_decl, replacement_di_type);
2319 dib.replaceTemporary(fwd_decl, replacement_di_ty);
23052320 // 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);
2307 return replacement_di_type;
2321 try dg.object.di_type_map.put(gpa, ty, replacement_di_ty);
2322 return replacement_di_ty;
23082323 },
23092324 .ErrorSet => {
23102325 // TODO make this a proper enum with all the error codes in it.
......@@ -2313,20 +2328,80 @@ pub const DeclGen = struct {
23132328 return gop.value_ptr.*;
23142329 },
23152330 .Struct => {
2316 const owner_decl = ty.getOwnerDecl();
2317
2331 const compile_unit_scope = dg.object.di_compile_unit.?.toScope();
23182332 const name = try ty.nameAlloc(gpa); // TODO this is a leak
23192333 const fwd_decl = dib.createReplaceableCompositeType(
23202334 DW.TAG.structure_type,
23212335 name.ptr,
2322 dg.object.di_compile_unit.?.toScope(),
2336 compile_unit_scope,
23232337 null, // file
23242338 0, // line
23252339 );
23262340 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
23282402 const TODO_implement_this = true; // TODO
23292403 if (TODO_implement_this or !ty.hasRuntimeBits()) {
2404 const owner_decl = ty.getOwnerDecl();
23302405 const struct_di_ty = try dg.makeEmptyNamespaceDIType(owner_decl);
23312406 dib.replaceTemporary(fwd_decl, struct_di_ty);
23322407 // The recursive call to `lowerDebugType` via `makeEmptyNamespaceDIType`
......@@ -2336,65 +2411,6 @@ pub const DeclGen = struct {
23362411 }
23372412 @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
23982414 //const struct_obj = ty.castTag(.@"struct").?.data;
23992415
24002416 //if (struct_obj.layout == .Packed) {
......@@ -2554,7 +2570,10 @@ pub const DeclGen = struct {
25542570 defer param_di_types.deinit();
25552571
25562572 // 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;
25582577 try param_di_types.append(try dg.lowerDebugType(di_ret_ty));
25592578
25602579 if (sret) {