Cpp文件使用代码追踪源码函数调试
include $(CLEAR_VARS)
LOCAL_MODULE := mysettings
LOCAL_ARM_MODE :=arm
#LOCAL_SHARED_LIBRARIES := libutils libcutils liblog
LOCAL_CFLAGS :=
-fexceptions
-frtti
#Android.bp
#// 启用 C++ 异常和 RTTI
cpp: {
exception: “enabled”,
rtti: “enabled”,
},
#// 移除 cpp 属性,改用 cflags
cflags: [
“-fexceptions”, // 启用 C++ 异常
“-frtti”, // 启用 RTTI
],
#cflags: [
“-DANDROID_CPP_FEATURES=exceptions rtti”,
#],
#LOCAL_MODULE_FILENAME:=libjniUtil
LOCAL_SRC_FILES :=systemJni.cpp TestCJni.c TestCpp.cpp
#prop/watchprops.c prop/hashmap.c
LOCAL_LDLIBS :=-llog
#LOCAL_LDFLAGS := Wl,-hash-style=sysv
#libsysv-hash-table-library_ldflags := Wl,-hash-style=sysv
include $(BUILD_SHARED_LIBRARY)
#include <c++/v1/stdexcept>
//using namespace std;
//在 Android NDK 开发中,ALOG_ASSERT、ALOGE 和 abort 的头文件来源如下:
//ALOG_ASSERT / ALOGE:
//这些是 Android 特有的日志宏,用于 Native 层日志输出
// 头文件:#include <android/log.h>
// 需要在 Android.mk 中添加:LOCAL_LDLIBS += -llog
//abort():
//标准 C 库函数,用于异常终止程序
// 头文件:#include <stdlib.h>
// 标准库函数,无需额外链接库
// 示例代码:
#include <android/log.h> // ALOG_ASSERT, ALOGE
#include <stdlib.h> // abort
#define LOG_TAG “MyNativeCode”
void someFunction() {
int* ptr = nullptr;
// 断言检查,条件为false时终止并输出日志
// ALOG_ASSERT(ptr != nullptr, “Pointer should not be null!”);
// 输出错误日志但继续执行
// ALOGE(“This is an error message: %d”, 42);
// 直接终止程序
abort();
}
//注意:在非 Android 环境下,ALOG_* 宏不可用,需使用标准 C++ 日志方法替代
//3. 使用调试器(GDB/LlDB)
//通过调试器设置断点、单步执行和查看调用栈。
//bash
//# Android 设备调试示例
// adb shell gdbserver :5039 /path/to/your/binary # 在设备上启动 GDB 服务器
// arm-linux-androideabi-gdb # 主机端启动 GDB
// (gdb) target remote :5039 # 连接到设备
//(gdb) break funcA # 设置断点
//(gdb) continue # 继续执行
//(gdb) backtrace # 查看调用栈
//
// 优点:强大灵活,可实时查看变量状态。
//缺点:需要调试环境,可能影响程序行为
//4. 使用回溯库(Backtrace)
//在运行时动态获取调用栈信息,适合记录异常发生时的上下文。
//#include <backtrace/Backtrace.h>
void logStackTrace() {
// android::Backtrace bt;
// bt.Unwind(1); // 跳过当前函数
// bt.Dump(LOG_TAG); // 输出到日志
}
void funcC() {
if (/errorCondition/true) {
LOGE(“Error occurred! Stack trace:”);
// logStackTrace(); // 记录当前调用栈
}
}
//优点:无需调试器,适合生产环境捕获异常。
//缺点:依赖平台库(如 Android 的 libbacktrace)
//5. 使用编译选项(__builtin_return_address)
//GCC/Clang 提供的内置函数可获取调用者地址。
#include <stdio.h>
void printCaller() {
void* caller = __builtin_return_address(0); // 当前函数返回地址
void* parent = __builtin_return_address(1); // 调用者返回地址
printf(“%s: called from %p (parent=%p)\n”, func, caller, parent);
}
//优点:轻量级,无需额外库。
//缺点:返回地址需结合调试符号解析,可读性差。
//7. 自定义钩子(Hook)
//通过函数指针或动态链接库(DLL)注入修改函数行为。
// 使用 LD_PRELOAD 技术替换标准库函数
#define _GNU_SOURCE
#include <dlfcn.h>
#include <stdio.h>
// 原始函数指针
static ssize_t (real_write)(int fd, const void buf, size_t count) = NULL;
// 替换函数
ssize_t write(int fd, const void* buf, size_t count) {
printf(“HOOK: write(fd=%d, buf=%p, count=%zu)\n”, fd, buf, count);
// 调用原始函数
if (!real_write) {
// 关键修改:显式类型转换
real_write = (ssize_t (*)(int, const void *, size_t))dlsym(RTLD_NEXT, "write");
// 检查dlsym调用是否失败
if (!real_write) {
fprintf(stderr, "dlsym error: %s\n", dlerror());
// 处理错误,例如返回错误值或调用原始write
return -1;
}
}
return real_write(fd, buf, count);
}
//优点:无需修改源代码,适合第三方库调试。
//缺点:侵入性强,可能导致不稳定
using namespace std;
//cPP语言抛出异常
void throwTest() {
// std::shared_ptraidl::android::hardware::camera::device::ICameraDevice aidl =NULL;
// aidl = aidl.make_shared();
// aidl.get();
// aidl.get();
// throw exception(“throwException 抛出异常对象”);
// __throw_length_error();
//::open()
//::write()
//pwrite()
throw new std::bad_alloc();
throw std::runtime_error(std::string(func));
throw std::bad_typeid();
throw std::range_error(std::string(func));
throw std::bad_alloc();
throw std::exception();
throw std::bad_exception();
throw std::bad_cast();
int index =0;
int size =0;
// 替换为
// ALOG_ASSERT(index < size, “%s: index out of range (index=%d, size=%d)”,
// func, index, size);
// 方案 2:使用日志 + 终止(适合生产环境)
// 如果需要在生产环境中保留错误记录但不崩溃,可以使用日志 + 条件终止。
// cpp
// 严重错误,记录日志后终止程序
// ALOGF(“FATAL: %s: index out of range (index=%d, size=%d)”,
// func, index, size);
abort(); // 可选:是否强制终止
// 或仅记录错误(不终止)
// ALOGE(“ERROR: %s: index out of range (index=%d, size=%d)”,
// func, index, size);
// 方案 3:使用断言(仅用于调试)
// ALOG_ASSERT( “%s: index out of range”, func);
// 或者使用系统断言
assert( “index out of range”);
// 正常处理
// LOGI(ERROR) << func << “: index out of range”;
throw std::out_of_range(std::string(__func__));
throw std::invalid_argument(std::string(__func__));
throw std::current_exception();
throw std::exception();
throw std::exception_ptr();
// __throw_logic_error(__func__);
throw std::bad_exception();
throw std::bad_exception();
throw std::overflow_error(std::string(__func__));
throw std::underflow_error(std::string(__func__));
// throw std::length_error(std::string(func));
throw std::domain_error(std::string(func));
throw std::invalid_argument(std::string(__func__));
throw std::out_of_range(std::string(__func__));
throw std::runtime_error(std::string(__func__));
throw std::out_of_range(std::string(__func__));
char *test;
test = nullptr;
if (strcmp("", "")) {
}
}
-
使用标准 C++ 日志替代方案
cpp
#include #include // for abort()
void someFunction() {
int* ptr = nullptr;// 替代ALOG_ASSERT:条件不满足时终止程序
if (ptr == nullptr) {
std::cerr << “Assertion failed: Pointer should not be null!” << std::endl;
std::abort();
}// 替代ALOGE:输出错误信息
std::cerr << "This is an error message: " << 42 << std::endl;// 或使用printf风格(需包含)
// printf(“This is an error message: %d\n”, 42);} -
自定义日志宏(推荐方案)
创建一个跨平台的日志头文件,兼容 Android 和非 Android 环境:
cpp
// utils/Logger.h#ifndef UTILS_LOGGER_H#define UTILS_LOGGER_H
#ifdef ANDROID
#include <android/log.h>
#define LOG_TAG “MyApp”
#define LOG_ERROR(…) __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, VA_ARGS)
#define LOG_ASSERT(condition, …) ((condition) ? (void)0 :
(__android_log_assert(#condition, LOG_TAG, VA_ARGS), std::abort()))#else
#include
#include
#define LOG_ERROR(…) fprintf(stderr, VA_ARGS)
#define LOG_ASSERT(condition, …) ((condition) ? (void)0 :
(fprintf(stderr, “Assertion failed: %s\n”, #condition),
fprintf(stderr, VA_ARGS),
std::abort()))#endif
#endif // UTILS_LOGGER_H
使用示例:
cpp
#include “utils/Logger.h”
void someFunction() {
int* ptr = nullptr;
LOG_ASSERT(ptr != nullptr, "Pointer should not be null!");
LOG_ERROR("This is an error message: %d\n", 42);}
这种方案的优势是:
完全兼容 Android 环境的原有日志
可以在非 Android 环境(如 Windows/Linux 桌面开发)中正常工作
保持了与 ALOG_系列宏一致的使用习惯