Skip to content

Commit 5977936

Browse files
echron-aristak-hagio
authored andcommitted
Add "log -c" option to display printk caller id
Add support so that dmesg entries include the optional Linux Kernel debug CONFIG option PRINTK_CALLER which adds an optional dmesg field that contains the Thread Id or CPU Id that is issuing the printk to add the message to the kernel ring buffer. If enabled, this CONFIG option makes debugging simpler as dmesg entries for a specific thread or CPU can be recognized. The config option was introduced with Linux 5.1 [1]. Size of the PRINTK_CALLER field is determined by the maximum number tasks that can be run on the system which is limited by the value of /proc/sys/kernel/pid_max as pid values are from 0 to value - 1. This value determines the number of id digits needed by the caller id. The PRINTK_CALLER field is printed as T<id> for a Task Id or C<id> for a CPU Id for a printk in CPU context. The values are left space padded and enclosed in parentheses such as: [ T123] or [ C16] Our patch adds the PRINTK_CALLER field after the timestamp if the printk caller log / dmesg option (-c) is selected: crash> log -m -c ... [ 0.014179] [ T1] <6>Secure boot disabled [ 0.014179] [ T29] <6>RAMDISK: [mem 0x3cf4f000-0x437bbfff] ... [1] 15ff2069cb7f ("printk: Add caller information to printk() output.") Resolves: crash-utility#164 Signed-off-by: Ivan Delalande <[email protected]> Signed-off-by: Edward Chron <[email protected]> Signed-off-by: Kazuhito Hagio <[email protected]>
1 parent 3d60d9d commit 5977936

File tree

5 files changed

+88
-9
lines changed

5 files changed

+88
-9
lines changed

defs.h

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2239,6 +2239,7 @@ struct offset_table { /* stash of commonly-used offsets */
22392239
long mnt_namespace_mounts;
22402240
long mnt_namespace_nr_mounts;
22412241
long mount_mnt_node;
2242+
long log_caller_id;
22422243
};
22432244

