forked from getsentry/coredump-uploader
Bugfixes
This commit is contained in:
@ -7,6 +7,7 @@ import sys
|
|||||||
import os
|
import os
|
||||||
import click
|
import click
|
||||||
import time
|
import time
|
||||||
|
import datetime
|
||||||
import signal
|
import signal
|
||||||
|
|
||||||
|
|
||||||
@ -53,19 +54,28 @@ class Image:
|
|||||||
class Stacktrace:
|
class Stacktrace:
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.frames = []
|
self.frames = []
|
||||||
|
self.registers = {}
|
||||||
|
|
||||||
def append_frame(self, frame=None):
|
def append_frame(self, frame=None):
|
||||||
self.frames.append(frame)
|
self.frames.append(frame)
|
||||||
|
|
||||||
|
def ad_register(self, name, value):
|
||||||
|
self.registers[name] = value
|
||||||
|
|
||||||
def reverse_list(self):
|
def reverse_list(self):
|
||||||
self.frames.reverse()
|
self.frames.reverse()
|
||||||
|
|
||||||
def to_json(self):
|
def to_json(self):
|
||||||
|
for i, frame in enumerate(self.frames):
|
||||||
|
try:
|
||||||
|
self.frames[i] = frame.to_json()
|
||||||
|
except:
|
||||||
|
continue
|
||||||
return self.__dict__
|
return self.__dict__
|
||||||
|
|
||||||
|
|
||||||
class Thread:
|
class Thread:
|
||||||
def __init__(self, id="", name=None, crashed=None, stacktrace=None):
|
def __init__(self, id="", name=None, crashed=False, stacktrace=None):
|
||||||
self.id = id
|
self.id = id
|
||||||
self.name = name
|
self.name = name
|
||||||
self.crashed = crashed
|
self.crashed = crashed
|
||||||
@ -75,6 +85,8 @@ class Thread:
|
|||||||
return self.stacktrace
|
return self.stacktrace
|
||||||
|
|
||||||
def to_json(self):
|
def to_json(self):
|
||||||
|
if self.stacktrace is not None:
|
||||||
|
self.stacktrace = self.stacktrace.to_json()
|
||||||
return self.__dict__
|
return self.__dict__
|
||||||
|
|
||||||
|
|
||||||
@ -159,6 +171,17 @@ _register_re = re.compile(
|
|||||||
"""
|
"""
|
||||||
)
|
)
|
||||||
|
|
||||||
|
_thread_id_re = re.compile(
|
||||||
|
r"(?i)(?P<thread_id>\d+) (\(thread 0x[0-9a-f]+ )?\((?P<thread_name>.*?)\)\)?"
|
||||||
|
)
|
||||||
|
|
||||||
|
_exit_signal_re = re.compile(r"(?i)terminated with signal (?P<type>[a-z0-9]+),")
|
||||||
|
|
||||||
|
_thread_re = re.compile(
|
||||||
|
r"(?x)^Thread .*? (\n\n|.\(gdb\)\squit)", flags=re.DOTALL | re.MULTILINE
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
def code_id_to_debug_id(code_id):
|
def code_id_to_debug_id(code_id):
|
||||||
return str(uuid.UUID(bytes_le=binascii.unhexlify(code_id)[:16]))
|
return str(uuid.UUID(bytes_le=binascii.unhexlify(code_id)[:16]))
|
||||||
|
|
||||||
@ -204,8 +227,8 @@ def get_image(temp):
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def execute_gdb(gdb_path, path_to_core, path_to_executable):
|
def execute_gdb(gdb_path, path_to_core, path_to_executable, gdb_command):
|
||||||
"""creates a subprocess for gdb and returns it"""
|
"""creates a subprocess for gdb and returns the output from gdb"""
|
||||||
|
|
||||||
if gdb_path is None:
|
if gdb_path is None:
|
||||||
process = subprocess.Popen(
|
process = subprocess.Popen(
|
||||||
@ -223,73 +246,62 @@ def execute_gdb(gdb_path, path_to_core, path_to_executable):
|
|||||||
except OSError as err:
|
except OSError as err:
|
||||||
error(err)
|
error(err)
|
||||||
|
|
||||||
return process
|
output, errors = process.communicate(input=gdb_command)
|
||||||
|
if errors:
|
||||||
|
error(errors)
|
||||||
|
|
||||||
|
output.decode("utf-8")
|
||||||
|
|
||||||
|
return output
|
||||||
|
|
||||||
|
|
||||||
def get_all_threads(process):
|
def get_all_threads(gdb_output):
|
||||||
"""Returns a list with all threads and backtraces"""
|
"""Returns a list with all threads and backtraces"""
|
||||||
|
|
||||||
thread_list = []
|
thread_list = []
|
||||||
counter_threads = 0
|
counter_threads = 0
|
||||||
|
|
||||||
output, errors = process.communicate(input="thread apply all bt")
|
|
||||||
if errors:
|
|
||||||
error(errors)
|
|
||||||
|
|
||||||
gdb_output = output.decode("utf-8")
|
|
||||||
|
|
||||||
# splits gdb output to get each Thread
|
|
||||||
try:
|
|
||||||
gdb_output = output.split("\n\nThread ")
|
|
||||||
except:
|
|
||||||
error("gdb output error")
|
|
||||||
|
|
||||||
crashed_thread_id = re.search(
|
crashed_thread_id = re.search(
|
||||||
r"(?i)current thread is (?P<thread_id>\d+)",
|
r"(?i)current thread is (?P<thread_id>\d+)", gdb_output,
|
||||||
gdb_output[0],
|
|
||||||
)
|
)
|
||||||
if crashed_thread_id:
|
if crashed_thread_id:
|
||||||
crashed_thread_id = crashed_thread_id.group("thread_id")
|
crashed_thread_id = crashed_thread_id.group("thread_id")
|
||||||
|
|
||||||
# Get the exit Signal from the gdb-output
|
# Get the exit Signal from the gdb-output
|
||||||
try:
|
exit_signal = re.search(_exit_signal_re, gdb_output)
|
||||||
exit_signal = re.search(
|
if exit_signal:
|
||||||
r"(?i)terminated with signal (?P<type>[a-z0-9]+),", gdb_output[0]
|
exit_signal = exit_signal.group("type")
|
||||||
).group("type")
|
else:
|
||||||
except:
|
|
||||||
exit_signal = "Core"
|
exit_signal = "Core"
|
||||||
|
|
||||||
del gdb_output[0]
|
# Searches for threads in gdb_output
|
||||||
gdb_output.reverse()
|
for temp in re.finditer(_thread_re, gdb_output):
|
||||||
|
thread_backtrace = str(temp.group())
|
||||||
for thread_backtrace in gdb_output:
|
|
||||||
stacktrace = Stacktrace()
|
stacktrace = Stacktrace()
|
||||||
|
|
||||||
# gets the Thread ID
|
# Gets the Thread ID
|
||||||
thread_id = re.match(r"(?i)(?P<thread_id>\d+) \(thread 0x[0-9a-f]+ \((?P<thread_name>.*)\)\)", thread_backtrace)
|
thread_id = re.search(_thread_id_re, thread_backtrace,)
|
||||||
if thread_id is None:
|
if thread_id is None:
|
||||||
continue
|
continue
|
||||||
else:
|
else:
|
||||||
thread_name = thread_id.group("thread_name")
|
thread_name = thread_id.group("thread_name")
|
||||||
print("name: %s" % thread_name)
|
|
||||||
thread_id = thread_id.group("thread_id")
|
thread_id = thread_id.group("thread_id")
|
||||||
|
|
||||||
# gets each frame from the Thread
|
# Gets each frame from the Thread
|
||||||
for match in re.finditer(_frame_re, thread_backtrace):
|
for match in re.finditer(_frame_re, thread_backtrace):
|
||||||
frame = get_frame(match)
|
frame = get_frame(match)
|
||||||
if frame is not None:
|
if frame is not None:
|
||||||
stacktrace.append_frame(frame.to_json())
|
stacktrace.append_frame(frame)
|
||||||
|
|
||||||
stacktrace.reverse_list()
|
stacktrace.reverse_list()
|
||||||
|
|
||||||
crashed = thread_id == crashed_thread_id
|
crashed = thread_id == crashed_thread_id
|
||||||
|
|
||||||
# appends a Thread to the thread_list
|
# Appends a Thread to the thread_list
|
||||||
thread_list.append(
|
thread_list.append(Thread(thread_id, thread_name, crashed, stacktrace))
|
||||||
Thread(thread_id, thread_name, crashed, stacktrace.to_json())
|
|
||||||
)
|
|
||||||
counter_threads += 1
|
counter_threads += 1
|
||||||
|
|
||||||
|
thread_list.reverse()
|
||||||
print("Threads found: " + str(counter_threads))
|
print("Threads found: " + str(counter_threads))
|
||||||
return thread_list, exit_signal
|
return thread_list, exit_signal
|
||||||
|
|
||||||
@ -319,39 +331,50 @@ def main(
|
|||||||
if elfutils_path is not None and os.path.exists(elfutils_path) is not True:
|
if elfutils_path is not None and os.path.exists(elfutils_path) is not True:
|
||||||
error("Wrong path for elfutils")
|
error("Wrong path for elfutils")
|
||||||
|
|
||||||
# execute gdb
|
|
||||||
process = execute_gdb(gdb_path, path_to_core, path_to_executable)
|
|
||||||
|
|
||||||
if all_threads:
|
if all_threads:
|
||||||
thread_list, exit_signal = get_all_threads(process)
|
gdb_output = execute_gdb(
|
||||||
|
gdb_path, path_to_core, path_to_executable, "thread apply all bt"
|
||||||
|
)
|
||||||
|
thread_list, exit_signal = get_all_threads(gdb_output)
|
||||||
|
|
||||||
else:
|
else:
|
||||||
stacktrace = Stacktrace()
|
stacktrace = Stacktrace()
|
||||||
|
|
||||||
output, errors = process.communicate(input="bt")
|
gdb_output = execute_gdb(gdb_path, path_to_core, path_to_executable, "bt")
|
||||||
if errors:
|
|
||||||
error(errors)
|
|
||||||
|
|
||||||
gdb_output = output.decode("utf-8")
|
|
||||||
if not "#0" in gdb_output:
|
if not "#0" in gdb_output:
|
||||||
error("gdb output error")
|
error("gdb output error")
|
||||||
|
|
||||||
# Get the exit Signal from the gdb-output
|
# Get the exit Signal from the gdb-output
|
||||||
try:
|
exit_signal = re.search(_exit_signal_re, gdb_output)
|
||||||
exit_signal = re.search(
|
if exit_signal:
|
||||||
r"(?i)terminated with signal (?P<type>[a-z0-9]+),", gdb_output
|
exit_signal = exit_signal.group("type")
|
||||||
).group("type")
|
else:
|
||||||
except:
|
|
||||||
exit_signal = "Core"
|
exit_signal = "Core"
|
||||||
|
|
||||||
# Searches for frames in the GDB-Output
|
# Searches for frames in the GDB-Output
|
||||||
for match in re.finditer(_frame_re, gdb_output):
|
for match in re.finditer(_frame_re, gdb_output):
|
||||||
frame = get_frame(match)
|
frame = get_frame(match)
|
||||||
if frame is not None:
|
if frame is not None:
|
||||||
stacktrace.append_frame(frame.to_json())
|
stacktrace.append_frame(frame)
|
||||||
|
|
||||||
stacktrace.reverse_list()
|
stacktrace.reverse_list()
|
||||||
|
|
||||||
|
# Get registers from gdb
|
||||||
|
gdb_output = execute_gdb(
|
||||||
|
gdb_path, path_to_core, path_to_executable, "info registers"
|
||||||
|
)
|
||||||
|
|
||||||
|
for match in re.finditer(_register_re, gdb_output):
|
||||||
|
if match is not None:
|
||||||
|
if all_threads:
|
||||||
|
thread_list[0].stacktrace.ad_register(
|
||||||
|
match.group("register_name"), match.group("register_value")
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
stacktrace.ad_register(
|
||||||
|
match.group("register_name"), match.group("register_value")
|
||||||
|
)
|
||||||
|
|
||||||
image_list = []
|
image_list = []
|
||||||
|
|
||||||
# execute eu-unstrip
|
# execute eu-unstrip
|
||||||
@ -396,38 +419,69 @@ def main(
|
|||||||
except AttributeError:
|
except AttributeError:
|
||||||
timestamp = stat.st_mtime
|
timestamp = stat.st_mtime
|
||||||
|
|
||||||
# build the json for sentry
|
# Get signal Number from signal name
|
||||||
|
try:
|
||||||
|
temp = str(
|
||||||
|
"-l" + re.match(r"SIG(?P<exit_signal>.*)", exit_signal).group("exit_signal")
|
||||||
|
)
|
||||||
|
exit_signal_number = subprocess.check_output(["kill", temp])
|
||||||
|
except err:
|
||||||
|
exit_signal_number = None
|
||||||
|
|
||||||
|
# Make the image_list to json
|
||||||
|
for i, image in enumerate(image_list):
|
||||||
|
try:
|
||||||
|
image_list[i] = image.to_json()
|
||||||
|
except:
|
||||||
|
continue
|
||||||
|
|
||||||
|
# Gets the stacktrace from the thread_list
|
||||||
if all_threads:
|
if all_threads:
|
||||||
|
stacktrace = None
|
||||||
for temp in thread_list:
|
for temp in thread_list:
|
||||||
if temp.crashed:
|
if temp.crashed:
|
||||||
stacktrace = temp.get_stacktrace()
|
stacktrace = temp.get_stacktrace()
|
||||||
break
|
break
|
||||||
|
|
||||||
data = {
|
if stacktrace is None:
|
||||||
"platform": "native",
|
stacktrace = thread_list[0].get_stacktrace()
|
||||||
"exception": {
|
thread_list[0].crashed = True
|
||||||
"type": "Crash",
|
|
||||||
"mechanism": {"type": "coredump", "handled": False, "synthetic": True},
|
for i, thread in enumerate(thread_list):
|
||||||
"stacktrace": stacktrace,
|
try:
|
||||||
},
|
thread_list[i] = thread.to_json()
|
||||||
"debug_meta": {"images": [ob.to_json() for ob in image_list]},
|
except:
|
||||||
"threads": {"values": [ob.to_json() for ob in thread_list]},
|
continue
|
||||||
}
|
|
||||||
else:
|
else:
|
||||||
data = {
|
thread_list = None
|
||||||
"platform": "native",
|
|
||||||
"exception": {
|
# Build the json for sentry
|
||||||
"type": "Crash",
|
sdk_name = "coredump.uploader.sdk"
|
||||||
"mechanism": {
|
sdk_version = "0.0.1"
|
||||||
"type": "coredump",
|
|
||||||
"handled": False,
|
data = {
|
||||||
"synthetic": True,
|
"timestamp": timestamp,
|
||||||
"signal": {"number": None, "code": None, "name": exit_signal,},
|
"platform": "native",
|
||||||
|
"exception": {
|
||||||
|
"type": "Crash",
|
||||||
|
"mechanism": {
|
||||||
|
"type": "coredump",
|
||||||
|
"handled": False,
|
||||||
|
"synthetic": True,
|
||||||
|
"meta": {
|
||||||
|
"signal": {
|
||||||
|
"number": int(exit_signal_number),
|
||||||
|
"code": None,
|
||||||
|
"name": exit_signal,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
"stacktrace": stacktrace.to_json(),
|
|
||||||
},
|
},
|
||||||
"debug_meta": {"images": [ob.to_json() for ob in image_list]},
|
"stacktrace": stacktrace.to_json(),
|
||||||
}
|
},
|
||||||
|
"debug_meta": {"images": image_list},
|
||||||
|
"threads": {"values": thread_list},
|
||||||
|
"sdk": {"name": sdk_name, "version": sdk_version,},
|
||||||
|
}
|
||||||
|
|
||||||
sentry_sdk.init(sentry_dsn)
|
sentry_sdk.init(sentry_dsn)
|
||||||
event_id = sentry_sdk.capture_event(data)
|
event_id = sentry_sdk.capture_event(data)
|
||||||
|
Reference in New Issue
Block a user