Skip to content

Commit

Permalink
[CilkSanitizer] Add support to synthesize hooks, such as __csan_llvm_…
Browse files Browse the repository at this point in the history
…hyper_lookup, that return a value.
  • Loading branch information
neboat committed Dec 2, 2024
1 parent cb4db0b commit 61bbf1b
Show file tree
Hide file tree
Showing 4 changed files with 385 additions and 8 deletions.
40 changes: 32 additions & 8 deletions llvm/lib/Transforms/Instrumentation/CilkSanitizer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -39,8 +39,10 @@
#include "llvm/IR/DebugInfoMetadata.h"
#include "llvm/IR/Function.h"
#include "llvm/IR/IRBuilder.h"
#include "llvm/IR/Instructions.h"
#include "llvm/IR/IntrinsicInst.h"
#include "llvm/IR/Intrinsics.h"
#include "llvm/IR/LLVMContext.h"
#include "llvm/IR/Module.h"
#include "llvm/InitializePasses.h"
#include "llvm/ProfileData/InstrProf.h"
Expand Down Expand Up @@ -587,6 +589,7 @@ struct CilkSanitizerImpl : public CSIImpl {
}

FunctionCallee getOrInsertSynthesizedHook(StringRef Name, FunctionType *T,
int ReturnParam = -1,
AttributeList AL = AttributeList());
};

