Depend on libhandy

This commit is contained in:
Bleak Grey 2020-05-30 14:39:41 +03:00
parent bf17d460f4
commit 7faca4090e
5 changed files with 6 additions and 663 deletions

View File

@ -18,6 +18,7 @@ To build the app, make sure you have these dependencies:
* libsoup2.4-dev
* libgranite-dev
* libjson-glib-dev
* libhandy-0.0-dev
Then run `install.sh` in the project directory to install the app.

View File

@ -4,10 +4,11 @@ gnome = import('gnome')
i18n = import('i18n')
#add_project_arguments(['--disable-warnings', '-g', '-X', '-rdynamic'], language: 'vala')
add_project_arguments(['-g', '-rdynamic', '-export-dynamic'], language: 'c')
#add_project_arguments(['-g', '-rdynamic', '-export-dynamic'], language: 'c')
add_global_arguments([
'-DGETTEXT_PACKAGE="@0@"'.format(meson.project_name())
'-DGETTEXT_PACKAGE="@0@"'.format(meson.project_name()),
'-DHANDY_USE_UNSTABLE_API',
],
language: 'c',
)
@ -21,9 +22,6 @@ asresources = gnome.compile_resources(
executable(
meson.project_name(),
asresources,
'src/Stacktrace.vala', #TODO: move into a separate lib
'src/Build.vala',
'src/Application.vala',
'src/Desktop.vala',
@ -81,8 +79,7 @@ executable(
dependency('granite', version: '>=5.2.0'),
dependency('json-glib-1.0'),
dependency('libsoup-2.4'),
meson.get_compiler('vala').find_library('linux', required: true), #Required by Stacktrace.vala
dependency('libhandy-0.0', version: '>=0.0.13'),
],
install: true,
link_args: '-export-dynamic'

View File

@ -63,10 +63,7 @@ namespace Tootle {
public static int main (string[] args) {
Gtk.init (ref args);
Stacktrace.register_handlers ();
//assert (true == false); // I'm not crazy. It's for stacktrace testing.
Hdy.init (ref args);
try {
var opt_context = new OptionContext ("- Options");
opt_context.add_main_entries (app_options, null);

View File

@ -1,651 +0,0 @@
/*
* Copyright (C) 2014 PerfectCarl - https://github.com/PerfectCarl/vala-stacktrace
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
public class Stacktrace {
public class Frame {
// Address used by addr2line
public string address { get;private set;default = "";}
public string line { get;private set;default = "";}
public string line_number { get;private set;default = "";}
public string file_path { get;private set;default = "";}
public string file_short_path { get;private set;default = "";}
public string function { get;private set;default = "";}
public Frame (string address, string line, string function, string file_path, string file_short_path) {
this._address = address;
this._line = line;
this._file_path = file_path;
this._file_short_path = file_short_path;
this._function = function;
this.line_number = extract_line (line);
}
public string to_string () {
var result = line;
if (result == "")
result = " C library at address [" + address + "]";
return result + " [" + address + "]";
}
}
public enum Style {
RESET = 0,
BRIGHT = 1,
DIM = 2,
UNDERLINE = 3,
BLINK = 4,
REVERSE = 7,
HIDDEN = 8
}
public enum CriticalHandler {
IGNORE,
PRINT_STACKTRACE,
CRASH
}
public enum Color {
BLACK = 0,
RED = 1,
GREEN = 2,
YELLOW = 3,
BLUE = 4,
MAGENTA = 5,
CYAN = 6,
WHITE = 7
}
public Gee.ArrayList<Frame> _frames = new Gee.ArrayList<Frame>();
private Frame first_vala = null;
private int max_file_name_length = 0;
private int max_line_number_length = 0;
private bool is_all_function_name_blank = true;
private bool is_all_file_name_blank = true;
private ProcessSignal sig;
public static bool enabled { get;set;default = true;}
public static bool hide_installed_libraries { get;set;default = false;}
public static Color default_highlight_color { get;set;default = Color.WHITE;}
public static Color default_error_background { get;set;default = Color.RED;}
public Color highlight_color { get;set;default = Color.WHITE;}
public Color error_background { get;set;default = Color.RED;}
public Gee.ArrayList<Frame> frames {
get {
return _frames;
}
}
public Stacktrace (GLib.ProcessSignal sig = GLib.ProcessSignal.TTOU) {
this.sig = sig;
error_background = default_error_background;
highlight_color = default_highlight_color;
//hide_installed_libraries = true;
create_stacktrace ();
}
private string get_module_name () {
var path = new char[1024];
Posix.readlink ("/proc/self/exe", path);
string result = (string) path;
return result;
}
// TODO CARL convert this piece of code to vala conventions
public static string get_relative_path (string p_fullDestinationPath, string p_startPath) {
string[] l_startPathParts = p_startPath.split ("/");
string[] l_destinationPathParts = p_fullDestinationPath.split ("/");
int l_sameCounter = 0;
while ((l_sameCounter < l_startPathParts.length) &&
(l_sameCounter < l_destinationPathParts.length) &&
l_startPathParts[l_sameCounter] == l_destinationPathParts[l_sameCounter]) {
l_sameCounter++;
}
if (l_sameCounter == 0) {
return p_fullDestinationPath; // There is no relative link.
}
StringBuilder l_builder = new StringBuilder ();
for (int i = l_sameCounter ; i < l_startPathParts.length ; i++) {
l_builder.append ("../");
}
for (int i = l_sameCounter ; i < l_destinationPathParts.length ; i++) {
l_builder.append (l_destinationPathParts[i] + "/");
}
// CARL l_builder.Length--;
// Remove the last /
var result = l_builder.str;
result = result.substring (0, result.length - 1);
return result;
}
private string extract_short_file_path (string file_path) {
var path = Environment.get_current_dir ();
/*var i = file_path.index_of ( path );
if( i>=0 )
return file_path.substring ( path.length, file_path.length - path.length );
return file_path; */
var result = get_relative_path (file_path, path);
return result;
}
public bool is_custom {
get {
return sig == ProcessSignal.TTOU;
}
}
// input : '/home/cran/Documents/Projects/elementary/noise/instant-beta/build/core/libnoise-core.so.0(noise_job_repository_create_job+0x309) [0x7ff60a021e69]'
// ouput: 0x309
private int extract_base_address (string line) {
int result = 0 ;
var start = line.last_index_of ("+");
if (start >= 0) {
var end = line.last_index_of (")");
if( end > start ) {
var text = line.substring (start+3,end-start-3) ;
text.scanf("%x", &result);
}
}
return result ;
}
private void process_info_for_file (string full_line, string str ) {
func = "" ;
file_path = "";
short_file_path = "";
l = "";
file_line = "";
func_line = "";
var lines = full_line.split ("\n");
if (lines.length > 0)
func_line = lines[0];
if (lines.length > 1)
file_line = lines[1];
if (file_line == "??:0" || file_line == "??:?")
file_line = "";
func = extract_function_name (str);
file_path = "";
short_file_path = "";
l = "";
if (file_line != "") {
if (func == "")
func = extract_function_name_from_line (func_line);
file_path = extract_file_path (file_line);
short_file_path = extract_short_file_path (file_path);
l = extract_line (file_line);
}
}
string func = "" ;
string file_path = "";
string short_file_path = "";
string l = "";
string file_line = "";
string func_line = "";
private void process_info_from_lib (string file_path, string str) {
var cmd2 = "nm %s".printf(file_path) ;
var addr1_s = execute_command_sync_get_output (cmd2) ;
MatchInfo info ;
try {
Regex regex = new Regex ("\\n[^ ]* T "+func);
if( regex.match (addr1_s, 0, out info) )
{
while( info.matches() ){
var lll = info.fetch(0) ;
//stdout.printf ( "lll '%s'\n", lll ) ;
addr1_s = lll.substring(0, lll.index_of(" ")) ;
info.next();
}
}
} catch (RegexError e)
{
critical( "Error while processing regex %s", e.message ) ;
}
//stdout.printf ("addr1_s %s\n", addr1_s) ;
int addr1 = 0 ;
addr1_s.scanf("%x", &addr1);
if( addr1 != 0 ) {
int addr2 = extract_base_address (str) ;
string addr3 = "%#08x".printf (addr1+addr2);
var new_full_line = process_line (file_path, addr3);
process_info_for_file (new_full_line, str ) ;
}
}
private void create_stacktrace () {
int frame_count = 100;
int skipped_frames_count = 5;
// Stacktrace not due to a crash
if (is_custom)
skipped_frames_count = 3;
void *[] array = new void *[frame_count];
_frames.clear ();
first_vala = null;
max_file_name_length = 0;
is_all_function_name_blank = true;
is_all_file_name_blank = true;
#if VALA_0_26
var size = Linux.Backtrace.@get (array);
var strings = Linux.Backtrace.symbols (array);
#else
int size = Linux.backtrace (array, frame_count);
unowned string[] strings = Linux.backtrace_symbols (array, size);
// Needed because of some weird bug
strings.length = size;
#endif
int[] addresses = (int[])array;
string module = get_module_name ();
// First ones are the handler
for (int i = skipped_frames_count ; i < size ; i++) {
int address = addresses[i];
string str = strings[i];
var addr = extract_address (str);
var full_line = process_line (module, addr);
process_info_for_file( full_line, str) ;
if (file_line == "") {
file_path = extract_file_path_from (str);
}
if( file_path.has_suffix(".so.0")) {
process_info_from_lib (file_path, str) ;
}
//stdout.printf ("Building %d \n . addr: [%s]\n . full_line: '%s'\n . file_line: '%s'\n . func_line: '%s'\n . str : '%s'\n . func: '%s'\n . file: '%s'\n . line: '%s'\n",
//i, addr, full_line, file_line, func_line, str, func, file_path, l);
if (func != "" && file_path.has_suffix (".vala") && is_all_function_name_blank)
is_all_function_name_blank = false;
if (short_file_path != "" && is_all_file_name_blank)
is_all_file_name_blank = false;
var frame = new Frame (addr, file_line, func, file_path, short_file_path);
if (first_vala == null && file_path.has_suffix (".vala"))
first_vala = frame;
if (short_file_path.length > max_file_name_length)
max_file_name_length = short_file_path.length;
if (l.length > max_line_number_length)
max_line_number_length = l.length;
_frames.add (frame);
}
}
private string extract_function_name (string line) {
if (line == "")
return "";
var start = line.index_of ("(");
if (start >= 0) {
var end = line.index_of ("+", start);
if (end >= 0) {
var result = line.substring (start + 1, end - start - 1);
return result.strip ();
}
}
return "";
}
private string extract_function_name_from_line (string line) {
return line.strip ();
}
private string extract_file_path_from (string str) {
if (str == "")
return "";
/*if( str.index_of("??") >= 0)
//result = result.substring (4, line.length - 4 );
stdout.printf ("ERR2?? : %s\n", str ) ; */
var start = str.index_of ("(");
if (start >= 0) {
return str.substring (0, start).strip ();
}
return str.strip ();
}
private string extract_file_path (string line) {
var result = line;
if (result == "")
return "";
if (result == "??:0??:0")
return "";
// For some reason, the file name can starts with ??:0
if (result.has_prefix ("??:0"))
result = result.substring (4, line.length - 4);
// stdout.printf ("ERR1?? : %s\n", line ) ;
var start = result.index_of (":");
if (start >= 0) {
result = result.substring (0, start);
return result.strip ();
}
return "";
}
public static string extract_line (string line) {
var result = line;
if (result == "")
return "";
if (result.has_prefix ("??:0"))
result = result.substring (4, line.length - 4);
var start = result.index_of (":");
if (start >= 0) {
result = result.substring (start + 1, line.length - start - 1);
var end = result.index_of ("(");
if (end >= 0) {
result = result.substring (0, end);
}
return result.strip ();
}
return "";
}
private string extract_address (string line) {
if (line == "")
return "";
var start = line.index_of ("[");
if (start >= 0) {
var end = line.index_of ("]", start);
if (end >= 0) {
var result = line.substring (start + 1, end - start - 1);
return result.strip ();
}
}
return "";
}
private string execute_command_sync_get_output (string cmd) {
try {
int exitCode;
string std_out;
string std_err;
Process.spawn_command_line_sync (cmd, out std_out, out std_err, out exitCode);
return std_out;
}
catch (Error e) {
warning (@"Error while executing '$cmd': $(e.message)");
return "";
}
}
// Poor's man demangler. libunwind is another dep
// TODO : Optimize this
// module : app
// address : 0x007f80
// output : /home/cran/Projects/noise/noise-perf-instant-search/tests/errors.vala:87
string process_line (string module, string address) {
var cmd = "addr2line -f -e %s %s".printf (module, address);
var result = execute_command_sync_get_output (cmd);
//stdout.printf( "CMD %s\n", cmd) ;
return result;
}
private string get_reset_code () {
// return get_color_code (Style.RESET, Colors.WHITE, Colors.BLACK);
return "\x1b[0m";
}
private string get_reset_style () {
return get_color_code (Style.DIM, highlight_color, background_color);
}
private string get_color_code (Style attr, Color fg, Color bg = background_color) {
/* Command is the control command to the terminal */
if (bg == Color.BLACK)
return "%c[%d;%dm".printf (0x1B, (int) attr, (int) fg + 30);
else
return "%c[%d;%d;%dm".printf (0x1B, (int) attr, (int) fg + 30, (int) bg + 40);
}
private string get_signal_name () {
return sig.to_string ();
}
private string get_highlight_code () {
return get_color_code (Style.BRIGHT, highlight_color);
}
private string get_printable_function (Frame frame, int padding = 0) {
var result = "";
var is_unknown = false;
if (frame.function == "") {
result = "<unknown> " + frame.address;
is_unknown = true;
} else {
var s = "";
int count = padding - get_signal_name ().length;
if (padding != 0 && count > 0)
s = string.nfill (count, ' ');
result = "'" + frame.function + "'" + s;
}
if (is_unknown)
return result + get_reset_code ();
else
return get_highlight_code () + result + get_reset_code ();
}
private string get_printable_line_number (Frame frame, bool pad = true) {
var path = frame.line_number;
var result = "";
var color = get_highlight_code ();
if (path.length >= max_line_number_length || !pad)
result = color + path + get_reset_style ();
else {
result = color + path + get_reset_style ();
result = string.nfill (max_line_number_length - path.length, ' ') + result;
}
return result;
}
private string get_printable_file_short_path (Frame frame, bool pad = true) {
var path = frame.file_short_path;
var result = "";
var color = get_highlight_code ();
if (path.length >= max_file_name_length || !pad)
result = color + path + get_reset_style ();
else {
result = color + path + get_reset_style ();
result = result + string.nfill (max_file_name_length - path.length, ' ');
}
return result;
}
Color background_color = Color.BLACK;
int title_length = 0;
private string get_printable_title () {
var c = get_color_code (Style.DIM, highlight_color, background_color);
var color = get_highlight_code ();
var result = "" ;
if( is_custom)
result = "%sA function was called in %s".printf (
c,
get_reset_style ());
else
result = "%sAn error occured %s(%s)%s".printf (
c,
color,
get_signal_name (),
get_reset_style ());
title_length = get_signal_name ().length;
return result;
}
private string get_reason () {
// var c = get_reset_code();
var color = get_highlight_code ();
if (sig == ProcessSignal.TRAP) {
return "The reason is likely %san uncaught error%s".printf (
color, get_reset_code ());
}
if (sig == ProcessSignal.ABRT) {
return "The reason is likely %sa failed assertion (assert...)%s".printf (
color, get_reset_code ());
}
if (sig == ProcessSignal.SEGV) {
return "The reason is likely %sa null reference being used%s".printf (
color, get_reset_code ());
}
return "Unknown reason";
}
public void print () {
stdout.printf ("\n");
background_color = error_background;
var header = "%s%s\n".printf (get_printable_title (),
get_reset_code ());
if (first_vala != null) {
header = "%s in %s, line %s in %s\n".printf (
get_printable_title (),
get_printable_file_short_path (first_vala, false),
get_printable_line_number (first_vala, false),
get_printable_function (first_vala) + get_reset_code ());
title_length += first_vala.line_number.length +
first_vala.function.length +
first_vala.file_short_path.length;
}
stdout.printf (header);
background_color = Color.BLACK;
if( !is_custom) {
var reason = get_reason ();
stdout.printf ("%s\n", reason);
}
// Has the user forgot to compile with -g -X -rdynamic flag ?
if (is_all_file_name_blank) {
//var advice = " %sNote%s: no file path and line numbers can be retrieved. Are you sure %syou added -g -X -rdynamic%s to valac command line?\n";
var advice = "%sNote%s: no vala function name can be retrieved.";
var color = get_highlight_code ();
stdout.printf (advice, color, get_reset_code (), color, get_reset_code ());
}
// Has the user forgot to compile with rdynamic flag ?
if (is_all_function_name_blank && !is_all_file_name_blank) {
var advice = "%sNote%s: no vala function name can be retrieved.";
//var advice = " %sNote%s: no vala function name can be retrieved. Are you sure %syou added -X -rdynamic%s to valac command line?\n";
var color = get_highlight_code ();
stdout.printf (advice, color, get_reset_code (), color, get_reset_code ());
}
stdout.printf ("\n");
int i = 1;
bool has_displayed_first_vala = false;
foreach (var frame in _frames) {
var show_frame = frame.function != "" || frame.file_path.has_suffix (".vala") || frame.file_path.has_suffix (".c");
if (hide_installed_libraries && has_displayed_first_vala)
show_frame = show_frame && frame.file_short_path != "";
// Ignore glib tracing code if displayed before the first vala frame
if ((frame.function == "g_logv" || frame.function == "g_log") && !has_displayed_first_vala)
show_frame = false;
if (show_frame) {
// #2 ./OtherModule.c line 80 in 'other_module_do_it'
// at /home/cran/Projects/noise/noise-perf-instant-search/tests/errors/module/OtherModule.vala:10
var str = " %s #%d %s line %s in %s\n";
background_color = Color.BLACK;
var lead = " ";
var function_padding = 0;
if (frame == first_vala) {
has_displayed_first_vala = true;
lead = "*";
background_color = error_background;
function_padding = 22;
}
var l_number = "";
if (frame.line_number == "") {
str = " %s #%d <unknown> %s in %s\n";
var func_name = get_printable_function (frame);
var fill_len = int.max (max_file_name_length + max_line_number_length - 1, 0);
str = str.printf (
lead,
i,
string.nfill (fill_len, ' '),
func_name);
} else {
str = str.printf (
lead,
i,
get_printable_file_short_path (frame),
get_printable_line_number (frame),
get_printable_function (frame, function_padding));
l_number = ":" + frame.line_number;
}
stdout.printf (str);
str = " at %s%s\n".printf (
frame.file_path, l_number);
stdout.printf (str);
i++;
}
}
}
public static void register_handlers () {
Process.@signal (ProcessSignal.SEGV, handler);
Process.@signal (ProcessSignal.ABRT, handler);
Process.@signal (ProcessSignal.TRAP, handler);
}
public static CriticalHandler critical_handling { get;set;default = CriticalHandler.PRINT_STACKTRACE;}
public static void handler (int sig) {
Stacktrace stack = new Stacktrace ((ProcessSignal) sig);
stack.print ();
if (sig != ProcessSignal.TRAP ||
(sig == ProcessSignal.TRAP && critical_handling == CriticalHandler.CRASH))
Process.exit (1);
}
}

View File

@ -107,7 +107,6 @@ public class Tootle.Views.Notifications : Views.Base, IAccountListener, IStreamL
}
public override bool accepts (ref string event) {
warning (event);
return true;
}