mirror of
https://codeberg.org/ziglang/zig.git
synced 2025-12-09 15:19:07 +00:00
LLVM: add debug info for opaque, vector, and tuples
Also fix UAF of Type memory in the di_type_map.
This commit is contained in:
parent
fa57335ec6
commit
874b51d8d4
1 changed files with 95 additions and 76 deletions
|
|
@ -1909,6 +1909,9 @@ pub const DeclGen = struct {
|
|||
const gop = try dg.object.di_type_map.getOrPut(gpa, ty);
|
||||
if (gop.found_existing) return gop.value_ptr.*;
|
||||
errdefer assert(dg.object.di_type_map.remove(ty));
|
||||
// The Type memory is ephemeral; since we want to store a longer-lived
|
||||
// reference, we need to copy it here.
|
||||
gop.key_ptr.* = try ty.copy(dg.object.type_map_arena.allocator());
|
||||
const target = dg.module.getTarget();
|
||||
const dib = dg.object.di_builder.?;
|
||||
switch (ty.zigTypeTag()) {
|
||||
|
|
@ -2084,7 +2087,7 @@ pub const DeclGen = struct {
|
|||
),
|
||||
};
|
||||
|
||||
const replacement_di_type = dib.createStructType(
|
||||
const replacement_di_ty = dib.createStructType(
|
||||
compile_unit_scope,
|
||||
name.ptr,
|
||||
di_file,
|
||||
|
|
@ -2099,10 +2102,10 @@ pub const DeclGen = struct {
|
|||
null, // vtable holder
|
||||
"", // unique id
|
||||
);
|
||||
dib.replaceTemporary(fwd_decl, replacement_di_type);
|
||||
dib.replaceTemporary(fwd_decl, replacement_di_ty);
|
||||
// The recursive call to `lowerDebugType` means we can't use `gop` anymore.
|
||||
try dg.object.di_type_map.put(gpa, ty, replacement_di_type);
|
||||
return replacement_di_type;
|
||||
try dg.object.di_type_map.put(gpa, ty, replacement_di_ty);
|
||||
return replacement_di_ty;
|
||||
}
|
||||
|
||||
const elem_di_ty = try lowerDebugType(dg, ptr_info.pointee_type);
|
||||
|
|
@ -2118,6 +2121,10 @@ pub const DeclGen = struct {
|
|||
return ptr_di_ty;
|
||||
},
|
||||
.Opaque => {
|
||||
if (ty.tag() == .anyopaque) {
|
||||
gop.value_ptr.* = dib.createBasicType("anyopaque", 0, DW.ATE.signed);
|
||||
return gop.value_ptr.*;
|
||||
}
|
||||
const name = try ty.nameAlloc(gpa); // TODO this is a leak
|
||||
const owner_decl = ty.getOwnerDecl();
|
||||
const opaque_di_ty = dib.createForwardDeclType(
|
||||
|
|
@ -2144,7 +2151,15 @@ pub const DeclGen = struct {
|
|||
return array_di_ty;
|
||||
},
|
||||
.Vector => {
|
||||
@panic("TODO debug info type for vector");
|
||||
const vector_di_ty = dib.createVectorType(
|
||||
ty.abiSize(target) * 8,
|
||||
ty.abiAlignment(target) * 8,
|
||||
try lowerDebugType(dg, ty.childType()),
|
||||
ty.vectorLen(),
|
||||
);
|
||||
// The recursive call to `lowerDebugType` means we can't use `gop` anymore.
|
||||
try dg.object.di_type_map.put(gpa, ty, vector_di_ty);
|
||||
return vector_di_ty;
|
||||
},
|
||||
.Optional => {
|
||||
const name = try ty.nameAlloc(gpa); // TODO this is a leak
|
||||
|
|
@ -2209,7 +2224,7 @@ pub const DeclGen = struct {
|
|||
),
|
||||
};
|
||||
|
||||
const replacement_di_type = dib.createStructType(
|
||||
const replacement_di_ty = dib.createStructType(
|
||||
compile_unit_scope,
|
||||
name.ptr,
|
||||
di_file,
|
||||
|
|
@ -2224,10 +2239,10 @@ pub const DeclGen = struct {
|
|||
null, // vtable holder
|
||||
"", // unique id
|
||||
);
|
||||
dib.replaceTemporary(fwd_decl, replacement_di_type);
|
||||
dib.replaceTemporary(fwd_decl, replacement_di_ty);
|
||||
// The recursive call to `lowerDebugType` means we can't use `gop` anymore.
|
||||
try dg.object.di_type_map.put(gpa, ty, replacement_di_type);
|
||||
return replacement_di_type;
|
||||
try dg.object.di_type_map.put(gpa, ty, replacement_di_ty);
|
||||
return replacement_di_ty;
|
||||
},
|
||||
.ErrorUnion => {
|
||||
const err_set_ty = ty.errorUnionSet();
|
||||
|
|
@ -2286,7 +2301,7 @@ pub const DeclGen = struct {
|
|||
),
|
||||
};
|
||||
|
||||
const replacement_di_type = dib.createStructType(
|
||||
const replacement_di_ty = dib.createStructType(
|
||||
compile_unit_scope,
|
||||
name.ptr,
|
||||
di_file,
|
||||
|
|
@ -2301,10 +2316,10 @@ pub const DeclGen = struct {
|
|||
null, // vtable holder
|
||||
"", // unique id
|
||||
);
|
||||
dib.replaceTemporary(fwd_decl, replacement_di_type);
|
||||
dib.replaceTemporary(fwd_decl, replacement_di_ty);
|
||||
// The recursive call to `lowerDebugType` means we can't use `gop` anymore.
|
||||
try dg.object.di_type_map.put(gpa, ty, replacement_di_type);
|
||||
return replacement_di_type;
|
||||
try dg.object.di_type_map.put(gpa, ty, replacement_di_ty);
|
||||
return replacement_di_ty;
|
||||
},
|
||||
.ErrorSet => {
|
||||
// TODO make this a proper enum with all the error codes in it.
|
||||
|
|
@ -2313,20 +2328,80 @@ pub const DeclGen = struct {
|
|||
return gop.value_ptr.*;
|
||||
},
|
||||
.Struct => {
|
||||
const owner_decl = ty.getOwnerDecl();
|
||||
|
||||
const compile_unit_scope = dg.object.di_compile_unit.?.toScope();
|
||||
const name = try ty.nameAlloc(gpa); // TODO this is a leak
|
||||
const fwd_decl = dib.createReplaceableCompositeType(
|
||||
DW.TAG.structure_type,
|
||||
name.ptr,
|
||||
dg.object.di_compile_unit.?.toScope(),
|
||||
compile_unit_scope,
|
||||
null, // file
|
||||
0, // line
|
||||
);
|
||||
gop.value_ptr.* = fwd_decl;
|
||||
|
||||
if (ty.isTupleOrAnonStruct()) {
|
||||
const tuple = ty.tupleFields();
|
||||
|
||||
var di_fields: std.ArrayListUnmanaged(*llvm.DIType) = .{};
|
||||
defer di_fields.deinit(gpa);
|
||||
|
||||
try di_fields.ensureUnusedCapacity(gpa, tuple.types.len);
|
||||
|
||||
comptime assert(struct_layout_version == 2);
|
||||
var offset: u64 = 0;
|
||||
|
||||
for (tuple.types) |field_ty, i| {
|
||||
const field_val = tuple.values[i];
|
||||
if (field_val.tag() != .unreachable_value) continue;
|
||||
|
||||
const field_size = field_ty.abiSize(target);
|
||||
const field_align = field_ty.abiAlignment(target);
|
||||
const field_offset = std.mem.alignForwardGeneric(u64, offset, field_align);
|
||||
offset = field_offset + field_size;
|
||||
|
||||
const field_name = if (ty.castTag(.anon_struct)) |payload|
|
||||
try gpa.dupeZ(u8, payload.data.names[i])
|
||||
else
|
||||
try std.fmt.allocPrintZ(gpa, "{d}", .{i});
|
||||
defer gpa.free(field_name);
|
||||
|
||||
try di_fields.append(gpa, dib.createMemberType(
|
||||
fwd_decl.toScope(),
|
||||
field_name,
|
||||
null, // file
|
||||
0, // line
|
||||
field_size * 8, // size in bits
|
||||
field_align * 8, // align in bits
|
||||
field_offset * 8, // offset in bits
|
||||
0, // flags
|
||||
try dg.lowerDebugType(field_ty),
|
||||
));
|
||||
}
|
||||
|
||||
const replacement_di_ty = dib.createStructType(
|
||||
compile_unit_scope,
|
||||
name.ptr,
|
||||
null, // file
|
||||
0, // line
|
||||
ty.abiSize(target) * 8, // size in bits
|
||||
ty.abiAlignment(target) * 8, // align in bits
|
||||
0, // flags
|
||||
null, // derived from
|
||||
di_fields.items.ptr,
|
||||
@intCast(c_int, di_fields.items.len),
|
||||
0, // run time lang
|
||||
null, // vtable holder
|
||||
"", // unique id
|
||||
);
|
||||
dib.replaceTemporary(fwd_decl, replacement_di_ty);
|
||||
// The recursive call to `lowerDebugType` means we can't use `gop` anymore.
|
||||
try dg.object.di_type_map.put(gpa, ty, replacement_di_ty);
|
||||
return replacement_di_ty;
|
||||
}
|
||||
|
||||
const TODO_implement_this = true; // TODO
|
||||
if (TODO_implement_this or !ty.hasRuntimeBits()) {
|
||||
const owner_decl = ty.getOwnerDecl();
|
||||
const struct_di_ty = try dg.makeEmptyNamespaceDIType(owner_decl);
|
||||
dib.replaceTemporary(fwd_decl, struct_di_ty);
|
||||
// The recursive call to `lowerDebugType` via `makeEmptyNamespaceDIType`
|
||||
|
|
@ -2336,65 +2411,6 @@ pub const DeclGen = struct {
|
|||
}
|
||||
@panic("TODO debug info type for struct");
|
||||
|
||||
//const gop = try dg.object.type_map.getOrPut(gpa, ty);
|
||||
//if (gop.found_existing) return gop.value_ptr.*;
|
||||
|
||||
//// The Type memory is ephemeral; since we want to store a longer-lived
|
||||
//// reference, we need to copy it here.
|
||||
//gop.key_ptr.* = try ty.copy(dg.object.type_map_arena.allocator());
|
||||
|
||||
//if (ty.isTupleOrAnonStruct()) {
|
||||
// const tuple = ty.tupleFields();
|
||||
// const llvm_struct_ty = dg.context.structCreateNamed("");
|
||||
// gop.value_ptr.* = llvm_struct_ty; // must be done before any recursive calls
|
||||
|
||||
// var llvm_field_types: std.ArrayListUnmanaged(*const llvm.Type) = .{};
|
||||
// defer llvm_field_types.deinit(gpa);
|
||||
|
||||
// try llvm_field_types.ensureUnusedCapacity(gpa, tuple.types.len);
|
||||
|
||||
// comptime assert(struct_layout_version == 2);
|
||||
// var offset: u64 = 0;
|
||||
// var big_align: u32 = 0;
|
||||
|
||||
// for (tuple.types) |field_ty, i| {
|
||||
// const field_val = tuple.values[i];
|
||||
// if (field_val.tag() != .unreachable_value) continue;
|
||||
|
||||
// const field_align = field_ty.abiAlignment(target);
|
||||
// big_align = @maximum(big_align, field_align);
|
||||
// const prev_offset = offset;
|
||||
// offset = std.mem.alignForwardGeneric(u64, offset, field_align);
|
||||
|
||||
// const padding_len = offset - prev_offset;
|
||||
// if (padding_len > 0) {
|
||||
// const llvm_array_ty = dg.context.intType(8).arrayType(@intCast(c_uint, padding_len));
|
||||
// try llvm_field_types.append(gpa, llvm_array_ty);
|
||||
// }
|
||||
// const field_llvm_ty = try dg.llvmType(field_ty);
|
||||
// try llvm_field_types.append(gpa, field_llvm_ty);
|
||||
|
||||
// offset += field_ty.abiSize(target);
|
||||
// }
|
||||
// {
|
||||
// const prev_offset = offset;
|
||||
// offset = std.mem.alignForwardGeneric(u64, offset, big_align);
|
||||
// const padding_len = offset - prev_offset;
|
||||
// if (padding_len > 0) {
|
||||
// const llvm_array_ty = dg.context.intType(8).arrayType(@intCast(c_uint, padding_len));
|
||||
// try llvm_field_types.append(gpa, llvm_array_ty);
|
||||
// }
|
||||
// }
|
||||
|
||||
// llvm_struct_ty.structSetBody(
|
||||
// llvm_field_types.items.ptr,
|
||||
// @intCast(c_uint, llvm_field_types.items.len),
|
||||
// .False,
|
||||
// );
|
||||
|
||||
// return llvm_struct_ty;
|
||||
//}
|
||||
|
||||
//const struct_obj = ty.castTag(.@"struct").?.data;
|
||||
|
||||
//if (struct_obj.layout == .Packed) {
|
||||
|
|
@ -2554,7 +2570,10 @@ pub const DeclGen = struct {
|
|||
defer param_di_types.deinit();
|
||||
|
||||
// Return type goes first.
|
||||
const di_ret_ty = if (sret) Type.void else fn_info.return_type;
|
||||
const di_ret_ty = if (sret or !fn_info.return_type.hasRuntimeBits())
|
||||
Type.void
|
||||
else
|
||||
fn_info.return_type;
|
||||
try param_di_types.append(try dg.lowerDebugType(di_ret_ty));
|
||||
|
||||
if (sret) {
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue