forked from getsentry/coredump-uploader
Bugfixes
This commit is contained in:
@ -42,6 +42,7 @@ class Image:
|
|||||||
debug_id="",
|
debug_id="",
|
||||||
code_id="",
|
code_id="",
|
||||||
code_file="",
|
code_file="",
|
||||||
|
arch="",
|
||||||
):
|
):
|
||||||
self.type = type
|
self.type = type
|
||||||
self.image_addr = image_addr
|
self.image_addr = image_addr
|
||||||
@ -49,6 +50,7 @@ class Image:
|
|||||||
self.debug_id = debug_id
|
self.debug_id = debug_id
|
||||||
self.code_id = code_id
|
self.code_id = code_id
|
||||||
self.code_file = code_file
|
self.code_file = code_file
|
||||||
|
self.arch = arch
|
||||||
|
|
||||||
def to_json(self):
|
def to_json(self):
|
||||||
return self.__dict__
|
return self.__dict__
|
||||||
@ -235,7 +237,7 @@ def get_image(temp):
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def get_threads(gdb_output, all_threads):
|
def get_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
|
||||||
@ -282,13 +284,30 @@ def get_threads(gdb_output, all_threads):
|
|||||||
counter_threads += 1
|
counter_threads += 1
|
||||||
|
|
||||||
thread_list.reverse()
|
thread_list.reverse()
|
||||||
if not all_threads and len(thread_list) > 1:
|
print("Threads found: " + str(counter_threads))
|
||||||
del thread_list[1:]
|
|
||||||
if all_threads:
|
|
||||||
print("Threads found: " + str(counter_threads))
|
|
||||||
return thread_list, exit_signal, stacktrace_temp, crashed_thread_id
|
return thread_list, exit_signal, stacktrace_temp, crashed_thread_id
|
||||||
|
|
||||||
|
|
||||||
|
def get_stacktrace(gdb_output):
|
||||||
|
"""Returns the stacktrace and the exit signal """
|
||||||
|
if not "#0" in gdb_output:
|
||||||
|
error("gdb output error")
|
||||||
|
stacktrace = Stacktrace()
|
||||||
|
# Get the exit Signal from the gdb-output
|
||||||
|
exit_signal = re.search(_exit_signal_re, gdb_output)
|
||||||
|
if exit_signal:
|
||||||
|
exit_signal = exit_signal.group("type")
|
||||||
|
else:
|
||||||
|
exit_signal = "Core"
|
||||||
|
# Searches for frames in the GDB-Output
|
||||||
|
for match in re.finditer(_frame_re, gdb_output):
|
||||||
|
frame = get_frame(match)
|
||||||
|
if frame is not None:
|
||||||
|
stacktrace.append_frame(frame)
|
||||||
|
stacktrace.reverse_list()
|
||||||
|
return stacktrace, exit_signal
|
||||||
|
|
||||||
|
|
||||||
def error(message):
|
def error(message):
|
||||||
print("error: {}".format(message))
|
print("error: {}".format(message))
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
@ -314,7 +333,7 @@ def signal_name_to_signal_number(signal_name):
|
|||||||
exit_signal_number = subprocess.check_output(["kill", temp])
|
exit_signal_number = subprocess.check_output(["kill", temp])
|
||||||
except AttributeError:
|
except AttributeError:
|
||||||
exit_signal_number = None
|
exit_signal_number = None
|
||||||
|
|
||||||
return exit_signal_number
|
return exit_signal_number
|
||||||
|
|
||||||
|
|
||||||
@ -351,26 +370,6 @@ class CoredumpUploader(object):
|
|||||||
self.elfutils_path = elfutils_path
|
self.elfutils_path = elfutils_path
|
||||||
self.all_threads = all_threads
|
self.all_threads = all_threads
|
||||||
|
|
||||||
def get_stacktrace(self, gdb_output):
|
|
||||||
"""Returns the stacktrace and the exit signal """
|
|
||||||
if not "#0" in gdb_output:
|
|
||||||
error("gdb output error")
|
|
||||||
stacktrace = Stacktrace()
|
|
||||||
# Get the exit Signal from the gdb-output
|
|
||||||
exit_signal = re.search(_exit_signal_re, gdb_output)
|
|
||||||
if exit_signal:
|
|
||||||
exit_signal = exit_signal.group("type")
|
|
||||||
else:
|
|
||||||
exit_signal = "Core"
|
|
||||||
# Searches for frames in the GDB-Output
|
|
||||||
for match in re.finditer(_frame_re, gdb_output):
|
|
||||||
frame = get_frame(match)
|
|
||||||
if frame is not None:
|
|
||||||
stacktrace.append_frame(frame)
|
|
||||||
stacktrace.reverse_list()
|
|
||||||
|
|
||||||
return stacktrace, exit_signal
|
|
||||||
|
|
||||||
def execute_gdb(self, path_to_core, gdb_command):
|
def execute_gdb(self, path_to_core, gdb_command):
|
||||||
"""creates a subprocess for gdb and returns the output from gdb"""
|
"""creates a subprocess for gdb and returns the output from gdb"""
|
||||||
|
|
||||||
@ -413,13 +412,13 @@ class CoredumpUploader(object):
|
|||||||
return output.decode("utf-8")
|
return output.decode("utf-8")
|
||||||
|
|
||||||
def get_registers(self, path_to_core, stacktrace):
|
def get_registers(self, path_to_core, stacktrace):
|
||||||
"""Returns the stacktrace with the registers, the signal and the message."""
|
"""Returns the stacktrace with the registers, the gdb-version and the message."""
|
||||||
gdb_output = self.execute_gdb(path_to_core, "info registers")
|
gdb_output = self.execute_gdb(path_to_core, "info registers")
|
||||||
gdb_version = re.match(r"GNU gdb \(.*?\) (?P<gdb_version>.*)", gdb_output)
|
gdb_version = re.match(r"GNU gdb \(.*?\) (?P<gdb_version>.*)", gdb_output)
|
||||||
if gdb_version:
|
if gdb_version:
|
||||||
gdb_version = gdb_version.group("gdb_version")
|
gdb_version = gdb_version.group("gdb_version")
|
||||||
|
|
||||||
message = re.search(r"(?P<message>Core was generated .*\n.*) ", gdb_output)
|
message = re.search(r"(?P<message>Core was generated .*\n.*)", gdb_output)
|
||||||
if message:
|
if message:
|
||||||
message = message.group("message")
|
message = message.group("message")
|
||||||
|
|
||||||
@ -440,10 +439,16 @@ class CoredumpUploader(object):
|
|||||||
if os.path.isfile(path_to_core) is not True:
|
if os.path.isfile(path_to_core) is not True:
|
||||||
error("Wrong path to coredump")
|
error("Wrong path to coredump")
|
||||||
|
|
||||||
gdb_output = self.execute_gdb(path_to_core, "thread apply all bt")
|
if self.all_threads:
|
||||||
(thread_list, exit_signal, stacktrace, crashed_thread_id,) = get_threads(
|
gdb_output = self.execute_gdb(path_to_core, "thread apply all bt")
|
||||||
gdb_output, self.all_threads
|
(thread_list, exit_signal, stacktrace, crashed_thread_id,) = get_threads(
|
||||||
)
|
gdb_output
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
gdb_output = self.execute_gdb(path_to_core, "bt")
|
||||||
|
stacktrace, exit_signal = get_stacktrace(gdb_output)
|
||||||
|
thread_list = None
|
||||||
|
crashed_thread_id = None
|
||||||
|
|
||||||
# gets the registers, the gdb-version and the message
|
# gets the registers, the gdb-version and the message
|
||||||
stacktrace, gdb_version, message = self.get_registers(path_to_core, stacktrace)
|
stacktrace, gdb_version, message = self.get_registers(path_to_core, stacktrace)
|
||||||
@ -463,13 +468,6 @@ class CoredumpUploader(object):
|
|||||||
# Get signal Number from signal name
|
# Get signal Number from signal name
|
||||||
exit_signal_number = signal_name_to_signal_number(exit_signal)
|
exit_signal_number = signal_name_to_signal_number(exit_signal)
|
||||||
|
|
||||||
# Make the image_list and thread_list to json
|
|
||||||
for i, image in enumerate(image_list):
|
|
||||||
try:
|
|
||||||
image_list[i] = image.to_json()
|
|
||||||
except:
|
|
||||||
continue
|
|
||||||
|
|
||||||
# Get elfutils version
|
# Get elfutils version
|
||||||
process = subprocess.Popen(
|
process = subprocess.Popen(
|
||||||
[self.elfutils_path, "--version"],
|
[self.elfutils_path, "--version"],
|
||||||
@ -490,8 +488,8 @@ class CoredumpUploader(object):
|
|||||||
["uname", "-s", "-r"], stdout=subprocess.PIPE, stdin=subprocess.PIPE,
|
["uname", "-s", "-r"], stdout=subprocess.PIPE, stdin=subprocess.PIPE,
|
||||||
)
|
)
|
||||||
os_context, err = process.communicate()
|
os_context, err = process.communicate()
|
||||||
|
os_context = re.search(r"(?P<name>.*?) (?P<version>.*)", os_context)
|
||||||
if os_context:
|
if os_context:
|
||||||
os_context = re.search(r"(?P<name>.*?) (?P<version>.*)", os_context)
|
|
||||||
os_name = os_context.group("name")
|
os_name = os_context.group("name")
|
||||||
os_version = os_context.group("version")
|
os_version = os_context.group("version")
|
||||||
else:
|
else:
|
||||||
@ -502,9 +500,44 @@ class CoredumpUploader(object):
|
|||||||
)
|
)
|
||||||
os_raw_context, err = process.communicate()
|
os_raw_context, err = process.communicate()
|
||||||
|
|
||||||
|
# Get App Contex
|
||||||
|
process = subprocess.Popen(
|
||||||
|
["file", path_to_core], stdout=subprocess.PIPE, stdin=subprocess.PIPE,
|
||||||
|
)
|
||||||
|
app_context, err = process.communicate()
|
||||||
|
app_context = re.search(
|
||||||
|
r"from '.*?( (?P<args>.*))?', .* execfn: '.*\/(?P<app_name>.*?)', platform: '(?P<arch>.*?)'",
|
||||||
|
app_context,
|
||||||
|
)
|
||||||
|
if app_context:
|
||||||
|
args = app_context.group("args")
|
||||||
|
app_name = app_context.group("app_name")
|
||||||
|
arch = app_context.group("arch")
|
||||||
|
|
||||||
# Make a json from the Thread_list
|
# Make a json from the Thread_list
|
||||||
for i, thread in enumerate(thread_list):
|
if thread_list:
|
||||||
thread_list[i] = thread.to_json()
|
for i, thread in enumerate(thread_list):
|
||||||
|
thread_list[i] = thread.to_json()
|
||||||
|
|
||||||
|
# Make the image_list to json
|
||||||
|
for i, image in enumerate(image_list):
|
||||||
|
try:
|
||||||
|
if arch:
|
||||||
|
image_list[i].arch = arch
|
||||||
|
image_list[i] = image.to_json()
|
||||||
|
except:
|
||||||
|
continue
|
||||||
|
|
||||||
|
# Get value, exception from message
|
||||||
|
message = re.search(
|
||||||
|
r"(?P<message>.*)\n(?P<value>.*?, (?P<type>.*?)\.)", message
|
||||||
|
)
|
||||||
|
if message:
|
||||||
|
value_exception = message.group("value")
|
||||||
|
type_exception = message.group("type")
|
||||||
|
message = message.group("message")
|
||||||
|
if type_exception is None:
|
||||||
|
type_exception = exit_signal
|
||||||
|
|
||||||
# Build the json for sentry
|
# Build the json for sentry
|
||||||
sentry_sdk.integrations.modules.ModulesIntegration = None
|
sentry_sdk.integrations.modules.ModulesIntegration = None
|
||||||
@ -516,9 +549,10 @@ class CoredumpUploader(object):
|
|||||||
"event_id": event_id,
|
"event_id": event_id,
|
||||||
"timestamp": timestamp,
|
"timestamp": timestamp,
|
||||||
"platform": "native",
|
"platform": "native",
|
||||||
|
"message": {"message": message,},
|
||||||
"exception": {
|
"exception": {
|
||||||
"value": message,
|
"value": value_exception,
|
||||||
"type": exit_signal,
|
"type": type_exception,
|
||||||
"thread_id": crashed_thread_id,
|
"thread_id": crashed_thread_id,
|
||||||
"mechanism": {
|
"mechanism": {
|
||||||
"type": "coredump",
|
"type": "coredump",
|
||||||
@ -547,6 +581,7 @@ class CoredumpUploader(object):
|
|||||||
"raw_description": os_raw_context,
|
"raw_description": os_raw_context,
|
||||||
},
|
},
|
||||||
"runtime": None,
|
"runtime": None,
|
||||||
|
"app": {"app_name": app_name, "argv": args,},
|
||||||
},
|
},
|
||||||
"debug_meta": {"images": image_list},
|
"debug_meta": {"images": image_list},
|
||||||
"threads": {"values": thread_list},
|
"threads": {"values": thread_list},
|
||||||
@ -607,7 +642,7 @@ def watch(context, watch_dir):
|
|||||||
observer.schedule(handler, watch_dir, recursive=False)
|
observer.schedule(handler, watch_dir, recursive=False)
|
||||||
observer.start()
|
observer.start()
|
||||||
|
|
||||||
print("Watchdog started, looking for new coredumps in dir: %s" % watch_dir)
|
print("Watchdog started, looking for new coredumps in : %s" % watch_dir)
|
||||||
print("Press ctrl+c to stop\n")
|
print("Press ctrl+c to stop\n")
|
||||||
|
|
||||||
try:
|
try:
|
||||||
|
@ -12,6 +12,7 @@ from coredump_uploader import Thread
|
|||||||
from coredump_uploader import Stacktrace
|
from coredump_uploader import Stacktrace
|
||||||
from coredump_uploader import get_threads
|
from coredump_uploader import get_threads
|
||||||
from coredump_uploader import signal_name_to_signal_number
|
from coredump_uploader import signal_name_to_signal_number
|
||||||
|
from coredump_uploader import get_stacktrace
|
||||||
|
|
||||||
|
|
||||||
def test_code_id_to_debug_id():
|
def test_code_id_to_debug_id():
|
||||||
@ -168,6 +169,7 @@ def test_image_to_json():
|
|||||||
"debug_id": None,
|
"debug_id": None,
|
||||||
"code_id": "b417c0ba7cc5cf06d1d1bed6652cedb9253c60d0",
|
"code_id": "b417c0ba7cc5cf06d1d1bed6652cedb9253c60d0",
|
||||||
"code_file": "/lib/x86_64-linux-gnu/libc.so.6",
|
"code_file": "/lib/x86_64-linux-gnu/libc.so.6",
|
||||||
|
"arch": "",
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -246,9 +248,7 @@ Thread 3 (Thread 0x5846 (LWP 40)):
|
|||||||
],
|
],
|
||||||
)
|
)
|
||||||
def test_get_threads(gdb_output):
|
def test_get_threads(gdb_output):
|
||||||
thread_list, exit_signal, stacktrace, crashed_thread_id = get_threads(
|
thread_list, exit_signal, stacktrace, crashed_thread_id = get_threads(gdb_output)
|
||||||
gdb_output, True
|
|
||||||
)
|
|
||||||
assert exit_signal == "SIGSEGV"
|
assert exit_signal == "SIGSEGV"
|
||||||
assert thread_list[2].to_json() == {
|
assert thread_list[2].to_json() == {
|
||||||
"id": "1",
|
"id": "1",
|
||||||
@ -326,3 +326,45 @@ def test_get_threads(gdb_output):
|
|||||||
"registers": {},
|
"registers": {},
|
||||||
}
|
}
|
||||||
assert crashed_thread_id == "1"
|
assert crashed_thread_id == "1"
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize(
|
||||||
|
"gdb_output",
|
||||||
|
[
|
||||||
|
"""
|
||||||
|
For help, type "help".
|
||||||
|
Type "apropos word" to search for commands related to "word"...
|
||||||
|
Reading symbols from a.out...done.
|
||||||
|
[New LWP 1335]
|
||||||
|
Core was generated by `./a.out'.
|
||||||
|
Program terminated with signal SIGSEGV, Segmentation fault.
|
||||||
|
#0 0x000056416d5c760a in crashing_function () at ./test.c:3
|
||||||
|
3 *bad_pointer = 1;
|
||||||
|
(gdb) bt
|
||||||
|
#0 0x000056416d5c760a in crashing_function () at ./test.c:3
|
||||||
|
#1 0x000056416d5c761c in main () at ./test.c:7
|
||||||
|
(gdb) quit"""
|
||||||
|
],
|
||||||
|
)
|
||||||
|
def test_get_stacktrace(gdb_output):
|
||||||
|
stacktrace, exit_signal = get_stacktrace(gdb_output)
|
||||||
|
assert exit_signal == "SIGSEGV"
|
||||||
|
assert stacktrace.to_json() == {
|
||||||
|
"frames": [
|
||||||
|
{
|
||||||
|
"filename": "./test.c",
|
||||||
|
"function": "crashing_function",
|
||||||
|
"instruction_addr": "0x000056416d5c760a",
|
||||||
|
"lineno": 3,
|
||||||
|
"package": None,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"filename": "./test.c",
|
||||||
|
"function": "crashing_function",
|
||||||
|
"instruction_addr": "0x000056416d5c760a",
|
||||||
|
"lineno": 3,
|
||||||
|
"package": None,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
"registers": {},
|
||||||
|
}
|
||||||
|
Reference in New Issue
Block a user