[DBGHELP] Add experimental rsym support. CORE-12773
[reactos.git] / reactos / dll / win32 / dbghelp / rsym.c
1 /*
2 * PROJECT: ReactOS dbghelp extension
3 * LICENSE: GPLv2+ - See COPYING in the top level directory
4 * PURPOSE: Parse rsym information for use with dbghelp
5 * PROGRAMMER: Mark Jansen
6 */
7
8 #include "dbghelp_private.h"
9 #include <reactos/rossym.h>
10
11 WINE_DEFAULT_DEBUG_CHANNEL(dbghelp_rsym);
12
13
14 typedef struct rsym_file_entry_s
15 {
16 const char* File;
17 unsigned Source;
18 } rsym_file_entry_t;
19
20 typedef struct rsym_func_entry_s
21 {
22 ULONG_PTR Address;
23 struct symt_function* func;
24 struct rsym_func_entry_s* next;
25 } rsym_func_entry_t;
26
27
28
29 /******************************************************************
30 * rsym_finalize_function (copied from stabs_finalize_function)
31 *
32 * Ends function creation: mainly:
33 * - cleans up line number information
34 * - tries to set up a debug-start tag (FIXME: heuristic to be enhanced)
35 */
36 static void rsym_finalize_function(struct module* module, struct symt_function* func)
37 {
38 IMAGEHLP_LINE64 il;
39 struct location loc;
40
41 if (!func) return;
42 symt_normalize_function(module, func);
43 /* To define the debug-start of the function, we use the second line number.
44 * Not 100% bullet proof, but better than nothing
45 */
46 if (symt_fill_func_line_info(module, func, func->address, &il) &&
47 symt_get_func_line_next(module, &il))
48 {
49 loc.kind = loc_absolute;
50 loc.offset = il.Address - func->address;
51 symt_add_function_point(module, func, SymTagFuncDebugStart,
52 &loc, NULL);
53 }
54 }
55
56
57 static int is_metadata_sym(const char* name)
58 {
59 ULONG len = name ? strlen(name) : 0;
60 return len > 3 && name[0] == '_' && name[1] != '_' && name[len-1] == '_' && name[len-2] == '_';
61 };
62
63 static int use_raw_address(const char* name)
64 {
65 if (!name)
66 return 0;
67
68 if (!strcmp(name, "__ImageBase"))
69 return 1;
70
71 if (!strcmp(name, "__RUNTIME_PSEUDO_RELOC_LIST__"))
72 return 1;
73
74 return 0;
75 }
76
77
78 BOOL rsym_parse(struct module* module, unsigned long load_offset,
79 const void* rsym_ptr, int rsymlen)
80 {
81 const ROSSYM_HEADER* RosSymHeader;
82 const ROSSYM_ENTRY* First, *Last, *Entry;
83 const CHAR* Strings;
84
85 struct pool pool;
86 struct sparse_array file_table, func_table;
87 rsym_func_entry_t* first_func = NULL;
88
89
90 RosSymHeader = rsym_ptr;
91
92 if (RosSymHeader->SymbolsOffset < sizeof(ROSSYM_HEADER)
93 || RosSymHeader->StringsOffset < RosSymHeader->SymbolsOffset + RosSymHeader->SymbolsLength
94 || rsymlen < RosSymHeader->StringsOffset + RosSymHeader->StringsLength
95 || 0 != (RosSymHeader->SymbolsLength % sizeof(ROSSYM_ENTRY)))
96 {
97 WARN("Invalid ROSSYM_HEADER\n");
98 return FALSE;
99 }
100
101 First = (const ROSSYM_ENTRY *)((const char*)rsym_ptr + RosSymHeader->SymbolsOffset);
102 Last = First + RosSymHeader->SymbolsLength / sizeof(ROSSYM_ENTRY);
103 Strings = (const CHAR*)rsym_ptr + RosSymHeader->StringsOffset;
104
105 pool_init(&pool, 65536);
106 sparse_array_init(&file_table, sizeof(rsym_file_entry_t), 64);
107 sparse_array_init(&func_table, sizeof(rsym_func_entry_t), 128);
108
109 for (Entry = First; Entry != Last; Entry++)
110 {
111 ULONG Address = load_offset + Entry->Address;
112 if (!Entry->FileOffset)
113 {
114 rsym_func_entry_t* func = sparse_array_find(&func_table, Entry->FunctionOffset);
115
116 /* We do not want to define a data point where there is already a function! */
117 if (!func || func->Address != Address)
118 {
119 const char* SymbolName = Strings + Entry->FunctionOffset;
120 if (!is_metadata_sym(SymbolName))
121 {
122 /* TODO: How should we determine the size? */
123 ULONG Size = sizeof(ULONG);
124 if (use_raw_address(SymbolName))
125 Address = Entry->Address;
126
127 symt_new_public(module, NULL, SymbolName, Address, Size);
128 }
129 else
130 {
131 /* Maybe use it to fill some metadata? */
132 }
133 }
134 }
135 else
136 {
137 rsym_file_entry_t* file = sparse_array_find(&file_table, Entry->FileOffset);
138 rsym_func_entry_t* func = sparse_array_find(&func_table, Entry->FunctionOffset);
139
140 if (!file)
141 {
142 file = sparse_array_add(&file_table, Entry->FileOffset, &pool);
143 file->File = Strings + Entry->FileOffset;
144 file->Source = source_new(module, NULL, Strings + Entry->FileOffset);
145 }
146
147 if (!func)
148 {
149 func = sparse_array_add(&func_table, Entry->FunctionOffset, &pool);
150 func->func = symt_new_function(module, NULL, Strings + Entry->FunctionOffset,
151 Address, 0, NULL);
152 func->Address = Address;
153 func->next = first_func;
154 first_func = func;
155 }
156
157 /* TODO: What if we have multiple chunks scattered around? */
158 symt_add_func_line(module, func->func, file->Source, Entry->SourceLine, Address - func->Address);
159 }
160 }
161
162 while (first_func)
163 {
164 /* TODO: Size of function? */
165 rsym_finalize_function(module, first_func->func);
166 first_func = first_func->next;
167 }
168
169 module->module.SymType = SymDia;
170 module->module.CVSig = 'R' | ('S' << 8) | ('Y' << 16) | ('M' << 24);
171 module->module.LineNumbers = TRUE;
172 module->module.GlobalSymbols = TRUE;
173 module->module.TypeInfo = FALSE;
174 module->module.SourceIndexed = TRUE;
175 module->module.Publics = TRUE;
176
177 pool_destroy(&pool);
178
179 return TRUE;
180 }
181