[Crash-utility] [PATCH 2/2] crash: support s390 debug feature version 3

Mikhail Zaslonko zaslonko at linux.ibm.com
Wed Aug 12 14:56:41 UTC 2020


With kernel commit 0990d836ce "s390/debug: debug feature version 3" the
__debug_entry structure has been modified by:
  - removing redundant union
  - expanding microseconds timestamp to 60 bits and storing it in the
    absolute Unix time format taking Epoch Index into account
  - expanding cpuid field to 16 bits
Current crash patch aims to:
  - define debug_entry_v3_t data type for new debug entry structure
  and process V3 debug entries accordingly
  - adjust debug entries header output by setting minimum width for
    cpuid to 4 digits and expanding function name width to 26 characters
  - adjust output alignment for the header and debug entries
  - minor code cleanup

Signed-off-by: Mikhail Zaslonko <zaslonko at linux.ibm.com>
---
 s390dbf.c | 130 +++++++++++++++++++++++++++++++-----------------------
 1 file changed, 74 insertions(+), 56 deletions(-)

diff --git a/s390dbf.c b/s390dbf.c
index 232ceb8..5f53170 100644
--- a/s390dbf.c
+++ b/s390dbf.c
@@ -165,6 +165,7 @@ static inline int set_cmd_flags(command_t *cmd, int flags, char *extraops)
 	return 0;
 }
 
+#define USEC_PER_SEC 1000000L
 /* Time of day clock value for 1970/01/01 */
 #define TOD_UNIX_EPOCH (0x8126d60e46000000LL - (0x3c26700LL * 1000000 * 4096))
 /* Time of day clock value for 1970/01/01 in usecs */
@@ -180,8 +181,8 @@ static inline void kl_s390tod_to_timeval(uint64_t todval, struct timeval *xtime)
 	todval_us += tod_clock_base_us;
 	/* Subtract EPOCH that we get time in usec since 1970 */
 	todval_us -= TOD_UNIX_EPOCH_US;
-	xtime->tv_sec  = todval_us / 1000000;
-	xtime->tv_usec = todval_us % 1000000;
+	xtime->tv_sec  = todval_us / USEC_PER_SEC;
+	xtime->tv_usec = todval_us % USEC_PER_SEC;
 }
 
 static inline int kl_struct_len(char* struct_name)
@@ -227,6 +228,7 @@ static inline kaddr_t kl_funcaddr(kaddr_t addr)
 
 #define DBF_VERSION_V1 1
 #define DBF_VERSION_V2 2
+#define DBF_VERSION_V3 3
 #define PAGE_SIZE 4096
 #define DEBUG_MAX_VIEWS	    10 /* max number of views in proc fs */
 #define DEBUG_MAX_PROCF_LEN	64 /* max length for a proc file name */
@@ -238,8 +240,9 @@ static inline kaddr_t kl_funcaddr(kaddr_t addr)
 typedef struct debug_view_s debug_view_t;
 
 /* struct to hold contents of struct __debug_entry from dump
+ * for DBF_VERSION_V1 and DBF_VERSION_V2
  */
