← Back to team overview

linuxdcpp-team team mailing list archive

[Branch ~dcplusplus-team/dcplusplus/trunk] Rev 2568: crash logger: find the enclosing function name

 

------------------------------------------------------------
revno: 2568
committer: poy <poy@xxxxxxxxxx>
branch nick: trunk
timestamp: Sun 2011-06-26 23:38:15 +0200
message:
  crash logger: find the enclosing function name
modified:
  win32/CrashLogger.cpp


--
lp:dcplusplus
https://code.launchpad.net/~dcplusplus-team/dcplusplus/trunk

Your team Dcplusplus-team is subscribed to branch lp:dcplusplus.
To unsubscribe from this branch go to https://code.launchpad.net/~dcplusplus-team/dcplusplus/trunk/+edit-subscription
=== modified file 'win32/CrashLogger.cpp'
--- win32/CrashLogger.cpp	2011-06-25 17:05:55 +0000
+++ win32/CrashLogger.cpp	2011-06-26 21:38:15 +0000
@@ -104,7 +104,46 @@
 	return DW_DLV_OK;
 }
 
-void getDebugInfo(string path, DWORD addr, string& file, int& line, int& column) {
+/* this recursive function browses through the children and siblings of a DIE, looking for the one
+DIE that specifically describes the enclosing function of the given address. */
+Dwarf_Die browseDIE(Dwarf_Debug dbg, Dwarf_Addr addr, Dwarf_Die die, Dwarf_Error& error) {
+
+	Dwarf_Addr lowpc, highpc;
+	if(dwarf_lowpc(die, &lowpc, &error) == DW_DLV_OK && dwarf_highpc(die, &highpc, &error) == DW_DLV_OK && addr >= lowpc && addr <= highpc) {
+		// found one! make sure it represents a function (section 3.3 of the DWARF 2 spec).
+		Dwarf_Half tag;
+		if(dwarf_tag(die, &tag, &error) == DW_DLV_OK && (tag == DW_TAG_subprogram || tag == DW_TAG_inlined_subroutine)) {
+			return die;
+		}
+	}
+
+	// flow to the next DIE. start with children then move to siblings.
+	Dwarf_Die next;
+
+	if(dwarf_child(die, &next, &error) == DW_DLV_OK) {
+		Dwarf_Die ret = browseDIE(dbg, addr, next, error);
+		if(ret) {
+			if(next != ret) {
+				dwarf_dealloc(dbg, next, DW_DLA_DIE);
+			}
+			return ret;
+		}
+	}
+
+	if(dwarf_siblingof(dbg, die, &next, &error) == DW_DLV_OK) {
+		Dwarf_Die ret = browseDIE(dbg, addr, next, error);
+		if(ret) {
+			if(next != ret) {
+				dwarf_dealloc(dbg, next, DW_DLA_DIE);
+			}
+			return ret;
+		}
+	}
+
+	return 0;
+}
+
+void getDebugInfo(string path, DWORD addr, string& file, int& line, int& column, string& function) {
 	if(path.empty())
 		return;
 	// replace the extension by "pdb".
@@ -148,14 +187,14 @@
 				Dwarf_Off die_offset;
 				if(dwarf_get_cu_die_offset(arange, &die_offset, &error) == DW_DLV_OK) {
 
-					Dwarf_Die die;
-					if(dwarf_offdie(dbg, die_offset, &die, &error) == DW_DLV_OK) {
+					Dwarf_Die cu_die;
+					if(dwarf_offdie(dbg, die_offset, &cu_die, &error) == DW_DLV_OK) {
 
 						/* inside this CU, find the exact statement (DWARF calls it a "line") that
 						corresponds to the address we want to find information about. */
 						Dwarf_Line* lines;
 						Dwarf_Signed line_count;
-						if(dwarf_srclines(die, &lines, &line_count, &error) == DW_DLV_OK) {
+						if(dwarf_srclines(cu_die, &lines, &line_count, &error) == DW_DLV_OK) {
 
 							/* skim through all available statements to find the one that fits best
 							(with an address <= "addr", as close as possible to "addr"). */
@@ -203,13 +242,45 @@
 							the global name of this CU's DIE which, according to section 3.1 of the
 							DWARF 2 spec, is almost what we want. */
 							char* name;
+							if(dwarf_diename(cu_die, &name, &error) == DW_DLV_OK) {
+								file = name;
+								dwarf_dealloc(dbg, name, DW_DLA_STRING);
+							}
+						}
+
+						/* to find the enclosing function, skim through the children and siblings
+						of this CU's DIE to find the one DIE that contains the frame address. */
+						Dwarf_Die die = browseDIE(dbg, addr, cu_die, error);
+						if(die) {
+
+							/* check if the DIE has a "specification" attribute which, according to
+							section 5.5.5 of the DWARF 2 spec, is a pointer to the DIE that
+							actually describes the function. */
+							Dwarf_Attribute attr;
+							if(dwarf_attr(die, DW_AT_specification, &attr, &error) == DW_DLV_OK) {
+								Dwarf_Off spec_offset;
+								if(dwarf_global_formref(attr, &spec_offset, &error) == DW_DLV_OK) {
+									Dwarf_Die spec_die;
+									if(dwarf_offdie(dbg, spec_offset, &spec_die, &error) == DW_DLV_OK) {
+										// replace the previous DIE by this new one.
+										dwarf_dealloc(dbg, die, DW_DLA_DIE);
+										die = spec_die;
+									}
+								}
+							}
+
+							/* as specified in section 3.3.1 of the DWARF 2 spec, the name of this
+							function-representing DIE should be what we are looking for. */
+							char* name;
 							if(dwarf_diename(die, &name, &error) == DW_DLV_OK) {
-								file = name;
+								function = name;
 								dwarf_dealloc(dbg, name, DW_DLA_STRING);
 							}
+
+							dwarf_dealloc(dbg, die, DW_DLA_DIE);
 						}
 
-						dwarf_dealloc(dbg, die, DW_DLA_DIE);
+						dwarf_dealloc(dbg, cu_die, DW_DLA_DIE);
 					}
 
 				}
@@ -355,6 +426,7 @@
 		string file;
 		int line = -1;
 		int column = -1;
+		string function;
 
 		IMAGEHLP_MODULE64 module = { sizeof(IMAGEHLP_MODULE64) };
 		if(!SymGetModuleInfo64(process, frame.AddrPC.Offset, &module))
@@ -363,7 +435,7 @@
 
 #ifdef __MINGW32__
 		// read DWARF debugging info if available.
-		getDebugInfo(module.LoadedImageName, frame.AddrPC.Offset, file, line, column);
+		getDebugInfo(module.LoadedImageName, frame.AddrPC.Offset, file, line, column, function);
 #endif
 
 		/* this is the usual Windows PDB reading method. we try it on MinGW too if reading DWARF
@@ -374,13 +446,12 @@
 			symbol->MaxNameLength = 254;
 			if(SymGetSymFromAddr64(process, frame.AddrPC.Offset, 0, symbol)) {
 				file = symbol->Name;
-			} else {
-				file = "?";
 			}
 
 			IMAGEHLP_LINE64 info = { sizeof(IMAGEHLP_LINE64) };
 			DWORD col;
 			if(SymGetLineFromAddr64(process, frame.AddrPC.Offset, &col, &info)) {
+				function = file;
 				file = info.FileName;
 				line = info.LineNumber;
 				column = col;
@@ -388,7 +459,7 @@
 		}
 
 		// write the data collected about this frame to the file.
-		fprintf(f, "%s", file.c_str());
+		fprintf(f, "%s", file.empty() ? "?" : file.c_str());
 		if(line >= 0) {
 			fprintf(f, " (%d", line);
 			if(column >= 0) {
@@ -396,6 +467,9 @@
 			}
 			fputs(")", f);
 		}
+		if(!function.empty()) {
+			fprintf(f, " in function %s", function.c_str());
+		}
 		fputs("\n", f);
 	}
 
@@ -429,7 +503,7 @@
 
 LPTOP_LEVEL_EXCEPTION_FILTER prevFilter;
 
-} // anonymous namespace
+} // unnamed namespace
 
 CrashLogger::CrashLogger() {
 	prevFilter = SetUnhandledExceptionFilter(exception_filter);