2 +----------------------------------------------------------------------+
4 +----------------------------------------------------------------------+
5 | Copyright (c) 2010-present Facebook, Inc. (http://www.facebook.com) |
6 +----------------------------------------------------------------------+
7 | This source file is subject to version 3.01 of the PHP license, |
8 | that is bundled with this package in the file LICENSE, and is |
9 | available through the world-wide-web at the following url: |
10 | http://www.php.net/license/3_01.txt |
11 | If you did not receive a copy of the PHP license and are unable to |
12 | obtain it through the world-wide-web, please send a note to |
13 | license@php.net so we can mail you a copy immediately. |
14 +----------------------------------------------------------------------+
16 #include "hphp/hhbbc/debug.h"
23 #include <boost/filesystem/path.hpp>
24 #include <boost/filesystem/operations.hpp>
25 #include <boost/filesystem/fstream.hpp>
30 #include <folly/portability/Stdlib.h>
32 #include "hphp/hhbbc/class-util.h"
33 #include "hphp/hhbbc/context.h"
34 #include "hphp/hhbbc/misc.h"
35 #include "hphp/hhbbc/parallel.h"
37 namespace HPHP
{ namespace HHBBC
{
39 namespace fs
= boost::filesystem
;
41 //////////////////////////////////////////////////////////////////////
45 const StaticString
s_invoke("__invoke");
47 template<class Operation
>
48 void with_file(fs::path dir
, const php::Unit
* u
, Operation op
) {
49 auto const file
= dir
/ fs::path(u
->filename
->data());
50 fs::create_directories(fs::path(file
).remove_filename());
52 fs::ofstream
out(file
);
54 throw std::runtime_error(std::string("failed to open file ") +
61 throw std::runtime_error(std::string("couldn't write file ") +
66 using NameTy
= std::pair
<SString
,PropStateElem
<>>;
67 std::vector
<NameTy
> sorted_prop_state(const PropState
& ps
) {
68 std::vector
<NameTy
> ret(begin(ps
), end(ps
));
71 [&] (NameTy a
, NameTy b
) { return a
.first
->compare(b
.first
) < 0; }
76 void dump_class_state(std::ostream
& out
,
78 const php::Class
* c
) {
79 auto const clsName
= normalized_class_name(*c
);
82 auto const invoke
= find_method(c
, s_invoke
.get());
83 auto const useVars
= index
.lookup_closure_use_vars(invoke
);
84 for (auto i
= size_t{0}; i
< useVars
.size(); ++i
) {
85 out
<< clsName
<< "->" << c
->properties
[i
].name
->data() << " :: "
86 << show(useVars
[i
]) << '\n';
89 auto const pprops
= sorted_prop_state(
90 index
.lookup_private_props(c
)
92 for (auto const& kv
: pprops
) {
93 out
<< clsName
<< "->" << kv
.first
->data() << " :: "
94 << show(kv
.second
.ty
) << '\n';
97 auto const sprops
= sorted_prop_state(
98 index
.lookup_private_statics(c
)
100 for (auto const& kv
: sprops
) {
101 out
<< clsName
<< "::$" << kv
.first
->data() << " :: "
102 << show(kv
.second
.ty
) << '\n';
105 for (auto const& prop
: c
->properties
) {
106 out
<< clsName
<< "::$" << prop
.name
->data() << " :: "
107 << show(index
.lookup_public_static(Context
{}, c
, prop
.name
)) << '\n';
111 for (auto const& constant
: c
->constants
) {
113 auto const ty
= from_cell(*constant
.val
);
114 out
<< clsName
<< "::" << constant
.name
->data() << " :: "
115 << (ty
.subtypeOf(BUninit
) ? "<dynamic>" : show(ty
)) << '\n';
120 void dump_func_state(std::ostream
& out
,
122 const php::Func
* f
) {
123 if (f
->unit
->pseudomain
.get() == f
) return;
125 auto const name
= f
->cls
128 normalized_class_name(*f
->cls
), f
->name
->data()
130 : folly::sformat("{}()", f
->name
->toCppString());
132 auto const retTy
= index
.lookup_return_type_raw(f
);
133 out
<< name
<< " :: " << show(retTy
) << '\n';
138 //////////////////////////////////////////////////////////////////////
140 std::string
debug_dump_to() {
141 if (!Trace::moduleEnabledRelease(Trace::hhbbc_dump
, 1)) return "";
143 trace_time
tracer("debug dump");
146 if (auto const dumpDir
= getenv("HHBBC_DUMP_DIR")) {
147 return fs::path(dumpDir
);
149 char dirBuf
[] = "/tmp/hhbbcXXXXXX";
150 auto const dtmpRet
= mkdtemp(dirBuf
);
152 throw std::runtime_error(
153 std::string("Failed to create temporary directory") +
156 return fs::path(dtmpRet
);
159 fs::create_directory(dir
);
161 Trace::ftraceRelease("debug dump going to {}\n", dir
.string());
165 void dump_representation(const std::string
& dir
, const php::Unit
* unit
) {
166 auto const rep_dir
= fs::path
{dir
} / "representation";
167 with_file(rep_dir
, unit
, [&] (std::ostream
& out
) {
168 out
<< show(*unit
, true);
173 void dump_index(const std::string
& dir
,
175 const php::Unit
* unit
) {
176 if (!*unit
->filename
->data()) {
177 // The native systemlibs: for now just skip.
181 auto ind_dir
= fs::path
{dir
} / "index";
183 with_file(ind_dir
, unit
, [&] (std::ostream
& out
) {
184 for (auto& c
: unit
->classes
) {
185 dump_class_state(out
, index
, c
.get());
186 for (auto& m
: c
->methods
) {
187 dump_func_state(out
, index
, m
.get());
191 for (auto& f
: unit
->funcs
) {
192 dump_func_state(out
, index
, f
.get());
198 void debug_dump_program(const Index
& index
, const php::Program
& program
) {
199 auto const dir
= debug_dump_to();
200 if (dir
.empty()) return;
202 if (Trace::moduleEnabledRelease(Trace::hhbbc_dump
, 2)) {
203 trace_time
tracer2("debug dump: representation");
206 [&] (const std::unique_ptr
<php::Unit
>& u
) {
207 dump_representation(dir
, u
.get());
213 trace_time
tracer2("debug dump: index");
216 [&] (const std::unique_ptr
<php::Unit
>& u
) {
217 dump_index(dir
, index
, u
.get());
222 Trace::ftraceRelease("debug dump done\n");
225 //////////////////////////////////////////////////////////////////////