-typedef struct debug_entry_s{
+typedef struct debug_entry_v1_s{
 	union {
 		struct {
 			unsigned long long clock:52;
@@ -251,9 +254,16 @@ typedef struct debug_entry_s{
 		unsigned long long stck;
 	} id;
 	kaddr_t caller; /* changed from void* to kaddr_t */
-} __attribute__((packed)) debug_entry_t;
-/* typedef struct __debug_entry debug_entry_t; */
+} __attribute__((packed)) debug_entry_v1_t;
 
+/* for DBF_VERSION_V3 */
+typedef struct debug_entry_v3_s{
+	unsigned long long clock:60;
+	unsigned long long exception:1;
+	unsigned long long level:3;
+	kaddr_t caller; /* changed from void* to kaddr_t */
+	unsigned short cpuid;
+} __attribute__((packed)) debug_entry_v3_t;
 
 static unsigned int dbf_version;
 
@@ -284,7 +294,7 @@ typedef struct debug_info_s {
 /* functions to generate dbf output
  */
 typedef int (debug_header_proc_t) (debug_info_t* id, debug_view_t* view,
-				   int area, debug_entry_t* entry,
+				   int area, void* entry,
 				   char* out_buf);
 typedef int (debug_format_proc_t) (debug_info_t* id, debug_view_t* view,
 				   char* out_buf, const char* in_buf);
@@ -322,35 +332,45 @@ EBCASC(char *inout, size_t len)
  */
 static int
 dflt_header_fn(debug_info_t * id, debug_view_t *view,
-	       int area, debug_entry_t * entry, char *out_buf)
+	       int area, void *entry, char *out_buf)
 {
 	struct timeval time_val;
-	unsigned long long time;
-	char *except_str;
-	kaddr_t caller;
 	int rc = 0;
+	unsigned long long time;
+	unsigned short level = 0, cpuid = 0;
+	char *except_str = "-";
+	kaddr_t caller = 0;
 	char *caller_name;
+	int name_width = 26;
 	int offset;
 	char caller_buf[30];
-	unsigned int level;
 	syment_t *caller_sym;
-	debug_entry_t lentry; /* store byte swapped values of entry */
 
-	lentry.id.stck = KL_GET_UINT64(&entry->id);
-	lentry.caller = KL_GET_PTR(&entry->caller);
-	level = lentry.id.fields.level;
-	time = lentry.id.stck;
-
-	kl_s390tod_to_timeval(time, &time_val);
+	switch (dbf_version) {
+	case DBF_VERSION_V1:
+	case DBF_VERSION_V2:
+		level = ((debug_entry_v1_t *) entry)->id.fields.level;
+		cpuid = ((debug_entry_v1_t *) entry)->id.fields.cpuid;
+		time = ((debug_entry_v1_t *) entry)->id.stck;
+		if (((debug_entry_v1_t *) entry)->id.fields.exception)
+			except_str = "*";
+		caller = ((debug_entry_v1_t *) entry)->caller;
+		kl_s390tod_to_timeval(time, &time_val);
+		break;
+	case DBF_VERSION_V3:
+		level = ((debug_entry_v3_t *) entry)->level;
+		cpuid = ((debug_entry_v3_t *) entry)->cpuid;
+		time = ((debug_entry_v3_t *) entry)->clock;
+		if (((debug_entry_v3_t *) entry)->exception)
+			except_str = "*";
+		caller = ((debug_entry_v3_t *) entry)->caller;
+		time_val.tv_sec  = time / USEC_PER_SEC;
+		time_val.tv_usec = time % USEC_PER_SEC;
+		break;
+	}
 
-	if (lentry.id.fields.exception)
-		except_str = "*";
-	else
-		except_str = "-";
-	caller = lentry.caller;
-	if(KL_ARCH == KL_ARCH_S390){
+	if(KL_ARCH == KL_ARCH_S390)
 		caller &= 0x7fffffff;
-	}
 	caller_sym = kl_lkup_symaddr(caller);
 	if(caller_sym){
 		caller_name = caller_sym->s_name;
@@ -361,20 +381,12 @@ dflt_header_fn(debug_info_t * id, debug_view_t *view,
 		caller_name = caller_buf;
 		offset = 0;
 	}
+	rc += sprintf(out_buf,
+	      "%02i %011lu:%06lu %1u %1s %04i <%-*s+%04i>  ",
+	      area, time_val.tv_sec, time_val.tv_usec, level,
+	      except_str, cpuid,
+	      name_width, caller_name, offset);
 
-	if(KL_ARCH == KL_ARCH_S390X){
-		rc += sprintf(out_buf, 
-			      "%02i %011lu:%06lu %1u %1s %02i <%20s+%04i>  ",
-			      area, time_val.tv_sec, time_val.tv_usec, level,
-			      except_str, entry->id.fields.cpuid, caller_name,
-			      offset);
-	} else {
-		rc += sprintf(out_buf,
-			      "%02i %011lu:%06lu %1u %1s %02i <%-20s+%04i>  ",
-			      area, time_val.tv_sec, time_val.tv_usec, level,
-			      except_str, lentry.id.fields.cpuid, caller_name,
-			      offset);
-	}
 	return rc;
 }
 
@@ -539,9 +551,9 @@ prolog_fn(debug_info_t * id,
 {
 	int rc = 0;
 
-	rc = sprintf(out_buf, "AREA TIME LEVEL EXCEPTION CP CALLING FUNCTION"
-		     "   + OFFSET  DATA\n==================================="
-		     "=======================================\n");
+	rc = sprintf(out_buf, "AREA TIME LEVEL EXCEPTION CP   CALLING FUNCTION"
+		     " + OFFSET          DATA\n==============================="
+		     "===========================================\n");
 	return rc;
 }
 
@@ -663,10 +675,10 @@ debug_view_t sprintf_view = {
 };
 
 
-static debug_entry_t *
-debug_find_oldest_entry(debug_entry_t *entries, int num, int entry_size)
+static debug_entry_v1_t *
+debug_find_oldest_entry(debug_entry_v1_t *entries, int num, int entry_size)
 {
-	debug_entry_t *result, *current;
+	debug_entry_v1_t *result, *current;
 	int i;
 	uint64_t clock1, clock2;
 
@@ -681,7 +693,7 @@ debug_find_oldest_entry(debug_entry_t *entries, int num, int entry_size)
 		clock2 = KL_GET_UINT64(&clock2);
 		if (clock1 < clock2)
 			result = current;
-		current = (debug_entry_t *) ((char *) current + entry_size);
+		current = (debug_entry_v1_t *) ((char *) current + entry_size);
 	}
 	return result;
 }
@@ -697,7 +709,7 @@ debug_format_output_v1(debug_info_t * debug_area, debug_view_t *view,
 {
 	int i, j, len;
 	int nr_of_entries;
-	debug_entry_t *act_entry, *last_entry;
+	debug_entry_v1_t *act_entry, *last_entry;
 	char *act_entry_data;
 	char buf[2048];
 	size_t items ATTRIBUTE_UNUSED;
@@ -720,7 +732,7 @@ debug_format_output_v1(debug_info_t * debug_area, debug_view_t *view,
 		act_entry = debug_find_oldest_entry(debug_area->areas[i],
 						    nr_of_entries,
 						    debug_area->entry_size);
-		last_entry = (debug_entry_t *) ((char *) debug_area->areas[i] +
+		last_entry = (debug_entry_v1_t *) ((char *) debug_area->areas[i] +
 			     (PAGE_SIZE << debug_area->page_order) -
 			     debug_area->entry_size);
 		for (j = 0; j < nr_of_entries; j++) {
@@ -740,7 +752,7 @@ debug_format_output_v1(debug_info_t * debug_area, debug_view_t *view,
 				memset(buf, 0, 2048); 
 			}
 			act_entry =
-			    (debug_entry_t *) (((char *) act_entry) +
+			    (debug_entry_v1_t *) (((char *) act_entry) +
 					       debug_area->entry_size);
 			if (act_entry > last_entry)
 				act_entry = debug_area->areas[i];
@@ -759,7 +771,7 @@ debug_format_output_v2(debug_info_t * debug_area,
 		    debug_view_t *view, FILE * ofp)
 {
 	int i, j, k, len;
-	debug_entry_t *act_entry;
+	void *act_entry;
 	char *act_entry_data;
 	char buf[2048];
 	size_t items ATTRIBUTE_UNUSED;
@@ -783,7 +795,11 @@ debug_format_output_v2(debug_info_t * debug_area,
 			act_entry = debug_area->areas_v2[i][j];
 			for (k = 0; k < nr_entries_per_page; k++) {
 				act_entry_data = (char*)act_entry + dbe_size;
-				if (act_entry->id.stck == 0)
+				if (dbf_version == DBF_VERSION_V3 &&
+				    ((debug_entry_v3_t *) act_entry)->clock == 0)
+					break;	/* empty entry */
+				else if (dbf_version < DBF_VERSION_V3 &&
+				    ((debug_entry_v1_t *) act_entry)->id.stck == 0)
 					break;	/* empty entry */
 				if (view->header_proc) {
 					len = view->header_proc(debug_area, 
@@ -797,8 +813,8 @@ debug_format_output_v2(debug_info_t * debug_area,
 					items = fwrite(buf,len, 1, ofp);
 					memset(buf, 0, 2048); 
 				}
-				act_entry = (debug_entry_t *) (((char *) 
-					act_entry) + debug_area->entry_size);
+				act_entry = ((char *) act_entry) +
+					debug_area->entry_size;
 			}
 		}
 	}
@@ -905,7 +921,7 @@ debug_get_areas_v1(debug_info_t* db_info, void* k_dbi)
        	mem_pos = KL_ULONG(k_dbi,"debug_info","areas");
        	for (i = 0; i < db_info->nr_areas; i++) {
 		dbe_addr = KL_VREAD_PTR(mem_pos);
-	       	db_info->areas[i] = (debug_entry_t *) malloc(area_size);
+		db_info->areas[i] = (debug_entry_v1_t *) malloc(area_size);
 		/* read raw data for debug area */
 	       	GET_BLOCK(dbe_addr, area_size, db_info->areas[i]);
 		mem_pos += KL_NBPW;
@@ -1328,11 +1344,13 @@ s390dbf_cmd(command_t * cmd)
 
 	dbf_version = KL_VREAD_UINT32(dbf_version_sym->s_addr);
 
-	if ((dbf_version != DBF_VERSION_V1) && (dbf_version != DBF_VERSION_V2)){
+	if ((dbf_version != DBF_VERSION_V1) &&
+	    (dbf_version != DBF_VERSION_V2) &&
+	    (dbf_version != DBF_VERSION_V3)) {
 		fprintf(cmd->efp,"lcrash does not support the"
 			" debug feature version of the dump kernel:\n");
-		fprintf(cmd->efp,"DUMP: %i SUPPORTED: %i and %i\n",
-			dbf_version, DBF_VERSION_V1, DBF_VERSION_V2);
+		fprintf(cmd->efp,"DUMP: %i SUPPORTED: %i, %i and %i\n",
+			dbf_version, DBF_VERSION_V1, DBF_VERSION_V2, DBF_VERSION_V3);
 		return -1;
 	}
 
-- 
2.17.1




More information about the Crash-utility mailing list