How to print a shared pointer value at runtime

I was able to extract string from basic_string pointer. And now, I am trying to print the content of a shared pointer. In following code snipet, you can see the output of a simple cpp file, where I am passing a string to a function strr() and I was able to retrieve the value of that string at runtime which is

Going to Strr function.
It's a new line.

You can see the content of this string in arg_values.

Provide 2 inputs => a,b.
If a is greater than 10 then subtract(string) function will be called. Otherwise str(string) will be called
455
65


User:  main is calling _ZNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEC1EPKcRKS3_
_ZNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEC1EPKcRKS3_ is called from this callInst  invoke void @_ZNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEC1EPKcRKS3_(%"class.std::__cxx11::basic_string"* noundef nonnull align 8 dereferenceable(32) %agg.tmp, i8* noundef getelementptr inbounds ([42 x i8], [42 x i8]* @.str.4, i64 0, i64 0), %"class.std::allocator"* noundef nonnull align 1 dereferenceable(1) %ref.tmp)
          to label %invoke.cont unwind label %lpad, !dbg !871

a is greater than 10


User:  main is calling _Z4strrNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE
_Z4strrNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE is called from this callInst  %call5 = invoke noundef i32 @_Z4strrNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE(%"class.std::__cxx11::basic_string"* noundef %agg.tmp)
          to label %invoke.cont4 unwind label %lpad3, !dbg !872

Wed Mar 15 20:15:07 2023
Unix time: 1678932907
arguments:  _Z4strrNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE 
 _Z4strrNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE %"class.std::__cxx11::basic_string"* %s
arg_values: Going to Strr function.
It's a new line.

Total Process time:0.000010
It's a string


User:  main is calling _ZNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEED1Ev
_ZNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEED1Ev is called from this callInst  call void @_ZNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEED1Ev(%"class.std::__cxx11::basic_string"* noundef nonnull align 8 dereferenceable(32) %agg.tmp) #3, !dbg !872

The function in IR looks like this,

define dso_local noundef i32 @_Z4strrNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE(%"class.std::__cxx11::basic_string"* noundef %0) #5 {
  %calltmp = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([26 x i8], [26 x i8]* @str.3, i32 0, i32 0))
  %calltmp1 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([22 x i8], [22 x i8]* @str.4, i32 0, i32 0))
  %calltmp2 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([21 x i8], [21 x i8]* @9, i32 0, i32 0), i8* getelementptr inbounds ([61 x i8], [61 x i8]* @10, i32 0, i32 0), i8* getelementptr inbounds ([100 x i8], [100 x i8]* @11, i32 0, i32 0))
  %2 = load %"class.std::__cxx11::basic_string", %"class.std::__cxx11::basic_string"* %0, align 8
  %calltmp3 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([16 x i8], [16 x i8]* @12, i32 0, i32 0), %"class.std::__cxx11::basic_string" %2)
  %calltmp4 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([29 x i8], [29 x i8]* @str.5, i32 0, i32 0))
  %3 = call i32 (i8*, ...) @printf(i8* noundef getelementptr inbounds ([15 x i8], [15 x i8]* @.str, i64 0, i64 0))
  ret i32 0
}

I am able to retrieve the content simply by loading the pointer to a load inst,
%2 = load %"class.std::__cxx11::basic_string", %"class.std::__cxx11::basic_string"* %0, align 8

Using following piece of code,

for (auto &v : arg_values) {
        if(v->getType()->isPointerTy()){
                //String is loaded here
                llvm::Value *loadedValue = builder.CreateLoad(v->getType()->getPointerElementType(),v);
                argsV.push_back(loadedValue);
                continue;
        }
        argsV.push_back(v);
}

Now, if I try to print this function arguments at runtime,


