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