Skip to content

Commit 874b51d

Browse files
committed
LLVM: add debug info for opaque, vector, and tuples
Also fix UAF of Type memory in the di_type_map.
1 parent fa57335 commit 874b51d

File tree

1 file changed

+95
-76
lines changed

1 file changed

+95
-76
lines changed

src/codegen/llvm.zig

Lines changed: 95 additions & 76 deletions
Original file line numberDiff line numberDiff line change
@@ -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) {

0 commit comments

Comments
 (0)