define linkonce_odr dso_local void @_ZN13mqtt_callback15message_arrivedESt10shared_ptrIKN4mqtt7messageEE(%class.mqtt_callback* noundef nonnull align 8 dereferenceable(8) %0, %"class.std::shared_ptr.12"* noundef %1) unnamed_addr #7 comdat align 2 personality i8* bitcast (i32 (...)* @__gxx_personality_v0 to i8*) {
  %calltmp = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([26 x i8], [26 x i8]* @str.3, i32 0, i32 0))
  %calltmp1 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([22 x i8], [22 x i8]* @str.4, i32 0, i32 0))
  %calltmp2 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([25 x i8], [25 x i8]* @9, i32 0, i32 0), i8* getelementptr inbounds ([70 x i8], [70 x i8]* @10, i32 0, i32 0), i8* getelementptr inbounds ([94 x i8], [94 x i8]* @11, i32 0, i32 0), i8* getelementptr inbounds ([125 x i8], [125 x i8]* @12, i32 0, i32 0))
  %calltmp3 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([19 x i8], [19 x i8]* @13, i32 0, i32 0))
  %calltmp4 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([29 x i8], [29 x i8]* @str.5, i32 0, i32 0))
  %3 = alloca %class.mqtt_callback*, align 8
  %4 = alloca %"class.std::__cxx11::basic_string", align 8
  %5 = alloca i8*, align 8
  %6 = alloca i32, align 4
  store %class.mqtt_callback* %0, %class.mqtt_callback** %3, align 8
  %7 = load %class.mqtt_callback*, %class.mqtt_callback** %3, align 8
  %8 = call noundef nonnull align 8 dereferenceable(8) %"class.std::basic_ostream"* @_ZStlsISt11char_traitsIcEERSt13basic_ostreamIcT_ES5_PKc(%"class.std::basic_ostream"* noundef nonnull align 8 dereferenceable(8) @_ZSt4cout, i8* noundef getelementptr inbounds ([28 x i8], [28 x i8]* @.str.18, i64 0, i64 0))
  %9 = bitcast %"class.std::shared_ptr.12"* %1 to %"class.std::__shared_ptr_access.14"*
  %10 = call noundef %"class.mqtt::message"* @_ZNKSt19__shared_ptr_accessIKN4mqtt7messageELN9__gnu_cxx12_Lock_policyE2ELb0ELb0EEptEv(%"class.std::__shared_ptr_access.14"* noundef nonnull align 1 dereferenceable(1) %9) #3
  %11 = call noundef nonnull align 8 dereferenceable(32) %"class.std::__cxx11::basic_string"* @_ZNK4mqtt7message9get_topicB5cxx11Ev(%"class.mqtt::message"* noundef nonnull align 8 dereferenceable(120) %10)
  %12 = call noundef nonnull align 8 dereferenceable(8) %"class.std::basic_ostream"* @_ZStlsIcSt11char_traitsIcESaIcEERSt13basic_ostreamIT_T0_ES7_RKNSt7__cxx1112basic_stringIS4_S5_T1_EE(%"class.std::basic_ostream"* noundef nonnull align 8 dereferenceable(8) %8, %"class.std::__cxx11::basic_string"* noundef nonnull align 8 dereferenceable(32) %11)
  %13 = call noundef nonnull align 8 dereferenceable(8) %"class.std::basic_ostream"* @_ZNSolsEPFRSoS_E(%"class.std::basic_ostream"* noundef nonnull align 8 dereferenceable(8) %12, %"class.std::basic_ostream"* (%"class.std::basic_ostream"*)* noundef @_ZSt4endlIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_)
  %14 = call noundef nonnull align 8 dereferenceable(8) %"class.std::basic_ostream"* @_ZStlsISt11char_traitsIcEERSt13basic_ostreamIcT_ES5_PKc(%"class.std::basic_ostream"* noundef nonnull align 8 dereferenceable(8) @_ZSt4cout, i8* noundef getelementptr inbounds ([18 x i8], [18 x i8]* @.str.19, i64 0, i64 0))
  %15 = bitcast %"class.std::shared_ptr.12"* %1 to %"class.std::__shared_ptr_access.14"*
  %16 = call noundef %"class.mqtt::message"* @_ZNKSt19__shared_ptr_accessIKN4mqtt7messageELN9__gnu_cxx12_Lock_policyE2ELb0ELb0EEptEv(%"class.std::__shared_ptr_access.14"* noundef nonnull align 1 dereferenceable(1) %15) #3
  call void @_ZNK4mqtt7message9to_stringB5cxx11Ev(%"class.std::__cxx11::basic_string"* sret(%"class.std::__cxx11::basic_string") align 8 %4, %"class.mqtt::message"* noundef nonnull align 8 dereferenceable(120) %16)
  %17 = invoke noundef nonnull align 8 dereferenceable(8) %"class.std::basic_ostream"* @_ZStlsIcSt11char_traitsIcESaIcEERSt13basic_ostreamIT_T0_ES7_RKNSt7__cxx1112basic_stringIS4_S5_T1_EE(%"class.std::basic_ostream"* noundef nonnull align 8 dereferenceable(8) %14, %"class.std::__cxx11::basic_string"* noundef nonnull align 8 dereferenceable(32) %4)
          to label %18 unwind label %21

