Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

C++ stack in the message embed being useless / contains no info #29

Open
p0358 opened this issue Aug 30, 2022 · 8 comments
Open

C++ stack in the message embed being useless / contains no info #29

p0358 opened this issue Aug 30, 2022 · 8 comments

Comments

@p0358
Copy link

p0358 commented Aug 30, 2022

Hello, first of all -- thanks for this integration, it's pretty nice.

While using it with C++ I noticed though that the "Stack" section of the embed is pretty useless currently, I would appreciate considering looking into whether it could be improved:
obraz

In comparison with Sentry's UI:
obraz

All of the things seen in the above UI would are pretty important and would be good to be included:

  • library module name
  • relative offset value (to look up in debugger or disassembler)
  • function name, if available
  • file+line, if available
@IanMitchell
Copy link
Owner

Hey! The Sentry payload is kind of adhoc - if you post an example one for your project I can definitely improve the parser

@p0358
Copy link
Author

p0358 commented Aug 30, 2022

The full payload is very long, I can send it to you somewhere privately because I'm not sure if it wouldn't reveal too much information in whole (just let me know where if you'd like, something like Twitter DM might be the simplest), but here's example last two stack frames:

            [...],
              {
                "function": "sub_18036DCA0",
                "symbol": "sub_18036DCA0",
                "package": "C:\\GAME\\Bin\\engine.dll",
                "in_app": false,
                "data": {
                  "orig_in_app": -1,
                  "symbolicator_status": "symbolicated"
                },
                "instruction_addr": "0x1d47b2bdcc5",
                "trust": "cfi"
              },
              {
                "function": "test_crash1",
                "raw_function": "test_crash1(CCommand const&)",
                "symbol": "test_crash1(CCommand const&)",
                "package": "C:\\GAME\\Bin\\tforevive.dll",
                "filename": "MiscConCommands.cpp",
                "abs_path": "D:\\a\\tforevive_cpp\\tforevive_cpp\\Hook\\MiscConCommands.cpp",
                "lineno": 99,
                "pre_context": [
                  "",
                  "void test_crash1(const CCommand& args)",
                  "{",
                  "    spdlog::warn(\"Testing crash 1\");"
                ],
                "context_line": "    std::cout << \"Oops:\" << *((int*)0);",
                "post_context": [
                  "}",
                  "",
                  "void test_crash2(const CCommand& args)",
                  "{",
                  "    spdlog::warn(\"Testing crash 2\");"
                ],
                "in_app": false,
                "data": {
                  "orig_in_app": -1,
                  "symbolicator_status": "symbolicated"
                },
                "instruction_addr": "0x7ffc1fbdea1d",
                "trust": "context"
              }

Out of this it's already possible to extract module name (package key, everything after last \, probably remove .dll extension (consider / and other extensions in case of non-Windows)).

Notice that for the first library the information is limited, as there's only a debug file available, with no source code. Similarly the symbols are sometimes missing, in such case there's only package and instruction_addr to work with (no function name)...

Now unfortunately instruction_addr is absolute, and due to ASLR wouldn't tell us anything, so in order to display a relative address, the parser will need to dive into the modules section, find the corresponding module, and subtract its base address. This is what Sentry's UI seems to be doing on the fly.

They seem to be located in a [...]->debug_meta->images array in the JSON tree (debug_meta is on the same object level as tags, right next to it).

It seems that location of code_file can be compared to find the right module, and then image_addr can be subtracted from instruction_addr in the stack.

    "debug_meta": {
      "images": [
        {
          "code_id": "4df2bcacd2000",
          "code_file": "C:\\WINDOWS\\SYSTEM32\\MSVCR100.dll",
          "debug_id": "25656ec1-1750-43b6-96d8-93aea9e1984b-1",
          "debug_file": "msvcr100.amd64.pdb",
          "image_addr": "0x56af0000",
          "image_size": 860160,
          "debug_status": "unused",
          "features": {
            "has_debug_info": false,
            "has_sources": false,
            "has_symbols": false,
            "has_unwind_info": false
          },
          "unwind_status": "unused",
          "type": "pe"
        },
        {
          "code_id": "59ae294e31d4000",
          "code_file": "C:\\GAME\\Bin\\engine.dll",
          "debug_id": "65417b2c-dd48-464f-90c1-a36aebe8c8da-1",
          "debug_file": "C:\\Game\\Live\\src\\engine\\Retail\\x64\\engine.pdb",
          "arch": "x86_64",
          "image_addr": "0x1d47af50000",
          "image_size": 52248576,
          "candidates": [
            {
              "download": {
                "status": "notfound"
              },
              "source": "sentry:amd",
              "source_name": "AMD"
            },
            {
              "download": {
                "details": "",
                "status": "noperm"
              },
              "source": "sentry:intel",
              "source_name": "Intel"
            },
            {
              "download": {
                "details": "",
                "status": "noperm"
              },
              "source": "sentry:intel",
              "source_name": "Intel"
            },
            {
              "download": {
                "details": "",
                "status": "noperm"
              },
              "source": "sentry:intel",
              "source_name": "Intel"
            },
            {
              "download": {
                "details": "",
                "status": "noperm"
              },
              "source": "sentry:intel",
              "source_name": "Intel"
            },
            {
              "download": {
                "status": "notfound"
              },
              "source": "sentry:microsoft",
              "source_name": "Microsoft"
            },
            {
              "download": {
                "status": "notfound"
              },
              "source": "sentry:nvidia",
              "source_name": "NVIDIA"
            },
            {
              "download": {
                "features": {
                  "has_debug_info": false,
                  "has_sources": false,
                  "has_symbols": true,
                  "has_unwind_info": true
                },
                "status": "ok"
              },
              "location": "sentry://project_debug_file/197338063",
              "source": "sentry:project",
              "source_name": "Sentry",
              "unwind": {
                "status": "ok"
              }
            },
            {
              "debug": {
                "status": "ok"
              },
              "download": {
                "features": {
                  "has_debug_info": true,
                  "has_sources": false,
                  "has_symbols": true,
                  "has_unwind_info": false
                },
                "status": "ok"
              },
              "location": "sentry://project_debug_file/197897242",
              "source": "sentry:project",
              "source_name": "Sentry"
            }
          ],
          "debug_status": "found",
          "features": {
            "has_debug_info": true,
            "has_sources": false,
            "has_symbols": true,
            "has_unwind_info": true
          },
          "unwind_status": "found",
          "type": "pe"
        },

The last thing to add could be, in event->exception->values:

    "exception": {
      "values": [
        {
          "type": "EXCEPTION_ACCESS_VIOLATION_READ / 0x0",
          "value": "Fatal Error: EXCEPTION_ACCESS_VIOLATION_READ / 0x0",

It would be nice if the exception type or value could be also printed somewhere, preferably right under the issue name similarly to how Sentry displays it on the summary (issue name itself is usually just crashing function name).

So an idea for stack display could be like this:

tforevive +0x08ea1d   |  test_crash1 (MiscConCommands.cpp:99)
engine    +0x36dcc5   |  sub_18036DCA0
engine    +0x23f2c0   |  Cmd_ExecuteCommand
engine    +0x23da29   |  Cbuf_Execute
[etc...]

Also in case the source code is not available, it would be good to skip the source code context display instead of showing just >undefined:
obraz

Again lmk if you'd like to be sent the whole massive payload JSON somewhere and thank you for looking into this.

@IanMitchell
Copy link
Owner

Gotcha! Yeah if you don't mind emailing the JSON to me so I can test with it that would be wonderful - [email protected]. I'm out traveling right now so I unfortunately won't be able to start on this for about two weeks I think, but can post an update once I start!

@p0358
Copy link
Author

p0358 commented Aug 30, 2022

All right, I've sent the email with the JSON (posting just in case it wouldn't arrive or ended up in spam). There's no rush, happy travelling!

@IanMitchell
Copy link
Owner

hey @p0358 - I don't think I ever received the email actually. Would you mind resending it?

@p0358
Copy link
Author

p0358 commented Sep 20, 2022

I've re-sent it (there's JSON as attachment, the hookbin link has expired though, but the JSON still has the full event payload)

@p0358
Copy link
Author

p0358 commented Mar 16, 2023

Hello, any progress on this perchance? :)

@IanMitchell
Copy link
Owner

Haven't had much time, sorry - been swamped with work. If you're impatient, you can clone this locally and set up an ngrok tunnel to it, and then point Sentry to that tunnel - firing off an event will let you debug what the parser is getting caught up on!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants