From 0a89af236065735f88b0840b404d5cea9fe958f1 Mon Sep 17 00:00:00 2001 From: Armin Ronacher Date: Tue, 24 Nov 2020 21:23:34 +0100 Subject: [PATCH 01/12] feat(dif): Added WASM support to difs --- src/sentry/constants.py | 1 + src/sentry/models/debugfile.py | 4 +++- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/src/sentry/constants.py b/src/sentry/constants.py index 49957da6aa9f05..b1e976ba286dc6 100644 --- a/src/sentry/constants.py +++ b/src/sentry/constants.py @@ -282,6 +282,7 @@ def get_all_languages(): "application/x-elf-binary": "elf", "application/x-dosexec": "pe", "application/x-ms-pdb": "pdb", + "application/wasm": "wasm", "text/x-proguard+plain": "proguard", "application/x-sentry-bundle+zip": "sourcebundle", } diff --git a/src/sentry/models/debugfile.py b/src/sentry/models/debugfile.py index 00d3883da8e9ae..d8b4b38661748e 100644 --- a/src/sentry/models/debugfile.py +++ b/src/sentry/models/debugfile.py @@ -149,6 +149,8 @@ def file_extension(self): return ".pdb" if self.file_format == "sourcebundle": return ".src.zip" + if self.file_format == "wasm": + return ".wasm" return "" @@ -190,7 +192,7 @@ def create_dif_from_id(project, meta, fileobj=None, file=None): """ if meta.file_format == "proguard": object_name = "proguard-mapping" - elif meta.file_format in ("macho", "elf", "pdb", "pe", "sourcebundle"): + elif meta.file_format in ("macho", "elf", "pdb", "pe", "wasm", "sourcebundle"): object_name = meta.name elif meta.file_format == "breakpad": object_name = meta.name[:-4] if meta.name.endswith(".sym") else meta.name From 1c1d9d013a9f7700d404159caaa444033db5bfd2 Mon Sep 17 00:00:00 2001 From: Armin Ronacher Date: Wed, 25 Nov 2020 00:16:14 +0100 Subject: [PATCH 02/12] feat: Added in_image key to native plugin --- src/sentry/lang/native/processing.py | 23 +++++++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) diff --git a/src/sentry/lang/native/processing.py b/src/sentry/lang/native/processing.py index 9c8c15684ca93c..760e07d8bb103e 100644 --- a/src/sentry/lang/native/processing.py +++ b/src/sentry/lang/native/processing.py @@ -77,6 +77,9 @@ def _merge_frame(new_frame, symbolicated): frame_meta = new_frame.setdefault("data", {}) frame_meta["symbolicator_status"] = symbolicated["status"] + # We generally do not want to retain the ingestion only "in_image" key. + new_frame.pop("in_image", None) + def _handle_image_status(status, image, sdk_info, data): if status in ("found", "unused"): @@ -283,6 +286,19 @@ def _handles_frame(data, frame): return is_native_platform(platform) and "instruction_addr" in frame +def frame_to_symbolicator_frame(frame, modules): + rv = dict(frame) + + in_image = rv.pop("in_image", None) + if in_image: + for idx, module in enumerate(modules): + if module["debug_id"] == in_image: + rv["in_module"] = idx + break + + return rv + + def process_payload(data): project = Project.objects.get_from_cache(id=data["project"]) @@ -294,11 +310,15 @@ def process_payload(data): if any(is_native_platform(x) for x in stacktrace.platforms) ] + modules = native_images_from_data(data) + stacktraces = [ { "registers": sinfo.stacktrace.get("registers") or {}, "frames": [ - f for f in reversed(sinfo.stacktrace.get("frames") or ()) if _handles_frame(data, f) + frame_to_symbolicator_frame(f, modules) + for f in reversed(sinfo.stacktrace.get("frames") or ()) + if _handles_frame(data, f) ], } for sinfo in stacktrace_infos @@ -307,7 +327,6 @@ def process_payload(data): if not any(stacktrace["frames"] for stacktrace in stacktraces): return - modules = native_images_from_data(data) signal = signal_from_data(data) response = symbolicator.process_payload(stacktraces=stacktraces, modules=modules, signal=signal) From 5d546b96c311961f34f8c45d554b3762763264a5 Mon Sep 17 00:00:00 2001 From: Armin Ronacher Date: Wed, 25 Nov 2020 23:42:26 +0100 Subject: [PATCH 03/12] fix: Make it work with latest symbolicator --- src/sentry/lang/native/processing.py | 7 +++++-- src/sentry/lang/native/utils.py | 3 +-- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/src/sentry/lang/native/processing.py b/src/sentry/lang/native/processing.py index 760e07d8bb103e..22705c759c325b 100644 --- a/src/sentry/lang/native/processing.py +++ b/src/sentry/lang/native/processing.py @@ -77,7 +77,10 @@ def _merge_frame(new_frame, symbolicated): frame_meta = new_frame.setdefault("data", {}) frame_meta["symbolicator_status"] = symbolicated["status"] - # We generally do not want to retain the ingestion only "in_image" key. + # We generally do not want to retain the ingestion only "in_image" key. This + # means we also throw away the information if an address is relative or absolute + # even though symbolicator could tell us about this. This is acceptable for us + # at the moment. new_frame.pop("in_image", None) @@ -293,7 +296,7 @@ def frame_to_symbolicator_frame(frame, modules): if in_image: for idx, module in enumerate(modules): if module["debug_id"] == in_image: - rv["in_module"] = idx + rv["addr_base_module"] = idx break return rv diff --git a/src/sentry/lang/native/utils.py b/src/sentry/lang/native/utils.py index c7a2e074bc5b54..6886cf0c4c70d3 100644 --- a/src/sentry/lang/native/utils.py +++ b/src/sentry/lang/native/utils.py @@ -24,6 +24,7 @@ "elf", # Linux "macho", # macOS, iOS "pe", # Windows + "wasm", # WASM ) # Default disables storing crash reports. @@ -40,8 +41,6 @@ def is_native_image(image): return ( bool(image) and image.get("type") in NATIVE_IMAGE_TYPES - and image.get("image_addr") is not None - and image.get("image_size") is not None and (image.get("debug_id") or image.get("id") or image.get("uuid")) is not None ) From 9b150ff11771d063568fb4fff0a7cc4896a4b9b8 Mon Sep 17 00:00:00 2001 From: Armin Ronacher Date: Thu, 26 Nov 2020 14:41:25 +0100 Subject: [PATCH 04/12] feat: Add addr_mode support --- src/sentry/lang/native/processing.py | 33 ++++++++++++++++++---------- 1 file changed, 21 insertions(+), 12 deletions(-) diff --git a/src/sentry/lang/native/processing.py b/src/sentry/lang/native/processing.py index 22705c759c325b..d5cde55035dc5d 100644 --- a/src/sentry/lang/native/processing.py +++ b/src/sentry/lang/native/processing.py @@ -73,16 +73,12 @@ def _merge_frame(new_frame, symbolicated): new_frame["context_line"] = symbolicated["context_line"] if symbolicated.get("post_context"): new_frame["post_context"] = symbolicated["post_context"] + if symbolicated.get("addr_mode"): + new_frame["addr_mode"] = symbolicated["addr_mode"] if symbolicated.get("status"): frame_meta = new_frame.setdefault("data", {}) frame_meta["symbolicator_status"] = symbolicated["status"] - # We generally do not want to retain the ingestion only "in_image" key. This - # means we also throw away the information if an address is relative or absolute - # even though symbolicator could tell us about this. This is acceptable for us - # at the moment. - new_frame.pop("in_image", None) - def _handle_image_status(status, image, sdk_info, data): if status in ("found", "unused"): @@ -289,15 +285,28 @@ def _handles_frame(data, frame): return is_native_platform(platform) and "instruction_addr" in frame +def _expand_addr_mode(addr_mode, modules): + if addr_mode in (None, "abs"): + return "abs" + if addr_mode.startswith("rel:"): + arg = addr_mode[4:] + + for idx, module in enumerate(modules): + if module.get("debug_id") == arg: + return "rel:%d" % idx + + if arg.isdigit(): + return addr_mode + + # This is wrong but we want to set the addr mode to abs if somone + # sends a bad mode. + return "abs" + + def frame_to_symbolicator_frame(frame, modules): rv = dict(frame) - in_image = rv.pop("in_image", None) - if in_image: - for idx, module in enumerate(modules): - if module["debug_id"] == in_image: - rv["addr_base_module"] = idx - break + rv["addr_mode"] = _expand_addr_mode(rv.get("addr_mode"), modules) return rv From a62bd25013375f8361feca3551cc7f4937227674 Mon Sep 17 00:00:00 2001 From: Armin Ronacher Date: Thu, 26 Nov 2020 17:48:19 +0100 Subject: [PATCH 05/12] ref: Use implied addr_mode --- src/sentry/lang/native/processing.py | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/sentry/lang/native/processing.py b/src/sentry/lang/native/processing.py index d5cde55035dc5d..ed6c4f97ae3def 100644 --- a/src/sentry/lang/native/processing.py +++ b/src/sentry/lang/native/processing.py @@ -73,8 +73,13 @@ def _merge_frame(new_frame, symbolicated): new_frame["context_line"] = symbolicated["context_line"] if symbolicated.get("post_context"): new_frame["post_context"] = symbolicated["post_context"] - if symbolicated.get("addr_mode"): - new_frame["addr_mode"] = symbolicated["addr_mode"] + + addr_mode = symbolicated.get("addr_mode") + if addr_mode is None: + new_frame.pop("addr_mode", None) + else: + new_frame["addr_mode"] = addr_mode + if symbolicated.get("status"): frame_meta = new_frame.setdefault("data", {}) frame_meta["symbolicator_status"] = symbolicated["status"] From bfda128894270fbf91bee58b479111d15e2e7737 Mon Sep 17 00:00:00 2001 From: Armin Ronacher Date: Fri, 27 Nov 2020 12:55:24 +0100 Subject: [PATCH 06/12] feat: Make UI understand addressing modes --- scripts/ensure-venv.sh | 4 +- setup.py | 4 +- src/sentry/interfaces/stacktrace.py | 3 ++ .../interfaces/debugMeta/debugImage.tsx | 10 +++-- .../events/interfaces/debugMeta/index.tsx | 39 ++++++++++++++++--- .../events/interfaces/frame/line.tsx | 19 ++++++++- .../events/interfaces/stacktraceContent.tsx | 19 ++++++--- src/sentry/static/sentry/app/types/index.tsx | 1 + 8 files changed, 79 insertions(+), 20 deletions(-) diff --git a/scripts/ensure-venv.sh b/scripts/ensure-venv.sh index 3b4ba679deec3f..18dcef1d35a751 100755 --- a/scripts/ensure-venv.sh +++ b/scripts/ensure-venv.sh @@ -11,7 +11,7 @@ python_bin="python2.7" if [ "$SENTRY_PYTHON3" = "1" ]; then venv_name=".venv3" - python_bin="python3.6" + python_bin="python3.8" fi die() { @@ -27,7 +27,7 @@ if [ -n "$VIRTUAL_ENV" ]; then # TODO: Update this to strictly check .python-version if [ "$SENTRY_PYTHON3" = "1" ]; then - python -c "import sys; sys.exit(sys.version_info[:2] != (3, 6))" || + python -c "import sys; sys.exit(sys.version_info[:2] != (3, 8))" || die "For some reason, the virtualenv isn't Python 3.6." else python -c "import sys; sys.exit(sys.version_info[:2] != (2, 7))" || diff --git a/setup.py b/setup.py index 3aa6863c4abba5..a48c3f87974f9c 100755 --- a/setup.py +++ b/setup.py @@ -4,8 +4,8 @@ import os import sys -if os.environ.get("SENTRY_PYTHON3") == "1" and sys.version_info[:2] != (3, 6): - sys.exit("Error: Sentry [In EXPERIMENTAL python 3 mode] requires Python 3.6.") +if os.environ.get("SENTRY_PYTHON3") == "1" and sys.version_info[:2] != (3, 8): + sys.exit("Error: Sentry [In EXPERIMENTAL python 3 mode] requires Python 3.8.") if os.environ.get("SENTRY_PYTHON3") != "1" and sys.version_info[:2] != (2, 7): sys.exit("Error: Sentry requires Python 2.7.") diff --git a/src/sentry/interfaces/stacktrace.py b/src/sentry/interfaces/stacktrace.py index ab85617171311c..6f7211e9a835fd 100644 --- a/src/sentry/interfaces/stacktrace.py +++ b/src/sentry/interfaces/stacktrace.py @@ -144,6 +144,7 @@ def to_python(cls, data, raw=False): "image_addr", "in_app", "instruction_addr", + "addr_mode", "lineno", "module", "package", @@ -172,6 +173,7 @@ def to_json(self): "symbol": self.symbol, "symbol_addr": self.symbol_addr, "instruction_addr": self.instruction_addr, + "addr_mode": self.addr_mode, "trust": self.trust, "in_app": self.in_app, "context_line": self.context_line, @@ -196,6 +198,7 @@ def get_api_context(self, is_public=False, pad_addr=None, platform=None): "package": self.package, "platform": self.platform, "instructionAddr": pad_hex_addr(self.instruction_addr, pad_addr), + "addrMode": self.addr_mode or "abs", "symbolAddr": pad_hex_addr(self.symbol_addr, pad_addr), "function": function, "rawFunction": self.raw_function, diff --git a/src/sentry/static/sentry/app/components/events/interfaces/debugMeta/debugImage.tsx b/src/sentry/static/sentry/app/components/events/interfaces/debugMeta/debugImage.tsx index fbf9f212e23285..4361442347d66e 100644 --- a/src/sentry/static/sentry/app/components/events/interfaces/debugMeta/debugImage.tsx +++ b/src/sentry/static/sentry/app/components/events/interfaces/debugMeta/debugImage.tsx @@ -176,9 +176,13 @@ const DebugImage = React.memo(({image, orgId, projectId, showDetails, style}: Pr {renderIconElement()} - {formatAddress(startAddress, IMAGE_ADDR_LEN)} –{' '} - - {formatAddress(endAddress, IMAGE_ADDR_LEN)} + {startAddress && endAddress ? ( + + {formatAddress(startAddress, IMAGE_ADDR_LEN)} –{' '} + + {formatAddress(endAddress, IMAGE_ADDR_LEN)} + + ) : null} diff --git a/src/sentry/static/sentry/app/components/events/interfaces/debugMeta/index.tsx b/src/sentry/static/sentry/app/components/events/interfaces/debugMeta/index.tsx index 01e56551ed2cac..230a5a81cc7bf4 100644 --- a/src/sentry/static/sentry/app/components/events/interfaces/debugMeta/index.tsx +++ b/src/sentry/static/sentry/app/components/events/interfaces/debugMeta/index.tsx @@ -55,6 +55,10 @@ type State = { panelBodyHeight?: number; }; +function normalizeId(id: string | undefined): string { + return id ? id.trim().toLowerCase().replace(/[- ]/g, '') : ''; +} + const cache = new CellMeasurerCache({ fixedWidth: true, defaultHeight: 81, @@ -159,19 +163,24 @@ class DebugMeta extends React.PureComponent { } // When searching for an address, check for the address range of the image - // instead of an exact match. + // instead of an exact match. Note that images cannot be found by index + // if they are at 0x0. For those relative addressing has to be used. if (searchTerm.indexOf('0x') === 0) { const needle = parseAddress(searchTerm); - if (needle > 0) { + if (needle > 0 && image.image_addr !== '0x0') { const [startAddress, endAddress] = getImageRange(image); return needle >= startAddress && needle < endAddress; } } + // the searchTerm ending at "!" is the end of the ID search. + const relMatch = normalizeId(searchTerm).match(/^\s*(.*?)!/); + const idSearchTerm = normalizeId((relMatch && relMatch[1]) || searchTerm); + return ( // Prefix match for identifiers - (image.code_id?.toLowerCase() || '').indexOf(searchTerm) === 0 || - (image.debug_id?.toLowerCase() || '').indexOf(searchTerm) === 0 || + normalizeId(image.code_id).indexOf(idSearchTerm) === 0 || + normalizeId(image.debug_id).indexOf(idSearchTerm) === 0 || // Any match for file paths (image.code_file?.toLowerCase() || '').indexOf(searchTerm) >= 0 || (image.debug_file?.toLowerCase() || '').indexOf(searchTerm) >= 0 @@ -214,9 +223,27 @@ class DebugMeta extends React.PureComponent { return undefined; } - const searchTerm = this.state.filter.toLowerCase(); + const searchTerm = normalizeId(this.state.filter.toLowerCase()); + const relMatch = searchTerm.match(/^\s*(.*?)!(.*)$/); - return frames.find(frame => frame.instructionAddr?.toLowerCase() === searchTerm); + if (relMatch) { + const debugImages = this.getDebugImages().map( + (image, idx) => [idx, image] as [number, Image] + ); + const filteredImages = debugImages.filter(([_, image]) => this.filterImage(image)); + if (filteredImages.length === 1) { + return frames.find(frame => { + return ( + frame.addrMode === `rel:${filteredImages[0][0]}` && + frame.instructionAddr?.toLowerCase() === relMatch[2] + ); + }); + } else { + return undefined; + } + } else { + return frames.find(frame => frame.instructionAddr?.toLowerCase() === searchTerm); + } } getDebugImages() { diff --git a/src/sentry/static/sentry/app/components/events/interfaces/frame/line.tsx b/src/sentry/static/sentry/app/components/events/interfaces/frame/line.tsx index 93178ba523e995..b22f392cd61dba 100644 --- a/src/sentry/static/sentry/app/components/events/interfaces/frame/line.tsx +++ b/src/sentry/static/sentry/app/components/events/interfaces/frame/line.tsx @@ -56,6 +56,18 @@ type State = { isExpanded?: boolean; }; +function makeFilter( + addr: string, + addrMode: string | undefined, + image?: React.ComponentProps['image'] +): string { + let filter = addr; + if (!(!addrMode || addrMode === 'abs') && image) { + filter = image.debug_id + '!' + filter; + } + return filter; +} + export class Line extends React.Component { static defaultProps = { isExpanded: false, @@ -147,7 +159,12 @@ export class Line extends React.Component { scrollToImage = event => { event.stopPropagation(); // to prevent collapsing if collapsable - DebugMetaActions.updateFilter(this.props.data.instructionAddr); + const {instructionAddr, addrMode} = this.props.data; + if (instructionAddr) { + DebugMetaActions.updateFilter( + makeFilter(instructionAddr, addrMode, this.props.image) + ); + } scrollToElement('#packages'); }; diff --git a/src/sentry/static/sentry/app/components/events/interfaces/stacktraceContent.tsx b/src/sentry/static/sentry/app/components/events/interfaces/stacktraceContent.tsx index 30d60ab50ccbc4..cb5a15d0f347d1 100644 --- a/src/sentry/static/sentry/app/components/events/interfaces/stacktraceContent.tsx +++ b/src/sentry/static/sentry/app/components/events/interfaces/stacktraceContent.tsx @@ -78,14 +78,18 @@ export default class StacktraceContent extends React.Component { ); }; - findImageForAddress(address: Frame['instructionAddr']) { + findImageForAddress(address: Frame['instructionAddr'], addrMode: Frame['addrMode']) { const images = this.props.event.entries.find(entry => entry.type === 'debugmeta') ?.data?.images; return images && address - ? images.find(img => { - const [startAddress, endAddress] = getImageRange(img); - return address >= startAddress && address < endAddress; + ? images.find((img, idx) => { + if (!addrMode || addrMode === 'abs') { + const [startAddress, endAddress] = getImageRange(img); + return address >= startAddress && address < endAddress; + } else { + return addrMode === `rel:${idx}`; + } }) : null; } @@ -152,7 +156,10 @@ export default class StacktraceContent extends React.Component { const maxLengthOfAllRelativeAddresses = data.frames.reduce( (maxLengthUntilThisPoint, frame) => { - const correspondingImage = this.findImageForAddress(frame.instructionAddr); + const correspondingImage = this.findImageForAddress( + frame.instructionAddr, + frame.addrMode + ); try { const relativeAddress = ( @@ -188,7 +195,7 @@ export default class StacktraceContent extends React.Component { } if (this.frameIsVisible(frame, nextFrame) && !repeatedFrame) { - const image = this.findImageForAddress(frame.instructionAddr); + const image = this.findImageForAddress(frame.instructionAddr, frame.addrMode); frames.push( Date: Fri, 27 Nov 2020 13:28:02 +0100 Subject: [PATCH 07/12] revert stuff --- scripts/ensure-venv.sh | 4 ++-- setup.py | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/scripts/ensure-venv.sh b/scripts/ensure-venv.sh index 18dcef1d35a751..3b4ba679deec3f 100755 --- a/scripts/ensure-venv.sh +++ b/scripts/ensure-venv.sh @@ -11,7 +11,7 @@ python_bin="python2.7" if [ "$SENTRY_PYTHON3" = "1" ]; then venv_name=".venv3" - python_bin="python3.8" + python_bin="python3.6" fi die() { @@ -27,7 +27,7 @@ if [ -n "$VIRTUAL_ENV" ]; then # TODO: Update this to strictly check .python-version if [ "$SENTRY_PYTHON3" = "1" ]; then - python -c "import sys; sys.exit(sys.version_info[:2] != (3, 8))" || + python -c "import sys; sys.exit(sys.version_info[:2] != (3, 6))" || die "For some reason, the virtualenv isn't Python 3.6." else python -c "import sys; sys.exit(sys.version_info[:2] != (2, 7))" || diff --git a/setup.py b/setup.py index a48c3f87974f9c..3aa6863c4abba5 100755 --- a/setup.py +++ b/setup.py @@ -4,8 +4,8 @@ import os import sys -if os.environ.get("SENTRY_PYTHON3") == "1" and sys.version_info[:2] != (3, 8): - sys.exit("Error: Sentry [In EXPERIMENTAL python 3 mode] requires Python 3.8.") +if os.environ.get("SENTRY_PYTHON3") == "1" and sys.version_info[:2] != (3, 6): + sys.exit("Error: Sentry [In EXPERIMENTAL python 3 mode] requires Python 3.6.") if os.environ.get("SENTRY_PYTHON3") != "1" and sys.version_info[:2] != (2, 7): sys.exit("Error: Sentry requires Python 2.7.") From d78a30739ccc1f33a3d0c4c7407c502f2d08bc22 Mon Sep 17 00:00:00 2001 From: Armin Ronacher Date: Fri, 27 Nov 2020 17:23:46 +0100 Subject: [PATCH 08/12] ref: remove addrMode when abs --- src/sentry/interfaces/stacktrace.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/sentry/interfaces/stacktrace.py b/src/sentry/interfaces/stacktrace.py index 6f7211e9a835fd..70635e05873a61 100644 --- a/src/sentry/interfaces/stacktrace.py +++ b/src/sentry/interfaces/stacktrace.py @@ -198,7 +198,6 @@ def get_api_context(self, is_public=False, pad_addr=None, platform=None): "package": self.package, "platform": self.platform, "instructionAddr": pad_hex_addr(self.instruction_addr, pad_addr), - "addrMode": self.addr_mode or "abs", "symbolAddr": pad_hex_addr(self.symbol_addr, pad_addr), "function": function, "rawFunction": self.raw_function, @@ -217,6 +216,10 @@ def get_api_context(self, is_public=False, pad_addr=None, platform=None): } if not is_public: data["vars"] = self.vars + + if self.addr_mode and self.addr_mode != "abs": + data["addrMode"] = self.addr_mode + # TODO(dcramer): abstract out this API if self.data and "sourcemap" in data: data.update( From 18d3c4a85ff01b79a69a869fdbe2ed20d68cc4c5 Mon Sep 17 00:00:00 2001 From: Jan Michael Auer Date: Mon, 30 Nov 2020 20:14:21 +0100 Subject: [PATCH 09/12] build: Symbolic 8.0.0 --- requirements-base.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements-base.txt b/requirements-base.txt index 1eace7b88c3915..7ced01c4a65e39 100644 --- a/requirements-base.txt +++ b/requirements-base.txt @@ -58,7 +58,7 @@ six>=1.11.0,<1.12.0 sqlparse>=0.2.0,<0.3.0 statsd>=3.1.0,<3.2.0 structlog==17.1.0 -symbolic>=7.3.5,<8.0.0 +symbolic>=8.0.0,<9.0.0 toronado>=0.0.11,<0.1.0 ua-parser>=0.10.0,<0.11.0 unidiff>=0.5.4 From 5edcf513eb8d7178dc41b171185e0af8e0cd6767 Mon Sep 17 00:00:00 2001 From: Jan Michael Auer Date: Tue, 1 Dec 2020 13:31:31 +0100 Subject: [PATCH 10/12] fix(test): Update test_dif_error_response after symbolic upgrade --- tests/sentry/api/endpoints/test_dif_assemble.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/tests/sentry/api/endpoints/test_dif_assemble.py b/tests/sentry/api/endpoints/test_dif_assemble.py index a36d7549fdb4d2..ee293900337f44 100644 --- a/tests/sentry/api/endpoints/test_dif_assemble.py +++ b/tests/sentry/api/endpoints/test_dif_assemble.py @@ -241,6 +241,4 @@ def test_dif_error_response(self): assert response.status_code == 200, response.content assert response.data[total_checksum]["state"] == ChunkFileState.ERROR - assert response.data[total_checksum]["detail"].startswith( - "Unsupported debug information file" - ) + assert "unsupported object file format" in response.data[total_checksum]["detail"] From b7ce4aca6285359d699b547ae3cd28efffe170a7 Mon Sep 17 00:00:00 2001 From: Armin Ronacher Date: Tue, 1 Dec 2020 14:31:42 +0100 Subject: [PATCH 11/12] ref: change normalization code for native images --- src/sentry/lang/native/processing.py | 71 +++++++++++++++++----------- 1 file changed, 44 insertions(+), 27 deletions(-) diff --git a/src/sentry/lang/native/processing.py b/src/sentry/lang/native/processing.py index ed6c4f97ae3def..50f50c187c34a2 100644 --- a/src/sentry/lang/native/processing.py +++ b/src/sentry/lang/native/processing.py @@ -24,6 +24,8 @@ from sentry.stacktraces.processing import find_stacktraces_in_data from sentry.utils.compat import zip +from symbolic import normalize_debug_id, ParseDebugIdError + logger = logging.getLogger(__name__) @@ -290,28 +292,47 @@ def _handles_frame(data, frame): return is_native_platform(platform) and "instruction_addr" in frame -def _expand_addr_mode(addr_mode, modules): - if addr_mode in (None, "abs"): - return "abs" - if addr_mode.startswith("rel:"): - arg = addr_mode[4:] - - for idx, module in enumerate(modules): - if module.get("debug_id") == arg: - return "rel:%d" % idx - - if arg.isdigit(): - return addr_mode - - # This is wrong but we want to set the addr mode to abs if somone - # sends a bad mode. - return "abs" - - -def frame_to_symbolicator_frame(frame, modules): - rv = dict(frame) - - rv["addr_mode"] = _expand_addr_mode(rv.get("addr_mode"), modules) +def get_frames_for_symbolication(data, modules): + modules_by_debug_id = None + rv = [] + + for frame in reversed(data.get("frames") or ()): + if not _handles_frame(data, frame): + continue + s_frame = dict(frame) + + # validate and expand addressing modes. If we can't validate and + # expand it, we keep None which is absolute. That's not great but + # at least won't do damage. + addr_mode = s_frame.pop("addr_mode", None) + sanitized_addr_mode = None + + # None and abs mean absolute addressing explicitly. + if addr_mode in (None, "abs"): + pass + # this is relative addressing to module by index or debug id. + elif addr_mode.startswith("rel:"): + arg = addr_mode[4:] + idx = None + + if modules_by_debug_id is None: + modules_by_debug_id = dict( + (x.get("debug_id"), idx) for idx, x in enumerate(modules) + ) + try: + idx = modules_by_debug_id.get(normalize_debug_id(arg)) + except ParseDebugIdError: + pass + + if idx is None and arg.isdigit(): + idx = int(arg) + + if idx is not None: + sanitized_addr_mode = "rel:%d" % idx + + if sanitized_addr_mode is not None: + s_frame["addr_mode"] = sanitized_addr_mode + rv.append(s_frame) return rv @@ -332,11 +353,7 @@ def process_payload(data): stacktraces = [ { "registers": sinfo.stacktrace.get("registers") or {}, - "frames": [ - frame_to_symbolicator_frame(f, modules) - for f in reversed(sinfo.stacktrace.get("frames") or ()) - if _handles_frame(data, f) - ], + "frames": get_frames_for_symbolication(data, modules), } for sinfo in stacktrace_infos ] From aff0602c08efa34617bdb4b3d1fee9b57ac7133b Mon Sep 17 00:00:00 2001 From: Armin Ronacher Date: Tue, 1 Dec 2020 14:58:29 +0100 Subject: [PATCH 12/12] fix: correctly pass frames --- src/sentry/lang/native/processing.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/sentry/lang/native/processing.py b/src/sentry/lang/native/processing.py index 50f50c187c34a2..203b1880256ec0 100644 --- a/src/sentry/lang/native/processing.py +++ b/src/sentry/lang/native/processing.py @@ -292,11 +292,11 @@ def _handles_frame(data, frame): return is_native_platform(platform) and "instruction_addr" in frame -def get_frames_for_symbolication(data, modules): +def get_frames_for_symbolication(frames, data, modules): modules_by_debug_id = None rv = [] - for frame in reversed(data.get("frames") or ()): + for frame in reversed(frames): if not _handles_frame(data, frame): continue s_frame = dict(frame) @@ -353,7 +353,9 @@ def process_payload(data): stacktraces = [ { "registers": sinfo.stacktrace.get("registers") or {}, - "frames": get_frames_for_symbolication(data, modules), + "frames": get_frames_for_symbolication( + sinfo.stacktrace.get("frames") or (), data, modules + ), } for sinfo in stacktrace_infos ]