22442245
struct size_table { /* stash of commonly-used sizes */
@@ -6108,12 +6109,13 @@ void dump_log(int);
61086109
void parse_kernel_version(char *);
61096110

61106111
#define LOG_LEVEL(v) ((v) & 0x07)
6111-
#define SHOW_LOG_LEVEL (0x1)
6112-
#define SHOW_LOG_DICT (0x2)
6113-
#define SHOW_LOG_TEXT (0x4)
6114-
#define SHOW_LOG_AUDIT (0x8)
6115-
#define SHOW_LOG_CTIME (0x10)
6116-
#define SHOW_LOG_SAFE (0x20)
6112+
#define SHOW_LOG_LEVEL (0x1)
6113+
#define SHOW_LOG_DICT (0x2)
6114+
#define SHOW_LOG_TEXT (0x4)
6115+
#define SHOW_LOG_AUDIT (0x8)
6116+
#define SHOW_LOG_CTIME (0x10)
6117+
#define SHOW_LOG_SAFE (0x20)
6118+
#define SHOW_LOG_CALLER (0x40)
61176119
void set_cpu(int);
61186120
void clear_machdep_cache(void);
61196121
struct stack_hook *gather_text_list(struct bt_info *);
@@ -7588,6 +7590,10 @@ int calc_kaslr_offset(ulong *, ulong *);
75887590
*/
75897591
void dump_lockless_record_log(int);
75907592

7593+
/* caller_id default and max character sizes based on pid field size */
7594+
#define PID_CHARS_MAX 16 /* Max Number of PID characters */
7595+
#define PID_CHARS_DEFAULT 8 /* Default number of PID characters */
7596+
75917597
/*
75927598
* gnu_binutils.c
75937599
*/

help.c

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4024,7 +4024,7 @@ NULL
40244024
char *help_log[] = {
40254025
"log",
40264026
"dump system message buffer",
4027-
"[-Ttdmas]",
4027+
"[-Ttdmasc]",
40284028
" This command dumps the kernel log_buf contents in chronological order. The",
40294029
" command supports the older log_buf formats, which may or may not contain a",
40304030
" timestamp inserted prior to each message, as well as the newer variable-length",
@@ -4047,7 +4047,11 @@ char *help_log[] = {
40474047
" been copied out to the user-space audit daemon.",
40484048
" -s Dump the printk logs remaining in kernel safe per-CPU buffers that",
40494049
" have not been flushed out to log_buf.",
4050-
" ",
4050+
" -c Display the caller id field that identifies either the thread id or",
4051+
" the CPU id (if in CPU context) that called printk(), if available.",
4052+
" Generally available on Linux 5.1 to 5.9 kernels configured with",
4053+
" CONFIG_PRINTK_CALLER or Linux 5.10 and later kernels.",
4054+
" ",
40514055
"\nEXAMPLES",
40524056
" Dump the kernel message buffer:\n",
40534057
" %s> log",
@@ -4215,6 +4219,17 @@ char *help_log[] = {
42154219
" CPU: 0 ADDR: ffff8ca4fbc1ad00 LEN: 0 MESSAGE_LOST: 0",
42164220
" (empty)",
42174221
" ...",
4222+
" ",
4223+
" Display the caller id that identifies the thread id of the task (begins",
4224+
" with 'T') or the processor id (begins with 'C' for in CPU context) that",
4225+
" called printk(), if available.\n",
4226+
" %s> log -c",
4227+
" ...",
4228+
" [ 0.014179] [ T1] Secure boot disabled",
4229+
" [ 0.014179] [ T29] RAMDISK: [mem 0x3cf4f000-0x437bbfff]",
4230+
" [ 0.198789] [ C0] DMAR: DRHD: handling fault status reg 3",
4231+
" ...",
4232+
42184233
NULL
42194234
};
42204235

kernel.c

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5089,7 +5089,7 @@ cmd_log(void)
50895089

50905090
msg_flags = 0;
50915091

5092-
while ((c = getopt(argcnt, args, "Ttdmas")) != EOF) {
5092+
while ((c = getopt(argcnt, args, "Ttdmasc")) != EOF) {
50935093
switch(c)
50945094
{
50955095
case 'T':
@@ -5110,6 +5110,9 @@ cmd_log(void)
51105110
case 's':
51115111
msg_flags |= SHOW_LOG_SAFE;
51125112
break;
5113+
case 'c':
5114+
msg_flags |= SHOW_LOG_CALLER;
5115+
break;
51135116
default:
51145117
argerrs++;
51155118
break;
@@ -5369,6 +5372,25 @@ dump_log_entry(char *logptr, int msg_flags)
53695372
fprintf(fp, "%s", buf);
53705373
}
53715374

5375+
/*
5376+
* The PRINTK_CALLER id field was introduced with Linux-5.1 so if
5377+
* requested, Kernel version >= 5.1 and field exists print caller_id.
5378+
*/
5379+
if (msg_flags & SHOW_LOG_CALLER &&
5380+
VALID_MEMBER(log_caller_id)) {
5381+
const unsigned int cpuid = 0x80000000;
5382+
char cbuf[PID_CHARS_MAX];
5383+
unsigned int cid;
5384+
5385+
/* Get id type, isolate just id value in cid for print */
5386+
cid = UINT(logptr + OFFSET(log_caller_id));
5387+
sprintf(cbuf, "%c%d", (cid & cpuid) ? 'C' : 'T', cid & ~cpuid);
5388+
sprintf(buf, "[%*s] ", PID_CHARS_DEFAULT, cbuf);
5389+
5390+
ilen += strlen(buf);
5391+
fprintf(fp, "%s", buf);
5392+
}
5393+
53725394
level = LOG_LEVEL(level);
53735395

53745396
if (msg_flags & SHOW_LOG_LEVEL) {
@@ -5424,6 +5446,7 @@ dump_variable_length_record_log(int msg_flags)
54245446
* from log to printk_log. See 62e32ac3505a0cab.
54255447
*/
54265448
log_struct_name = "printk_log";
5449+
MEMBER_OFFSET_INIT(log_caller_id, "printk_log", "caller_id");
54275450
} else
54285451
log_struct_name = "log";
54295452

printk.c

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ struct prb_map {
99
unsigned long desc_ring_count;
1010
char *descs;
1111
char *infos;
12+
unsigned int pid_max_chars;
1213

1314
char *text_data_ring;
1415
unsigned long text_data_ring_size;
@@ -162,6 +163,24 @@ dump_record(struct prb_map *m, unsigned long id, int msg_flags)
162163
fprintf(fp, "%s", buf);
163164
}
164165

166+
/*
167+
* The lockless ringbuffer introduced in Linux-5.10 always has
168+
* the caller_id field available, so if requested, print it.
169+
*/
170+
if (msg_flags & SHOW_LOG_CALLER) {
171+
const unsigned int cpuid = 0x80000000;
172+
char cbuf[PID_CHARS_MAX];
173+
unsigned int cid;
174+
175+
/* Get id type, isolate id value in cid for print */
176+
cid = UINT(info + OFFSET(printk_info_caller_id));
177+
sprintf(cbuf, "%c%d", (cid & cpuid) ? 'C' : 'T', cid & ~cpuid);
178+
sprintf(buf, "[%*s] ", m->pid_max_chars, cbuf);
179+
180+
ilen += strlen(buf);
181+
fprintf(fp, "%s", buf);
182+
}
183+
165184
if (msg_flags & SHOW_LOG_LEVEL) {
166185
level = UCHAR(info + OFFSET(printk_info_level)) >> 5;
167186
sprintf(buf, "<%x>", level);
@@ -262,6 +281,21 @@ dump_lockless_record_log(int msg_flags)
262281
goto out_text_data;
263282
}
264283

284+
/* If caller_id was requested, get the pid_max value for print */
285+
if (msg_flags & SHOW_LOG_CALLER) {
286+
unsigned int pidmax;
287+
288+
get_symbol_data("pid_max", sizeof(pidmax), &pidmax);
289+
if (pidmax <= 99999)
290+
m.pid_max_chars = 6;
291+
else if (pidmax <= 999999)
292+
m.pid_max_chars = 7;
293+
else
294+
m.pid_max_chars = PID_CHARS_DEFAULT;
295+
} else {
296+
m.pid_max_chars = PID_CHARS_DEFAULT;
297+
}
298+
265299
/* ready to go */
266300

267301
tail_id = ULONG(m.desc_ring + OFFSET(prb_desc_ring_tail_id) +

symbols.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11550,6 +11550,7 @@ dump_offset_table(char *spec, ulong makestruct)
1155011550
OFFSET(log_level));
1155111551
fprintf(fp, " log_flags_level: %ld\n",
1155211552
OFFSET(log_flags_level));
11553+
fprintf(fp, " log_caller_id: %ld\n", OFFSET(log_caller_id));
1155311554

1155411555
fprintf(fp, " printk_info_seq: %ld\n", OFFSET(printk_info_seq));
1155511556
fprintf(fp, " printk_info_ts_nseq: %ld\n", OFFSET(printk_info_ts_nsec));

0 commit comments

Comments
 (0)