Skip to content

Commit ded625a

Browse files
committed
[DRAFT][lldb] Upstream lldb-rpc-gen and LLDB RPC server-side emitters
This commit upstreams lldb-rpc-gen, a tool that emits the client and server interfaces used for LLDB RPC. This is the initial commit in the upstreaming process for LLDB RPC. lldb-rpc-gen is a ClangTool that reads the LLDB SB API headers and uses their information to generate the interfaces for RPC. This commit specifically adds the server-side emitters for easier review. The client-side interface will be added in a later commit. RFC: https://discourse.llvm.org/t/rfc-upstreaming-lldb-rpc/85804
1 parent d35bf17 commit ded625a

15 files changed

+2386
-0
lines changed
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
#!/usr/bin/env python3
2+
# Usage: convert-lldb-header-to-rpc-header.py <path/to/input-header.h> <path/to/output-header.h>
3+
4+
import argparse
5+
import os
6+
import re
7+
import subprocess
8+
9+
10+
def main():
11+
parser = argparse.ArgumentParser()
12+
parser.add_argument("input")
13+
parser.add_argument("output")
14+
args = parser.parse_args()
15+
input_path = str(args.input)
16+
output_path = str(args.output)
17+
with open(input_path, "r+") as input_file:
18+
lines = input_file.readlines()
19+
20+
with open(output_path, "w+") as output_file:
21+
for line in lines:
22+
# NOTE: We do not use lldb-forward or lldb-versioning in RPC.
23+
if re.match(
24+
r'#include "lldb/lldb-forward|#include "lldb/lldb-versioning', line
25+
):
26+
continue
27+
# For lldb-defines.h
28+
elif re.match(r".+LLDB_LLDB_", line):
29+
output_file.write(re.sub(r"LLDB_LLDB_", r"LLDB_RPC_", line))
30+
# For SBDefines.h
31+
elif re.match(r".+LLDB_API_", line):
32+
output_file.write(re.sub(r"LLDB_API_", r"LLDB_RPC_API_", line))
33+
# For lldb-rpc-version.h and lldb-rpc-defines.h
34+
elif re.match(r".+LLDB_VERSION", line):
35+
output_file.write(re.sub(r"LLDB_VERSION", r"LLDB_RPC_VERSION", line))
36+
elif re.match(r".+LLDB_REVISION", line):
37+
output_file.write(re.sub(r"LLDB_REVISION", r"LLDB_RPC_REVISION", line))
38+
elif re.match(r".+LLDB_VERSION_STRING", line):
39+
output_file.write(
40+
re.sub(r"LLDB_VERSION_STRING", r"LLDB_RPC_VERSION_STRING", line)
41+
)
42+
# For local #includes
43+
elif re.match(r'#include "lldb/lldb-', line):
44+
output_file.write(re.sub(r"lldb/lldb-", r"lldb-rpc-", line))
45+
# Rename the lldb namespace to lldb-rpc
46+
elif re.match(r"namespace lldb", line):
47+
output_file.write(re.sub(r"lldb", r"lldb_rpc", line))
48+
# Rename namespace references
49+
elif re.match(r".+lldb::", line):
50+
output_file.write(re.sub(r"lldb::", r"lldb_rpc::", line))
51+
else:
52+
# Write any line that doesn't need to be converted
53+
output_file.write(line)
54+
55+
56+
if __name__ == "__main__":
57+
main()
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
#!/usr/bin/env python3
2+
# Usage: framework-header-include-fix.py <path/to/input-header.h> <path/to/output-header.h>
3+
4+
import argparse
5+
import os
6+
import re
7+
import subprocess
8+
9+
10+
def main():
11+
parser = argparse.ArgumentParser()
12+
parser.add_argument("input")
13+
parser.add_argument("output")
14+
args = parser.parse_args()
15+
input_path = str(args.input)
16+
output_path = str(args.output)
17+
with open(input_path, "r+") as input_file:
18+
lines = input_file.readlines()
19+
20+
with open(output_path, "w+") as output_file:
21+
for line in lines:
22+
if re.match(r".+<lldb-rpc/common", line):
23+
output_file.write(re.sub(r"<lldb-rpc/common", r"<LLDBRPC", line))
24+
elif re.match(r'#include "(.*)"', line):
25+
include_filename = re.search(r'#include "(.*)"', line).groups()[0]
26+
output_file.write(
27+
re.sub(
28+
r'#include "(.*)"',
29+
r"#include <LLDBRPC/" + include_filename + ">",
30+
line,
31+
)
32+
)
33+
else:
34+
# Write any line that doesn't need to be converted
35+
output_file.write(line)
36+
37+
38+
if __name__ == "__main__":
39+
main()
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
#!/usr/bin/env python3
2+
# Usage: framework-header-version-fix.py <path/to/input-header.h> <path/to/output-header.h> MAJOR MINOR PATCH
3+
4+
import argparse
5+
import os
6+
import re
7+
import subprocess
8+
9+
10+
def main():
11+
parser = argparse.ArgumentParser()
12+
parser.add_argument("input")
13+
parser.add_argument("output")
14+
parser.add_argument("lldb_version_major")
15+
parser.add_argument("lldb_version_minor")
16+
parser.add_argument("lldb_version_patch")
17+
args = parser.parse_args()
18+
input_path = str(args.input)
19+
output_path = str(args.output)
20+
lldb_version_major = str(args.lldb_version_major)
21+
lldb_version_minor = str(args.lldb_version_minor)
22+
lldb_version_patch = str(args.lldb_version_patch)
23+
24+
with open(input_path, "r+") as input_file:
25+
lines = input_file.readlines()
26+
27+
with open(output_path, "w+") as output_file:
28+
for line in lines:
29+
if re.match(r"//#define LLDB_RPC_VERSION$", line):
30+
output_file.write(
31+
re.sub(
32+
r"//#define LLDB_RPC_VERSION",
33+
r"#define LLDB_RPC_VERSION " + lldb_version_major,
34+
line,
35+
)
36+
)
37+
elif re.match(r"//#define LLDB_RPC_REVISION$", line):
38+
output_file.write(
39+
re.sub(
40+
r"//#define LLDB_RPC_REVISION",
41+
r"#define LLDB_RPC_REVISION " + lldb_version_minor,
42+
line,
43+
)
44+
)
45+
elif re.match(r"//#define LLDB_RPC_VERSION_STRING$", line):
46+
output_file.write(
47+
re.sub(
48+
r"//#define LLDB_RPC_VERSION_STRING",
49+
r'#define LLDB_RPC_VERSION_STRING "{0}.{1}.{2}"'.format(
50+
lldb_version_major, lldb_version_minor, lldb_version_patch
51+
),
52+
line,
53+
)
54+
)
55+
else:
56+
# Write any line that doesn't need to be converted
57+
output_file.write(line)
58+
59+
60+
if __name__ == "__main__":
61+
main()

