Include a back trace in problem report technical details.
This adds a dependcy on libunwind for generating the back trace. * src/CMakeLists.txt: Require libunwind-generic package and libunwind VAPI. Update docs and debian/control with new dependencies. * src/engine/api/geary-problem-report.vala (ProblemReport): Generate a stack trace in the default constructor if an error is specified. * src/client/components/main-window-info-bar.vala (MainWindowInfoBar::format_details): Include stack trafe from problem report in output if present. * ui/main-window-info-bar.ui: Add a ScrolledWindow around the TextView since the details could now be quite large. * bindings/vapi/libunwind.vapi: Add bindings for libunwind courtesy Guillaume Poirier-Morency, add Error enum.
This commit is contained in:
parent
0d1efc2fe0
commit
bcca75f5a8
7 changed files with 150 additions and 17 deletions
6
INSTALL
6
INSTALL
|
|
@ -46,6 +46,7 @@
|
||||||
* webkit2gtk-4.0
|
* webkit2gtk-4.0
|
||||||
* gcr-3
|
* gcr-3
|
||||||
* enchant
|
* enchant
|
||||||
|
* libunwind
|
||||||
* messaging-menu (optional; enables support for Ubuntu Unity
|
* messaging-menu (optional; enables support for Ubuntu Unity
|
||||||
messaging menu)
|
messaging menu)
|
||||||
* unity (optional; enables support for Ubuntu Unity launcher)
|
* unity (optional; enables support for Ubuntu Unity launcher)
|
||||||
|
|
@ -67,7 +68,7 @@
|
||||||
desktop-file-utils gnome-doc-utils libcanberra-devel libgee-devel \
|
desktop-file-utils gnome-doc-utils libcanberra-devel libgee-devel \
|
||||||
glib2-devel gmime-devel gtk3-devel libnotify-devel sqlite-devel \
|
glib2-devel gmime-devel gtk3-devel libnotify-devel sqlite-devel \
|
||||||
webkitgtk4-devel libsecret-devel libxml2-devel vala-tools \
|
webkitgtk4-devel libsecret-devel libxml2-devel vala-tools \
|
||||||
gcr-devel enchant-devel
|
gcr-devel enchant-devel libunwind-devel
|
||||||
|
|
||||||
|
|
||||||
* Installing dependencies on Ubuntu/Debian
|
* Installing dependencies on Ubuntu/Debian
|
||||||
|
|
@ -86,7 +87,8 @@
|
||||||
cmake desktop-file-utils gnome-doc-utils libcanberra-dev \
|
cmake desktop-file-utils gnome-doc-utils libcanberra-dev \
|
||||||
libgee-0.8-dev libglib2.0-dev libgmime-2.6-dev libgtk-3-dev \
|
libgee-0.8-dev libglib2.0-dev libgmime-2.6-dev libgtk-3-dev \
|
||||||
libsecret-1-dev libxml2-dev libnotify-dev libsqlite3-dev \
|
libsecret-1-dev libxml2-dev libnotify-dev libsqlite3-dev \
|
||||||
libwebkit2gtk-4.0-dev libgcr-3-dev libenchant-dev
|
libwebkit2gtk-4.0-dev libgcr-3-dev libenchant-dev \
|
||||||
|
libunwind-dev
|
||||||
|
|
||||||
And for Ubuntu Unity integration:
|
And for Ubuntu Unity integration:
|
||||||
|
|
||||||
|
|
|
||||||
63
bindings/vapi/libunwind.vapi
Normal file
63
bindings/vapi/libunwind.vapi
Normal file
|
|
@ -0,0 +1,63 @@
|
||||||
|
/*
|
||||||
|
* Based on version from Sentry-GLib: https://github.com/arteymix/sentry-glib
|
||||||
|
* Courtesy of Guillaume Poirier-Morency <guillaumepoiriermorency@gmail.com>
|
||||||
|
*/
|
||||||
|
|
||||||
|
[CCode (cprefix = "UNW_", lower_case_cprefix = "unw_", cheader_filename = "libunwind.h")]
|
||||||
|
namespace Unwind
|
||||||
|
{
|
||||||
|
|
||||||
|
[CCode (cname = "unw_context_t")]
|
||||||
|
public struct Context
|
||||||
|
{
|
||||||
|
[CCode (cname = "unw_getcontext")]
|
||||||
|
public Context ();
|
||||||
|
}
|
||||||
|
|
||||||
|
[CCode (cname = "unw_proc_info_t")]
|
||||||
|
public struct ProcInfo
|
||||||
|
{
|
||||||
|
void* start_ip;
|
||||||
|
void* end_ip;
|
||||||
|
void* lsda;
|
||||||
|
void* handler;
|
||||||
|
void* gp;
|
||||||
|
long flags;
|
||||||
|
int format;
|
||||||
|
}
|
||||||
|
|
||||||
|
[CCode (cname = "unw_frame_regnum_t")]
|
||||||
|
public enum Reg
|
||||||
|
{
|
||||||
|
IP,
|
||||||
|
SP,
|
||||||
|
EH
|
||||||
|
}
|
||||||
|
|
||||||
|
[CCode (cname = "unw_cursor_t", cprefix = "unw_")]
|
||||||
|
public struct Cursor
|
||||||
|
{
|
||||||
|
public Cursor.local (Context ctx);
|
||||||
|
public int get_proc_info (out ProcInfo pip);
|
||||||
|
public int get_proc_name (uint8[] bufp, out long offp = null);
|
||||||
|
public int get_reg (Reg reg, out void* valp);
|
||||||
|
public int step ();
|
||||||
|
}
|
||||||
|
|
||||||
|
[CCode (cname = "unw_error_t", cprefix = "UNW_E", has_type_id = false)]
|
||||||
|
public enum Error
|
||||||
|
{
|
||||||
|
SUCCESS,
|
||||||
|
UNSPEC,
|
||||||
|
NOMEM,
|
||||||
|
BADREG,
|
||||||
|
READONLYREG,
|
||||||
|
STOPUNWIND,
|
||||||
|
INVALIDIP,
|
||||||
|
BADFRAME,
|
||||||
|
INVAL,
|
||||||
|
BADVERSION,
|
||||||
|
NOINFO
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
2
debian/control
vendored
2
debian/control
vendored
|
|
@ -23,6 +23,7 @@ Build-Depends: debhelper (>= 8),
|
||||||
gnome-doc-utils,
|
gnome-doc-utils,
|
||||||
libgcr-3-dev (>= 3.10.1),
|
libgcr-3-dev (>= 3.10.1),
|
||||||
libenchant-dev (>= 1.6.0)
|
libenchant-dev (>= 1.6.0)
|
||||||
|
libunwind8-dev (>= 1.1)
|
||||||
Standards-Version: 3.8.3
|
Standards-Version: 3.8.3
|
||||||
Homepage: https://wiki.gnome.org/Apps/Geary
|
Homepage: https://wiki.gnome.org/Apps/Geary
|
||||||
|
|
||||||
|
|
@ -45,6 +46,7 @@ Depends: ${shlibs:Depends}, ${misc:Depends},
|
||||||
libgcr-base-3-1 (>= 3.10.1),
|
libgcr-base-3-1 (>= 3.10.1),
|
||||||
libgcr-ui-3-1 (>= 3.10.1),
|
libgcr-ui-3-1 (>= 3.10.1),
|
||||||
libenchant1c2a (>= 1.6.0)
|
libenchant1c2a (>= 1.6.0)
|
||||||
|
libunwind8 (>= 1.1)
|
||||||
Description: Email application
|
Description: Email application
|
||||||
Geary is an email application built around conversations, for the
|
Geary is an email application built around conversations, for the
|
||||||
GNOME 3 desktop. It allows you to read, find and send email with a
|
GNOME 3 desktop. It allows you to read, find and send email with a
|
||||||
|
|
|
||||||
|
|
@ -512,6 +512,7 @@ pkg_check_modules(DEPS REQUIRED
|
||||||
webkit2gtk-web-extension-4.0>=${TARGET_WEBKIT}
|
webkit2gtk-web-extension-4.0>=${TARGET_WEBKIT}
|
||||||
javascriptcoregtk-4.0>=${TARGET_WEBKIT}
|
javascriptcoregtk-4.0>=${TARGET_WEBKIT}
|
||||||
enchant>=1.6
|
enchant>=1.6
|
||||||
|
libunwind-generic>=1.1
|
||||||
${EXTRA_CLIENT_PKG_CONFIG}
|
${EXTRA_CLIENT_PKG_CONFIG}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -529,6 +530,7 @@ set(ENGINE_PACKAGES
|
||||||
gio-2.0
|
gio-2.0
|
||||||
glib-2.0
|
glib-2.0
|
||||||
gmime-2.6
|
gmime-2.6
|
||||||
|
libunwind
|
||||||
javascriptcore-4.0
|
javascriptcore-4.0
|
||||||
libxml-2.0
|
libxml-2.0
|
||||||
posix
|
posix
|
||||||
|
|
|
||||||
|
|
@ -213,12 +213,18 @@ public class MainWindowInfoBar : Gtk.InfoBar {
|
||||||
"Endpoint: %s\n", service_report.endpoint.to_string()
|
"Endpoint: %s\n", service_report.endpoint.to_string()
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
details.append_printf(
|
if (this.report.error == null) {
|
||||||
"Error type: %s\n", (this.report.error != null) ? this.report.format_error_type() : "None specified"
|
details.append("No error reported");
|
||||||
);
|
} else {
|
||||||
details.append_printf(
|
details.append_printf("Error type: %s\n", this.report.format_error_type());
|
||||||
"Message: %s\n", (this.report.error != null) ? this.report.error.message : "None specified"
|
details.append_printf("Message: %s\n", this.report.error.message);
|
||||||
);
|
}
|
||||||
|
if (this.report.backtrace != null) {
|
||||||
|
details.append("Back trace:\n");
|
||||||
|
foreach (Geary.ProblemReport.StackFrame frame in this.report.backtrace) {
|
||||||
|
details.append_printf(" - %s\n", frame.to_string());
|
||||||
|
}
|
||||||
|
}
|
||||||
return details.str;
|
return details.str;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -9,6 +9,7 @@
|
||||||
/** Describes available problem types. */
|
/** Describes available problem types. */
|
||||||
public enum Geary.ProblemType {
|
public enum Geary.ProblemType {
|
||||||
|
|
||||||
|
|
||||||
/** Indicates an engine problem not covered by one of the other types. */
|
/** Indicates an engine problem not covered by one of the other types. */
|
||||||
GENERIC_ERROR,
|
GENERIC_ERROR,
|
||||||
|
|
||||||
|
|
@ -30,6 +31,7 @@ public enum Geary.ProblemType {
|
||||||
/** Indicates an outgoing message was sent, but not saved. */
|
/** Indicates an outgoing message was sent, but not saved. */
|
||||||
SEND_EMAIL_SAVE_FAILED;
|
SEND_EMAIL_SAVE_FAILED;
|
||||||
|
|
||||||
|
|
||||||
/** Determines the appropriate problem type for an IOError. */
|
/** Determines the appropriate problem type for an IOError. */
|
||||||
public static ProblemType for_ioerror(IOError error) {
|
public static ProblemType for_ioerror(IOError error) {
|
||||||
if (error is IOError.CONNECTION_REFUSED ||
|
if (error is IOError.CONNECTION_REFUSED ||
|
||||||
|
|
@ -54,16 +56,61 @@ public enum Geary.ProblemType {
|
||||||
*/
|
*/
|
||||||
public class Geary.ProblemReport : Object {
|
public class Geary.ProblemReport : Object {
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents an individual stack frame in a call back-trace.
|
||||||
|
*/
|
||||||
|
public class StackFrame {
|
||||||
|
|
||||||
|
|
||||||
|
/** Name of the function being called. */
|
||||||
|
public string name = "unknown";
|
||||||
|
|
||||||
|
|
||||||
|
internal StackFrame(Unwind.Cursor frame) {
|
||||||
|
uint8 proc_name[256];
|
||||||
|
int ret = -frame.get_proc_name(proc_name);
|
||||||
|
if (ret == Unwind.Error.SUCCESS ||
|
||||||
|
ret == Unwind.Error.NOMEM) {
|
||||||
|
this.name = (string) proc_name;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public string to_string() {
|
||||||
|
return this.name;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/** Describes the type of being reported. */
|
/** Describes the type of being reported. */
|
||||||
public ProblemType problem_type { get; private set; }
|
public ProblemType problem_type { get; private set; }
|
||||||
|
|
||||||
/** The exception caused the problem, if any. */
|
/** The exception caused the problem, if any. */
|
||||||
public Error? error { get; private set; default = null; }
|
public Error? error { get; private set; default = null; }
|
||||||
|
|
||||||
|
/** A back trace from when the problem report was constructed. */
|
||||||
|
public Gee.List<StackFrame>? backtrace = null;
|
||||||
|
|
||||||
|
|
||||||
public ProblemReport(ProblemType type, Error? error) {
|
public ProblemReport(ProblemType type, Error? error) {
|
||||||
this.problem_type = type;
|
this.problem_type = type;
|
||||||
this.error = error;
|
this.error = error;
|
||||||
|
|
||||||
|
if (error != null) {
|
||||||
|
// Some kind of exception occurred, so build a trace. This
|
||||||
|
// is far from perfect, but at least we will know where it
|
||||||
|
// was getting caught.
|
||||||
|
this.backtrace = new Gee.LinkedList<StackFrame>();
|
||||||
|
Unwind.Context trace = Unwind.Context();
|
||||||
|
Unwind.Cursor cursor = Unwind.Cursor.local(trace);
|
||||||
|
|
||||||
|
// This misses the first frame, but that's this
|
||||||
|
// constructor call, so we don't really care.
|
||||||
|
while (cursor.step() != 0) {
|
||||||
|
this.backtrace.add(new StackFrame(cursor));
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Returns a string representation of the report, for debugging only. */
|
/** Returns a string representation of the report, for debugging only. */
|
||||||
|
|
|
||||||
|
|
@ -119,19 +119,30 @@
|
||||||
</packing>
|
</packing>
|
||||||
</child>
|
</child>
|
||||||
<child>
|
<child>
|
||||||
<object class="GtkTextView" id="detail_text">
|
<object class="GtkScrolledWindow">
|
||||||
|
<property name="width_request">600</property>
|
||||||
|
<property name="height_request">200</property>
|
||||||
<property name="visible">True</property>
|
<property name="visible">True</property>
|
||||||
<property name="can_focus">True</property>
|
<property name="can_focus">True</property>
|
||||||
<property name="hexpand">True</property>
|
<property name="hexpand">True</property>
|
||||||
<property name="vexpand">True</property>
|
<property name="vexpand">True</property>
|
||||||
<property name="editable">False</property>
|
<property name="shadow_type">in</property>
|
||||||
<property name="wrap_mode">word</property>
|
<child>
|
||||||
<property name="left_margin">6</property>
|
<object class="GtkTextView" id="detail_text">
|
||||||
<property name="right_margin">6</property>
|
<property name="visible">True</property>
|
||||||
<property name="top_margin">6</property>
|
<property name="can_focus">True</property>
|
||||||
<property name="bottom_margin">6</property>
|
<property name="hexpand">True</property>
|
||||||
<property name="cursor_visible">False</property>
|
<property name="vexpand">True</property>
|
||||||
<property name="monospace">True</property>
|
<property name="editable">False</property>
|
||||||
|
<property name="wrap_mode">word</property>
|
||||||
|
<property name="left_margin">6</property>
|
||||||
|
<property name="right_margin">6</property>
|
||||||
|
<property name="top_margin">6</property>
|
||||||
|
<property name="bottom_margin">6</property>
|
||||||
|
<property name="cursor_visible">False</property>
|
||||||
|
<property name="monospace">True</property>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
</object>
|
</object>
|
||||||
<packing>
|
<packing>
|
||||||
<property name="left_attach">0</property>
|
<property name="left_attach">0</property>
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue