From e91bd0f14c92be0a4eb39a1d4ce6dc044d9bfc27 Mon Sep 17 00:00:00 2001 From: Michal R Date: Sun, 2 Nov 2025 12:26:16 +0100 Subject: [PATCH] [LLVM-C] Add binding to `BitcodeReader::getBitcodeProducerString` Add `LLVMGetBircodeProducerString` function in LLVM C API that binds to `BitcodeReader::getBitcodeProducerString` in LLVM C++ API. --- llvm/include/llvm-c/BitReader.h | 9 ++++ llvm/lib/Bitcode/Reader/BitReader.cpp | 21 ++++++++ llvm/test/Bindings/llvm-c/producer_string.ll | 2 + llvm/tools/llvm-c-test/llvm-c-test.h | 1 + llvm/tools/llvm-c-test/main.c | 6 +++ llvm/tools/llvm-c-test/module.c | 57 +++++++++++++++++++- 6 files changed, 94 insertions(+), 2 deletions(-) create mode 100644 llvm/test/Bindings/llvm-c/producer_string.ll diff --git a/llvm/include/llvm-c/BitReader.h b/llvm/include/llvm-c/BitReader.h index 9dcdbf436454f..928372bb72ad8 100644 --- a/llvm/include/llvm-c/BitReader.h +++ b/llvm/include/llvm-c/BitReader.h @@ -84,6 +84,15 @@ LLVM_C_ABI LLVMBool LLVMGetBitcodeModule(LLVMMemoryBufferRef MemBuf, LLVM_C_ABI LLVMBool LLVMGetBitcodeModule2(LLVMMemoryBufferRef MemBuf, LLVMModuleRef *OutM); +/** + * Reads the producer string from the bitcode header in the given memory + * buffer. Returns 0 on success. The produced string must be disposed with + * LLVMDisposeMessage. + */ +LLVM_C_ABI LLVMBool LLVMGetBitcodeProducerString(LLVMMemoryBufferRef MemBuf, + char **OutProducer, + char **OutMessage); + /** * @} */ diff --git a/llvm/lib/Bitcode/Reader/BitReader.cpp b/llvm/lib/Bitcode/Reader/BitReader.cpp index da2cf0770ec5a..2163e4d909b87 100644 --- a/llvm/lib/Bitcode/Reader/BitReader.cpp +++ b/llvm/lib/Bitcode/Reader/BitReader.cpp @@ -130,3 +130,24 @@ LLVMBool LLVMGetBitcodeModule2(LLVMMemoryBufferRef MemBuf, LLVMModuleRef *OutM) { return LLVMGetBitcodeModuleInContext2(LLVMGetGlobalContext(), MemBuf, OutM); } + +LLVMBool LLVMGetBitcodeProducerString(LLVMMemoryBufferRef MemBuf, + char **OutProducer, char **OutMessage) { + MemoryBufferRef Buf = unwrap(MemBuf)->getMemBufferRef(); + + Expected ProducerOrErr = getBitcodeProducerString(Buf); + if (!ProducerOrErr) { + std::string Message; + handleAllErrors(ProducerOrErr.takeError(), + [&](ErrorInfoBase &EIB) { Message = EIB.message(); }); + if (OutMessage) + *OutMessage = strdup(Message.c_str()); + if (OutProducer) + *OutProducer = nullptr; + return 1; + } + + if (OutProducer) + *OutProducer = strdup(ProducerOrErr->c_str()); + return 0; +} diff --git a/llvm/test/Bindings/llvm-c/producer_string.ll b/llvm/test/Bindings/llvm-c/producer_string.ll new file mode 100644 index 0000000000000..9dd40f62dfee0 --- /dev/null +++ b/llvm/test/Bindings/llvm-c/producer_string.ll @@ -0,0 +1,2 @@ +; RUN: llvm-as < %s | llvm-c-test --module-get-producer-string | FileCheck %s +; CHECK: LLVM{{[0-9]+.*}} diff --git a/llvm/tools/llvm-c-test/llvm-c-test.h b/llvm/tools/llvm-c-test/llvm-c-test.h index 4c5a88ce0447e..e140688adf583 100644 --- a/llvm/tools/llvm-c-test/llvm-c-test.h +++ b/llvm/tools/llvm-c-test/llvm-c-test.h @@ -28,6 +28,7 @@ LLVMModuleRef llvm_load_module(LLVMContextRef C, bool Lazy, bool New); int llvm_module_dump(bool Lazy, bool New); int llvm_module_list_functions(void); int llvm_module_list_globals(void); +int llvm_module_get_producer_string(void); // calc.c int llvm_calc(void); diff --git a/llvm/tools/llvm-c-test/main.c b/llvm/tools/llvm-c-test/main.c index d1963b702888b..5d532d0d5e3f8 100644 --- a/llvm/tools/llvm-c-test/main.c +++ b/llvm/tools/llvm-c-test/main.c @@ -33,6 +33,10 @@ static void print_usage(void) { " Read bitcode from stdin - list summary of functions\n\n"); fprintf(stderr, " * --module-list-globals\n"); fprintf(stderr, " Read bitcode from stdin - list summary of globals\n\n"); + fprintf(stderr, " * --module-get-producer-string\n"); + fprintf( + stderr, + " Read bitcode from stdin - print the producer identification\n\n"); fprintf(stderr, " * --targets-list\n"); fprintf(stderr, " List available targets\n\n"); fprintf(stderr, " * --object-list-sections\n"); @@ -79,6 +83,8 @@ int main(int argc, char **argv) { return llvm_module_list_functions(); } else if (argc == 2 && !strcmp(argv[1], "--module-list-globals")) { return llvm_module_list_globals(); + } else if (argc == 2 && !strcmp(argv[1], "--module-get-producer-string")) { + return llvm_module_get_producer_string(); } else if (argc == 2 && !strcmp(argv[1], "--targets-list")) { return llvm_targets_list(); } else if (argc == 2 && !strcmp(argv[1], "--object-list-sections")) { diff --git a/llvm/tools/llvm-c-test/module.c b/llvm/tools/llvm-c-test/module.c index 9698f0983d5b6..1eaad627697a5 100644 --- a/llvm/tools/llvm-c-test/module.c +++ b/llvm/tools/llvm-c-test/module.c @@ -7,8 +7,7 @@ |* *| |*===----------------------------------------------------------------------===*| |* *| -|* This file implements the --module-dump, --module-list-functions and *| -|* --module-list-globals commands in llvm-c-test. *| +|* This file implements the module-related commands in llvm-c-test. *| |* *| \*===----------------------------------------------------------------------===*/ @@ -135,3 +134,57 @@ int llvm_module_list_globals(void) { return 0; } + +int llvm_module_get_producer_string(void) { + LLVMMemoryBufferRef MB; + char *Msg = NULL; + if (LLVMCreateMemoryBufferWithSTDIN(&MB, &Msg)) { + fprintf(stderr, "Error reading file: %s\n", Msg); + LLVMDisposeMessage(Msg); + return 1; + } + + char *Producer = NULL; + char *Err = NULL; + LLVMBool Res = LLVMGetBitcodeProducerString(MB, &Producer, &Err); + LLVMDisposeMemoryBuffer(MB); + + int Ret = 0; + if (Res) { + if (Producer) + fprintf(stderr, + "LLVMGetBitcodeProducerString returned %d, but Producer is not " + "NULL: %s", + Res, Producer); + if (Err) + fprintf(stderr, "LLVMGetBitcodeProducerSring returned %d, error: %s\n", + Res, Err); + else + fprintf(stderr, + "LLVMGetBitcodeProducerString returned %d, but the error is NULL", + Res); + Ret = 1; + } else { + if (!Producer) { + fprintf(stderr, + "LLVMGetBitcodeProducerString returned %d, but Producer is NULL", + Res); + Ret = 1; + } + if (Err) { + fprintf(stderr, + "LLVMGetBitcodeProducerString returned %d, Producer is not NULL: " + "%s, but also returned an error: %s", + Res, Producer, Err); + Ret = 1; + } + + printf("%s\n", Producer); + } + + if (Err) + LLVMDisposeMessage(Err); + if (Producer) + LLVMDisposeMessage(Producer); + return Ret; +}