18:                                               ; preds = %2
  %19 = invoke noundef nonnull align 8 dereferenceable(8) %"class.std::basic_ostream"* @_ZNSolsEPFRSoS_E(%"class.std::basic_ostream"* noundef nonnull align 8 dereferenceable(8) %17, %"class.std::basic_ostream"* (%"class.std::basic_ostream"*)* noundef @_ZSt4endlIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_)
          to label %20 unwind label %21

20:                                               ; preds = %18
  call void @_ZNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEED1Ev(%"class.std::__cxx11::basic_string"* noundef nonnull align 8 dereferenceable(32) %4) #3
  ret void

21:                                               ; preds = %18, %2
  %22 = landingpad { i8*, i32 }
          cleanup
  %23 = extractvalue { i8*, i32 } %22, 0
  store i8* %23, i8** %5, align 8
  %24 = extractvalue { i8*, i32 } %22, 1
  store i32 %24, i32* %6, align 4
  call void @_ZNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEED1Ev(%"class.std::__cxx11::basic_string"* noundef nonnull align 8 dereferenceable(32) %4) #3
  br label %25

25:                                               ; preds = %21
  %26 = load i8*, i8** %5, align 8
  %27 = load i32, i32* %6, align 4
  %28 = insertvalue { i8*, i32 } undef, i8* %26, 0
  %29 = insertvalue { i8*, i32 } %28, i32 %27, 1
  resume { i8*, i32 } %29
}

Which takes these arguments and 2nd one of those arguments is a shared pointer,

define linkonce_odr dso_local void @_ZN13mqtt_callback15message_arrivedESt10shared_ptrIKN4mqtt7messageEE(%class.mqtt_callback* noundef nonnull align 8 dereferenceable(8) %0, %"class.std::shared_ptr.12"* noundef %1) unnamed_addr #7 comdat align 2 personality i8* bitcast (i32 (...)* @__gxx_personality_v0 to i8*) {
...
}

How do I extract the content of this function arguments? I tried following,

  • putting a check for the shared pointer.
for (auto &v : arg_values) {
        if(v->getType()->isPointerTy()){
                llvm::Type *elementType = v->getType()->getPointerElementType();
                if (auto *ptrType = llvm::dyn_cast<llvm::PointerType>(elementType)) {
                    llvm::Type *pointedType = ptrType->getPointerElementType();
                    if (pointedType->isIntegerTy(8)) {
                        llvm::Type *sharedPtrType = llvm::Type::getInt8PtrTy(context); // modify for actual shared pointer type
                        if (ptrType == sharedPtrType) {
                            // Pointer to a shared pointer of a string
                            llvm::Value *sharedPtrValue = builder.CreateLoad(elementType, v);
                            llvm::Value *loadedValue = builder.CreateLoad(sharedPtrValue->getType()->getPointerElementType(), sharedPtrValue);
                            argsV.push_back(loadedValue);
                        }
                    }
                }

                continue;
        }
        argsV.push_back(v);
}

But it is reading some wrong registers, I think,

Connecting to MQTT server: 'tcp://localhost:1883'...OK

Subscribing to topic: my/topic...OK

Wed Mar 15 16:56:30 2023
Unix time: 1678920990
arguments:  _ZN13mqtt_callback15message_arrivedESt10shared_ptrIKN4mqtt7messageEE 
 _ZN13mqtt_callback15message_arrivedESt10shared_ptrIKN4mqtt7messageEE %class.mqtt_callback* %this
 _ZN13mqtt_callback15message_arrivedESt10shared_ptrIKN4mqtt7messageEE %class.mqtt_callback* %this%"class.std::shared_ptr.12"* %msg
arg_values: (null)
 ^�F�
Total Process time:0.000006
Message received on topic: my/topic
Message content: Hello, MQTT!
^Z
[2]+  Stopped                 ./subscriber

  • Dereferencing the shared pointer
for (auto &v : arg_values) {
        if(v->getType()->isPointerTy()){
                v->dump();
                llvm::Value* sharedPtrValue = builder.CreateLoad(v->getType()->getPointerElementType(),v);
                llvm::Value* ptrValue = builder.CreateExtractValue(sharedPtrValue, {0});
                llvm::Value* loadedValue = CreateLoad(ptrValue->getType()->getPointerElementType(),ptrValue,"");
                argsV.push_back(loadedValue);
                argsV.push_back(builder.CreateGlobalStringPtr("pointer"));
         
                continue;
        }
        argsV.push_back(v);
}