Expand Down Expand Up @@ -3668,6 +3671,7 @@ bool CilkSanitizerImpl::instrumentAtomic(Instruction *I, IRBuilder<> &IRB) {

FunctionCallee CilkSanitizerImpl::getOrInsertSynthesizedHook(StringRef Name,
FunctionType *T,
int ReturnParam,
AttributeList AL) {
// If no bitcode file has been linked, then we cannot check if it contains a
// particular library hook. Simply return the hook. If the Cilksan library
Expand All @@ -3680,14 +3684,28 @@ FunctionCallee CilkSanitizerImpl::getOrInsertSynthesizedHook(StringRef Name,
if (FunctionsInBitcode.contains(std::string(Name)))
return getHookFunction(Name, T, AL);

// If the function is already present, just return it.
if (Function *F = M.getFunction(Name))
if (F->getFunctionType() == T)
return M.getOrInsertFunction(Name, T);

// We did not find the library hook in the linked bitcode file. Synthesize a
// default version of the hook that simply calls __csan_default_libhook.
FunctionCallee NewHook = M.getOrInsertFunction(Name, T, AL);
Function *NewHookFn = cast<Function>(NewHook.getCallee());
NewHookFn->setOnlyAccessesInaccessibleMemOrArgMem();
NewHookFn->setDoesNotThrow();
BasicBlock *Entry = BasicBlock::Create(M.getContext(), "entry", NewHookFn);
IRBuilder<> IRB(ReturnInst::Create(M.getContext(), Entry));
LLVMContext &Ctx = M.getContext();
assert((T->getReturnType() == Type::getVoidTy(Ctx) || ReturnParam >= 0) &&
"Synthesizing hook with return value, but no return parameter "
"specified.");
BasicBlock *Entry = BasicBlock::Create(Ctx, "entry", NewHookFn);
// Return void or the parameter at the specified index.
ReturnInst *RI =
(T->getReturnType() == Type::getVoidTy(Ctx) || ReturnParam < 0)
? ReturnInst::Create(Ctx, Entry)
: ReturnInst::Create(Ctx, NewHookFn->getArg(ReturnParam), Entry);
IRBuilder<> IRB(RI);

// Insert a call to the default library function hook
Type *IDType = IRB.getInt64Ty();
Expand Down Expand Up @@ -3818,9 +3836,11 @@ bool CilkSanitizerImpl::instrumentIntrinsicCall(

// Populate the AfterHook parameters with the parameters of the instrumented
// function itself.
int ReturnParam = -1;
Value *SavedStack = nullptr;
const DataLayout &DL = M.getDataLayout();
if (!Called->getReturnType()->isVoidTy()) {
ReturnParam = AfterHookParamVals.size();
Type *RetTy = Called->getReturnType();
if (!needToSpillType(RetTy)) {
// We can simply pass the return value directly to the hook.
Expand Down Expand Up @@ -3871,8 +3891,8 @@ bool CilkSanitizerImpl::instrumentIntrinsicCall(
case Intrinsic::hyper_lookup: {
FunctionType *AfterHookTy =
FunctionType::get(IRB.getPtrTy(), AfterHookParamTys, Called->isVarArg());
FunctionCallee AfterIntrinCallHook =
getOrInsertSynthesizedHook(("__csan_" + Buf).str(), AfterHookTy);
FunctionCallee AfterIntrinCallHook = getOrInsertSynthesizedHook(
("__csan_" + Buf).str(), AfterHookTy, ReturnParam);
CallInst *HookCall =
insertHookCall(&*Iter, AfterIntrinCallHook, AfterHookParamVals);
II->replaceUsesWithIf(HookCall, [HookCall](Use &U) {
Expand All @@ -3884,8 +3904,8 @@ bool CilkSanitizerImpl::instrumentIntrinsicCall(

FunctionType *AfterHookTy =
FunctionType::get(IRB.getVoidTy(), AfterHookParamTys, Called->isVarArg());
FunctionCallee AfterIntrinCallHook =
getOrInsertSynthesizedHook(("__csan_" + Buf).str(), AfterHookTy);
FunctionCallee AfterIntrinCallHook = getOrInsertSynthesizedHook(
("__csan_" + Buf).str(), AfterHookTy, ReturnParam);

// Insert the hook call
insertHookCall(&*Iter, AfterIntrinCallHook, AfterHookParamVals);
Expand Down Expand Up @@ -3958,7 +3978,9 @@ bool CilkSanitizerImpl::instrumentLibCall(Instruction *I,
{CallsiteId, FuncId, NumMVVal, PropVal});
SmallVector<Value *, 8> AfterHookDefaultVals(
{DefaultID, DefaultID, IRB.getInt8(0), DefaultPropVal});
int ReturnParam = -1;
if (!Called->getReturnType()->isVoidTy()) {
ReturnParam = AfterHookParamTys.size();
AfterHookParamTys.push_back(Called->getReturnType());
AfterHookParamVals.push_back(CB);
AfterHookDefaultVals.push_back(
Expand All @@ -3972,7 +3994,7 @@ bool CilkSanitizerImpl::instrumentLibCall(Instruction *I,
FunctionType *AfterHookTy =
FunctionType::get(IRB.getVoidTy(), AfterHookParamTys, Called->isVarArg());
FunctionCallee AfterLibCallHook = getOrInsertSynthesizedHook(
("__csan_" + Called->getName()).str(), AfterHookTy);
("__csan_" + Called->getName()).str(), AfterHookTy, ReturnParam);

BasicBlock::iterator Iter(I);
if (IsInvoke) {
Expand Down Expand Up @@ -4595,7 +4617,9 @@ bool CilkSanitizerImpl::instrumentAllocFnLibCall(Instruction *I,
{AllocFnId, FuncId, NumMVVal, PropVal});
SmallVector<Value *, 8> AfterHookDefaultVals(
{DefaultID, DefaultID, IRB.getInt8(0), DefaultPropVal});
int ReturnParam = -1;
if (!Called->getReturnType()->isVoidTy()) {
ReturnParam = AfterHookParamVals.size();
AfterHookParamTys.push_back(Called->getReturnType());
AfterHookParamVals.push_back(CB);
AfterHookDefaultVals.push_back(
Expand All @@ -4609,7 +4633,7 @@ bool CilkSanitizerImpl::instrumentAllocFnLibCall(Instruction *I,
FunctionType *AfterHookTy =
FunctionType::get(IRB.getVoidTy(), AfterHookParamTys, Called->isVarArg());
FunctionCallee AfterLibCallHook = getOrInsertSynthesizedHook(
("__csan_alloc_" + Called->getName()).str(), AfterHookTy);
("__csan_alloc_" + Called->getName()).str(), AfterHookTy, ReturnParam);

// Insert the hook after the call.
BasicBlock::iterator Iter(I);
Expand Down
188 changes: 188 additions & 0 deletions llvm/test/Transforms/Tapir/CilkSanitizer/cabs-fstat64.ll
Original file line number Diff line number Diff line change
@@ -0,0 +1,188 @@
; Check synthesis of Cilksan hooks for cabs and fstat64.
; Although both of these functions return values, their Cilksan hooks should return void.
;
; RUN: opt < %s -passes="cilksan" -cilksan-bc-path=%S/null-bitcode.bc -S | FileCheck %s
target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128"
target triple = "x86_64-unknown-linux-gnu"

module asm ".globl _ZSt21ios_base_library_initv"

%"class.std::basic_ostream" = type { ptr, %"class.std::basic_ios" }
%"class.std::basic_ios" = type { %"class.std::ios_base", ptr, i8, i8, ptr, ptr, ptr, ptr }
%"class.std::ios_base" = type { ptr, i64, i64, i32, i32, i32, ptr, %"struct.std::ios_base::_Words", [8 x %"struct.std::ios_base::_Words"], i32, ptr, %"class.std::locale" }
%"struct.std::ios_base::_Words" = type { ptr, i64 }
%"class.std::locale" = type { ptr }
%struct.stat64 = type { i64, i64, i64, i32, i32, i32, i32, i64, i64, i64, i64, %struct.timespec, %struct.timespec, %struct.timespec, [3 x i64] }
%struct.timespec = type { i64, i64 }
%"class.std::ctype" = type <{ %"class.std::locale::facet.base", [4 x i8], ptr, i8, [7 x i8], ptr, ptr, ptr, i8, [256 x i8], [256 x i8], i8, [6 x i8] }>
%"class.std::locale::facet.base" = type <{ ptr, i32 }>

@_ZSt4cout = external global %"class.std::basic_ostream", align 8

; Function Attrs: mustprogress norecurse sanitize_cilk uwtable
define dso_local noundef i32 @main() local_unnamed_addr #0 {
entry:
%buf = alloca %struct.stat64, align 8
%call.i.i = tail call noundef double @cabs(double noundef 1.000000e+00, double noundef 2.000000e+00) #5
%call.i = tail call noundef nonnull align 8 dereferenceable(8) ptr @_ZNSo9_M_insertIdEERSoT_(ptr noundef nonnull align 8 dereferenceable(8) @_ZSt4cout, double noundef %call.i.i)
%vtable.i = load ptr, ptr %call.i, align 8, !tbaa !5
%vbase.offset.ptr.i = getelementptr i8, ptr %vtable.i, i64 -24
%vbase.offset.i = load i64, ptr %vbase.offset.ptr.i, align 8
%add.ptr.i = getelementptr inbounds i8, ptr %call.i, i64 %vbase.offset.i
%_M_ctype.i.i = getelementptr inbounds %"class.std::basic_ios", ptr %add.ptr.i, i64 0, i32 5
%0 = load ptr, ptr %_M_ctype.i.i, align 8, !tbaa !8
%tobool.not.i.i.i = icmp eq ptr %0, null
br i1 %tobool.not.i.i.i, label %if.then.i.i.i, label %_ZSt13__check_facetISt5ctypeIcEERKT_PS3_.exit.i.i

if.then.i.i.i: ; preds = %entry
tail call void @_ZSt16__throw_bad_castv() #6
unreachable

_ZSt13__check_facetISt5ctypeIcEERKT_PS3_.exit.i.i: ; preds = %entry
%_M_widen_ok.i.i.i = getelementptr inbounds %"class.std::ctype", ptr %0, i64 0, i32 8
%1 = load i8, ptr %_M_widen_ok.i.i.i, align 8, !tbaa !20
%tobool.not.i1.i.i = icmp eq i8 %1, 0
br i1 %tobool.not.i1.i.i, label %if.end.i.i.i, label %if.then.i2.i.i

if.then.i2.i.i: ; preds = %_ZSt13__check_facetISt5ctypeIcEERKT_PS3_.exit.i.i
%arrayidx.i.i.i = getelementptr inbounds %"class.std::ctype", ptr %0, i64 0, i32 9, i64 10
%2 = load i8, ptr %arrayidx.i.i.i, align 1, !tbaa !23
br label %_ZSt4endlIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_.exit

if.end.i.i.i: ; preds = %_ZSt13__check_facetISt5ctypeIcEERKT_PS3_.exit.i.i
tail call void @_ZNKSt5ctypeIcE13_M_widen_initEv(ptr noundef nonnull align 8 dereferenceable(570) %0)
%vtable.i.i.i = load ptr, ptr %0, align 8, !tbaa !5
%vfn.i.i.i = getelementptr inbounds ptr, ptr %vtable.i.i.i, i64 6
%3 = load ptr, ptr %vfn.i.i.i, align 8
%call.i.i.i = tail call noundef signext i8 %3(ptr noundef nonnull align 8 dereferenceable(570) %0, i8 noundef signext 10)
br label %_ZSt4endlIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_.exit

_ZSt4endlIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_.exit: ; preds = %if.then.i2.i.i, %if.end.i.i.i
%retval.0.i.i.i = phi i8 [ %2, %if.then.i2.i.i ], [ %call.i.i.i, %if.end.i.i.i ]
%call1.i = tail call noundef nonnull align 8 dereferenceable(8) ptr @_ZNSo3putEc(ptr noundef nonnull align 8 dereferenceable(8) %call.i, i8 noundef signext %retval.0.i.i.i)
%call.i.i4 = tail call noundef nonnull align 8 dereferenceable(8) ptr @_ZNSo5flushEv(ptr noundef nonnull align 8 dereferenceable(8) %call1.i)
call void @llvm.lifetime.start.p0(i64 144, ptr nonnull %buf) #5
%call3 = call i32 @fstat64(i32 noundef 0, ptr noundef nonnull %buf) #5
%4 = load i64, ptr %buf, align 8, !tbaa !24
%call.i2 = tail call noundef nonnull align 8 dereferenceable(8) ptr @_ZNSo9_M_insertImEERSoT_(ptr noundef nonnull align 8 dereferenceable(8) @_ZSt4cout, i64 noundef %4)
%vtable.i5 = load ptr, ptr %call.i2, align 8, !tbaa !5
%vbase.offset.ptr.i6 = getelementptr i8, ptr %vtable.i5, i64 -24
%vbase.offset.i7 = load i64, ptr %vbase.offset.ptr.i6, align 8
%add.ptr.i8 = getelementptr inbounds i8, ptr %call.i2, i64 %vbase.offset.i7
%_M_ctype.i.i9 = getelementptr inbounds %"class.std::basic_ios", ptr %add.ptr.i8, i64 0, i32 5
%5 = load ptr, ptr %_M_ctype.i.i9, align 8, !tbaa !8
%tobool.not.i.i.i10 = icmp eq ptr %5, null
br i1 %tobool.not.i.i.i10, label %if.then.i.i.i23, label %_ZSt13__check_facetISt5ctypeIcEERKT_PS3_.exit.i.i11

if.then.i.i.i23: ; preds = %_ZSt4endlIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_.exit
tail call void @_ZSt16__throw_bad_castv() #6
unreachable

_ZSt13__check_facetISt5ctypeIcEERKT_PS3_.exit.i.i11: ; preds = %_ZSt4endlIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_.exit
%_M_widen_ok.i.i.i12 = getelementptr inbounds %"class.std::ctype", ptr %5, i64 0, i32 8
%6 = load i8, ptr %_M_widen_ok.i.i.i12, align 8, !tbaa !20
%tobool.not.i1.i.i13 = icmp eq i8 %6, 0
br i1 %tobool.not.i1.i.i13, label %if.end.i.i.i19, label %if.then.i2.i.i14

if.then.i2.i.i14: ; preds = %_ZSt13__check_facetISt5ctypeIcEERKT_PS3_.exit.i.i11
%arrayidx.i.i.i15 = getelementptr inbounds %"class.std::ctype", ptr %5, i64 0, i32 9, i64 10
%7 = load i8, ptr %arrayidx.i.i.i15, align 1, !tbaa !23
br label %_ZSt4endlIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_.exit24

if.end.i.i.i19: ; preds = %_ZSt13__check_facetISt5ctypeIcEERKT_PS3_.exit.i.i11
tail call void @_ZNKSt5ctypeIcE13_M_widen_initEv(ptr noundef nonnull align 8 dereferenceable(570) %5)
%vtable.i.i.i20 = load ptr, ptr %5, align 8, !tbaa !5
%vfn.i.i.i21 = getelementptr inbounds ptr, ptr %vtable.i.i.i20, i64 6
%8 = load ptr, ptr %vfn.i.i.i21, align 8
%call.i.i.i22 = tail call noundef signext i8 %8(ptr noundef nonnull align 8 dereferenceable(570) %5, i8 noundef signext 10)
br label %_ZSt4endlIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_.exit24

_ZSt4endlIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_.exit24: ; preds = %if.then.i2.i.i14, %if.end.i.i.i19
%retval.0.i.i.i16 = phi i8 [ %7, %if.then.i2.i.i14 ], [ %call.i.i.i22, %if.end.i.i.i19 ]
%call1.i17 = tail call noundef nonnull align 8 dereferenceable(8) ptr @_ZNSo3putEc(ptr noundef nonnull align 8 dereferenceable(8) %call.i2, i8 noundef signext %retval.0.i.i.i16)
%call.i.i18 = tail call noundef nonnull align 8 dereferenceable(8) ptr @_ZNSo5flushEv(ptr noundef nonnull align 8 dereferenceable(8) %call1.i17)
call void @llvm.lifetime.end.p0(i64 144, ptr nonnull %buf) #5
ret i32 0
}

; CHECK: define {{.*}}i32 @main()
; CHECK: %[[CABS_CALL:.+]] = {{.*}}call {{.*}}double @cabs(double noundef 1.000000e+00, double noundef 2.000000e+00)
; CHECK-NEXT: call {{.*}}void @__csan_cabs(i64 %{{.+}}, i64 %{{.+}}, i8 0, i64 0, double %[[CABS_CALL]], double 1.000000e+00, double 2.000000e+00)
; CHECK: %call3 = call {{.*}}i32 @fstat64(i32 noundef 0, ptr {{.*}}%[[BUF:.+]])
; CHECK-NEXT: call {{.*}}void @__csan_fstat64(i64 %{{.+}}, i64 %{{.+}}, i8 1, i64 0, i32 %call3, i32 0, ptr {{.*}}%[[BUF]])

; CHECK: define {{.*}}void @__csan_cabs(i64 %0, i64 %1, i8 %2, i64 %3, double %4, double %5, double %6)
; CHECK-NEXT: entry:
; CHECK-NEXT: call void @__csan_default_libhook(i64 %0, i64 %1, i8 %2)
; CHECK-NEXT: ret void
; CHECK-NEXT: }

; CHECK: define {{.*}}void @__csan_fstat64(i64 %0, i64 %1, i8 %2, i64 %3, i32 %4, i32 %5, ptr %6)
; CHECK-NEXT: entry:
; CHECK-NEXT: call void @__csan_default_libhook(i64 %0, i64 %1, i8 %2)
; CHECK-NEXT: ret void
; CHECK-NEXT: }

; Function Attrs: mustprogress nocallback nofree nosync nounwind willreturn memory(argmem: readwrite)
declare void @llvm.lifetime.start.p0(i64 immarg, ptr nocapture) #1

; Function Attrs: mustprogress nocallback nofree nosync nounwind willreturn memory(argmem: readwrite)
declare void @llvm.lifetime.end.p0(i64 immarg, ptr nocapture) #1

; Function Attrs: nofree nounwind
declare noundef i32 @fstat64(i32 noundef, ptr nocapture noundef) local_unnamed_addr #2

; Function Attrs: nofree nounwind
declare double @cabs(double noundef, double noundef) local_unnamed_addr #2

declare noundef nonnull align 8 dereferenceable(8) ptr @_ZNSo9_M_insertIdEERSoT_(ptr noundef nonnull align 8 dereferenceable(8), double noundef) local_unnamed_addr #3

declare noundef nonnull align 8 dereferenceable(8) ptr @_ZNSo3putEc(ptr noundef nonnull align 8 dereferenceable(8), i8 noundef signext) local_unnamed_addr #3

declare noundef nonnull align 8 dereferenceable(8) ptr @_ZNSo5flushEv(ptr noundef nonnull align 8 dereferenceable(8)) local_unnamed_addr #3

; Function Attrs: cold noreturn
declare void @_ZSt16__throw_bad_castv() local_unnamed_addr #4

declare void @_ZNKSt5ctypeIcE13_M_widen_initEv(ptr noundef nonnull align 8 dereferenceable(570)) local_unnamed_addr #3

declare noundef nonnull align 8 dereferenceable(8) ptr @_ZNSo9_M_insertImEERSoT_(ptr noundef nonnull align 8 dereferenceable(8), i64 noundef) local_unnamed_addr #3

attributes #0 = { mustprogress norecurse sanitize_cilk uwtable "min-legal-vector-width"="0" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+cmov,+cx8,+fxsr,+mmx,+sse,+sse2,+x87" "tune-cpu"="generic" }
attributes #1 = { mustprogress nocallback nofree nosync nounwind willreturn memory(argmem: readwrite) }
attributes #2 = { nofree nounwind "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+cmov,+cx8,+fxsr,+mmx,+sse,+sse2,+x87" "tune-cpu"="generic" }
attributes #3 = { "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+cmov,+cx8,+fxsr,+mmx,+sse,+sse2,+x87" "tune-cpu"="generic" }
attributes #4 = { cold noreturn "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+cmov,+cx8,+fxsr,+mmx,+sse,+sse2,+x87" "tune-cpu"="generic" }
attributes #5 = { nounwind }
attributes #6 = { cold noreturn }

!llvm.module.flags = !{!0, !1, !2, !3}
!llvm.ident = !{!4}

!0 = !{i32 1, !"wchar_size", i32 4}
!1 = !{i32 8, !"PIC Level", i32 2}
!2 = !{i32 7, !"PIE Level", i32 2}
!3 = !{i32 7, !"uwtable", i32 2}
!4 = !{!"clang version 18.1.8 ([email protected]:neboat/opencilk-project.git c3cd84365e099ab6dfa4b484475ef66f33f16eab)"}
!5 = !{!6, !6, i64 0}
!6 = !{!"vtable pointer", !7, i64 0}
!7 = !{!"Simple C++ TBAA"}
!8 = !{!9, !15, i64 240}
!9 = !{!"_ZTSSt9basic_iosIcSt11char_traitsIcEE", !10, i64 0, !15, i64 216, !12, i64 224, !19, i64 225, !15, i64 232, !15, i64 240, !15, i64 248, !15, i64 256}
!10 = !{!"_ZTSSt8ios_base", !11, i64 8, !11, i64 16, !13, i64 24, !14, i64 28, !14, i64 32, !15, i64 40, !16, i64 48, !12, i64 64, !17, i64 192, !15, i64 200, !18, i64 208}
!11 = !{!"long", !12, i64 0}
!12 = !{!"omnipotent char", !7, i64 0}
!13 = !{!"_ZTSSt13_Ios_Fmtflags", !12, i64 0}
!14 = !{!"_ZTSSt12_Ios_Iostate", !12, i64 0}
!15 = !{!"any pointer", !12, i64 0}
!16 = !{!"_ZTSNSt8ios_base6_WordsE", !15, i64 0, !11, i64 8}
!17 = !{!"int", !12, i64 0}
!18 = !{!"_ZTSSt6locale", !15, i64 0}
!19 = !{!"bool", !12, i64 0}
!20 = !{!21, !12, i64 56}
!21 = !{!"_ZTSSt5ctypeIcE", !22, i64 0, !15, i64 16, !19, i64 24, !15, i64 32, !15, i64 40, !15, i64 48, !12, i64 56, !12, i64 57, !12, i64 313, !12, i64 569}
!22 = !{!"_ZTSNSt6locale5facetE", !17, i64 8}
!23 = !{!12, !12, i64 0}
!24 = !{!25, !11, i64 0}
!25 = !{!"_ZTS6stat64", !11, i64 0, !11, i64 8, !11, i64 16, !17, i64 24, !17, i64 28, !17, i64 32, !17, i64 36, !11, i64 40, !11, i64 48, !11, i64 56, !11, i64 64, !26, i64 72, !26, i64 88, !26, i64 104, !12, i64 120}
!26 = !{!"_ZTS8timespec", !11, i64 0, !11, i64 8}
Loading

0 comments on commit 61bbf1b

Please sign in to comment.