buffer
This commit is contained in:
189
source/buffer/internal.h
Normal file
189
source/buffer/internal.h
Normal file
@@ -0,0 +1,189 @@
|
||||
// /*
|
||||
// * Linux内核诊断工具--杂项定义头文件
|
||||
// *
|
||||
// * Copyright (C) 2020 Alibaba Ltd.
|
||||
// *
|
||||
// * 作者: Baoyou Xie <baoyou.xie@linux.alibaba.com>
|
||||
// *
|
||||
// * License terms: GNU General Public License (GPL) version 3
|
||||
// *
|
||||
// */
|
||||
|
||||
// #include <string>
|
||||
// #include <set>
|
||||
// #include "uapi/ali_diagnose.h"
|
||||
// #include "json/json.h"
|
||||
|
||||
// #include <fcntl.h>
|
||||
// #include <sys/ioctl.h>
|
||||
// #include <unistd.h>
|
||||
|
||||
// #include "debug.h"
|
||||
|
||||
// extern std::set<int> g_proc_map;
|
||||
|
||||
// int run_trace_main(int argc, char **argv);
|
||||
// int sys_delay_main(int argc, char **argv);
|
||||
// int sched_delay_main(int argc, char **argv);
|
||||
// int throttle_delay_main(int argc, char **argv);
|
||||
// int load_monitor_main(int argc, char **argv);
|
||||
// int exit_monitor_main(int argc, char **argv);
|
||||
// int utilization_main(int argc, char **argv);
|
||||
// int perf_main(int argc, char **argv);
|
||||
// int tcp_retrans_main(int argc, char **argv);
|
||||
// int tcp_connect_main(int argc, char **argv);
|
||||
// int rw_top_main(int argc, char **argv);
|
||||
// int irq_delay_main(int argc, char **argv);
|
||||
// int mutex_monitor_main(int argc, char **argv);
|
||||
// int alloc_top_main(int argc, char **argv);
|
||||
// int alloc_load_main(int argc, char **argv);
|
||||
// int drop_packet_main(int argc, char **argv);
|
||||
// int fs_orphan_main(int argc, char **argv);
|
||||
// int df_du_main(int argc, char **argv);
|
||||
// int exec_monitor_main(int argc, char **argv);
|
||||
// int fs_shm_main(int argc, char **argv);
|
||||
// int irq_stats_main(int argc, char **argv);
|
||||
// int irq_trace_main(int argc, char **argv);
|
||||
// int kprobe_main(int argc, char **argv);
|
||||
// int mm_leak_main(int argc, char **argv);
|
||||
// int proc_monitor_main(int argc, char **argv);
|
||||
// int runq_info_main(int argc, char **argv);
|
||||
// int reboot_main(int argc, char **argv);
|
||||
// int pi_main(int argc, char *argv[]);
|
||||
// int memcpy_main(int argc, char* argv[]);
|
||||
// int md5_main(int argc, char *argv[]);
|
||||
// int net_bandwidth_main(int argc, char *argv[]);
|
||||
// int sig_info_main(int argc, char *argv[]);
|
||||
// int task_monitor_main(int argc, char **argv);
|
||||
// int rw_sem_main(int argc, char **argv);
|
||||
// int rss_monitor_main(int argc, char **argv);
|
||||
|
||||
// void usage_run_trace(void);
|
||||
// void usage_sys_delay(void);
|
||||
// void usage_load_monitor(void);
|
||||
// void usage_exit_monitor(void);
|
||||
// void usage_utilization(void);
|
||||
// void usage_perf();
|
||||
// void usage_tcp_retrans();
|
||||
// void usage_rw_top();
|
||||
// void usage_irq_delay();
|
||||
// void usage_mutex_monitor();
|
||||
// void usage_alloc_top();
|
||||
// void usage_drop_packet();
|
||||
// void usage_fs_orphan();
|
||||
// void usage_exec_monitor();
|
||||
// void usage_fs_shm();
|
||||
// void usage_irq_stats();
|
||||
// void usage_irq_trace();
|
||||
// void usage_kprobe();
|
||||
// void usage_mm_leak();
|
||||
// void usage_testcase(void);
|
||||
// void usage_pupil(void);
|
||||
// void usage_sched_delay(void);
|
||||
// void usage_reboot(void);
|
||||
// void usage_test_memcpy(void);
|
||||
// void usage_test_pi(void);
|
||||
// void usage_test_md5(void);
|
||||
// void usage_net_bandwidth(void);
|
||||
// void usage_sig_info(void);
|
||||
// void usage_task_monitor(void);
|
||||
// void usage_rw_sem(void);
|
||||
// void usage_rss_monitor(void);
|
||||
// void usage_throttle_delay(void);
|
||||
|
||||
// int uprobe_main(int argc, char **argv);
|
||||
// void usage_uprobe();
|
||||
|
||||
// int ping_delay_main(int argc, char *argv[]);
|
||||
// void usage_ping_delay(void);
|
||||
// int ping_delay6_main(int argc, char *argv[]);
|
||||
// void usage_ping_delay6(void);
|
||||
|
||||
// int test_run_trace_main(int argc, char *argv[]);
|
||||
// void usage_test_run_trace(void);
|
||||
|
||||
// int memcg_stats_main(int argc, char *argv[]);
|
||||
// void usage_memcg_stats(void);
|
||||
|
||||
// int diag_activate(const char func[]);
|
||||
// int diag_deactivate(const char func[]);
|
||||
|
||||
// void diag_printf_inode(struct diag_inode_detail *inode);
|
||||
// void diag_printf_time(struct diag_timespec *tv);
|
||||
// void diag_printf_task(struct diag_task_detail *task);
|
||||
// void diag_printf_proc_chains(struct diag_proc_chains_detail *proc_chains);
|
||||
// void diag_printf_proc_chains(struct diag_proc_chains_detail *proc_chains, int reverse);
|
||||
// void diag_printf_proc_chains(struct diag_proc_chains_detail *proc_chains, int reverse, int detail);
|
||||
// void diag_printf_kern_stack(struct diag_kern_stack_detail *kern_stack);
|
||||
// void diag_printf_kern_stack(struct diag_kern_stack_detail *kern_stack, int reverse);
|
||||
// void diag_printf_user_stack(int pid, int ns_pid, const char *comm,
|
||||
// struct diag_user_stack_detail *user_stack);
|
||||
// void diag_printf_user_stack(int pid, int ns_pid, const char *comm,
|
||||
// struct diag_user_stack_detail *user_stack, int attach);
|
||||
// void diag_printf_user_stack(int pid, int ns_pid, const char *comm,
|
||||
// struct diag_user_stack_detail *user_stack, int attach, int reverse);
|
||||
// void diag_printf_raw_stack(int pid, int ns_pid, const char *comm,
|
||||
// struct diag_raw_stack_detail *raw_stack);
|
||||
// void diag_printf_raw_stack(int pid, int ns_pid, const char *comm,
|
||||
// struct diag_raw_stack_detail *raw_stack, int attach);
|
||||
// void init_java_env(const char *agent, int pid, int ns_pid, const char *comm, std::set<int> &);
|
||||
// void diag_unwind_raw_stack(int pid, int ns_pid,
|
||||
// struct diag_raw_stack_detail *raw_stack, unsigned long stack[BACKTRACE_DEPTH]);
|
||||
|
||||
// void diag_sls_time(struct diag_timespec *tv, Json::Value &owner);
|
||||
// void diag_sls_task(struct diag_task_detail *tsk_info, Json::Value &task);
|
||||
// void diag_sls_proc_chains(struct diag_proc_chains_detail *proc_chains, Json::Value &task);
|
||||
// void diag_sls_kern_stack(struct diag_kern_stack_detail *kern_stack, Json::Value &task);
|
||||
// void diag_sls_user_stack(pid_t pid, pid_t ns_pid, const char *comm,
|
||||
// struct diag_user_stack_detail *user_stack, Json::Value &task);
|
||||
// void diag_sls_user_stack(pid_t pid, pid_t ns_pid, const char *comm,
|
||||
// struct diag_user_stack_detail *user_stack, Json::Value &task, int attach);
|
||||
// void diag_sls_inode(struct diag_inode_detail *inode, Json::Value &root);
|
||||
// int log_config(char *arg, char *sls_file, int *p_syslog_enabled);
|
||||
// void write_syslog(int enabled, const char mod[], struct diag_timespec *tv, unsigned long id, int seq, Json::Value &root);
|
||||
// void write_file(char *sls_file, const char mod[], struct diag_timespec *tv, unsigned long id, int seq, Json::Value &root);
|
||||
// void diag_ip_addr_to_str(unsigned char *ip_addr,const char type[], Json::Value &root);
|
||||
// #define ULONG_MAX (~0UL)
|
||||
// #define STACK_IS_END(v) ((v) == 0 || (v) == ULONG_MAX)
|
||||
|
||||
// class pid_cmdline {
|
||||
// private:
|
||||
// std::map<int, std::string> cmdlines;
|
||||
// public:
|
||||
// void clear(void);
|
||||
// std::string & get_pid_cmdline(int pid);
|
||||
// };
|
||||
|
||||
// int jmaps_main(int argc, char **argv);
|
||||
// void restore_global_env();
|
||||
// int attach_ns_env(int pid);
|
||||
// int java_attach_once(int flag_no_attach = 0);
|
||||
|
||||
// extern class pid_cmdline pid_cmdline;
|
||||
|
||||
// extern void clear_symbol_info(class pid_cmdline &pid_cmdline, std::set<int> &procs, int dist);
|
||||
// extern unsigned int ipstr2int(const char *ipstr);
|
||||
// extern char *int2ipstr(const unsigned int ip, char *ipstr, const unsigned int ip_str_len);
|
||||
|
||||
// extern int is_linux_2_6_x(void);
|
||||
// extern int linux_2_6_x;
|
||||
|
||||
// int sys_cost_main(int argc, char **argv);
|
||||
// void usage_sys_cost();
|
||||
|
||||
// int fs_cache_main(int argc, char *argv[]);
|
||||
// void usage_fs_cache(void);
|
||||
|
||||
// int high_order_main(int argc, char *argv[]);
|
||||
// void usage_high_order(void);
|
||||
|
||||
// int pmu_main(int argc, char **argv);
|
||||
// void usage_pmu(void);
|
||||
|
||||
// int testcase_main(int argc, char *argv[]);
|
||||
|
||||
// struct timeval;
|
||||
// struct timezone;
|
||||
// extern "C" {
|
||||
// void diag_gettimeofday(struct diag_timespec *tv, struct timezone *tz);
|
||||
// }
|
||||
215
source/buffer/trace_buffer.c
Normal file
215
source/buffer/trace_buffer.c
Normal file
@@ -0,0 +1,215 @@
|
||||
/*
|
||||
* diagnose-tools 工具通用调试缓冲区模块
|
||||
* 这是为了解决procfs/trace的问题而编写
|
||||
*
|
||||
* Copyright (C) 2020 Alibaba Ltd.
|
||||
*
|
||||
* 作者: Baoyou Xie <baoyou.xie@linux.alibaba.com>
|
||||
*
|
||||
* License terms: GNU General Public License (GPL) version 3
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/vmalloc.h>
|
||||
|
||||
// #include "internal.h"
|
||||
#include "trace_buffer.h"
|
||||
|
||||
int init_diag_trace_buffer(struct diag_trace_buffer *buffer,
|
||||
unsigned int buf_size)
|
||||
{
|
||||
int ret = -ENOMEM;
|
||||
char *buf1 = NULL, *buf2 = NULL;
|
||||
|
||||
ret = -EINVAL;
|
||||
if (buf_size < 10 * DIAG_TRACE_BUF_SIZE)
|
||||
return ret;
|
||||
|
||||
buf1 = vmalloc(buf_size);
|
||||
if (!buf1)
|
||||
goto out_nomem;
|
||||
|
||||
buf2 = vmalloc(buf_size);
|
||||
if (!buf2)
|
||||
goto out_nomem;
|
||||
|
||||
memset(buf1, 0, buf_size);
|
||||
memset(buf2, 0, buf_size);
|
||||
memset(buffer, 0, sizeof(struct diag_trace_buffer));
|
||||
buffer->buf_size = buf_size;
|
||||
buffer->buffer.data = buf1;
|
||||
spin_lock_init(&buffer->buffer.lock);
|
||||
mutex_init(&buffer->buffer.mutex);
|
||||
buffer->product.data = buf2;
|
||||
|
||||
ret = 0;
|
||||
return ret;
|
||||
out_nomem:
|
||||
if (buf1)
|
||||
vfree(buf1);
|
||||
if (buf2)
|
||||
vfree(buf2);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void destroy_diag_trace_buffer(struct diag_trace_buffer *buffer)
|
||||
{
|
||||
if (buffer->buffer.data)
|
||||
vfree(buffer->buffer.data);
|
||||
if (buffer->product.data)
|
||||
vfree(buffer->product.data);
|
||||
|
||||
memset(buffer, 0, sizeof(struct diag_trace_buffer));
|
||||
}
|
||||
|
||||
void discard_diag_trace_buffer(struct diag_trace_buffer *buffer)
|
||||
{
|
||||
unsigned long flags;
|
||||
|
||||
diag_trace_buffer_mutex_lock(buffer);
|
||||
diag_trace_buffer_spin_lock(buffer, flags);
|
||||
buffer->buffer.circle = buffer->buffer.pos = buffer->buffer.tail = 0;
|
||||
diag_trace_buffer_spin_unlock(buffer, flags);
|
||||
diag_trace_buffer_mutex_unlock(buffer);
|
||||
}
|
||||
|
||||
void backup_diag_trace_buffer(struct diag_trace_buffer *buffer)
|
||||
{
|
||||
unsigned long flags;
|
||||
|
||||
if (!buffer->buffer.data || !buffer->product.data)
|
||||
return;
|
||||
|
||||
diag_trace_buffer_mutex_lock(buffer);
|
||||
diag_trace_buffer_spin_lock(buffer, flags);
|
||||
|
||||
buffer->product.len = 0;
|
||||
if (buffer->buffer.pos < buffer->buf_size) {
|
||||
if (buffer->buffer.circle) {
|
||||
int tail_len = 0;
|
||||
if (buffer->buffer.tail > buffer->buffer.pos) {
|
||||
tail_len = buffer->buffer.tail - buffer->buffer.pos;
|
||||
|
||||
memcpy(buffer->product.data,
|
||||
buffer->buffer.data + buffer->buffer.pos,
|
||||
tail_len);
|
||||
}
|
||||
memcpy(buffer->product.data + tail_len,
|
||||
buffer->buffer.data,
|
||||
buffer->buffer.pos);
|
||||
buffer->product.len = buffer->buffer.pos + tail_len;
|
||||
} else {
|
||||
memcpy(buffer->product.data, buffer->buffer.data, buffer->buffer.pos);
|
||||
buffer->product.len = buffer->buffer.pos;
|
||||
}
|
||||
}
|
||||
|
||||
buffer->buffer.circle = buffer->buffer.pos = buffer->buffer.tail = 0;
|
||||
|
||||
diag_trace_buffer_spin_unlock(buffer, flags);
|
||||
diag_trace_buffer_mutex_unlock(buffer);
|
||||
}
|
||||
|
||||
asmlinkage int
|
||||
diag_trace_buffer_write_nolock(struct diag_trace_buffer *buffer,
|
||||
const void *data, size_t len)
|
||||
{
|
||||
unsigned int left;
|
||||
|
||||
left = buffer->buf_size - buffer->buffer.pos;
|
||||
if (len < left) {
|
||||
memcpy(buffer->buffer.data + buffer->buffer.pos,
|
||||
data, len);
|
||||
buffer->buffer.pos += len;
|
||||
} else {
|
||||
buffer->buffer.tail = buffer->buffer.pos;
|
||||
memcpy(buffer->buffer.data, data, len);
|
||||
buffer->buffer.pos = len;
|
||||
buffer->buffer.circle = 1;
|
||||
}
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
asmlinkage int
|
||||
diag_trace_buffer_write(struct diag_trace_buffer *buffer,
|
||||
const void *data, size_t len)
|
||||
{
|
||||
int ret;
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&buffer->buffer.lock, flags);
|
||||
ret = diag_trace_buffer_write_nolock(buffer, data, len);
|
||||
spin_unlock_irqrestore(&buffer->buffer.lock, flags);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static asmlinkage int
|
||||
__diag_trace_buffer_printk_nolock(struct diag_trace_buffer *buffer,
|
||||
const char *fmt, va_list ap)
|
||||
{
|
||||
unsigned int len = 0;
|
||||
unsigned int left;
|
||||
|
||||
len = vsnprintf(buffer->fmt_buffer, DIAG_TRACE_BUF_SIZE, fmt, ap);
|
||||
if (len > DIAG_TRACE_BUF_SIZE)
|
||||
return len;
|
||||
|
||||
left = buffer->buf_size - buffer->buffer.pos;
|
||||
if (len < left) {
|
||||
memcpy(buffer->buffer.data + buffer->buffer.pos,
|
||||
buffer->fmt_buffer, len);
|
||||
buffer->buffer.pos += len;
|
||||
} else {
|
||||
buffer->buffer.tail = buffer->buffer.pos;
|
||||
memcpy(buffer->buffer.data, buffer->fmt_buffer, len);
|
||||
buffer->buffer.pos = len;
|
||||
buffer->buffer.circle = 1;
|
||||
}
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
asmlinkage int
|
||||
diag_trace_buffer_printk_nolock(struct diag_trace_buffer *buffer,
|
||||
const char *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
int ret;
|
||||
|
||||
va_start(ap, fmt);
|
||||
ret = __diag_trace_buffer_printk_nolock(buffer, fmt, ap);
|
||||
va_end(ap);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
asmlinkage int
|
||||
diag_trace_buffer_printk(struct diag_trace_buffer *buffer,
|
||||
const char *fmt, ...)
|
||||
{
|
||||
int ret;
|
||||
unsigned long flags;
|
||||
va_list ap;
|
||||
|
||||
spin_lock_irqsave(&buffer->buffer.lock, flags);
|
||||
va_start(ap, fmt);
|
||||
ret = __diag_trace_buffer_printk_nolock(buffer, fmt, ap);
|
||||
va_end(ap);
|
||||
spin_unlock_irqrestore(&buffer->buffer.lock, flags);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void diag_trace_buffer_mutex_lock(struct diag_trace_buffer *buffer)
|
||||
{
|
||||
mutex_lock(&buffer->buffer.mutex);
|
||||
}
|
||||
|
||||
void diag_trace_buffer_mutex_unlock(struct diag_trace_buffer *buffer)
|
||||
{
|
||||
mutex_unlock(&buffer->buffer.mutex);
|
||||
}
|
||||
|
||||
106
source/buffer/trace_buffer.h
Normal file
106
source/buffer/trace_buffer.h
Normal file
@@ -0,0 +1,106 @@
|
||||
/*
|
||||
* diagnose-tools 工具通用调试缓冲区模块
|
||||
* 这是为了解决procfs/trace的问题而编写
|
||||
*
|
||||
* Copyright (C) 2020 Alibaba Ltd.
|
||||
*
|
||||
* 作者: Baoyou Xie <baoyou.xie@linux.alibaba.com>
|
||||
*
|
||||
* License terms: GNU General Public License (GPL) version 3
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/stddef.h>
|
||||
|
||||
/**
|
||||
* 调试缓冲区描述符
|
||||
* buffer: 当前正在接受调用者输出的缓冲区
|
||||
* data: 数据起始指针
|
||||
* pos: 当前写入位置
|
||||
* circle: 是否已经产生了回绕
|
||||
* tail: 有效位置的尾部
|
||||
* product: 将buffer中数据临时保存到此,避免影响记录速度
|
||||
* data: 数据起始指针
|
||||
* len: 数据有效长度
|
||||
* buf_size: buffer/product的大小
|
||||
*/
|
||||
#define DIAG_TRACE_BUF_SIZE 1024
|
||||
|
||||
struct diag_trace_buffer {
|
||||
struct {
|
||||
char *data;
|
||||
unsigned int pos;
|
||||
int circle;
|
||||
unsigned int tail;
|
||||
spinlock_t lock;
|
||||
struct mutex mutex;
|
||||
} buffer;
|
||||
|
||||
struct {
|
||||
char *data;
|
||||
unsigned int len;
|
||||
} product;
|
||||
|
||||
char fmt_buffer[DIAG_TRACE_BUF_SIZE];
|
||||
unsigned int buf_size;
|
||||
};
|
||||
|
||||
int init_diag_trace_buffer(struct diag_trace_buffer *buffer,
|
||||
unsigned int buf_size);
|
||||
void destroy_diag_trace_buffer(struct diag_trace_buffer *buffer);
|
||||
void discard_diag_trace_buffer(struct diag_trace_buffer *buffer);
|
||||
void backup_diag_trace_buffer(struct diag_trace_buffer *buffer);
|
||||
asmlinkage int
|
||||
diag_trace_buffer_printk_nolock(struct diag_trace_buffer *buffer,
|
||||
const char *fmt, ...);
|
||||
asmlinkage int
|
||||
diag_trace_buffer_printk(struct diag_trace_buffer *buffer,
|
||||
const char *fmt, ...);
|
||||
asmlinkage int
|
||||
diag_trace_buffer_write_nolock(struct diag_trace_buffer *buffer,
|
||||
const void *data, size_t len);
|
||||
asmlinkage int
|
||||
diag_trace_buffer_write(struct diag_trace_buffer *buffer,
|
||||
const void *data, size_t len);
|
||||
#define diag_trace_buffer_spin_lock(__buffer, flags) \
|
||||
spin_lock_irqsave(&((__buffer)->buffer.lock), flags)
|
||||
#define diag_trace_buffer_spin_unlock(__buffer, flags) \
|
||||
spin_unlock_irqrestore(&((__buffer)->buffer.lock), flags)
|
||||
void diag_trace_buffer_mutex_lock(struct diag_trace_buffer *buffer);
|
||||
void diag_trace_buffer_mutex_unlock(struct diag_trace_buffer *buffer);
|
||||
|
||||
void diagnose_trace_buffer_stack_trace(int pre, struct diag_trace_buffer *buffer,
|
||||
struct task_struct *p, unsigned long *backtrace);
|
||||
void diagnose_trace_buffer_nolock_stack_trace(int pre, struct diag_trace_buffer *buffer,
|
||||
struct task_struct *p, unsigned long *backtrace);
|
||||
void diagnose_trace_buffer_nolock_stack_trace_user(int pre, struct diag_trace_buffer *buffer,
|
||||
unsigned long *backtrace);
|
||||
void diagnose_trace_buffer_stack_trace_user(int pre, struct diag_trace_buffer *buffer,
|
||||
unsigned long *backtrace);
|
||||
void diagnose_trace_buffer_nolock_stack_trace_user_tsk(int pre, struct diag_trace_buffer *buffer,
|
||||
struct task_struct *tsk, unsigned long *backtrace);
|
||||
void diagnose_trace_buffer_stack_trace_user_tsk(int pre, struct diag_trace_buffer *buffer,
|
||||
struct task_struct *tsk, unsigned long *backtrace);
|
||||
void diag_trace_buffer_process_chain(int pre, struct diag_trace_buffer *buffer, struct task_struct *tsk);
|
||||
void diag_trace_buffer_nolock_process_chain(int pre, struct diag_trace_buffer *buffer, struct task_struct *tsk);
|
||||
void diag_trace_buffer_process_chain_cmdline(int pre, struct diag_trace_buffer *buffer, struct task_struct *tsk);
|
||||
void diag_trace_buffer_nolock_process_chain_cmdline(int pre, struct diag_trace_buffer *buffer, struct task_struct *tsk);
|
||||
void trace_buffer_cgroups_tsk(int pre, struct diag_trace_buffer *buffer, struct task_struct *tsk);
|
||||
void trace_buffer_nolock_cgroups_tsk(int pre, struct diag_trace_buffer *buffer, struct task_struct *tsk);
|
||||
void trace_buffer_cgroups(int pre, struct diag_trace_buffer *buffer);
|
||||
void trace_buffer_nolock_cgroups(int pre, struct diag_trace_buffer *buffer);
|
||||
void diag_trace_buffer_all_task_stack(int pre, struct diag_trace_buffer *buffer);
|
||||
void diag_trace_buffer_nolock_all_task_stack(int pre,
|
||||
struct diag_trace_buffer *buffer);
|
||||
void diagnose_trace_buffer_nolock_stack_trace_unfold(int pre, struct diag_trace_buffer *buffer,
|
||||
struct task_struct *p, unsigned long *backtrace);
|
||||
void diagnose_trace_buffer_nolock_stack_trace_unfold_user(int pre, struct diag_trace_buffer *buffer,
|
||||
unsigned long *backtrace);
|
||||
void diagnose_print_stack_trace_unfold_user_tsk(int pre, int might_sleep, struct task_struct *tsk, unsigned long *backtrace);
|
||||
void diagnose_trace_buffer_nolock_stack_trace_unfold_user_tsk(int pre, int might_sleep, struct diag_trace_buffer *buffer,
|
||||
struct task_struct *tsk, unsigned long *backtrace);
|
||||
void diagnose_trace_buffer_stack_trace_unfold_user_tsk(int pre, int might_sleep, struct diag_trace_buffer *buffer,
|
||||
struct task_struct *tsk, unsigned long *backtrace);
|
||||
|
||||
260
source/buffer/variant_buffer.c
Normal file
260
source/buffer/variant_buffer.c
Normal file
@@ -0,0 +1,260 @@
|
||||
/*
|
||||
* Linux内核诊断工具--工具通用调试缓冲区模块
|
||||
* 这是为了解决procfs/trace的问题而编写
|
||||
*
|
||||
* Copyright (C) 2020 Alibaba Ltd.
|
||||
*
|
||||
* 作者: Baoyou Xie <baoyou.xie@linux.alibaba.com>
|
||||
*
|
||||
* License terms: GNU General Public License (GPL) version 3
|
||||
*/
|
||||
|
||||
#include <linux/uaccess.h>
|
||||
#include <linux/vmalloc.h>
|
||||
|
||||
#include "trace_buffer.h"
|
||||
// #include "internal.h"
|
||||
#include "variant_buffer.h"
|
||||
|
||||
int init_diag_variant_buffer(struct diag_variant_buffer *buffer,
|
||||
unsigned int buf_size) {
|
||||
int ret = 0;
|
||||
|
||||
ret = -EINVAL;
|
||||
if (buf_size < 10 * DIAG_TRACE_BUF_SIZE)
|
||||
return ret;
|
||||
|
||||
memset(buffer, 0, sizeof(struct diag_variant_buffer));
|
||||
buffer->buf_size = buf_size;
|
||||
spin_lock_init(&buffer->lock);
|
||||
mutex_init(&buffer->mutex);
|
||||
|
||||
ret = 0;
|
||||
return ret;
|
||||
}
|
||||
|
||||
int alloc_diag_variant_buffer(struct diag_variant_buffer *buffer) {
|
||||
int ret = -ENOMEM;
|
||||
char *buf1 = NULL, *buf2 = NULL, *buf3 = NULL;
|
||||
unsigned int buf_size;
|
||||
|
||||
buf_size = buffer->buf_size;
|
||||
if (buffer->alloced)
|
||||
return 0;
|
||||
|
||||
ret = -EINVAL;
|
||||
if (buf_size < 10 * DIAG_TRACE_BUF_SIZE)
|
||||
return ret;
|
||||
|
||||
ret = -ENOMEM;
|
||||
buf1 = vmalloc(buf_size);
|
||||
if (!buf1)
|
||||
goto out_nomem;
|
||||
|
||||
buf2 = vmalloc(buf_size);
|
||||
if (!buf2)
|
||||
goto out_nomem;
|
||||
|
||||
buf3 = vmalloc(buf_size * 2);
|
||||
if (!buf3)
|
||||
goto out_nomem;
|
||||
|
||||
memset(buf1, 0, buf_size);
|
||||
memset(buf2, 0, buf_size);
|
||||
memset(buf3, 0, buf_size * 2);
|
||||
buffer->buffers[0].data = buf1;
|
||||
buffer->buffers[1].data = buf2;
|
||||
buffer->product.data = buf3;
|
||||
|
||||
buffer->alloced = 1;
|
||||
|
||||
ret = 0;
|
||||
return ret;
|
||||
out_nomem:
|
||||
if (buf1)
|
||||
vfree(buf1);
|
||||
if (buf2)
|
||||
vfree(buf2);
|
||||
if (buf3)
|
||||
vfree(buf3);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void destroy_diag_variant_buffer(struct diag_variant_buffer *buffer) {
|
||||
if (buffer->buffers[0].data)
|
||||
vfree(buffer->buffers[0].data);
|
||||
if (buffer->buffers[1].data)
|
||||
vfree(buffer->buffers[1].data);
|
||||
if (buffer->product.data)
|
||||
vfree(buffer->product.data);
|
||||
|
||||
memset(buffer, 0, sizeof(struct diag_variant_buffer));
|
||||
}
|
||||
|
||||
void discard_diag_variant_buffer(struct diag_variant_buffer *buffer) {
|
||||
unsigned long flags;
|
||||
|
||||
if (!buffer->alloced)
|
||||
return;
|
||||
|
||||
diag_variant_buffer_mutex_lock(buffer);
|
||||
diag_variant_buffer_spin_lock(buffer, flags);
|
||||
buffer->buffers[0].pos = buffer->buffers[1].pos = 0;
|
||||
buffer->buffer_toggle = 0;
|
||||
diag_variant_buffer_spin_unlock(buffer, flags);
|
||||
diag_variant_buffer_mutex_unlock(buffer);
|
||||
}
|
||||
|
||||
void backup_diag_variant_buffer(struct diag_variant_buffer *buffer) {
|
||||
unsigned long flags;
|
||||
|
||||
if (!buffer->alloced)
|
||||
return;
|
||||
|
||||
diag_variant_buffer_mutex_lock(buffer);
|
||||
diag_variant_buffer_spin_lock(buffer, flags);
|
||||
|
||||
buffer->product.len = 0;
|
||||
if (buffer->buffer_toggle == 0) {
|
||||
if (buffer->buffers[1].pos) {
|
||||
memcpy(buffer->product.data, buffer->buffers[1].data,
|
||||
buffer->buffers[1].pos);
|
||||
buffer->product.len = buffer->product.len + buffer->buffers[1].pos;
|
||||
}
|
||||
if (buffer->buffers[0].pos) {
|
||||
memcpy(buffer->product.data + buffer->product.len,
|
||||
buffer->buffers[0].data, buffer->buffers[0].pos);
|
||||
buffer->product.len = buffer->product.len + buffer->buffers[0].pos;
|
||||
}
|
||||
} else {
|
||||
if (buffer->buffers[0].pos) {
|
||||
memcpy(buffer->product.data, buffer->buffers[0].data,
|
||||
buffer->buffers[0].pos);
|
||||
buffer->product.len = buffer->product.len + buffer->buffers[0].pos;
|
||||
}
|
||||
if (buffer->buffers[1].pos) {
|
||||
memcpy(buffer->product.data + buffer->product.len,
|
||||
buffer->buffers[1].data, buffer->buffers[1].pos);
|
||||
buffer->product.len = buffer->product.len + buffer->buffers[1].pos;
|
||||
}
|
||||
}
|
||||
|
||||
buffer->buffers[0].pos = buffer->buffers[1].pos = 0;
|
||||
buffer->buffers[0].head = buffer->buffers[1].head = NULL;
|
||||
buffer->buffer_toggle = 0;
|
||||
|
||||
diag_variant_buffer_spin_unlock(buffer, flags);
|
||||
diag_variant_buffer_mutex_unlock(buffer);
|
||||
}
|
||||
|
||||
asmlinkage int diag_variant_buffer_reserve(struct diag_variant_buffer *buffer,
|
||||
size_t len) {
|
||||
int real_len = (len + sizeof(unsigned long)) & (sizeof(unsigned long) - 1);
|
||||
real_len += sizeof(struct diag_variant_buffer_head);
|
||||
/**
|
||||
* 这样可以简单的略过整型溢出检查。
|
||||
*/
|
||||
if (len > 1024 * 1024 * 1024)
|
||||
return len;
|
||||
if (!buffer->alloced)
|
||||
return len;
|
||||
|
||||
if (buffer->buffer_toggle == 0) {
|
||||
if (buffer->buffers[0].pos + real_len >= buffer->buf_size) {
|
||||
buffer->buffer_toggle = 1;
|
||||
buffer->buffers[1].pos = sizeof(struct diag_variant_buffer_head);
|
||||
buffer->buffers[1].head = (void *)buffer->buffers[1].data;
|
||||
memset(buffer->buffers[1].head, 0,
|
||||
sizeof(struct diag_variant_buffer_head));
|
||||
} else {
|
||||
buffer->buffers[0].head =
|
||||
(void *)buffer->buffers[0].data + buffer->buffers[0].pos;
|
||||
memset(buffer->buffers[0].head, 0,
|
||||
sizeof(struct diag_variant_buffer_head));
|
||||
buffer->buffers[0].pos += sizeof(struct diag_variant_buffer_head);
|
||||
}
|
||||
} else {
|
||||
if (buffer->buffers[1].pos + real_len >= buffer->buf_size) {
|
||||
buffer->buffer_toggle = 0;
|
||||
buffer->buffers[0].pos = sizeof(struct diag_variant_buffer_head);
|
||||
buffer->buffers[0].head = (void *)buffer->buffers[0].data;
|
||||
memset(buffer->buffers[0].head, 0,
|
||||
sizeof(struct diag_variant_buffer_head));
|
||||
} else {
|
||||
buffer->buffers[1].head =
|
||||
(void *)buffer->buffers[1].data + buffer->buffers[1].pos;
|
||||
memset(buffer->buffers[1].head, 0,
|
||||
sizeof(struct diag_variant_buffer_head));
|
||||
buffer->buffers[1].pos += sizeof(struct diag_variant_buffer_head);
|
||||
}
|
||||
}
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
asmlinkage int diag_variant_buffer_seal(struct diag_variant_buffer *buffer) {
|
||||
int idx = !!buffer->buffer_toggle;
|
||||
void *rbound = buffer->buffers[idx].data + buffer->buf_size;
|
||||
|
||||
if (!buffer->alloced)
|
||||
return -EINVAL;
|
||||
if ((void *)buffer->buffers[idx].head < (void *)buffer->buffers[idx].data)
|
||||
return -EINVAL;
|
||||
if ((void *)buffer->buffers[idx].head >
|
||||
(rbound - sizeof(struct diag_variant_buffer_head)))
|
||||
return -EINVAL;
|
||||
|
||||
buffer->buffers[idx].head->magic = DIAG_VARIANT_BUFFER_HEAD_MAGIC_SEALED;
|
||||
buffer->buffers[idx].head->len = (void *)buffer->buffers[idx].data +
|
||||
buffer->buffers[idx].pos -
|
||||
(void *)buffer->buffers[idx].head;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
asmlinkage int
|
||||
diag_variant_buffer_write_nolock(struct diag_variant_buffer *buffer,
|
||||
const void *data, size_t len) {
|
||||
unsigned int left;
|
||||
int idx = !!buffer->buffer_toggle;
|
||||
|
||||
if (!buffer->alloced)
|
||||
return -EINVAL;
|
||||
|
||||
left = buffer->buf_size - buffer->buffers[idx].pos;
|
||||
if (len < left) {
|
||||
memcpy(buffer->buffers[idx].data + buffer->buffers[idx].pos, data, len);
|
||||
buffer->buffers[idx].pos += len;
|
||||
}
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
void diag_variant_buffer_mutex_lock(struct diag_variant_buffer *buffer) {
|
||||
mutex_lock(&buffer->mutex);
|
||||
}
|
||||
|
||||
void diag_variant_buffer_mutex_unlock(struct diag_variant_buffer *buffer) {
|
||||
mutex_unlock(&buffer->mutex);
|
||||
}
|
||||
|
||||
int copy_to_user_variant_buffer(struct diag_variant_buffer *variant_buffer,
|
||||
void __user *ptr_len, void __user *buf,
|
||||
size_t size) {
|
||||
size_t len;
|
||||
int ret;
|
||||
|
||||
backup_diag_variant_buffer(variant_buffer);
|
||||
len = variant_buffer->product.len;
|
||||
if (size < len)
|
||||
len = size;
|
||||
ret = copy_to_user(buf, variant_buffer->product.data, len);
|
||||
if (!ret)
|
||||
ret = len;
|
||||
if (ret >= 0) {
|
||||
ret = copy_to_user(ptr_len, &ret, sizeof(int));
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
64
source/buffer/variant_buffer.h
Normal file
64
source/buffer/variant_buffer.h
Normal file
@@ -0,0 +1,64 @@
|
||||
/*
|
||||
* Linux内核诊断工具--工具通用调试缓冲区模块
|
||||
* 这是为了解决procfs/trace的问题而编写
|
||||
*
|
||||
* Copyright (C) 2020 Alibaba Ltd.
|
||||
*
|
||||
* 作者: Baoyou Xie <baoyou.xie@linux.alibaba.com>
|
||||
*
|
||||
* License terms: GNU General Public License (GPL) version 3
|
||||
*/
|
||||
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/stddef.h>
|
||||
|
||||
#define DIAG_VARIANT_BUFFER_HEAD_MAGIC_SEALED 197612031122
|
||||
#define DIAG_VARIANT_BUFFER_HEAD_MAGIC_UNSEALED 197612031234
|
||||
|
||||
struct diag_variant_buffer_head {
|
||||
unsigned long magic;
|
||||
unsigned long len;
|
||||
};
|
||||
|
||||
struct diag_variant_buffer {
|
||||
struct {
|
||||
char *data;
|
||||
unsigned int pos;
|
||||
struct diag_variant_buffer_head *head;
|
||||
} buffers[2];
|
||||
/* 0 or 1 */
|
||||
int buffer_toggle;
|
||||
|
||||
struct {
|
||||
char *data;
|
||||
unsigned int len;
|
||||
} product;
|
||||
|
||||
unsigned int buf_size;
|
||||
unsigned int alloced;
|
||||
spinlock_t lock;
|
||||
struct mutex mutex;
|
||||
};
|
||||
|
||||
#define diag_variant_buffer_spin_lock(__buffer, flags) \
|
||||
spin_lock_irqsave(&((__buffer)->lock), flags)
|
||||
#define diag_variant_buffer_spin_unlock(__buffer, flags) \
|
||||
spin_unlock_irqrestore(&((__buffer)->lock), flags)
|
||||
int init_diag_variant_buffer(struct diag_variant_buffer *buffer,
|
||||
unsigned int buf_size);
|
||||
int alloc_diag_variant_buffer(struct diag_variant_buffer *buffer);
|
||||
void destroy_diag_variant_buffer(struct diag_variant_buffer *buffer);
|
||||
void discard_diag_variant_buffer(struct diag_variant_buffer *buffer);
|
||||
void backup_diag_variant_buffer(struct diag_variant_buffer *buffer);
|
||||
asmlinkage int diag_variant_buffer_reserve(struct diag_variant_buffer *buffer,
|
||||
size_t len);
|
||||
asmlinkage int diag_variant_buffer_seal(struct diag_variant_buffer *buffer);
|
||||
asmlinkage int
|
||||
diag_variant_buffer_write_nolock(struct diag_variant_buffer *buffer,
|
||||
const void *data, size_t len);
|
||||
void diag_variant_buffer_mutex_lock(struct diag_variant_buffer *buffer);
|
||||
void diag_variant_buffer_mutex_unlock(struct diag_variant_buffer *buffer);
|
||||
int copy_to_user_variant_buffer(struct diag_variant_buffer *variant_buffer,
|
||||
void __user *ptr_len, void __user *buf,
|
||||
size_t size);
|
||||
Reference in New Issue
Block a user