This is an automated email from the ASF dual-hosted git repository.

tqchen pushed a commit to branch debug-symbol
in repository https://gitbox.apache.org/repos/asf/tvm.git

commit 40b6023a3a0df1b9f007ddb8b9e2f92285c994fa
Author: tqchen <[email protected]>
AuthorDate: Sun Aug 24 14:50:24 2025 -0400

    update
---
 ffi/CMakeLists.txt                  | 10 ++++++++--
 ffi/cmake/Utils/Library.cmake       |  8 ++++++++
 ffi/include/tvm/ffi/c_api.h         |  4 +++-
 ffi/include/tvm/ffi/error.h         |  4 ++--
 ffi/python/tvm_ffi/cython/base.pxi  |  3 ++-
 ffi/python/tvm_ffi/cython/error.pxi |  2 +-
 ffi/src/ffi/error.cc                |  2 +-
 ffi/src/ffi/extra/testing.cc        | 17 +++++++++--------
 ffi/src/ffi/traceback.cc            | 13 +++++++------
 ffi/src/ffi/traceback.h             | 34 +++++++++++++++++++++-------------
 ffi/src/ffi/traceback_win.cc        |  6 ++++--
 include/tvm/runtime/logging.h       |  2 +-
 src/tir/schedule/error.h            |  2 +-
 13 files changed, 68 insertions(+), 39 deletions(-)

diff --git a/ffi/CMakeLists.txt b/ffi/CMakeLists.txt
index 8e9ac09b6b..c85d0f181f 100644
--- a/ffi/CMakeLists.txt
+++ b/ffi/CMakeLists.txt
@@ -148,7 +148,7 @@ option(TVM_FFI_BUILD_TESTS "Adding test targets." OFF)
 if(CMAKE_CXX_COMPILER_ID MATCHES "GNU|Clang")
   if (TVM_FFI_USE_RELEASE_FLAGS)
     message(STATUS "Targeting global CXX flags to -O3 for optimized build")
-    target_compile_options(tvm_ffi_objs PRIVATE -O3 -g)
+    target_compile_options(tvm_ffi_objs PRIVATE -O3)
     target_compile_options(tvm_ffi_shared PRIVATE -O3)
     target_compile_options(tvm_ffi_static PRIVATE -O3)
   endif()
@@ -158,7 +158,9 @@ endif()
 include(cmake/Utils/CxxWarning.cmake)
 include(cmake/Utils/Sanitizer.cmake)
 
-tvm_ffi_add_cxx_warning(tvm_ffi_objs)
+# remap the file name to the source directory so we can see the
+# exact file name in traceback relative to the project source root
+tvm_ffi_add_prefix_map(tvm_ffi_objs ${CMAKE_SOURCE_DIR})
 
 ########## Adding cpp tests ##########
 
@@ -169,6 +171,7 @@ if (TVM_FFI_BUILD_TESTS)
   message(STATUS "Enable Testing")
   include(cmake/Utils/AddGoogleTest.cmake)
   add_subdirectory(tests/cpp/)
+  tvm_ffi_add_cxx_warning(tvm_ffi_objs)
 endif()
 
 ########## Install the related for normal cmake library ##########
@@ -208,9 +211,12 @@ if (TVM_FFI_BUILD_PYTHON_MODULE)
     ${CMAKE_CURRENT_SOURCE_DIR}/python/tvm_ffi/cython/object.pxi
     ${CMAKE_CURRENT_SOURCE_DIR}/python/tvm_ffi/cython/string.pxi
   )