lldb/tools/CMakeLists.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@ add_subdirectory(intel-features)
77
# example is `check-lldb`. So, we pass EXCLUDE_FROM_ALL here.
88
add_subdirectory(lldb-test EXCLUDE_FROM_ALL)
99
add_subdirectory(lldb-fuzzer EXCLUDE_FROM_ALL)
10+
add_subdirectory(lldb-rpc EXCLUDE_FROM_ALL)
11+
1012

1113
add_lldb_tool_subdirectory(lldb-instr)
1214
add_lldb_tool_subdirectory(lldb-dap)

lldb/tools/lldb-rpc/CMakeLists.txt

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
if(LLDB_CODESIGN_IDENTITY)
2+
# Use explicit LLDB identity
3+
set(LLVM_CODESIGNING_IDENTITY ${LLDB_CODESIGN_IDENTITY})
4+
else()
5+
# Use explicit LLVM identity or default to ad-hoc signing if empty
6+
if(NOT LLVM_CODESIGNING_IDENTITY)
7+
set(LLVM_CODESIGNING_IDENTITY -)
8+
endif()
9+
endif()
10+
11+
check_cxx_compiler_flag("-Wno-gnu-zero-variadic-macro-arguments"
12+
CXX_SUPPORTS_NO_GNU_ZERO_VARIADIC_MACRO_ARGUMENTS)
13+
14+
# LLDBRPCGeneration.cmake needs the LLDB_RPC_GEN_EXE variable
15+
# which gets defined in the lldb-rpc-gen folder, so we're adding
16+
# this folder before we add that file.
17+
add_lldb_tool_subdirectory(lldb-rpc-gen)
18+
include(${CMAKE_CURRENT_SOURCE_DIR}/LLDBRPCGeneration.cmake)
19+
include(${CMAKE_CURRENT_SOURCE_DIR}/LLDBRPCHeaders.cmake)
Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
if (NOT DEFINED LLDB_RPC_GEN_EXE)
2+
message(FATAL_ERROR
3+
"Unable to generate lldb-rpc sources because LLDB_RPC_GEN_EXE is not
4+
defined. If you are cross-compiling, please build lldb-rpc-gen for your host
5+
platform.")
6+
endif()
7+
set(lldb_rpc_generated_dir "${CMAKE_CURRENT_BINARY_DIR}/generated")
8+
set(lldb_rpc_server_generated_source_dir "${lldb_rpc_generated_dir}/server")
9+
set(lldb_rpc_lib_generated_source_dir "${lldb_rpc_generated_dir}/lib")
10+
set(lldb_rpc_client_generated_source_dir "${lldb_rpc_generated_dir}/client")
11+
12+
file(GLOB api_headers ${LLDB_SOURCE_DIR}/include/lldb/API/SB*.h)
13+
# We don't generate SBCommunication
14+
list(REMOVE_ITEM api_headers ${LLDB_SOURCE_DIR}/include/lldb/API/SBCommunication.h)
15+
# SBDefines.h is mostly definitions and forward declarations, nothing to
16+
# generate.
17+
list(REMOVE_ITEM api_headers ${LLDB_SOURCE_DIR}/include/lldb/API/SBDefines.h)
18+
19+
# Generate the list of byproducts. Note that we cannot just glob the files in
20+
# the directory with the generated sources because BYPRODUCTS needs to be known
21+
# at configure time but the files are generated at build time.
22+
set(lldb_rpc_gen_byproducts
23+
${lldb_rpc_generated_dir}/SBClasses.def
24+
${lldb_rpc_generated_dir}/SBAPI.def
25+
${lldb_rpc_generated_dir}/lldb.py
26+
${lldb_rpc_server_generated_source_dir}/SBAPI.h
27+
${lldb_rpc_lib_generated_source_dir}/LLDBRPC.h
28+
)
29+
30+
set(lldb_rpc_gen_server_impl_files)
31+
set(lldb_rpc_gen_lib_header_files)
32+
set(lldb_rpc_gen_lib_impl_files)
33+
foreach(path ${api_headers})
34+
get_filename_component(filename_no_ext ${path} NAME_WLE)
35+
36+
set(server_header_file "Server_${filename_no_ext}.h")
37+
list(APPEND lldb_rpc_gen_byproducts "${lldb_rpc_server_generated_source_dir}/${server_header_file}")
38+
39+
set(server_impl_file "Server_${filename_no_ext}.cpp")
40+
list(APPEND lldb_rpc_gen_byproducts "${lldb_rpc_server_generated_source_dir}/${server_impl_file}")
41+
list(APPEND lldb_rpc_gen_server_impl_files "${lldb_rpc_server_generated_source_dir}/${server_impl_file}")
42+
43+
set(lib_header_file "${filename_no_ext}.h")
44+
list(APPEND lldb_rpc_gen_byproducts "${lldb_rpc_lib_generated_source_dir}/${lib_header_file}")
45+
list(APPEND lldb_rpc_gen_lib_header_files "${lldb_rpc_lib_generated_source_dir}/${lib_header_file}")
46+
47+
set(lib_impl_file "${filename_no_ext}.cpp")
48+
list(APPEND lldb_rpc_gen_byproducts "${lldb_rpc_lib_generated_source_dir}/${lib_impl_file}")
49+
list(APPEND lldb_rpc_gen_lib_impl_files "${lldb_rpc_lib_generated_source_dir}/${lib_impl_file}")
50+
endforeach()
51+
list(APPEND lldb_rpc_gen_lib_impl_files "${CMAKE_CURRENT_BINARY_DIR}/generated/lib/RPCClientSideCallbacks.cpp")
52+
list(APPEND lldb_rpc_gen_lib_header_files "${lldb_rpc_lib_generated_source_dir}/LLDBRPC.h")
53+
54+
# Make sure that the clang-resource-dir is set correctly or else the tool will
55+
# fail to run. This is only needed when we do a standalone build.
56+
set(clang_resource_dir_arg)
57+
if (LLDB_BUILT_STANDALONE)
58+
if (TARGET clang-resource-headers)
59+
set(clang_resource_headers_dir
60+
$<TARGET_PROPERTY:clang-resource-headers,INTERFACE_INCLUDE_DIRECTORIES>)
61+
set(clang_resource_dir_arg --extra-arg="-resource-dir=${clang_resource_headers_dir}/..")
62+
else()
63+
set(clang_resource_dir_arg --extra-arg="-resource-dir=${LLDB_EXTERNAL_CLANG_RESOURCE_DIR}")
64+
endif()
65+
endif()
66+
67+
add_custom_command(OUTPUT ${lldb_rpc_gen_byproducts}
68+
COMMAND ${CMAKE_COMMAND} -E make_directory
69+
${lldb_rpc_generated_dir}
70+
71+
COMMAND ${CMAKE_COMMAND} -E make_directory
72+
${lldb_rpc_server_generated_source_dir}
73+
74+
COMMAND ${CMAKE_COMMAND} -E make_directory
75+
${lldb_rpc_lib_generated_source_dir}
76+
77+
COMMAND ${CMAKE_COMMAND} -E make_directory
78+
${lldb_rpc_client_generated_source_dir}
79+
80+
COMMAND ${LLDB_RPC_GEN_EXE}
81+
-p ${CMAKE_BINARY_DIR}
82+
--output-dir=${lldb_rpc_generated_dir}
83+
${clang_resource_dir_arg}
84+
--extra-arg="-USWIG"
85+
${api_headers}
86+
87+
DEPENDS ${LLDB_RPC_GEN_EXE} ${api_headers}
88+
COMMENT "Generating sources for lldb-rpc-server..."
89+
WORKING_DIRECTORY ${CMAKE_BINARY_DIR}
90+
)
91+
92+
add_custom_target(lldb-rpc-generate-sources
93+
DEPENDS
94+
${lldb_rpc_gen_byproducts}
95+
lldb-sbapi-dwarf-enums)

0 commit comments

Comments
 (0)