Add support to process INLINE records in symbol files

This adds the support to process INLINE and INLINE_ORIGIN records in
symbol files and to generate inlined frames using those records if
possible.

Bug: 1190878
Change-Id: Ia0b6d56c9de37cf818d9bb6842d58c9b68f235b2
Reviewed-on: https://chromium-review.googlesource.com/c/breakpad/breakpad/+/3024690
Reviewed-by: Lei Zhang <thestig@chromium.org>
Reviewed-by: Joshua Peraza <jperaza@chromium.org>
This commit is contained in:
Zequan Wu
2021-07-22 11:13:37 -07:00
committed by Joshua Peraza
parent 32096a2dc8
commit f080350795
18 changed files with 948 additions and 363 deletions

View File

@@ -40,6 +40,7 @@
#include <map>
#include <string>
#include <vector>
#include "common/using_std_string.h"
#include "google_breakpad/processor/source_line_resolver_base.h"
@@ -84,6 +85,8 @@ class BasicSourceLineResolver : public SourceLineResolverBase {
// Helper class, containing useful methods for parsing of Breakpad symbol files.
class SymbolParseHelper {
public:
using MemAddr = SourceLineResolverInterface::MemAddr;
// Parses a |file_line| declaration. Returns true on success.
// Format: FILE <id> <filename>.
// Notice, that this method modifies the input |file_line| which is why it
@@ -94,6 +97,32 @@ class SymbolParseHelper {
long* index, // out
char** filename); // out
// Parses a |inline_origin_line| declaration. Returns true on success.
// Format: INLINE_ORIGIN <origin_id> <file_id> <name>.
// Notice, that this method modifies the input |inline_origin_line| which is
// why it can't be const. On success, <origin_id>, <file_id> and <name> are
// stored in |*origin_id|, |*file_id|, and |*name|. No allocation is
// done, |*name| simply points inside |inline_origin_line|.
static bool ParseInlineOrigin(char* inline_origin_line, // in
long* origin_id, // out
long* file_id, // out
char** name); // out
// Parses a |inline| declaration. Returns true on success.
// Format: INLINE <inline_nest_level> <call_site_line> <origin_id> <address>
// <size> ....
// Notice, that this method modifies the input |inline|
// which is why it can't be const. On success, <inline_nest_level>,
// <call_site_line> and <origin_id> are stored in |*inline_nest_level|,
// |*call_site_line|, and |*origin_id|, and all pairs of (<address>, <size>)
// are added into ranges .
static bool ParseInline(
char* inline_line, // in
long* inline_nest_level, // out
long* call_site_line, // out
long* origin_id, // out
std::vector<std::pair<MemAddr, MemAddr>>* ranges); // out
// Parses a |function_line| declaration. Returns true on success.
// Format: FUNC [<multiple>] <address> <size> <stack_param_size> <name>.
// Notice, that this method modifies the input |function_line| which is why it

View File

@@ -84,11 +84,15 @@ class SourceLineResolverBase : public SourceLineResolverInterface {
virtual void UnloadModule(const CodeModule* module);
virtual bool HasModule(const CodeModule* module);
virtual bool IsModuleCorrupt(const CodeModule* module);
virtual void FillSourceLineInfo(StackFrame* frame);
virtual void FillSourceLineInfo(
StackFrame* frame,
std::vector<std::unique_ptr<StackFrame>>* inlined_frames);
virtual WindowsFrameInfo* FindWindowsFrameInfo(const StackFrame* frame);
virtual CFIFrameInfo* FindCFIFrameInfo(const StackFrame* frame);
// Nested structs and classes.
struct InlineOrigin;
struct Inline;
struct Line;
struct Function;
struct PublicSymbol;

View File

@@ -34,7 +34,9 @@
#ifndef GOOGLE_BREAKPAD_PROCESSOR_SOURCE_LINE_RESOLVER_INTERFACE_H__
#define GOOGLE_BREAKPAD_PROCESSOR_SOURCE_LINE_RESOLVER_INTERFACE_H__
#include <memory>
#include <string>
#include <vector>
#include "common/using_std_string.h"
#include "google_breakpad/common/breakpad_types.h"
@@ -91,8 +93,12 @@ class SourceLineResolverInterface {
// Fills in the function_base, function_name, source_file_name,
// and source_line fields of the StackFrame. The instruction and
// module_name fields must already be filled in.
virtual void FillSourceLineInfo(StackFrame* frame) = 0;
// module_name fields must already be filled in. If inlined_frames is not
// nullptr, it will try to construct inlined frames by adding them into
// inlined_frames in an order from outermost frame to inner most frame.
virtual void FillSourceLineInfo(
StackFrame* frame,
std::vector<std::unique_ptr<StackFrame>>* inlined_frames) = 0;
// If Windows stack walking information is available covering
// FRAME's instruction address, return a WindowsFrameInfo structure

View File

@@ -51,7 +51,8 @@ struct StackFrame {
FRAME_TRUST_FP, // Derived from frame pointer
FRAME_TRUST_CFI, // Derived from call frame info
FRAME_TRUST_PREWALKED, // Explicitly provided by some external stack walker.
FRAME_TRUST_CONTEXT // Given as instruction pointer in a context
FRAME_TRUST_CONTEXT, // Given as instruction pointer in a context
FRAME_TRUST_INLINE // Found by inline records in symbol files.
};
StackFrame()
@@ -60,9 +61,9 @@ struct StackFrame {
function_name(),
function_base(),
source_file_name(),
source_line(),
source_line(0),
source_line_base(),
trust(FRAME_TRUST_NONE) {}
trust(FRAME_TRUST_NONE){}
virtual ~StackFrame() {}
// Return a string describing how this stack frame was found
@@ -81,6 +82,8 @@ struct StackFrame {
return "previous frame's frame pointer";
case StackFrame::FRAME_TRUST_SCAN:
return "stack scanning";
case StackFrame::FRAME_TRUST_INLINE:
return "inline record";
default:
return "unknown";
}

View File

@@ -35,8 +35,10 @@
#ifndef GOOGLE_BREAKPAD_PROCESSOR_STACK_FRAME_SYMBOLIZER_H__
#define GOOGLE_BREAKPAD_PROCESSOR_STACK_FRAME_SYMBOLIZER_H__
#include <memory>
#include <set>
#include <string>
#include <vector>
#include "common/using_std_string.h"
#include "google_breakpad/common/breakpad_types.h"
@@ -79,7 +81,8 @@ class StackFrameSymbolizer {
const CodeModules* modules,
const CodeModules* unloaded_modules,
const SystemInfo* system_info,
StackFrame* stack_frame);
StackFrame* stack_frame,
std::vector<std::unique_ptr<StackFrame>>* inlined_frames);
virtual WindowsFrameInfo* FindWindowsFrameInfo(const StackFrame* frame);