+  # set working directory to source so we can see the exact file name in 
traceback
+  # relatived to the project source root
   add_custom_command(
       OUTPUT ${core_cpp}
       COMMAND ${Python_EXECUTABLE} -m cython --cplus ${core_pyx} -o ${core_cpp}
+      WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
       COMMENT "Transpiling ${core_pyx} to ${core_cpp}"
       DEPENDS ${cython_sources}
       VERBATIM
diff --git a/ffi/cmake/Utils/Library.cmake b/ffi/cmake/Utils/Library.cmake
index a6f6341d43..ff9744a5a9 100644
--- a/ffi/cmake/Utils/Library.cmake
+++ b/ffi/cmake/Utils/Library.cmake
@@ -14,6 +14,14 @@
 # KIND, either express or implied.  See the License for the
 # specific language governing permissions and limitations
 # under the License.
+
+function(tvm_ffi_add_prefix_map target_name prefix_path)
+  # Add prefix map so the path displayed becomes relative to prefix_path
+  if(CMAKE_CXX_COMPILER_ID MATCHES "GNU|Clang")
+    target_compile_options(${target_name} PRIVATE 
"-ffile-prefix-map=${prefix_path}/=")
+  endif()
+endfunction()
+
 function(tvm_ffi_add_apple_dsymutil target_name)
   # running dsymutil on macos to generate debugging symbols for backtraces
   if(APPLE AND TVM_FFI_USE_LIBBACKTRACE)
diff --git a/ffi/include/tvm/ffi/c_api.h b/ffi/include/tvm/ffi/c_api.h
index d54ef0ea49..b1107c4a0c 100644
--- a/ffi/include/tvm/ffi/c_api.h
+++ b/ffi/include/tvm/ffi/c_api.h
@@ -836,13 +836,15 @@ TVM_FFI_DLL const TVMFFITypeAttrColumn* 
TVMFFIGetTypeAttrColumn(const TVMFFIByte
  * \param filename The current file name.
  * \param lineno The current line number
  * \param func The current function
+ * \param cross_ffi_boundary Whether the traceback is crossing the ffi boundary
+ *                           or we should stop at the ffi boundary when 
detected
  * \return The traceback string
  *
  * \note filename/func can be nullptr, then these info are skipped, they are 
useful
  *       for cases when debug symbols is not available.
  */
 TVM_FFI_DLL const TVMFFIByteArray* TVMFFITraceback(const char* filename, int 
lineno,
-                                                   const char* func);
+                                                   const char* func, int 
cross_ffi_boundary);
 
 /*!
  * \brief Initialize the type info during runtime.
diff --git a/ffi/include/tvm/ffi/error.h b/ffi/include/tvm/ffi/error.h
index 5e5ceac667..ae06ca5a2c 100644
--- a/ffi/include/tvm/ffi/error.h
+++ b/ffi/include/tvm/ffi/error.h
@@ -216,7 +216,7 @@ class ErrorBuilder {
  */
 #define TVM_FFI_THROW(ErrorKind)                                               
            \
   ::tvm::ffi::details::ErrorBuilder(#ErrorKind,                                
            \
-                                    TVMFFITraceback(__FILE__, __LINE__, 
TVM_FFI_FUNC_SIG), \
+                                    TVMFFITraceback(__FILE__, __LINE__, 
TVM_FFI_FUNC_SIG, 0), \
                                     TVM_FFI_ALWAYS_LOG_BEFORE_THROW)           
            \
       .stream()
 
@@ -229,7 +229,7 @@ class ErrorBuilder {
  */
 #define TVM_FFI_LOG_AND_THROW(ErrorKind)                                       
                  \
   ::tvm::ffi::details::ErrorBuilder(#ErrorKind,                                
                  \
-                                    TVMFFITraceback(__FILE__, __LINE__, 
TVM_FFI_FUNC_SIG), true) \
+                                    TVMFFITraceback(__FILE__, __LINE__, 
TVM_FFI_FUNC_SIG, 0), true) \
       .stream()
 
 // Glog style checks with TVM_FFI prefix
diff --git a/ffi/python/tvm_ffi/cython/base.pxi 
b/ffi/python/tvm_ffi/cython/base.pxi
index e61eaf322d..4caecc1f96 100644
--- a/ffi/python/tvm_ffi/cython/base.pxi
+++ b/ffi/python/tvm_ffi/cython/base.pxi
@@ -187,7 +187,8 @@ cdef extern from "tvm/ffi/c_api.h":
     int TVMFFITypeKeyToIndex(TVMFFIByteArray* type_key, int32_t* out_tindex) 
nogil
     int TVMFFIDataTypeFromString(TVMFFIByteArray* str, DLDataType* out) nogil
     int TVMFFIDataTypeToString(const DLDataType* dtype, TVMFFIAny* out) nogil
-    const TVMFFIByteArray* TVMFFITraceback(const char* filename, int lineno, 
const char* func) nogil;
+    const TVMFFIByteArray* TVMFFITraceback(
+        const char* filename, int lineno, const char* func, int 
cross_ffi_boundary) nogil;
     int TVMFFINDArrayFromDLPack(DLManagedTensor* src, int32_t 
require_alignment,
                                 int32_t require_contiguous, 
TVMFFIObjectHandle* out) nogil
     int TVMFFINDArrayFromDLPackVersioned(DLManagedTensorVersioned* src,
diff --git a/ffi/python/tvm_ffi/cython/error.pxi 
b/ffi/python/tvm_ffi/cython/error.pxi
index 968860390a..b7771000fd 100644
--- a/ffi/python/tvm_ffi/cython/error.pxi
+++ b/ffi/python/tvm_ffi/cython/error.pxi
@@ -98,7 +98,7 @@ cdef inline int set_last_ffi_error(error) except -1:
     kind = ERROR_TYPE_TO_NAME.get(type(error), "RuntimeError")
     message = error.__str__()
     py_traceback = _TRACEBACK_TO_STR(error.__traceback__)
-    c_traceback = bytearray_to_str(TVMFFITraceback("<unknown>", 0, 
"<unknown>"))
+    c_traceback = bytearray_to_str(TVMFFITraceback(NULL, 0, NULL, 0))
 
     # error comes from an exception thrown from C++ side
     if hasattr(error, "__tvm_ffi_error__"):
diff --git a/ffi/src/ffi/error.cc b/ffi/src/ffi/error.cc
index 1ed0476203..faf5ea27e3 100644
--- a/ffi/src/ffi/error.cc
+++ b/ffi/src/ffi/error.cc
@@ -57,7 +57,7 @@ class SafeCallContext {
 void TVMFFIErrorSetRaisedFromCStr(const char* kind, const char* message) {
   // NOTE: run traceback here to simplify the depth of tracekback
   tvm::ffi::SafeCallContext::ThreadLocal()->SetRaisedByCstr(kind, message,
-                                                            
TVMFFITraceback(nullptr, 0, nullptr));
+                                                            
TVMFFITraceback(nullptr, 0, nullptr, 0));
 }
 
 void TVMFFIErrorSetRaised(TVMFFIObjectHandle error) {
diff --git a/ffi/src/ffi/extra/testing.cc b/ffi/src/ffi/extra/testing.cc
index e3efba6350..1a7bdb4e68 100644
--- a/ffi/src/ffi/extra/testing.cc
+++ b/ffi/src/ffi/extra/testing.cc
@@ -55,11 +55,16 @@ class TestObjectDerived : public TestObjectBase {
   TVM_FFI_DECLARE_FINAL_OBJECT_INFO(TestObjectDerived, TestObjectBase);
 };
 
-void TestRaiseError(String kind, String msg) {
-  throw ffi::Error(kind, msg, TVMFFITraceback(__FILE__, __LINE__, 
TVM_FFI_FUNC_SIG));
+TVM_FFI_NO_INLINE void TestRaiseError(String kind, String msg) {
+  // keep name and no liner for testing traceback
+  throw ffi::Error(kind, msg, TVMFFITraceback(__FILE__, __LINE__, 
TVM_FFI_FUNC_SIG, 0));
 }
 
-void TestApply(Function f, PackedArgs args, Any* ret) { f.CallPacked(args, 
ret); }
+TVM_FFI_NO_INLINE void TestApply(PackedArgs args, Any* ret) {
+  // keep name and no liner for testing traceback
+  auto f = args[0].cast<Function>();
+  f.CallPacked(args.Slice(1), ret);
+}
 
 TVM_FFI_STATIC_INIT_BLOCK({
   namespace refl = tvm::ffi::reflection;
@@ -78,11 +83,7 @@ TVM_FFI_STATIC_INIT_BLOCK({
       .def("testing.test_raise_error", TestRaiseError)
       .def_packed("testing.nop", [](PackedArgs args, Any* ret) { *ret = 
args[0]; })
       .def_packed("testing.echo", [](PackedArgs args, Any* ret) { *ret = 
args[0]; })
-      .def_packed("testing.apply",
-                  [](PackedArgs args, Any* ret) {
-                    auto f = args[0].cast<Function>();
-                    TestApply(f, args.Slice(1), ret);
-                  })
+      .def_packed("testing.apply", TestApply)
       .def("testing.run_check_signal",
            [](int nsec) {
              for (int i = 0; i < nsec; ++i) {
diff --git a/ffi/src/ffi/traceback.cc b/ffi/src/ffi/traceback.cc
index debe5c5b07..d232e05786 100644
--- a/ffi/src/ffi/traceback.cc
+++ b/ffi/src/ffi/traceback.cc
@@ -95,13 +95,11 @@ int BacktraceFullCallback(void* data, uintptr_t pc, const 
char* filename, int li
     backtrace_syminfo(_bt_state, pc, BacktraceSyminfoCallback, 
BacktraceErrorCallback, &symbol_str);
   }
   symbol = symbol_str.data();
-  // TVMFFITraceback function itself does not count
   if (IsTracebackFunction(filename, symbol)) return 0;
-
   if (stack_trace->ExceedTracebackLimit()) {
     return 1;
   }
-  if (ShouldStopTraceback(filename, symbol)) {
+  if (stack_trace->stop_at_boundary && DetectFFIBoundary(filename, symbol)) {
     return 1;
   }
   // skip extra frames
@@ -119,13 +117,15 @@ int BacktraceFullCallback(void* data, uintptr_t pc, const 
char* filename, int li
 }  // namespace ffi
 }  // namespace tvm
 
-const TVMFFIByteArray* TVMFFITraceback(const char* filename, int lineno, const 
char* func) {
+const TVMFFIByteArray* TVMFFITraceback(const char* filename, int lineno, const 
char* func,
+                                       int cross_ffi_boundary) {
   // We collapse the traceback into a single function
   // to simplify the traceback detection handling (since we need to detect 
TVMFFITraceback)
   static thread_local std::string traceback_str;
   static thread_local TVMFFIByteArray traceback_array;
   // pass in current line as here so last line of traceback is always accurate
   tvm::ffi::TracebackStorage traceback;
+  traceback.stop_at_boundary = cross_ffi_boundary == 0;
   if (filename != nullptr && func != nullptr) {
     traceback.skip_frame_count = 1;
     traceback.Append(filename, func, lineno);
@@ -148,7 +148,7 @@ void TVMFFISegFaultHandler(int sig) {
   // Technically we shouldn't do any allocation in a signal handler, but
   // Backtrace may allocate. What's the worst it could do? We're already
   // crashing.
-  const TVMFFIByteArray* traceback = TVMFFITraceback(nullptr, 0, nullptr);
+  const TVMFFIByteArray* traceback = TVMFFITraceback(nullptr, 0, nullptr, 1);
   std::cerr << "!!!!!!! Segfault encountered !!!!!!!\n"
             << std::string(traceback->data, traceback->size) << std::endl;
   // Re-raise signal with default handler
@@ -167,7 +167,8 @@ __attribute__((constructor)) void 
TVMFFIInstallSignalHandler(void) {
 #endif  // TVM_FFI_BACKTRACE_ON_SEGFAULT
 #else
 // fallback implementation simply print out the last trace
-const TVMFFIByteArray* TVMFFITraceback(const char* filename, int lineno, const 
char* func) {
+const TVMFFIByteArray* TVMFFITraceback(const char* filename, int lineno, const 
char* func,
+                                       int cross_ffi_boundary) {
   static thread_local std::string traceback_str;
   static thread_local TVMFFIByteArray traceback_array;
   std::ostringstream traceback_stream;
diff --git a/ffi/src/ffi/traceback.h b/ffi/src/ffi/traceback.h
index 7a8ac1e7b8..43768401a6 100644
--- a/ffi/src/ffi/traceback.h
+++ b/ffi/src/ffi/traceback.h
@@ -64,29 +64,37 @@ bool IsTracebackFunction(const char*, const char* symbol) {
  * \brief List frame patterns that should be excluded as they contain less 
information
  */
 inline bool ShouldExcludeFrame(const char* filename, const char* symbol) {
+  if (symbol != nullptr) {
+    if (strncmp(symbol, "tvm::ffi::Function", 18) == 0) {
+      return true;
+    }
+    if (strncmp(symbol, "tvm::ffi::details::", 19) == 0) {
+      return true;
+    }
+  }
   if (filename) {
     // Stack frames for TVM FFI
-    if (strstr(filename, "include/tvm/ffi/error.h")) {
+    if (strncmp(filename, "include/tvm/ffi/error.h", 23) == 0) {
       return true;
     }
-    if (strstr(filename, "include/tvm/ffi/function_details.h")) {
+    if (strncmp(filename, "include/tvm/ffi/function_details.h", 34) == 0) {
       return true;
     }
-    if (strstr(filename, "include/tvm/ffi/function.h")) {
+    if (strncmp(filename, "include/tvm/ffi/function.h", 26) == 0) {
       return true;
     }
-    if (strstr(filename, "include/tvm/ffi/any.h")) {
+    if (strncmp(filename, "include/tvm/ffi/any.h", 21) == 0) {
       return true;
     }
     // C++ stdlib frames
-    if (strstr(filename, "include/c++/")) {
+    if (strncmp(filename, "include/c++/", 12) == 0) {
       return true;
     }
   }
 
   if (symbol) {
     // C++ stdlib frames
-    if (strstr(symbol, "__libc_")) {
+    if (strncmp(symbol, "__libc_", 7) == 0) {
       return true;
     }
   }
@@ -94,7 +102,7 @@ inline bool ShouldExcludeFrame(const char* filename, const 
char* symbol) {
   // addresses with no symbol name.  This could be improved in the
   // future by using dladdr() to check whether an address is contained
   // in libffi.so
-  if (strstr(symbol, "ffi_call_")) {
+  if (strncmp(symbol, "ffi_call_", 9) == 0) {
     return true;
   }
   return false;
@@ -107,15 +115,15 @@ inline bool ShouldExcludeFrame(const char* filename, 
const char* symbol) {
  * \return true if the frame should stop the traceback.
  * \note We stop traceback at the FFI boundary.
  */
-inline bool ShouldStopTraceback(const char* filename, const char* symbol) {
+inline bool DetectFFIBoundary(const char* filename, const char* symbol) {
   if (symbol != nullptr) {
-    if (strncmp(symbol, "TVMFFIFunctionCall", 14) == 0) {
+    if (strncmp(symbol, "TVMFFIFunctionCall", 18) == 0) {
       return true;
     }
     // Python interpreter stack frames
     // we stop traceback at the Python interpreter stack frames
     // since these frame will be handled from by the python side.
-    if (strncmp(symbol, "_Py", 3) == 0 || strncmp(symbol, "PyObject", 9) == 0) 
{
+    if (strncmp(symbol, "_Py", 3) == 0 || strncmp(symbol, "PyObject", 8) == 0) 
{
       return true;
     }
   }
@@ -131,6 +139,8 @@ struct TracebackStorage {
   size_t max_frame_size = GetTracebackLimit();
   /*! \brief Number of frames to skip. */
   size_t skip_frame_count = 0;
+  /*! \brief Whether to stop at the ffi boundary. */
+  bool stop_at_boundary = true;
 
   void Append(const char* filename, const char* func, int lineno) {
     // skip frames with empty filename
@@ -146,9 +156,7 @@ struct TracebackStorage {
     }
     std::ostringstream trackeback_stream;
     trackeback_stream << "  File \"" << filename << "\"";
-    if (lineno != 0) {
-      trackeback_stream << ", line " << lineno;
-    }
+    trackeback_stream << ", line " << lineno;
     trackeback_stream << ", in " << func << '\n';
     lines.push_back(trackeback_stream.str());
   }
diff --git a/ffi/src/ffi/traceback_win.cc b/ffi/src/ffi/traceback_win.cc
index 1b7d2ee71c..0a5ff4426a 100644
--- a/ffi/src/ffi/traceback_win.cc
+++ b/ffi/src/ffi/traceback_win.cc
@@ -36,12 +36,14 @@
 
 #include "./traceback.h"
 
-const TVMFFIByteArray* TVMFFITraceback(const char* filename, int lineno, const 
char* func) {
+const TVMFFIByteArray* TVMFFITraceback(const char* filename, int lineno, const 
char* func,
+                                       int cross_ffi_boundary) {
   static thread_local std::string traceback_str;
   static thread_local TVMFFIByteArray traceback_array;
 
   // pass in current line as here so last line of traceback is always accurate
   tvm::ffi::TracebackStorage traceback;
+  traceback.stop_at_boundary = cross_ffi_boundary == 0;
   if (filename != nullptr && func != nullptr) {
     traceback.skip_frame_count = 1;
     traceback.Append(filename, func, lineno);
@@ -114,7 +116,7 @@ const TVMFFIByteArray* TVMFFITraceback(const char* 
filename, int lineno, const c
     if (IsTracebackFunction(filename, symbol)) {
       continue;
     }
-    if (ShouldStopTraceback(filename, symbol)) {
+    if (traceback.stop_at_boundary && DetectFFIBoundary(filename, symbol)) {
       break;
     }
     // skip extra frames
diff --git a/include/tvm/runtime/logging.h b/include/tvm/runtime/logging.h
index da715848e0..e9482a9907 100644
--- a/include/tvm/runtime/logging.h
+++ b/include/tvm/runtime/logging.h
@@ -206,7 +206,7 @@ class InternalError : public Error {
    */
   InternalError(std::string file, int lineno, std::string message)
       : Error(DetectKind(message), DetectMessage(message),
-              TVMFFITraceback(file.c_str(), lineno, "")) {}
+              TVMFFITraceback(file.c_str(), lineno, "", 0)) {}
 
  private:
   // try to detect the kind of error from the message when the error type
diff --git a/src/tir/schedule/error.h b/src/tir/schedule/error.h
index 0c185bea34..8ddffce3ce 100644
--- a/src/tir/schedule/error.h
+++ b/src/tir/schedule/error.h
@@ -31,7 +31,7 @@ class ScheduleError : public tvm::runtime::Error {
  public:
   /*! \brief Base constructor */
   ScheduleError()
-      : tvm::runtime::Error("ScheduleError", "", TVMFFITraceback(nullptr, 0, 
nullptr)) {}
+      : tvm::runtime::Error("ScheduleError", "", TVMFFITraceback(nullptr, 0, 
nullptr, 0)) {}
   /*! \brief The error occurred in this IRModule */
   virtual IRModule mod() const = 0;
   /*! \brief The locations of interest that we want to point out */

Reply via email to