[Crash-utility] [PATCH v2] kernel/timers: show time to expire for each timer

Dave Anderson anderson at redhat.com
Wed Jun 26 18:59:24 UTC 2019


Hi Oleksandr,

Looks good -- queued for crash-7.2.7:

  https://github.com/crash-utility/crash/commit/496d503e84147a24bdaf86782ab1d8af2fd76c9e

Thanks,
  Dave


----- Original Message -----
> Extend `timer` command to show time to expire (TTE) for each timer.
> 
> This is useful to verify what CPU is blocked due to looping with
> interrupts disabled or due to lack of resources to run the vCPU on a
> hypervisor side.
> 
> `help` output is amended accordingly. Old examples are replaced with two
> new ones, both are for the vmcore from the modern RHEL8 system.
> 
> The commit was tested on the vmcores with the following kernel versions:
> 
> * 2.6.18-436.el5
> * 2.6.32-431.el6.x86_64
> * 3.10.0-693.11.6.el7.x86_64
> * 4.18.0-80.1.2.el8_0.x86_64
> 
> Signed-off-by: Oleksandr Natalenko <oleksandr at redhat.com>
> ---
>  defs.h   |   1 +
>  help.c   | 167 ++++++++++++------------------------
>  kernel.c | 255 ++++++++++++++++++++++++++++++++++++++-----------------
>  tools.c  |   5 +-
>  4 files changed, 236 insertions(+), 192 deletions(-)
> 
> diff --git a/defs.h b/defs.h
> index ccffe58..ceb6eb7 100644
> --- a/defs.h
> +++ b/defs.h
> @@ -4387,6 +4387,7 @@ struct machine_specific {
>  #define INT_HEX      (0x40)
>  #define LONGLONG_HEX (0x80)
>  #define ZERO_FILL   (0x100)
> +#define SLONG_DEC   (0x200)
>  
>  #define INIT_TIME (1)
>  #define RUN_TIME  (2)
> diff --git a/help.c b/help.c
> index 581e616..4f67ccf 100644
> --- a/help.c
> +++ b/help.c
> @@ -2891,128 +2891,65 @@ char *help_timer[] = {
>  " -C cpu Restrict the output to one or more CPUs, where multiple cpu[s]
>  can",
>  "        be specified, for example, as \"1,3,5\", \"1-3\", or
>  \"1,3,5-7,10\".",
>  "\nEXAMPLES",
> +" Display the timer queue on an SMP system:\n",
>  "    %s> timer",
>  "    JIFFIES",
> -"      68102",
> -"    EXPIRES  TIMER_LIST/TABLE  FUNCTION",
> -"      68346      c0241934      c01775d4  <tcp_sltimer_handler>",
> -"      68379      c0241204      c01696d8  <dev_do_watchdog>",
> -"      68523      c7fcdfc0      c0112d6c  <process_timeout>",
> -"      68718      c7fd8edc      c018719c  <irlmp_discovery_timer_expired>",
> -"      68723   timer_table[2]   c01c707c  <rs_timer>",
> -"      68742      c20c1f7c      c0112d6c  <process_timeout>",
> -"      68742      c20c1f7c      c0112d6c  <process_timeout>",
> -"      68742      c20c1f7c      c0112d6c  <process_timeout>",
> -"      68752      c7fd1fc4      c0112d6c  <process_timeout>",
> -"      68752      c7fd1fc4      c0112d6c  <process_timeout>",
> -"      68989      c0241d40      c0168060  <neigh_periodic_timer>",
> -"      69028      c2533f7c      c0112d6c  <process_timeout>",
> -"      69134      c22dd868      c0181948  <unix_destroy_timer>",
> -"      71574      c0241430      c0169ea4  <rt_check_expire>",
> -"      72179      c7fb1c48      c01cb9a0  <vortex_timer>",
> -"      73144      c1b17f10      c0112d6c  <process_timeout>",
> -"      73259      c17a5f10      c0112d6c  <process_timeout>",
> -"     112929      c203ff10      c0112d6c  <process_timeout>",
> -"     372010      c2323f7c      c0112d6c  <process_timeout>",
> -"     372138      c2191f10      c0112d6c  <process_timeout>",
> -"    8653052      c1f13f10      c0112d6c  <process_timeout>",
> -" ",
> -"  Display the timer queue on a 2-cpu system:\n",
> -"    %s> timer",
> -"    TVEC_BASES[0]: c1299be0",
> -"     JIFFIES",
> -"    18256298",
> -"     EXPIRES  TIMER_LIST  FUNCTION",
> -"    18256406   cd5ddec0   c01232bb  <process_timeout>",
> -"    18256677   ceea93e0   c011e3cc  <it_real_fn>",
> -"    18256850   ceea7f64   c01232bb  <process_timeout>",
> -"    18258751   cd1d4f64   c01232bb  <process_timeout>",
> -"    18258792   cf5782f0   c011e3cc  <it_real_fn>",
> -"    18261266   c03c9f80   c022fad5  <rt_check_expire>",
> -"    18262196   c02dc2e0   c0233329  <peer_check_expire>",
> -"    18270518   ceb8bf1c   c01232bb  <process_timeout>",
> -"    18271327   c03c9120   c0222074  <flow_cache_new_hashrnd>",
> -"    18271327   c03ca580   c0233ace  <ipfrag_secret_rebuild>",
> -"    18272532   c02d1e18   c0129946  <delayed_work_timer_fn>",
> -"    18276518   c03c9fc0   c022fd40  <rt_secret_rebuild>",
> -"    18332334   ceea9970   c011e3cc  <it_real_fn>",
> -"    18332334   cfb6a840   c011e3cc  <it_real_fn>",
> -"    18665378   cec25ec0   c01232bb  <process_timeout>",
> -"    TVEC_BASES[1]: c12a1be0",
> -"     JIFFIES",
> -"    18256298",
> -"     EXPIRES  TIMER_LIST  FUNCTION",
> -"    18256493   c02c7d00   c013dad5  <wb_timer_fn>",
> -"    18256499   c12a2db8   c0129946  <delayed_work_timer_fn>",
> -"    18277900   ceebaec0   c01232bb  <process_timeout>",
> -"    18283769   cf739f64   c01232bb  <process_timeout>",
> -"    18331902   cee8af64   c01232bb  <process_timeout>",
> +"    4296291038",
> +"    ...",
> +"    TIMER_BASES[1][BASE_STD]: ffff9801aba5aa00",
> +"      EXPIRES        TTE         TIMER_LIST     FUNCTION",
> +"      4296282997    -8041  ffff9801aba55ce0  ffffffff83a3bda0
> <mce_timer_fn>",
> +"      4296283104    -7934  ffff97fd84bd35e0  ffffffff83ac6b70
> <delayed_work_timer_fn>",
> +"      4296291061       23  ffffa6b283967de0  ffffffff83b29880
> <process_timeout>",
> +"      4296291112       74  ffff9800c9b62ad8  ffffffff83e6b550
> <cursor_timer_handler>",
> +"      4296291345      307  ffff980186d5ef88  ffffffff84146b80
> <tcp_keepalive_timer>",
> +"      4296291484      446  ffff9801a7c54740  ffffffff84147f50
> <tcp_write_timer>",
> +"      4296291997      959  ffffffffc073f880  ffffffff83ac6b70
> <delayed_work_timer_fn>",
> +"      4296296213     5175  ffffa6b28339be18  ffffffff83b29880
> <process_timeout>",
> +"      4296304383    13345  ffff980194ca72a8  ffffffff8412e4e0
> <tw_timer_handler>",
> +"      4296305724    14686  ffff980194ca6918  ffffffff8412e4e0
> <tw_timer_handler>",
> +"      4296306036    14998  ffff980194ca6d58  ffffffff8412e4e0
> <tw_timer_handler>",
> +"      4296306883    15845  ffff980194ca7e58  ffffffff8412e4e0
> <tw_timer_handler>",
> +"      4296307588    16550  ffff9801aaa27e58  ffffffff8412e4e0
> <tw_timer_handler>",
> +"      4296307625    16587  ffff980194ca6a28  ffffffff8412e4e0
> <tw_timer_handler>",
> +"      4296313542    22504  ffff980194ca7c38  ffffffff8412e4e0
> <tw_timer_handler>",
> +"      4296317680    26642  ffff9800c9149c58  ffffffff840da870
> <neigh_timer_handler>",
> +"      4296317744    26706  ffff9801a5354468  ffffffff83ac6b70
> <delayed_work_timer_fn>",
> +"      4296343322    52284  ffff980194ca63c8  ffffffff8412e4e0
> <tw_timer_handler>",
> +"      4296343581    52543  ffff980194ca7088  ffffffff8412e4e0
> <tw_timer_handler>",
> +"      4296343597    52559  ffff9801aaa274c8  ffffffff8412e4e0
> <tw_timer_handler>",
> +"      4296714205   423167  ffffffff84caf3c0  ffffffff83ac6b70
> <delayed_work_timer_fn>",
> +"    TIMER_BASES[1][BASE_DEF]: ffff9801aba5bc80",
> +"      EXPIRES        TTE         TIMER_LIST     FUNCTION",
> +"      4296291264      226  ffffffff855eb238  ffffffff83c08fb0
> <writeout_period>",
> +"      4296319997    28959  ffffffffc06ede40  ffffffff83ac6b70
> <delayed_work_timer_fn>",
> +"      4296506084   215046  ffff9801aba629c8  ffffffff83ac5ea0
> <idle_worker_timeout>",
> +"    ...",
>  " ",
>  "  Display a new-style hrtimer queue:\n",
>  "    %s> timer -r",
> -"    CPU: 0  HRTIMER_CPU_BASE: c1e03fc0",
> -"      CLOCK: 0  HRTIMER_CLOCK_BASE: c1e03fc4  [ktime_get_real]",
> -"      (empty)",
> -"    ",
> -"      CLOCK: 1  HRTIMER_CLOCK_BASE: c1e03ff0  [ktime_get]",
> -"         CURRENT",
> -"      322894000000",
> -"       SOFTEXPIRES     EXPIRES    HRTIMER   FUNCTION",
> -"      322895000000  322895000000  c1e04080  c04833e0  <tick_sched_timer>",
> -"      324022213609  324022213609  c1e041c0  c04b17d0  <watchdog_timer_fn>",
> -"      326766922781  326766972781  f3a45f44  c0477ed0  <hrtimer_wakeup>",
> -"      364516801997  364516851997  f43bbf44  c0477ed0  <hrtimer_wakeup>",
> -" ",
> -"      CLOCK: 2  HRTIMER_CLOCK_BASE: c1e0401c  [ktime_get_boottime]",
> -"      (empty)",
> -"    ",
> -"    CPU: 1  HRTIMER_CPU_BASE: c1e43fc0",
> -"      CLOCK: 0  HRTIMER_CLOCK_BASE: c1e43fc4  [ktime_get_real]",
> -"      (empty)",
> -"    ",
> -"      CLOCK: 1  HRTIMER_CLOCK_BASE: c1e43ff0  [ktime_get]",
> -"         CURRENT",
> -"      322894000000",
> -"       SOFTEXPIRES     EXPIRES    HRTIMER   FUNCTION",
> -"      322895062500  322895062500  c1e44080  c04833e0  <tick_sched_timer>",
> -"      324087213609  324087213609  c1e441c0  c04b17d0  <watchdog_timer_fn>",
> -"      381034500892  381034550892  f3a1bea0  c0477ed0  <hrtimer_wakeup>",
> -" ",
> -"      CLOCK: 2  HRTIMER_CLOCK_BASE: c1e4401c  [ktime_get_boottime]",
> -"      (empty)",
>  "    ...",
> -" ",
> -"  Display an old-style hrtimer queue:\n",
> -"    %s> timer -r",
> -"    CPU: 0",
> -"      CLOCK: 0  HRTIMER_BASE: ca00dae0  [ktime_get_real]",
> -"      (empty)",
> -"    ",
> -"      CLOCK: 1  HRTIMER_BASE: ca00db0c  [ktime_get]",
> -"           CURRENT",
> -"      1480537567000000",
> -"           EXPIRES      HRTIMER   FUNCTION",
> -"      1480997557052703  f79c4944  c0427d18  <it_real_fn>",
> -"      1481009329944302  cdcbaf6c  c0436a1e  <hrtimer_wakeup>",
> -"      1481026181758643  ea01cf6c  c0436a1e  <hrtimer_wakeup>",
> -"      1481497068511094  f79a6244  c0427d18  <it_real_fn>",
> -"      1481589831928489  f7af6944  c0427d18  <it_real_fn>",
> -"      1481592731187337  f64ed784  c0427d18  <it_real_fn>",
> -"    ",
> -"    CPU: 1",
> -"      CLOCK: 0  HRTIMER_BASE: ca0148c4  [ktime_get_real]",
> +"    CPU: 2  HRTIMER_CPU_BASE: ffff9801aba9cf00",
> +"      CLOCK: 0  HRTIMER_CLOCK_BASE: ffff9801aba9cf40  [ktime_get]",
> +"         CURRENT",
> +"      1623742000000",
> +"       SOFTEXPIRES      EXPIRES         TTE         HRTIMER
> FUNCTION",
> +"      1623741000000  1623741000000    -1000000  ffff9801aba9d540
> ffffffff83b3c8e0  <tick_sched_timer>",
> +"      1624024000000  1624024000000   282000000  ffff9801aba9d720
> ffffffff83b7e7a0  <watchdog_timer_fn>",
> +"      1626000939806  1626010929804  2268929804  ffffa6b28399fa40
> ffffffff83b2c1e0  <hrtimer_wakeup>",
> +"      1627576915615  1627576915615  3834915615  ffff9801a5727978
> ffffffff83b365c0  <posix_timer_fn>",
> +"      1627637194488  1627647194487  3905194487  ffffa6b283977db0
> ffffffff83b2c1e0  <hrtimer_wakeup>",
> +"      1629937423000  1629937423000  6195423000  ffff9801a9af2900
> ffffffff83cf3d30  <timerfd_tmrproc>",
> +" ",
> +"      CLOCK: 1  HRTIMER_CLOCK_BASE: ffff9801aba9cf80  [ktime_get_real]",
> +"            CURRENT",
> +"      1558362388334558243",
> +"          SOFTEXPIRES            EXPIRES             TTE           HRTIMER
> FUNCTION",
> +"      1558362389331238000  1558362389331288000      996729757
> ffffa6b28574bcf0  ffffffff83b2c1e0  <hrtimer_wakeup>",
> +"      1558364372000000000  1558364372000000000  1983665441757
> ffff9801a3513278  ffffffff83b365c0  <posix_timer_fn>",
> +" ",
> +"      CLOCK: 2  HRTIMER_CLOCK_BASE: ffff9801aba9cfc0
> [ktime_get_boottime]",
>  "      (empty)",
> -"    ",
> -"      CLOCK: 1  HRTIMER_BASE: ca0148f0  [ktime_get]",
> -"           CURRENT",
> -"      1480537567000000",
> -"           EXPIRES      HRTIMER   FUNCTION",
> -"      1481017523822478  ca3b15c4  c0427d18  <it_real_fn>",
> -"      1481238077723188  f5f35f6c  c0436a1e  <hrtimer_wakeup>",
> -"      1481492107740948  f5dadf6c  c0436a1e  <hrtimer_wakeup>",
> -"      1482936527251241  ca1becc4  c0427d18  <it_real_fn>",
> -"      1482936545249010  f7d42e84  c0427d18  <it_real_fn>",
> -"      1492850155229325  ea01ef6c  c0436a1e  <hrtimer_wakeup>",
>  "    ...",
>  " ",
>  NULL
> diff --git a/kernel.c b/kernel.c
> index f01dc2e..818c29a 100644
> --- a/kernel.c
> +++ b/kernel.c
> @@ -42,8 +42,8 @@ static void dump_hrtimer_data(const ulong *cpus);
>  static void dump_hrtimer_clock_base(const void *, const int);
>  static void dump_hrtimer_base(const void *, const int);
>  static void dump_active_timers(const void *, ulonglong);
> -static int get_expires_len(const int, const ulong *, const int);
> -static void print_timer(const void *);
> +static int get_expires_len(const int, const ulong *, ulonglong, const int);
> +static void print_timer(const void *, ulonglong);
>  static ulonglong ktime_to_ns(const void *);
>  static void dump_timer_data(const ulong *cpus);
>  static void dump_timer_data_tvec_bases_v1(const ulong *cpus);
> @@ -52,10 +52,10 @@ static void dump_timer_data_tvec_bases_v3(const ulong
> *cpus);
>  static void dump_timer_data_timer_bases(const ulong *cpus);
>  struct tv_range;
>  static void init_tv_ranges(struct tv_range *, int, int, int);
> -static int do_timer_list(ulong,int, ulong *, void *,ulong *,struct tv_range
> *);
> -static int do_timer_list_v3(ulong, int, ulong *, void *,ulong *);
> +static int do_timer_list(ulong,int, ulong *, void *,ulong *, ulong *, struct
> tv_range *, ulong);
> +static int do_timer_list_v3(ulong, int, ulong *, void *,ulong *, ulong *,
> ulong);
>  struct timer_bases_data;
> -static int do_timer_list_v4(struct timer_bases_data *);
> +static int do_timer_list_v4(struct timer_bases_data *, ulong);
>  static int compare_timer_data(const void *, const void *);
>  static void panic_this_kernel(void);
>  static void dump_waitq(ulong, char *);
> @@ -7515,6 +7515,7 @@ dump_hrtimer_data(const ulong *cpus)
>  
>  static int expires_len = -1;
>  static int softexpires_len = -1;
> +static int tte_len = -1;
>  
>  static void
>  dump_hrtimer_clock_base(const void *hrtimer_bases, const int num)
> @@ -7578,6 +7579,7 @@ dump_active_timers(const void *base, ulonglong now)
>  	char buf2[BUFSIZE];
>  	char buf3[BUFSIZE];
>  	char buf4[BUFSIZE];
> +	char buf5[BUFSIZE];
>  
>  	next = 0;
>  	timer_list = 0;
> @@ -7637,10 +7639,11 @@ next_one:
>  
>  	/* dump hrtimers */
>  	/* print header */
> -	expires_len = get_expires_len(timer_cnt, timer_list, 0);
> +	expires_len = get_expires_len(timer_cnt, timer_list, 0, 0);
>  	if (expires_len < 7)
>  		expires_len = 7;
> -	softexpires_len = get_expires_len(timer_cnt, timer_list, 1);
> +	softexpires_len = get_expires_len(timer_cnt, timer_list, 0, 1);
> +	tte_len = get_expires_len(timer_cnt, timer_list, now, 2);
>  
>  	if (softexpires_len > -1) {
>  		if (softexpires_len < 11)
> @@ -7650,9 +7653,10 @@ next_one:
>  		sprintf(buf1, "%lld", now);
>  		fprintf(fp, "  %s\n", mkstring(buf1, softexpires_len,
>  			CENTER|RJUST, NULL));
> -		fprintf(fp, "  %s  %s  %s  %s\n",
> +		fprintf(fp, "  %s  %s  %s  %s  %s\n",
>  			mkstring(buf1, softexpires_len, CENTER|RJUST, "SOFTEXPIRES"),
>  			mkstring(buf2, expires_len, CENTER|RJUST, "EXPIRES"),
> +			mkstring(buf5, tte_len, CENTER|RJUST, "TTE"),
>  			mkstring(buf3, VADDR_PRLEN, CENTER|LJUST, "HRTIMER"),
>  			mkstring(buf4, VADDR_PRLEN, CENTER|LJUST, "FUNCTION"));
>  	} else {
> @@ -7660,8 +7664,9 @@ next_one:
>  			"CURRENT"));
>  		sprintf(buf1, "%lld", now);
>  		fprintf(fp, "  %s\n", mkstring(buf1, expires_len, CENTER|RJUST, NULL));
> -		fprintf(fp, "  %s  %s  %s\n",
> +		fprintf(fp, "  %s  %s  %s  %s\n",
>  			mkstring(buf1, expires_len, CENTER|RJUST, "EXPIRES"),
> +			mkstring(buf5, tte_len, CENTER|RJUST, "TTE"),
>  			mkstring(buf2, VADDR_PRLEN, CENTER|LJUST, "HRTIMER"),
>  			mkstring(buf3, VADDR_PRLEN, CENTER|LJUST, "FUNCTION"));
>  	}
> @@ -7675,12 +7680,12 @@ next_one:
>  		else
>  			timer = (void *)(timer_list[t] - OFFSET(hrtimer_node));
>  
> -		print_timer(timer);
> +		print_timer(timer, now);
>  	}
>  }
>  
>  static int
> -get_expires_len(const int timer_cnt, const ulong *timer_list, const int
> getsoft)
> +get_expires_len(const int timer_cnt, const ulong *timer_list, ulonglong now,
> const int getsoft)
>  {
>  	void *last_timer;
>  	char buf[BUFSIZE];
> @@ -7700,7 +7705,7 @@ get_expires_len(const int timer_cnt, const ulong
> *timer_list, const int getsoft)
>  		last_timer = (void *)(timer_list[timer_cnt -1] -
>  			OFFSET(hrtimer_node));
>  
> -	if (getsoft) {
> +	if (getsoft == 1) {
>  		/* soft expires exist*/
>  		if (VALID_MEMBER(hrtimer_softexpires)) {
>  			softexpires = ktime_to_ns(last_timer +
> @@ -7715,7 +7720,7 @@ get_expires_len(const int timer_cnt, const ulong
> *timer_list, const int getsoft)
>  			expires = ktime_to_ns(last_timer + OFFSET(hrtimer_node) +
>  				OFFSET(timerqueue_node_expires));
>  
> -		sprintf(buf, "%lld", expires);
> +		sprintf(buf, "%lld", getsoft ? expires - now : expires);
>  		len = strlen(buf);
>  	}
>  
> @@ -7726,14 +7731,15 @@ get_expires_len(const int timer_cnt, const ulong
> *timer_list, const int getsoft)
>   * print hrtimer and its related information
>   */
>  static void
> -print_timer(const void *timer)
> +print_timer(const void *timer, ulonglong now)
>  {
> -	ulonglong softexpires, expires;
> +	ulonglong softexpires, expires, tte;
>  	
>  	ulong function;
>  	char buf1[BUFSIZE];
>  	char buf2[BUFSIZE];
>  	char buf3[BUFSIZE];
> +	char buf4[BUFSIZE];
>  
>  	/* align information */
>  	fprintf(fp, "  ");
> @@ -7764,6 +7770,9 @@ print_timer(const void *timer)
>  	sprintf(buf1, "%lld", expires);
>  	fprintf(fp, "%s  ", mkstring(buf2, expires_len, CENTER|RJUST, buf1));
>  
> +	tte = expires - now;
> +	fprintf(fp, "%s  ", mkstring(buf4, tte_len, SLONG_DEC|RJUST, MKSTR(tte)));
> +
>  	fprintf(fp, "%lx  ", (ulong)timer);
>  
>  	if (readmem((ulong)(timer + OFFSET(hrtimer_function)), KVADDR, &function,
> @@ -7819,6 +7828,7 @@ struct timer_data {
>  	ulong address;
>  	ulong expires;
>  	ulong function;
> +	long tte;
>  };
>  
>  struct tv_range {
> @@ -7839,14 +7849,15 @@ dump_timer_data(const ulong *cpus)
>  	} timer_table[32];
>  	char buf[BUFSIZE];
>  	char buf1[BUFSIZE];
> +	char buf4[BUFSIZE];
>          struct timer_struct *tp;
> -        ulong mask, highest, function;
> +        ulong mask, highest, highest_tte, function;
>  	ulong jiffies, timer_jiffies;
>  	ulong *vec;
>  	long count;
>          int vec_root_size, vec_size;
>  	struct timer_data *td;
> -	int flen, tdx, old_timers_exist;
> +	int flen, tlen, tdx, old_timers_exist;
>          struct tv_range tv[TVN];
>  
>  	if (kt->flags2 & TIMER_BASES) {
> @@ -7900,15 +7911,15 @@ dump_timer_data(const ulong *cpus)
>  	init_tv_ranges(tv, vec_root_size, vec_size, 0);
>  
>          count += do_timer_list(symbol_value("tv1") +
>          OFFSET(timer_vec_root_vec),
> -		vec_root_size, vec, NULL, NULL, tv);
> +		vec_root_size, vec, NULL, NULL, NULL, tv, 0);
>          count += do_timer_list(symbol_value("tv2") + OFFSET(timer_vec_vec),
> -		vec_size, vec, NULL, NULL, tv);
> +		vec_size, vec, NULL, NULL, NULL, tv, 0);
>          count += do_timer_list(symbol_value("tv3") + OFFSET(timer_vec_vec),
> -		vec_size, vec, NULL, NULL, tv);
> +		vec_size, vec, NULL, NULL, NULL, tv, 0);
>          count += do_timer_list(symbol_value("tv4") + OFFSET(timer_vec_vec),
> -		vec_size, vec, NULL, NULL, tv);
> +		vec_size, vec, NULL, NULL, NULL, tv, 0);
>          count += do_timer_list(symbol_value("tv4") + OFFSET(timer_vec_vec),
> -		vec_size, vec, NULL, NULL, tv);
> +		vec_size, vec, NULL, NULL, NULL, tv, 0);
>  
>  	td = (struct timer_data *)
>  		GETBUF((count*2) * sizeof(struct timer_data));
> @@ -7920,6 +7931,7 @@ dump_timer_data(const ulong *cpus)
>  		get_symbol_data("timer_active", sizeof(ulong), &timer_active);
>  
>  	highest = 0;
> +	highest_tte = 0;
>          for (i = 0, mask = 1, tp = timer_table+0; old_timers_exist && mask;
>  	     i++, tp++, mask += mask) {
>                  if (mask > timer_active)
> @@ -7931,21 +7943,24 @@ dump_timer_data(const ulong *cpus)
>  		td[tdx].address = i;
>  		td[tdx].expires = tp->expires;
>  		td[tdx].function = (ulong)tp->fn;
> +		td[tdx].tte = tp->expires - jiffies;
>  		if (td[tdx].expires > highest)
>  			highest = td[tdx].expires;
> +		if (abs(td[tdx].tte) > highest_tte)
> +			highest_tte = abs(td[tdx].tte);
>  		tdx++;
>          }
>  
>  	do_timer_list(symbol_value("tv1") + OFFSET(timer_vec_root_vec),
> -		vec_root_size, vec, (void *)td, &highest, tv);
> +		vec_root_size, vec, (void *)td, &highest, &highest_tte, tv, jiffies);
>  	do_timer_list(symbol_value("tv2") + OFFSET(timer_vec_vec),
> -		vec_size, vec, (void *)td, &highest, tv);
> +		vec_size, vec, (void *)td, &highest, &highest_tte, tv, jiffies);
>  	do_timer_list(symbol_value("tv3") + OFFSET(timer_vec_vec),
> -		vec_size, vec, (void *)td, &highest, tv);
> +		vec_size, vec, (void *)td, &highest, &highest_tte, tv, jiffies);
>  	do_timer_list(symbol_value("tv4") + OFFSET(timer_vec_vec),
> -		vec_size, vec, (void *)td, &highest, tv);
> +		vec_size, vec, (void *)td, &highest, &highest_tte, tv, jiffies);
>  	tdx = do_timer_list(symbol_value("tv5") + OFFSET(timer_vec_vec),
> -		vec_size, vec, (void *)td, &highest, tv);
> +		vec_size, vec, (void *)td, &highest, &highest_tte, tv, jiffies);
>  
>          qsort(td, tdx, sizeof(struct timer_data), compare_timer_data);
>  
> @@ -7958,13 +7973,21 @@ dump_timer_data(const ulong *cpus)
>  	fprintf(fp, "%s\n", mkstring(buf, flen, CENTER|LJUST, "JIFFIES"));
>  	fprintf(fp, "%s\n", mkstring(buf, flen, RJUST|LONG_DEC,MKSTR(jiffies)));
>  
> -	fprintf(fp, "%s  TIMER_LIST/TABLE  FUNCTION\n",
> -		mkstring(buf, flen, CENTER|LJUST, "EXPIRES"));
> +	/* +1 accounts possible "-" sign */
> +	sprintf(buf4, "%ld", highest_tte);
> +	tlen = MAX(strlen(buf4) + 1, strlen("TTE"));
> +
> +	fprintf(fp, "%s  %s  TIMER_LIST/TABLE  FUNCTION\n",
> +		mkstring(buf, flen, CENTER|LJUST, "EXPIRES"),
> +		mkstring(buf4, tlen, CENTER|LJUST, "TTE"));
>  
>          for (i = 0; i < tdx; i++) {
>          	fprintf(fp, "%s",
>  		    mkstring(buf, flen, RJUST|LONG_DEC, MKSTR(td[i].expires)));
>  
> +                fprintf(fp, "  %s",
> +                    mkstring(buf4, tlen, RJUST|SLONG_DEC,
> MKSTR(td[i].tte)));
> +
>  		if (td[i].address < 32) {
>                          sprintf(buf, "timer_table[%ld]", td[i].address);
>                          fprintf(fp, "  %s  ",
> @@ -8003,15 +8026,16 @@ dump_timer_data(const ulong *cpus)
>  static void
>  dump_timer_data_tvec_bases_v1(const ulong *cpus)
>  {
> -	int i, cpu, tdx, flen;
> +	int i, cpu, tdx, flen, tlen;
>          struct timer_data *td;
>          int vec_root_size, vec_size;
>          struct tv_range tv[TVN];
> -	ulong *vec, jiffies, highest, function;
> +	ulong *vec, jiffies, highest, highest_tte, function;
>  	long count;
>  	char buf1[BUFSIZE];
>  	char buf2[BUFSIZE];
>  	char buf3[BUFSIZE];
> +	char buf4[BUFSIZE];
>  
>  	/*
>           */
> @@ -8038,33 +8062,35 @@ next_cpu:
>          init_tv_ranges(tv, vec_root_size, vec_size, cpu);
>  
>          count += do_timer_list(tv[1].base + OFFSET(tvec_root_s_vec),
> -                vec_root_size, vec, NULL, NULL, tv);
> +                vec_root_size, vec, NULL, NULL, NULL, tv, 0);
>          count += do_timer_list(tv[2].base + OFFSET(tvec_s_vec),
> -                vec_size, vec, NULL, NULL, tv);
> +                vec_size, vec, NULL, NULL, NULL, tv, 0);
>          count += do_timer_list(tv[3].base + OFFSET(tvec_s_vec),
> -                vec_size, vec, NULL, NULL, tv);
> +                vec_size, vec, NULL, NULL, NULL, tv, 0);
>          count += do_timer_list(tv[4].base + OFFSET(tvec_s_vec),
> -                vec_size, vec, NULL, NULL, tv);
> +                vec_size, vec, NULL, NULL, NULL, tv, 0);
>          count += do_timer_list(tv[5].base + OFFSET(tvec_s_vec),
> -                vec_size, vec, NULL, NULL, tv);
> +                vec_size, vec, NULL, NULL, NULL, tv, 0);
>  
>  	if (count)
>          	td = (struct timer_data *)
>                  	GETBUF((count*2) * sizeof(struct timer_data));
>          tdx = 0;
>  	highest = 0;
> +	highest_tte = 0;
> +
>          get_symbol_data("jiffies", sizeof(ulong), &jiffies);
>  
>          do_timer_list(tv[1].base + OFFSET(tvec_root_s_vec),
> -                vec_root_size, vec, (void *)td, &highest, tv);
> +                vec_root_size, vec, (void *)td, &highest, &highest_tte, tv,
> jiffies);
>          do_timer_list(tv[2].base + OFFSET(tvec_s_vec),
> -                vec_size, vec, (void *)td, &highest, tv);
> +                vec_size, vec, (void *)td, &highest, &highest_tte, tv,
> jiffies);
>          do_timer_list(tv[3].base + OFFSET(tvec_s_vec),
> -                vec_size, vec, (void *)td, &highest, tv);
> +                vec_size, vec, (void *)td, &highest, &highest_tte, tv,
> jiffies);
>          do_timer_list(tv[4].base + OFFSET(tvec_s_vec),
> -                vec_size, vec, (void *)td, &highest, tv);
> +                vec_size, vec, (void *)td, &highest, &highest_tte, tv,
> jiffies);
>          tdx = do_timer_list(tv[5].base + OFFSET(tvec_s_vec),
> -                vec_size, vec, (void *)td, &highest, tv);
> +                vec_size, vec, (void *)td, &highest, &highest_tte, tv,
> jiffies);
>  
>          qsort(td, tdx, sizeof(struct timer_data), compare_timer_data);
>  
> @@ -8077,8 +8103,13 @@ next_cpu:
>          fprintf(fp, "%s\n", mkstring(buf1,flen,
>  		RJUST|LONG_DEC,MKSTR(jiffies)));
>  
> -	fprintf(fp, "%s  %s  %s\n",
> +        /* +1 accounts possible "-" sign */
> +        sprintf(buf4, "%ld", highest_tte);
> +        tlen = MAX(strlen(buf4) + 1, strlen("TTE"));
> +
> +	fprintf(fp, "%s  %s  %s  %s\n",
>  		mkstring(buf1, flen, CENTER|RJUST, "EXPIRES"),
> +		mkstring(buf4, tlen, CENTER|RJUST, "TTE"),
>  		mkstring(buf2, VADDR_PRLEN, CENTER|LJUST, "TIMER_LIST"),
>  		mkstring(buf3, VADDR_PRLEN, CENTER|LJUST, "FUNCTION"));
>  
> @@ -8086,6 +8117,9 @@ next_cpu:
>                  fprintf(fp, "%s",
>                      mkstring(buf1, flen, RJUST|LONG_DEC,
>                      MKSTR(td[i].expires)));
>  
> +                fprintf(fp, "  %s",
> +                    mkstring(buf4, tlen, RJUST|SLONG_DEC,
> MKSTR(td[i].tte)));
> +
>                  fprintf(fp, "  %s  ", mkstring(buf1,
>  			MAX(VADDR_PRLEN, strlen("TIMER_LIST")),
>  			RJUST|CENTER|LONG_HEX, MKSTR(td[i].address)));
> @@ -8123,17 +8157,18 @@ next_cpu:
>  static void
>  dump_timer_data_tvec_bases_v2(const ulong *cpus)
>  {
> -	int i, cpu, tdx, flen;
> +	int i, cpu, tdx, flen, tlen;
>          struct timer_data *td;
>          int vec_root_size, vec_size;
>          struct tv_range tv[TVN];
> -	ulong *vec, jiffies, highest, function;
> +	ulong *vec, jiffies, highest, highest_tte, function;
>  	ulong tvec_bases;
>  	long count;
>  	struct syment *sp;
>  	char buf1[BUFSIZE];
>  	char buf2[BUFSIZE];
>  	char buf3[BUFSIZE];
> +	char buf4[BUFSIZE];
>  
>          vec_root_size = (i = ARRAY_LENGTH(tvec_root_s_vec)) ?
>                  i : get_array_length("tvec_root_s.vec", NULL,
>                  SIZE(list_head));
> @@ -8180,33 +8215,35 @@ next_cpu:
>          init_tv_ranges(tv, vec_root_size, vec_size, cpu);
>  
>          count += do_timer_list(tv[1].base + OFFSET(tvec_root_s_vec),
> -                vec_root_size, vec, NULL, NULL, tv);
> +                vec_root_size, vec, NULL, NULL, NULL, tv, 0);
>          count += do_timer_list(tv[2].base + OFFSET(tvec_s_vec),
> -                vec_size, vec, NULL, NULL, tv);
> +                vec_size, vec, NULL, NULL, NULL, tv, 0);
>          count += do_timer_list(tv[3].base + OFFSET(tvec_s_vec),
> -                vec_size, vec, NULL, NULL, tv);
> +                vec_size, vec, NULL, NULL, NULL, tv, 0);
>          count += do_timer_list(tv[4].base + OFFSET(tvec_s_vec),
> -                vec_size, vec, NULL, NULL, tv);
> +                vec_size, vec, NULL, NULL, NULL, tv, 0);
>          count += do_timer_list(tv[5].base + OFFSET(tvec_s_vec),
> -                vec_size, vec, NULL, NULL, tv);
> +                vec_size, vec, NULL, NULL, NULL, tv, 0);
>  
>  	if (count)
>          	td = (struct timer_data *)
>                  	GETBUF((count*2) * sizeof(struct timer_data));
>          tdx = 0;
>  	highest = 0;
> +	highest_tte = 0;
> +
>          get_symbol_data("jiffies", sizeof(ulong), &jiffies);
>  
>          do_timer_list(tv[1].base + OFFSET(tvec_root_s_vec),
> -                vec_root_size, vec, (void *)td, &highest, tv);
> +                vec_root_size, vec, (void *)td, &highest, &highest_tte, tv,
> jiffies);
>          do_timer_list(tv[2].base + OFFSET(tvec_s_vec),
> -                vec_size, vec, (void *)td, &highest, tv);
> +                vec_size, vec, (void *)td, &highest, &highest_tte, tv,
> jiffies);
>          do_timer_list(tv[3].base + OFFSET(tvec_s_vec),
> -                vec_size, vec, (void *)td, &highest, tv);
> +                vec_size, vec, (void *)td, &highest, &highest_tte, tv,
> jiffies);
>          do_timer_list(tv[4].base + OFFSET(tvec_s_vec),
> -                vec_size, vec, (void *)td, &highest, tv);
> +                vec_size, vec, (void *)td, &highest, &highest_tte, tv,
> jiffies);
>          tdx = do_timer_list(tv[5].base + OFFSET(tvec_s_vec),
> -                vec_size, vec, (void *)td, &highest, tv);
> +                vec_size, vec, (void *)td, &highest, &highest_tte, tv,
> jiffies);
>  
>          qsort(td, tdx, sizeof(struct timer_data), compare_timer_data);
>  
> @@ -8229,8 +8266,13 @@ next_cpu:
>          fprintf(fp, "%s\n", mkstring(buf1,flen,
>  		RJUST|LONG_DEC,MKSTR(jiffies)));
>  
> -	fprintf(fp, "%s  %s  %s\n",
> +        /* +1 accounts possible "-" sign */
> +        sprintf(buf4, "%ld", highest_tte);
> +        tlen = MAX(strlen(buf4) + 1, strlen("TTE"));
> +
> +	fprintf(fp, "%s  %s  %s  %s\n",
>  		mkstring(buf1, flen, CENTER|RJUST, "EXPIRES"),
> +		mkstring(buf4, tlen, CENTER|RJUST, "TTE"),
>  		mkstring(buf2, VADDR_PRLEN, CENTER|LJUST, "TIMER_LIST"),
>  		mkstring(buf3, VADDR_PRLEN, CENTER|LJUST, "FUNCTION"));
>  
> @@ -8238,6 +8280,9 @@ next_cpu:
>                  fprintf(fp, "%s",
>                      mkstring(buf1, flen, RJUST|LONG_DEC,
>                      MKSTR(td[i].expires)));
>  
> +                fprintf(fp, "  %s",
> +                    mkstring(buf4, tlen, RJUST|SLONG_DEC,
> MKSTR(td[i].tte)));
> +
>                  fprintf(fp, "  %s  ", mkstring(buf1,
>  			MAX(VADDR_PRLEN, strlen("TIMER_LIST")),
>  			RJUST|CENTER|LONG_HEX, MKSTR(td[i].address)));
> @@ -8274,17 +8319,18 @@ next_cpu:
>  static void
>  dump_timer_data_tvec_bases_v3(const ulong *cpus)
>  {
> -	int i, cpu, tdx, flen;
> +	int i, cpu, tdx, flen, tlen;
>  	struct timer_data *td;
>  	int vec_root_size, vec_size;
>  	struct tv_range tv[TVN];
> -	ulong *vec, jiffies, highest, function;
> +	ulong *vec, jiffies, highest, highest_tte, function;
>  	ulong tvec_bases;
>  	long count, head_size;
>  	struct syment *sp;
>  	char buf1[BUFSIZE];
>  	char buf2[BUFSIZE];
>  	char buf3[BUFSIZE];
> +	char buf4[BUFSIZE];
>  
>  	vec_root_size = vec_size = 0;
>  	head_size = SIZE(hlist_head);
> @@ -8325,33 +8371,35 @@ next_cpu:
>  	init_tv_ranges(tv, vec_root_size, vec_size, cpu);
>  
>  	count += do_timer_list_v3(tv[1].base + OFFSET(tvec_root_s_vec),
> -		vec_root_size, vec, NULL, NULL);
> +		vec_root_size, vec, NULL, NULL, NULL, 0);
>  	count += do_timer_list_v3(tv[2].base + OFFSET(tvec_s_vec),
> -		vec_size, vec, NULL, NULL);
> +		vec_size, vec, NULL, NULL, NULL, 0);
>  	count += do_timer_list_v3(tv[3].base + OFFSET(tvec_s_vec),
> -		vec_size, vec, NULL, NULL);
> +		vec_size, vec, NULL, NULL, NULL, 0);
>  	count += do_timer_list_v3(tv[4].base + OFFSET(tvec_s_vec),
> -		vec_size, vec, NULL, NULL);
> +		vec_size, vec, NULL, NULL, NULL, 0);
>  	count += do_timer_list_v3(tv[5].base + OFFSET(tvec_s_vec),
> -		vec_size, vec, NULL, NULL);
> +		vec_size, vec, NULL, NULL, NULL, 0);
>  
>  	if (count)
>  		td = (struct timer_data *)
>  			GETBUF((count*2) * sizeof(struct timer_data));
>  	tdx = 0;
>  	highest = 0;
> +	highest_tte = 0;
> +
>  	get_symbol_data("jiffies", sizeof(ulong), &jiffies);
>  
>  	do_timer_list_v3(tv[1].base + OFFSET(tvec_root_s_vec),
> -		vec_root_size, vec, (void *)td, &highest);
> +		vec_root_size, vec, (void *)td, &highest, &highest_tte, jiffies);
>  	do_timer_list_v3(tv[2].base + OFFSET(tvec_s_vec),
> -		vec_size, vec, (void *)td, &highest);
> +		vec_size, vec, (void *)td, &highest, &highest_tte, jiffies);
>  	do_timer_list_v3(tv[3].base + OFFSET(tvec_s_vec),
> -		vec_size, vec, (void *)td, &highest);
> +		vec_size, vec, (void *)td, &highest, &highest_tte, jiffies);
>  	do_timer_list_v3(tv[4].base + OFFSET(tvec_s_vec),
> -		vec_size, vec, (void *)td, &highest);
> +		vec_size, vec, (void *)td, &highest, &highest_tte, jiffies);
>  	tdx = do_timer_list_v3(tv[5].base + OFFSET(tvec_s_vec),
> -		vec_size, vec, (void *)td, &highest);
> +		vec_size, vec, (void *)td, &highest, &highest_tte, jiffies);
>  
>  	qsort(td, tdx, sizeof(struct timer_data), compare_timer_data);
>  
> @@ -8369,8 +8417,13 @@ next_cpu:
>  	fprintf(fp, "%s\n", mkstring(buf1,flen,
>  		RJUST|LONG_DEC,MKSTR(jiffies)));
>  
> -	fprintf(fp, "%s  %s  %s\n",
> +	/* +1 accounts possible "-" sign */
> +	sprintf(buf4, "%ld", highest_tte);
> +	tlen = MAX(strlen(buf4) + 1, strlen("TTE"));
> +
> +	fprintf(fp, "%s  %s  %s  %s\n",
>  		mkstring(buf1, flen, CENTER|RJUST, "EXPIRES"),
> +		mkstring(buf4, tlen, CENTER|RJUST, "TTE"),
>  		mkstring(buf2, VADDR_PRLEN, CENTER|LJUST, "TIMER_LIST"),
>  		mkstring(buf3, VADDR_PRLEN, CENTER|LJUST, "FUNCTION"));
>  
> @@ -8378,6 +8431,9 @@ next_cpu:
>  		fprintf(fp, "%s",
>  			mkstring(buf1, flen, RJUST|LONG_DEC, MKSTR(td[i].expires)));
>  
> +		fprintf(fp, "  %s",
> +			mkstring(buf4, tlen, RJUST|SLONG_DEC, MKSTR(td[i].tte)));
> +
>  		fprintf(fp, "  %s  ", mkstring(buf1,
>  			MAX(VADDR_PRLEN, strlen("TIMER_LIST")),
>  			RJUST|CENTER|LONG_HEX, MKSTR(td[i].address)));
> @@ -8517,7 +8573,9 @@ do_timer_list(ulong vec_kvaddr,
>  	      ulong *vec,
>  	      void *option,
>  	      ulong *highest,
> -	      struct tv_range *tv)
> +	      ulong *highest_tte,
> +	      struct tv_range *tv,
> +	      ulong jiffies)
>  {
>  	int i, t;
>  	int count, tdx;
> @@ -8595,8 +8653,11 @@ do_timer_list(ulong vec_kvaddr,
>                                          td[tdx].address = timer_list[t];
>                                          td[tdx].expires = expires;
>                                          td[tdx].function = function;
> +                                        td[tdx].tte = expires - jiffies;
>                                          if (highest && (expires > *highest))
>                                                  *highest = expires;
> +                                        if (highest_tte && (abs(td[tdx].tte)
> > *highest_tte))
> +                                                *highest_tte =
> abs(td[tdx].tte);
>                                          tdx++;
>                                  }
>  			}
> @@ -8659,8 +8720,11 @@ new_timer_list_format:
>                                  td[tdx].address = timer_list[t];
>                                  td[tdx].expires = expires;
>                                  td[tdx].function = function;
> +                                td[tdx].tte = expires - jiffies;
>                                  if (highest && (expires > *highest))
>                                          *highest = expires;
> +                                if (highest_tte && (abs(td[tdx].tte) >
> *highest_tte))
> +                                        *highest_tte = abs(td[tdx].tte);
>                                  tdx++;
>                          }
>  		}
> @@ -8677,7 +8741,9 @@ do_timer_list_v3(ulong vec_kvaddr,
>  	      int size,
>  	      ulong *vec,
>  	      void *option,
> -	      ulong *highest)
> +	      ulong *highest,
> +	      ulong *highest_tte,
> +	      ulong jiffies)
>  {
>  	int i, t;
>  	int count, tdx;
> @@ -8743,8 +8809,11 @@ do_timer_list_v3(ulong vec_kvaddr,
>  				td[tdx].address = timer_list[t];
>  				td[tdx].expires = expires;
>  				td[tdx].function = function;
> +				td[tdx].tte = expires - jiffies;
>  				if (highest && (expires > *highest))
>  					*highest = expires;
> +				if (highest_tte && (abs(td[tdx].tte) > *highest_tte))
> +					*highest_tte = abs(td[tdx].tte);
>  				tdx++;
>  			}
>  		}
> @@ -8766,7 +8835,7 @@ struct timer_bases_data {
>  };
>  
>  static int
> -do_timer_list_v4(struct timer_bases_data *data)
> +do_timer_list_v4(struct timer_bases_data *data, ulong jiffies)
>  {
>  	int i, t, timer_cnt, found;
>  	struct list_data list_data, *ld;
> @@ -8826,6 +8895,7 @@ do_timer_list_v4(struct timer_bases_data *data)
>  			data->timers[data->cnt].address = timer_list[t];
>  			data->timers[data->cnt].expires = expires;
>  			data->timers[data->cnt].function = function;
> +			data->timers[data->cnt].tte = expires - jiffies;
>  			data->cnt++;
>  
>  			if (data->cnt == data->total) {
> @@ -8852,12 +8922,13 @@ do_timer_list_v4(struct timer_bases_data *data)
>  static void
>  dump_timer_data_timer_bases(const ulong *cpus)
>  {
> -	int i, cpu, flen, base, nr_bases, found, display, j = 0;
> +	int i, cpu, flen, tlen, base, nr_bases, found, display, j = 0;
>  	struct syment *sp;
> -	ulong timer_base, jiffies, function;
> +	ulong timer_base, jiffies, function, highest_tte;
>  	struct timer_bases_data data;
>  	char buf1[BUFSIZE];
>  	char buf2[BUFSIZE];
> +	char buf4[BUFSIZE];
>  
>  	if (!(data.num_vectors = get_array_length("timer_base.vectors", NULL, 0)))
>  		error(FATAL, "cannot determine timer_base.vectors[] array size\n");
> @@ -8912,12 +8983,42 @@ next_base:
>  	data.cnt = 0;
>  	data.timer_base = timer_base;
>  
> -	found = do_timer_list_v4(&data);
> +	found = do_timer_list_v4(&data, jiffies);
>  	
>  	qsort(data.timers, found, sizeof(struct timer_data), compare_timer_data);
>  
> -	fprintf(fp, "  %s     TIMER_LIST     FUNCTION\n",
> -		mkstring(buf1, flen, LJUST, "EXPIRES"));
> +	highest_tte = 0;
> +	for (i = 0; i < found; i++) {
> +	    display = FALSE;
> +
> +	    if (is_kernel_text(data.timers[i].function)) {
> +		display = TRUE;
> +	    } else {
> +		if (readmem(data.timers[i].function, KVADDR, &function,
> +		    sizeof(ulong), "timer function",
> +		    RETURN_ON_ERROR|QUIET) && is_kernel_text(function)) {
> +		    display = TRUE;
> +		} else {
> +                    if (LIVE())
> +			display = FALSE;
> +		    else
> +			display = TRUE;
> +		}
> +	    }
> +
> +	    if (display) {
> +		if (abs(data.timers[i].tte) > highest_tte)
> +		    highest_tte = abs(data.timers[i].tte);
> +	    }
> +	}
> +
> +	/* +1 accounts possible "-" sign */
> +	sprintf(buf4, "%ld", highest_tte);
> +	tlen = MAX(strlen(buf4) + 1, strlen("TTE"));
> +
> +	fprintf(fp, "  %s     %s     TIMER_LIST     FUNCTION\n",
> +		mkstring(buf1, flen, LJUST, "EXPIRES"),
> +		mkstring(buf4, tlen, LJUST, "TTE"));
>  
>  	for (i = 0; i < found; i++) {
>  		display = FALSE;
> @@ -8946,6 +9047,8 @@ next_base:
>  		if (display) {
>  			fprintf(fp, "  %s",
>  				mkstring(buf1, flen, RJUST|LONG_DEC, MKSTR(data.timers[i].expires)));
> +			fprintf(fp, "  %s",
> +				mkstring(buf4, tlen, RJUST|SLONG_DEC, MKSTR(data.timers[i].tte)));
>  			mkstring(buf1, VADDR_PRLEN, RJUST|LONG_HEX,
>  			MKSTR(data.timers[i].address));
>  			fprintf(fp, "  %s  ", mkstring(buf2, 16, CENTER, buf1));
>  			fprintf(fp, "%s  <%s>\n",
> diff --git a/tools.c b/tools.c
> index 2d95c3a..5c0e63e 100644
> --- a/tools.c
> +++ b/tools.c
> @@ -1650,11 +1650,14 @@ mkstring(char *s, int size, ulong flags, const char
> *opt)
>  	int left;
>  	int right;
>  
> -	switch (flags & (LONG_DEC|LONG_HEX|INT_HEX|INT_DEC|LONGLONG_HEX|ZERO_FILL))
> +	switch (flags &
> (LONG_DEC|SLONG_DEC|LONG_HEX|INT_HEX|INT_DEC|LONGLONG_HEX|ZERO_FILL))
>  	{
>  	case LONG_DEC:
>  		sprintf(s, "%lu", (ulong)opt);
>  		break;
> +	case SLONG_DEC:
> +		sprintf(s, "%ld", (ulong)opt);
> +		break;
>  	case LONG_HEX:
>  		sprintf(s, "%lx", (ulong)opt);
>  		break;
> --
> 2.22.0
> 
> 




More information about the Crash-utility mailing list