I am getting this error,

make: Warning: File 'Makefile' has modification time 12506 s in the future
clang++-14 -o client.ll -S -emit-llvm client_subscriber.cpp
clang++-14 -I/usr/lib/llvm-14/include -std=c++14   -fno-exceptions -D_GNU_SOURCE -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -D__STDC_LIMIT_MACROS -Wl,-znodelete -fno-rtti -fpic -O3 -funroll-loops -Wall -D_FORTIFY_SOURCE=2 -g -Wno-pointer-sign -DVERSION=1  -Wno-variadic-macros -g -shared stringExtractPass.cpp -o instrument.so
#clang++-14 -o subscriber -lpaho-mqttpp3  -lpaho-mqtt3c -lpaho-mqtt3a -lmosquitto client_subscriber.cpp 	
clang++-14 -o subscriber -lpaho-mqttpp3  -lpaho-mqtt3c -lpaho-mqtt3a -lmosquitto -fno-discard-value-names -flegacy-pass-manager -g -Xclang -load -Xclang ./instrument.so client_subscriber.cpp
%class.mqtt_callback* %this
clang: /usr/lib/llvm-14/include/llvm/IR/Type.h:379: llvm::Type *llvm::Type::getNonOpaquePointerElementType() const: Assertion `getTypeID() == PointerTyID' failed.
PLEASE submit a bug report to https://github.com/llvm/llvm-project/issues/ and include the crash backtrace, preprocessed source, and associated run script.
Stack dump:
0.	Program arguments: /usr/lib/llvm-14/bin/clang -cc1 -triple x86_64-pc-linux-gnu -emit-obj -mrelax-all --mrelax-relocations -disable-free -clear-ast-before-backend -disable-llvm-verifier -main-file-name client_subscriber.cpp -mrelocation-model pic -pic-level 2 -pic-is-pie -mframe-pointer=all -fmath-errno -ffp-contract=on -fno-rounding-math -mconstructor-aliases -funwind-tables=2 -target-cpu x86-64 -tune-cpu generic -mllvm -treat-scalable-fixed-error-as-warning -debug-info-kind=constructor -dwarf-version=5 -debugger-tuning=gdb -fcoverage-compilation-dir=/home/u18new/LLVM_PASSES/LogPasses-new/messagePublishFunc/TopicExtraction/mqtt -resource-dir /usr/lib/llvm-14/lib/clang/14.0.6 -internal-isystem /usr/bin/../lib/gcc/x86_64-linux-gnu/7.5.0/../../../../include/c++/7.5.0 -internal-isystem /usr/bin/../lib/gcc/x86_64-linux-gnu/7.5.0/../../../../include/x86_64-linux-gnu/c++/7.5.0 -internal-isystem /usr/bin/../lib/gcc/x86_64-linux-gnu/7.5.0/../../../../include/c++/7.5.0/backward -internal-isystem /usr/lib/llvm-14/lib/clang/14.0.6/include -internal-isystem /usr/local/include -internal-isystem /usr/bin/../lib/gcc/x86_64-linux-gnu/7.5.0/../../../../x86_64-linux-gnu/include -internal-externc-isystem /usr/include/x86_64-linux-gnu -internal-externc-isystem /include -internal-externc-isystem /usr/include -fdeprecated-macro -fdebug-compilation-dir=/home/u18new/LLVM_PASSES/LogPasses-new/messagePublishFunc/TopicExtraction/mqtt -ferror-limit 19 -fgnuc-version=4.2.1 -flegacy-pass-manager -fcxx-exceptions -fexceptions -fcolor-diagnostics -load ./instrument.so -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /tmp/client_subscriber-a31ad4.o -x c++ client_subscriber.cpp
1.	<eof> parser at end of file
2.	Per-module optimization passes
3.	Running pass 'CPSTracker Pass' on module 'client_subscriber.cpp'.
 #0 0x00007f168612a6a1 llvm::sys::PrintStackTrace(llvm::raw_ostream&, int) (/usr/lib/x86_64-linux-gnu/libLLVM-14.so.1+0xe4e6a1)
 #1 0x00007f16861283ee llvm::sys::RunSignalHandlers() (/usr/lib/x86_64-linux-gnu/libLLVM-14.so.1+0xe4c3ee)
 #2 0x00007f168612abdb (/usr/lib/x86_64-linux-gnu/libLLVM-14.so.1+0xe4ebdb)
 #3 0x00007f168f400980 __restore_rt (/lib/x86_64-linux-gnu/libpthread.so.0+0x12980)
 #4 0x00007f1684566e87 raise /build/glibc-CVJwZb/glibc-2.27/signal/../sysdeps/unix/sysv/linux/raise.c:51:0
 #5 0x00007f16845687f1 abort /build/glibc-CVJwZb/glibc-2.27/stdlib/abort.c:81:0
 #6 0x00007f16845583fa __assert_fail_base /build/glibc-CVJwZb/glibc-2.27/assert/assert.c:89:0
 #7 0x00007f1684558472 (/lib/x86_64-linux-gnu/libc.so.6+0x30472)
 #8 0x00007f168114a923 (anonymous namespace)::CPSTracker::runOnModule(llvm::Module&) /home/u18new/LLVM_PASSES/LogPasses-new/messagePublishFunc/TopicExtraction/mqtt/stringExtractPass.cpp:0:0
 #9 0x00007f16862657c6 llvm::legacy::PassManagerImpl::run(llvm::Module&) (/usr/lib/x86_64-linux-gnu/libLLVM-14.so.1+0xf897c6)
#10 0x00007f168d45b69b clang::EmitBackendOutput(clang::DiagnosticsEngine&, clang::HeaderSearchOptions const&, clang::CodeGenOptions const&, clang::TargetOptions const&, clang::LangOptions const&, llvm::StringRef, llvm::Module*, clang::BackendAction, std::unique_ptr<llvm::raw_pwrite_stream, std::default_delete<llvm::raw_pwrite_stream> >) (/usr/lib/x86_64-linux-gnu/libclang-cpp.so.14+0x186569b)
#11 0x00007f168d77fc01 (/usr/lib/x86_64-linux-gnu/libclang-cpp.so.14+0x1b89c01)
#12 0x00007f168c5fb054 clang::ParseAST(clang::Sema&, bool, bool) (/usr/lib/x86_64-linux-gnu/libclang-cpp.so.14+0xa05054)
#13 0x00007f168d77bf51 clang::CodeGenAction::ExecuteAction() (/usr/lib/x86_64-linux-gnu/libclang-cpp.so.14+0x1b85f51)
#14 0x00007f168e11d727 clang::FrontendAction::Execute() (/usr/lib/x86_64-linux-gnu/libclang-cpp.so.14+0x2527727)
#15 0x00007f168e074d86 clang::CompilerInstance::ExecuteAction(clang::FrontendAction&) (/usr/lib/x86_64-linux-gnu/libclang-cpp.so.14+0x247ed86)
#16 0x00007f168e196e8b clang::ExecuteCompilerInvocation(clang::CompilerInstance*) (/usr/lib/x86_64-linux-gnu/libclang-cpp.so.14+0x25a0e8b)
#17 0x000000000041329f cc1_main(llvm::ArrayRef<char const*>, char const*, void*) (/usr/lib/llvm-14/bin/clang+0x41329f)
#18 0x00000000004114dc (/usr/lib/llvm-14/bin/clang+0x4114dc)
#19 0x0000000000411327 main (/usr/lib/llvm-14/bin/clang+0x411327)
#20 0x00007f1684549c87 __libc_start_main /build/glibc-CVJwZb/glibc-2.27/csu/../csu/libc-start.c:344:0
#21 0x000000000040e3da _start (/usr/lib/llvm-14/bin/clang+0x40e3da)
clang: error: unable to execute command: Aborted (core dumped)
clang: error: clang frontend command failed due to signal (use -v to see invocation)
Ubuntu clang version 14.0.6
Target: x86_64-pc-linux-gnu
Thread model: posix
InstalledDir: /usr/bin
clang: note: diagnostic msg: 
********************

PLEASE ATTACH THE FOLLOWING FILES TO THE BUG REPORT:
Preprocessed source(s) and associated run script(s) are located at:
clang: note: diagnostic msg: /tmp/client_subscriber-3e96d3.cpp
clang: note: diagnostic msg: /tmp/client_subscriber-3e96d3.sh
clang: note: diagnostic msg: 

********************
Makefile:28: recipe for target 'subscriber' failed
make: *** [subscriber] Error 254

probably need to bitcast again, but don’t want to do that again.

Any suggestions on how to extract the value of this mqtt function parameters at runtime.

The error is likely because you called getPointerElementType on a non-ptr type. I’d suggest assertions before such calls.