Update upload-coredump.py

This commit is contained in:
drindhauser
2020-01-09 11:00:17 +01:00
parent a2da0d0d47
commit 97be19c6eb

View File

@ -11,12 +11,18 @@ import time
class Frame:
def __init__(
self, instruction_addr="", name_of_function="", path="abs_path", lineno=None,
self,
instruction_addr=None,
function=None,
filename="abs_path",
lineno=None,
package=None,
):
self.instruction_addr = instruction_addr
self.name_of_function = name_of_function
self.path = path
self.function = function
self.filename = filename
self.lineno = lineno
self.package = package
def to_json(self):
return self.__dict__
@ -43,37 +49,64 @@ class Image:
return self.__dict__
class Stacktrace_for_thread:
def __init__(self):
self.frames = []
def append_frame(self, frame=None):
self.frames.append(frame)
def reverse_list(self):
self.frames.reverse()
def to_json(self):
return self.__dict__
class Thread:
def __init__(self, id="", name=None, crashed=None, frames=None):
self.stacktrace = {}
self.id = id
self.name = name
self.crashed = crashed
self.stacktrace = frames
def to_json(self):
return self.__dict__
_frame_re = re.compile(
r"""(?x)
r"""(?xim)
^
# frame number
\#\d+\s+
# instruction address (missing for first frame)
(?:
(?P<instruction_addr>0x[0-9a-f]+)
\sin\s
)?
# function name (?? if unknown)
(?P<function>.*)
\s
# arguments, ignored
\([^)]*\)
#address of instruction
(?P<instruction_addr>
0[xX][a-fA-F0-9]+
)
#name of function
(\sin)?
\s?
(.*::)?
(?P<name_of_function>
[a-zA-z]+
\s*
(?:
# package name, without debug info
from\s
(?P<package>[^ ]+)
|
# file name and line number
at\s
(?P<filename>[^ ]+)
:
(?P<lineno>\d+)
)?
#path from the file
(\s\(.*\))? (\sat\s)?
(?P<path>
.*\.c
)?
#Number of the line
:?
(?P<lineno>
[0-9]+
)*
"""
$
"""
)
_image_re = re.compile(
r"""(?x)
@ -108,7 +141,7 @@ _image_re = re.compile(
(?P<code_file>
[\/|\/][\w|\S]+|\S+\.\S+|[a-zA-Z]*
)?
"""
"""
)
@ -121,22 +154,21 @@ def error(message):
sys.exit(1)
def get_frame(gdb_output):
"""Parses the output from gdb """
def get_frame(temp):
""" """
frame = Frame()
temp = _frame_re.search(gdb_output)
if temp is None:
return
frame.instruction_addr = temp.group("instruction_addr")
frame.name_of_function = temp.group("name_of_function")
frame.function = temp.group("function")
if temp.group("lineno") is not None:
frame.lineno = int(temp.group("lineno"))
if temp.group("path") is not None:
frame.path = temp.group("path")
if temp.group("filename") is not None:
frame.filename = temp.group("filename")
if temp.group("package") is not None:
frame.package = temp.group("package")
return frame
@ -157,14 +189,82 @@ def get_image(image_string):
)
def get_all_threads(path_to_core, path_to_executable, gdb_path):
thread_list = []
counter_threads = 0
# execute gdb
if gdb_path is None:
process = subprocess.Popen(
["gdb", "-c", path_to_core, path_to_executable],
stdout=subprocess.PIPE,
stdin=subprocess.PIPE,
)
else:
try:
process = subprocess.Popen(
[gdb_path, "gdb", "-c", path_to_core, path_to_executable],
stdout=subprocess.PIPE,
stdin=subprocess.PIPE,
)
except OSError as err:
error(err)
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("Thread")
except:
error("gdb output error")
del gdb_output[0]
gdb_output.reverse()
for thread_backtrace in gdb_output:
stacktrace = Stacktrace_for_thread()
# gets the Thread ID
thread_id = re.search(r"(?x)LWP\s(?P<thread_id>[a-fA-F0-9]+)", thread_backtrace)
# gets each frame from the Thread
for match in re.finditer(_frame_re, thread_backtrace):
frame = get_frame(match)
if frame is not None:
stacktrace.append_frame(frame.to_json())
stacktrace.reverse_list()
if counter_threads == 0:
crashed = True
else:
crashed = False
# appends a Thread to the thread_list
thread_list.append(
Thread(thread_id.group("thread_id"), None, crashed, stacktrace.to_json())
)
counter_threads += 1
print("Threads found: " + str(counter_threads))
return thread_list
@click.command()
@click.argument("path_to_core")
@click.argument("path_to_executable")
@click.option("--sentry-dsn", required=False)
@click.option("--gdb-path", required=False)
@click.option("--elfutils-path", required=False)
def main(path_to_core, path_to_executable, sentry_dsn, gdb_path, elfutils_path):
@click.option("--all-threads", is_flag=True)
def main(
path_to_core, path_to_executable, sentry_dsn, gdb_path, elfutils_path, all_threads
):
# Validate input Path
if os.path.isfile(path_to_core) is not True:
error("Wrong path to coredump")
@ -181,9 +281,6 @@ def main(path_to_core, path_to_executable, sentry_dsn, gdb_path, elfutils_path):
image_list = []
frame_list = []
gdb_output = []
eu_unstrip_output = []
# execute gdb
if gdb_path is None:
process = subprocess.Popen(
@ -201,12 +298,21 @@ def main(path_to_core, path_to_executable, sentry_dsn, gdb_path, elfutils_path):
except OSError as err:
error(format(err))
output = re.search(r"#0.*", str(process.communicate(input="bt")))
try:
gdb_output = output.group().split("#")
except:
output, errors = process.communicate(input="bt")
if errors:
error(errors)
gdb_output = output.decode("utf-8")
if not "#0" in gdb_output:
error("gdb output error")
try:
type_of_event = re.search(
r"terminated with signal (?P<type>.*),", gdb_output
).group("type")
except:
type_of_event = "Core"
# execute eu-unstrip
if elfutils_path is None:
process = subprocess.Popen(
@ -234,8 +340,8 @@ def main(path_to_core, path_to_executable, sentry_dsn, gdb_path, elfutils_path):
eu_unstrip_output = str(output[0]).split("\n")
for x in range(1, len(gdb_output)):
frame = get_frame(gdb_output[x])
for match in re.finditer(_frame_re, gdb_output):
frame = get_frame(match)
if frame is not None:
frame_list.append(frame)
@ -244,20 +350,36 @@ def main(path_to_core, path_to_executable, sentry_dsn, gdb_path, elfutils_path):
if image is not None:
image_list.append(image)
frame_list.reverse()
type_of_event = "Core"
# build the json for sentry
data = {
"platform": "native",
"exception": {
"type": "Core",
"handled": "false",
"stacktrace": {"frames": [ob.to_json() for ob in frame_list]},
},
"debug_meta": {"images": [ob.to_json() for ob in image_list]},
}
if all_threads:
thread_list = get_all_threads(path_to_core, path_to_executable, gdb_path)
data = {
"platform": "native",
"exception": {
"type": type_of_event,
"mechanism": {"type": "coredump", "handled": False, "synthetic": True},
"stacktrace": {"frames": [ob.to_json() for ob in frame_list]},
},
"debug_meta": {"images": [ob.to_json() for ob in image_list]},
"threads": {"values": [ob.to_json() for ob in thread_list]},
}
else:
data = {
"platform": "native",
"exception": {
"type": type_of_event,
"mechanism": {"type": "coredump", "handled": False, "synthetic": True},
"stacktrace": {"frames": [ob.to_json() for ob in frame_list]},
},
"debug_meta": {"images": [ob.to_json() for ob in image_list]},
}
sentry_sdk.init(sentry_dsn)
sentry_sdk.capture_event(data)
print("Core dump sent to sentry!")
event_id = sentry_sdk.capture_event(data)
print("Core dump sent to sentry: %s" % (event_id,))
if __name__ == "__main__":