Commit 118e9141 authored by Xiao Shi's avatar Xiao Shi Committed by Facebook GitHub Bot

move folly gdb pretty printers to OSS repo

Summary: As title, move gdb pretty printers from internal repo to OSS repo

Reviewed By: yfeldblum

Differential Revision: D25684325

fbshipit-source-id: b7999dee1379801ee68553de64f16ac4db78b174
parent 63154657
#!/usr/bin/env python3
# Copyright (c) Facebook, Inc. and its affiliates.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import itertools
import socket
import gdb
import gdb.printing
import gdb.types
def escape_byte(b):
if b == 10:
return "\\n"
elif b == 34:
return '\\"'
elif b == 92:
return "\\\\"
elif 32 <= b < 127:
return chr(b)
else:
# Escape non-printable bytes with octal, which is what GDB
# uses when natively printing strings.
return "\\{0:03o}".format(b)
def repr_string(v, length):
# GDB API does not support retrieving the value as a byte string,
# so we need to round-trip through str (unicode) using surrogate
# escapes for non-decodable sequences.
decoded = v.string(encoding="utf8", errors="surrogateescape", length=length)
byte_string = decoded.encode("utf8", errors="surrogateescape")
return '"' + "".join(escape_byte(b) for b in byte_string) + '"'
class FBStringPrinter:
"""Print an FBString."""
def __init__(self, val):
self.val = val
def to_string(self):
size_of_size_t = gdb.lookup_type("size_t").sizeof
catmask = 0xC0000000 if (size_of_size_t == 4) else 0xC000000000000000
cap = self.val["store_"]["ml_"]["capacity_"]
category = cap & catmask
if category == 0: # small-string-optimized
v = self.val["store_"]["small_"]
sz = v.type.sizeof
length = sz - v[sz - 1]
return repr_string(v, length - 1)
else:
v = self.val["store_"]["ml_"]
length = v["size_"]
return repr_string(v["data_"], length)
def display_hint(self):
return "fbstring"
class StringPiecePrinter:
"""Print a (Mutable)StringPiece"""
def __init__(self, val):
self.val = val
def to_string(self):
ptr = self.val["b_"]
length = self.val["e_"] - ptr
return repr_string(ptr, length)
def display_hint(self):
return "folly::StringPiece"
class RangePrinter:
"""Print a Range"""
def __init__(self, val):
self.val = val
def children(self):
count = 0
item = self.val["b_"]
end = self.val["e_"]
while item != end:
yield "[%d]" % count, item.dereference()
count += 1
item += 1
def to_string(self):
length = self.val["e_"] - self.val["b_"]
value_type = self.val.type.template_argument(0)
return "folly::Range<%s> of length %d" % (value_type, length)
def display_hint(self):
return "folly::Range"
class DynamicPrinter:
"""Print a folly::dynamic."""
def __init__(self, val):
self.val = val
def to_string(self):
d = gdb.types.make_enum_dict(self.val["type_"].type)
names = {v: k for k, v in d.items()}
type_ = names[int(self.val["type_"])]
u = self.val["u_"]
if type_ == "folly::dynamic::NULLT":
return "NULL"
elif type_ == "folly::dynamic::ARRAY":
return u["array"]
elif type_ == "folly::dynamic::BOOL":
return u["boolean"]
elif type_ == "folly::dynamic::DOUBLE":
return u["doubl"]
elif type_ == "folly::dynamic::INT64":
return u["integer"]
elif type_ == "folly::dynamic::STRING":
return u["string"]
elif type_ == "folly::dynamic::OBJECT":
t = gdb.lookup_type("folly::dynamic::ObjectImpl").pointer()
raw_v = u["objectBuffer"]["__data"]
ptr = raw_v.address.reinterpret_cast(t)
return ptr.dereference()
else:
return "{unknown folly::dynamic type}"
def display_hint(self):
return "folly::dynamic"
class IPAddressPrinter:
"""Print a folly::IPAddress."""
def __init__(self, val):
self.val = val
def to_string(self):
result = ""
if self.val["family_"] == socket.AF_INET:
addr = self.val["addr_"]["ipV4Addr"]["addr_"]["bytes_"]["_M_elems"]
for i in range(0, 4):
result += "{:d}.".format(int(addr[i]))
elif self.val["family_"] == socket.AF_INET6:
addr = self.val["addr_"]["ipV6Addr"]["addr_"]["bytes_"]["_M_elems"]
for i in range(0, 8):
result += "{:02x}{:02x}:".format(int(addr[2 * i]), int(addr[2 * i + 1]))
else:
return "unknown address family {}".format(self.val["family_"])
return result[:-1]
def display_hint(self):
return "folly::IPAddress"
class SocketAddressPrinter:
"""Print a folly::SocketAddress."""
def __init__(self, val):
self.val = val
def to_string(self):
result = ""
if self.val["external_"] != 0:
return "unix address, printer TBD"
else:
ipPrinter = IPAddressPrinter(self.val["storage_"]["addr"])
if self.val["storage_"]["addr"]["family_"] == socket.AF_INET6:
result += "[" + ipPrinter.to_string() + "]"
else:
result += ipPrinter.to_string()
result += ":{}".format(self.val["port_"])
return result
def display_hint(self):
return "folly::SocketAddress"
# For Node and Value containers, i.e., kEnableItemIteration == false
class F14HashtableIterator:
def __init__(self, ht, is_node_container):
item_type = gdb.lookup_type("{}::{}".format(ht.type.name, "Item"))
self.item_ptr_type = item_type.pointer()
self.chunk_ptr = ht["chunks_"]
# chunk_count is always power of 2;
# For partial chunks, chunkMask_ = 0, so + 1 also works
chunk_count = ht["chunkMask_"] + 1
self.chunk_end = self.chunk_ptr + chunk_count
self.current_chunk = self.chunk_iter(self.chunk_ptr)
self.is_node_container = is_node_container
def __iter__(self):
return self
# generator to enumerate items in a given chunk
def chunk_iter(self, chunk_ptr):
chunk = chunk_ptr.dereference()
tags = chunk["tags_"]["_M_elems"]
raw_items = chunk["rawItems_"]["_M_elems"]
# Enumerate over slots in the chunk
for i in range(tags.type.sizeof):
# full items have the top bit set in the tag
if tags[i] & 0x80:
item_ptr = raw_items[i]["__data"].cast(self.item_ptr_type)
item = item_ptr.dereference()
# node containers stores a pointer to value_type whereas value
# containers store values inline
yield item.dereference() if self.is_node_container else item
def __next__(self):
while True:
try:
# exhaust the current chunk
return next(self.current_chunk)
except StopIteration:
# find the next chunk
self.chunk_ptr += 1
if self.chunk_ptr == self.chunk_end:
raise StopIteration
self.current_chunk = self.chunk_iter(self.chunk_ptr)
pass
# For Vector containers, i.e., kEnableItemIteration == true
class F14HashtableItemIterator:
def __init__(self, start, size):
self.item = start
self.end = self.item + size
def __iter__(self):
return self
def __next__(self):
# To iterator the first item, gdb will call __next__
if self.item == self.end:
raise StopIteration
val = self.item.dereference()
self.item = self.item + 1
return val
class F14Printer:
"""Print an F14 hash map or hash set"""
@staticmethod
def get_container_type_name(type):
name = type.unqualified().strip_typedefs().name
# strip template arguments
template_start = name.find("<")
if template_start < 0:
return name
return name[:template_start]
def __init__(self, val):
self.val = val
self.type = val.type
self.short_typename = self.get_container_type_name(self.type)
self.is_map = "Map" in self.short_typename
iter_type = gdb.lookup_type(
f"{self.type.unqualified().strip_typedefs()}::iterator"
)
self.is_node_container = "NodeContainer" in iter_type.name
self.enable_item_iteration = "VectorContainer" in iter_type.name
def hashtable(self):
return self.val["table_"]
def size(self):
return self.hashtable()["sizeAndPackedBegin_"]["size_"]
def to_string(self):
return "%s with %d elements" % (
self.short_typename,
self.size(),
)
@staticmethod
def format_one_map(elt):
return (elt["first"], elt["second"])
@staticmethod
def format_count(i):
return "[%d]" % i
@staticmethod
def flatten(list):
for elt in list:
for i in elt:
yield i
def children(self):
counter = map(self.format_count, itertools.count())
iter = (
F14HashtableItemIterator(self.hashtable()["values_"], self.size())
if self.enable_item_iteration
else F14HashtableIterator(self.hashtable(), self.is_node_container)
)
data = self.flatten(map(self.format_one_map, iter)) if self.is_map else iter
return zip(counter, data)
def display_hint(self):
return "map" if self.is_map else "array"
def build_pretty_printer():
pp = gdb.printing.RegexpCollectionPrettyPrinter("folly")
pp.add_printer("fbstring", "^folly::basic_fbstring<char,.*$", FBStringPrinter)
pp.add_printer(
"StringPiece", r"^folly::Range<(\w+ )*char( \w+)*\*>$", StringPiecePrinter
)
pp.add_printer("Range", r"^folly::Range<.*", RangePrinter)
pp.add_printer("dynamic", "^folly::dynamic$", DynamicPrinter)
pp.add_printer("IPAddress", "^folly::IPAddress$", IPAddressPrinter)
pp.add_printer("SocketAddress", "^folly::SocketAddress$", SocketAddressPrinter)
pp.add_printer("F14NodeMap", "^folly::F14NodeMap<.*$", F14Printer)
pp.add_printer("F14ValueMap", "^folly::F14ValueMap<.*$", F14Printer)
pp.add_printer("F14VectorMap", "^folly::F14VectorMap<.*$", F14Printer)
pp.add_printer("F14FastMap", "^folly::F14FastMap<.*$", F14Printer)
pp.add_printer("F14NodeSet", "^folly::F14NodeSet<.*$", F14Printer)
pp.add_printer("F14ValueSet", "^folly::F14ValueSet<.*$", F14Printer)
pp.add_printer("F14VectorSet", "^folly::F14VectorSet<.*$", F14Printer)
pp.add_printer("F14FastSet", "^folly::F14FastSet<.*$", F14Printer)
return pp
def load():
gdb.printing.register_pretty_printer(gdb, build_pretty_printer())
def info():
return "Pretty printers for folly containers"
/*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#define FOLLY_F14_PERTURB_INSERTION_ORDER 0
#include <folly/IPAddress.h>
#include <folly/Range.h>
#include <folly/SocketAddress.h>
#include <folly/container/F14Map.h>
#include <folly/container/F14Set.h>
#include <folly/dynamic.h>
#pragma GCC diagnostic ignored "-Wunused-variable"
int main() {
using namespace folly;
// FBString
fbstring empty = "";
fbstring small = "small";
fbstring maxsmall = "12345678901234567890123";
fbstring minmed = "123456789012345678901234";
fbstring large =
"abcdefghijklmnopqrstuvwxyz123456"
"abcdefghijklmnopqrstuvwxyz123456"
"abcdefghijklmnopqrstuvwxyz123456"
"abcdefghijklmnopqrstuvwxyz123456"
"abcdefghijklmnopqrstuvwxyz123456"
"abcdefghijklmnopqrstuvwxyz123456"
"abcdefghijklmnopqrstuvwxyz123456"
"abcdefghijklmnopqrstuvwxyz123456";
// StringPiece
auto emptypiece = StringPiece("");
auto otherpiece = StringPiece("strings. Strings! STRINGS!!");
// Range
std::array<int, 6> nums = {{1, 2, 3, 4, 5, 6}};
auto num_range = Range<const int*>(nums);
// Dynamic
dynamic dynamic_null = nullptr;
dynamic dynamic_array = dynamic::array("A string", 1, 2, 3, 4, 5);
dynamic dynamic_bool = true;
dynamic dynamic_double = 0.25;
dynamic dynamic_int64 = 8675309;
dynamic dynamic_string = "Hi!";
dynamic dynamic_object = dynamic::object;
dynamic_object["one"] = "two";
dynamic_object["eight"] = "ten";
// IPAddress
auto ipv4 = IPAddress("0.0.0.0");
auto ipv6 = IPAddress("2a03:2880:fffe:c:face:b00c:0:35");
// SocketAddress
auto ipv4socket = SocketAddress("127.0.0.1", 8080);
auto ipv6socket = SocketAddress("2a03:2880:fffe:c:face:b00c:0:35", 8080);
// F14 containers
F14NodeMap<std::string, int> m_node = {{"foo", 0}, {"bar", 1}, {"baz", 2}};
F14ValueMap<std::string, int> m_val = {{"foo", 0}};
F14VectorMap<std::string, int> m_vec = {{"foo", 0}, {"bar", 1}};
F14FastMap<int, std::string> m_fvec = {{42, "foo"}, {43, "bar"}, {44, "baz"}};
F14FastMap<int, int> m_fval = {{9, 0}, {8, 1}, {7, 2}};
F14NodeSet<std::string> s_node = {"foo", "bar", "baz"};
F14NodeSet<int> s_node_large;
for (auto i = 0; i < 20; ++i) {
s_node_large.emplace(i);
}
F14ValueSet<std::string> s_val = {"foo", "bar", "baz"};
F14ValueSet<uint32_t> s_val_i;
for (uint32_t i = 0; i < 20; ++i) {
s_val_i.emplace(i);
}
F14VectorSet<std::string> s_vec = {"foo", "bar", "baz"};
F14FastSet<std::string> s_fvec = {"foo", "bar", "baz"};
F14FastSet<int> s_fval = {42, 43, 44};
typedef F14FastSet<int> F14FastSetTypedef;
F14FastSetTypedef s_fval_typedef = {45, 46, 47};
const F14FastSet<int>& const_ref = s_fval;
__asm__ volatile("int $3"); // Auto breakpoint in gdb.
return 0;
}
fbload folly
# For folly::dynamic
fbload stl
run
#### FBString Tests ####
p empty
# CHECK: ""
p small
# CHECK: "small"
p maxsmall
# CHECK: "12345678901234567890123"
p minmed
# CHECK: "123456789012345678901234"
p large
# CHECK: "abcdefghijklmnopqrstuvwxyz123456abcdefghijklmnopqrstuvwxyz123456abcdefghijklmnopqrstuvwxyz123456abcdefghijklmnopqrstuvwxyz123456abcdefghijklmnopqrstuvwxyz123456abcdefghijklmnopqrstuvwxyz123456abcdefghijklmnopqrstuvwxyz123456abcdefghijklmnopqrstuvwxyz123456"
#### StringPiece Tests ####
p emptypiece
# CHECK: ""
p otherpiece
# CHECK: "strings. Strings! STRINGS!!"
#### Range Tests ####
p num_range
# CHECK: const int *
# CHECK: length 6
# CHECK: [0] = 1
# CHECK: [5] = 6
#### Dynamic Tests ####
p dynamic_null
# CHECK: NULL
p dynamic_array
# CHECK: length 6
# CHECK_SAME: "A string", 1, 2, 3, 4, 5
p dynamic_bool
# CHECK: true
p dynamic_double
# CHECK: .25
p dynamic_int64
# CHECK: 8675309
p dynamic_string
# CHECK: "Hi!"
p dynamic_object
# CHECK: 2 elements
# CHECK_DAG: ["one"] = "two"
# CHECK_DAG: ["eight"] = "ten"
#### IPAddress Tests ####
p ipv4
# CHECK: 0.0.0.0
p ipv6
# CHECK: 2a03:2880:fffe:000c:face:b00c:0000:0035
#### SocketAddress Tests ####
p ipv4socket
# CHECK: 127.0.0.1:8080
p ipv6socket
# CHECK: [2a03:2880:fffe:000c:face:b00c:0000:0035]:8080
#### F14 Tests ####
p m_node
# CHECK: folly::F14NodeMap with 3 elements = {["foo"] = 0, ["bar"] = 1,
# CHECK: ["baz"] = 2}
p m_val
# CHECK: folly::F14ValueMap with 1 elements = {["foo"] = 0}
p m_vec
# CHECK: folly::F14VectorMap with 2 elements = {["foo"] = 0, ["bar"] = 1}
p m_fvec
# CHECK: folly::F14FastMap with 3 elements = {[42] = "foo", [43] = "bar",
# CHECK: [44] = "baz"}
p m_fval
# CHECK: folly::F14FastMap with 3 elements = {[9] = 0, [8] = 1,
# CHECK: [7] = 2}
p s_node
# CHECK: folly::F14NodeSet with 3 elements = {"foo", "bar", "baz"}
p s_node_large
# CHECK: folly::F14NodeSet with 20 elements = {{{[0-9, ]*[[:space:]][0-9, ]*}}}
p s_val
# CHECK: folly::F14ValueSet with 3 elements = {"foo", "bar", "baz"}
p s_val_i
# CHECK: folly::F14ValueSet with 20 elements = {{{[0-9, ]*[[:space:]][0-9, ]*}}}
p s_vec
# CHECK: folly::F14VectorSet with 3 elements = {"foo", "bar", "baz"}
p s_fvec
# CHECK: folly::F14FastSet with 3 elements = {"foo", "bar", "baz"}
p s_fval
# CHECK: folly::F14FastSet with 3 elements = {42, 43, 44}
p s_fval_typedef
# CHECK: folly::F14FastSet with 3 elements = {45, 46, 47}
p const_ref
# CHECK: folly::F14FastSet with 3 elements = {42, 43, 44}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment