blob: d3e7ea7336a52d8b9165be4ba730216e526acd2d [file] [log] [blame]
// Copyright 2019 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef SRC_DEVELOPER_DEBUG_ZXDB_CLIENT_PRETTY_STACK_MANAGER_H_
#define SRC_DEVELOPER_DEBUG_ZXDB_CLIENT_PRETTY_STACK_MANAGER_H_
#include <vector>
#include "gtest/gtest_prod.h"
#include "src/developer/debug/zxdb/client/pretty_frame_glob.h"
#include "src/lib/fxl/memory/ref_counted.h"
namespace zxdb {
class Stack;
// Matches sequences of frames for pretty-ifying stacks. The patterns are expressed in
// PrettyFrameGlobs which match different parts of the stack frame or a wildcard range. The matched
// frames can then be collapsed and named with a descriptive string.
//
// Wildcard matching matches as few stack entries as possible (unlike many regular expression
// systems). Recursion can make the same sequence of frames appear multiple times in a stack, and
// we always want to hide as few frames as possible.
//
// Wildcard matching does not do backtracking. This means that the first frame after a wildcard
// picks up matching the stack again. If the sequence of matchers after this doesn't match, the
// code won't go search for a possibly different interpretation of the wildcard that does match.
// This behavior is unnecessary given typical stack matching requirements and affects complexity and
// performance.
class PrettyStackManager : public fxl::RefCountedThreadSafe<PrettyStackManager> {
public:
// Construct with fxl::MakeRefCounted().
struct StackGlob {
StackGlob(std::string d, std::vector<PrettyFrameGlob> f)
: description(std::move(d)), frames(std::move(f)) {}
std::string description;
std::vector<PrettyFrameGlob> frames;
};
struct Match {
Match() = default;
Match(size_t mc, const std::string& d) : match_count(mc), description(d) {}
// Returns true if this matches any frames.
operator bool() const { return match_count > 0; }
size_t match_count = 0;
std::string description;
};
// The grouped results of prettifying an entire stack.
struct FrameEntry {
// Index into the stack fo the first frame.
size_t begin_index = 0;
// Match if there was one starting at this location.
Match match;
// The frames corresponding to this item. If there's a match, this will contain the range of
// frames identified by the match_count. If there's no match, this will contain one frame.
std::vector<const Frame*> frames;
};
void SetMatchers(std::vector<StackGlob> matchers);
// Loads the hardcoded default matchers.
//
// TODO(bug 43549) this should be loaded from a configuration file somehow associated with the
// user's build instead of being hardcoded. This function can then be deleted.
void LoadDefaultMatchers();
// Returns the best match at the given index. The result will match no frames if there was no
// match at the given index.
Match GetMatchAt(const Stack& stack, size_t frame_index) const;
// Processes an entire stack, returning the grouped results.
std::vector<FrameEntry> ProcessStack(const Stack& stack) const;
private:
FRIEND_REF_COUNTED_THREAD_SAFE(PrettyStackManager);
FRIEND_MAKE_REF_COUNTED(PrettyStackManager);
FRIEND_TEST(PrettyStackManager, StackGlobMatchesAt);
PrettyStackManager() = default;
// Returns the number of frames matched (may be > stack_glob.size() if there were wildcard
// matches). Will return 0 if it's not a match.
static size_t StackGlobMatchesAt(const StackGlob& stack_glob, const Stack& stack,
size_t frame_start_index);
// Sorted in order of decreasing size (longest matchers are first).
std::vector<StackGlob> matchers_;
};
} // namespace zxdb
#endif // SRC_DEVELOPER_DEBUG_ZXDB_CLIENT_PRETTY_STACK_MANAGER_H_