00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042 #include <stdlib.h>
00043 #include <stdio.h>
00044 #include <strings.h>
00045 #include <sys/unwindP.h>
00046 #include "unwind_producer.h"
00047
00048
00049
00050
00051 __unw_table_entry_t *_unwind_table = NULL;
00052 __uint64_t _unwind_table_total_size = 0L;
00053 __uint64_t _unwind_table_size = 0L;
00054
00055 __unw_table_entry_t _current_unwind_table_entry = { 0L, 0L, 0L };
00056
00057
00058 __unw_info_t *_unwind_info = NULL;
00059 __uint64_t _unwind_info_total_size = 0L;
00060 __uint64_t _unwind_info_size = 0L;
00061
00062 __unw_info_t *_current_unwind_info = NULL;
00063 __uint64_t _current_unwind_info_total_size = 0L;
00064 __uint64_t _current_unwind_info_size = 0L;
00065
00066
00067 __uint64_t _current_procedure_size = 0L;
00068 __uint64_t _current_procedure_total_size = 0L;
00069 __uint64_t _current_region_total_size = 0L;
00070 __uint32_t _current_region_id = __UNW_UNDEF;
00071
00072
00073 __uint32_t _ehandler = 0;
00074 __uint32_t _uhandler = 0;
00075
00076
00077 __unw_addr_t _personality = 0L;
00078
00079
00080 void *_lang_spec_data = NULL;
00081 __uint64_t _lang_spec_data_size = 0L;
00082 __uint64_t _lang_spec_data_total_size = 0L;
00083
00084
00085 void *_imask = NULL;
00086 __uint64_t _imask_size = 0L;
00087 __uint64_t _imask_total_size = 0L;
00088
00089
00090 static const char _null_array[] = {
00091 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
00092 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
00093 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
00094 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
00095 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
00096 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
00097 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
00098 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
00099 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
00100 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
00101 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
00102 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
00103 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
00104 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
00105 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
00106 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
00107
00108
00109
00110
00111 __unw_error_t unwind_info_add_desc(__uint64_t size, char *buf) {
00112
00113 #ifdef DEBUG
00114 __uint64_t i;
00115 fprintf(stderr, "unwind_info_add_desc(): size=%llu \"",
00116 (unsigned long long)size);
00117 for (i = 0; i < size; i++) {
00118 fprintf(stderr, "%02x", (unsigned char)buf[i]);
00119 }
00120 fprintf(stderr, "\"\n");
00121 #endif
00122
00123 _current_unwind_info_size += size;
00124 while (_current_unwind_info_size >= _current_unwind_info_total_size) {
00125 _current_unwind_info_total_size *= 2;
00126 if (NULL == (_current_unwind_info =
00127 (__unw_info_t *)realloc((void *)_current_unwind_info,
00128 (size_t)_current_unwind_info_total_size))) {
00129 unwind_cleanup();
00130 return __UNW_REALLOC_ERROR;
00131 }
00132 #ifdef DEBUG
00133 fprintf(stderr, "unwind_info_add_desc(): ");
00134 fprintf(stderr, "reallocated _current_unwind_info @ 0x%llx, ",
00135 (unsigned long long)_current_unwind_info);
00136 fprintf(stderr, "total_size=%llu\n",
00137 (unsigned long long)_current_unwind_info_total_size);
00138 #endif
00139 }
00140 bcopy((const void *)buf, (void *)((char *)_current_unwind_info +
00141 _current_unwind_info_size - size), (size_t)size);
00142 #ifdef DEBUG
00143 fprintf(stderr, "unwind_info_add_desc(): ");
00144 fprintf(stderr, "updated _current_unwind_info @ 0x%llx, ",
00145 (unsigned long long)_current_unwind_info);
00146 fprintf(stderr, "size=%llu+%u, total_size=%llu\n",
00147 (unsigned long long)_current_unwind_info_size -
00148 (unsigned long long)size,
00149 size,
00150 (unsigned long long)_current_unwind_info_total_size);
00151 #endif
00152
00153 return __UNW_OK;
00154 }
00155
00156
00157
00158
00159 __unw_error_t unwind_info_initialize(__unw_info_t **info,
00160 __unw_addr_t start, __unw_addr_t end) {
00161
00162
00163 *info = NULL;
00164
00165
00166 if (NULL == _unwind_table) {
00167 _unwind_table_total_size = __UNW_TABLE_ENTRIES_SIZE;
00168 if (NULL == (_unwind_table =
00169 (__unw_table_entry_t *)malloc((size_t)
00170 (_unwind_table_total_size *
00171 sizeof(__unw_table_entry_t))))) {
00172 unwind_cleanup();
00173 return __UNW_MALLOC_ERROR;
00174 }
00175 #ifdef DEBUG
00176 fprintf(stderr, "unwind_info_initialize(): ");
00177 fprintf(stderr, "allocated _unwind_table @ 0x%llx, ",
00178 (unsigned long long)_unwind_table);
00179 fprintf(stderr, "total_size=%llu*%u\n",
00180 (unsigned long long)_unwind_table_total_size,
00181 sizeof(__unw_table_entry_t));
00182 #endif
00183 }
00184
00185
00186 if (NULL == _unwind_info) {
00187 _unwind_info_total_size = __UNW_INFO_SIZE;
00188 if (NULL == (_unwind_info =
00189 (__unw_info_t *)malloc((size_t)
00190 _unwind_info_total_size))) {
00191 unwind_cleanup();
00192 return __UNW_MALLOC_ERROR;
00193 }
00194 #ifdef DEBUG
00195 fprintf(stderr, "unwind_info_initialize(): ");
00196 fprintf(stderr, "allocated _unwind_info @ 0x%llx, total_size=%llu\n",
00197 (unsigned long long)_unwind_info,
00198 (unsigned long long)_unwind_info_total_size);
00199 #endif
00200 }
00201
00202
00203 if (NULL == _current_unwind_info) {
00204 _current_unwind_info_total_size = __UNW_CURRENT_INFO_SIZE;
00205 if (NULL == (_current_unwind_info =
00206 (__unw_info_t *)malloc((size_t)
00207 _current_unwind_info_total_size))) {
00208 unwind_cleanup();
00209 return __UNW_MALLOC_ERROR;
00210 }
00211 #ifdef DEBUG
00212 fprintf(stderr, "unwind_info_initialize(): ");
00213 fprintf(stderr, "allocated _current_unwind_info @ 0x%llx, ",
00214 (unsigned long long)_current_unwind_info);
00215 fprintf(stderr, "total_size=%llu\n",
00216 (unsigned long long)_current_unwind_info_total_size);
00217 #endif
00218 }
00219
00220
00221 _current_unwind_table_entry._start = start;
00222 _current_unwind_table_entry._end = end;
00223 _current_unwind_table_entry._info = (__unw_addr_t)_unwind_info_size;
00224
00225
00226 _current_unwind_info->_header = 0x0000000000000000L;
00227 _current_unwind_info_size = sizeof(__unw_dbl_word_t);
00228
00229
00230 _current_procedure_size = 0L;
00231 _current_procedure_total_size = (__uint64_t)(start - end) * 3;
00232 _current_region_total_size = 0L;
00233
00234
00235 _ehandler = 0;
00236 _uhandler = 0;
00237 _personality = 0L;
00238
00239
00240 _lang_spec_data_size = 0L;
00241
00242
00243 *info = _unwind_info + _unwind_info_size;
00244
00245 return __UNW_OK;
00246 }
00247
00248
00249
00250
00251
00252 __unw_error_t unwind_info_finalize(__unw_info_t *info) {
00253 __uint64_t real_size = 0L;
00254 __unw_error_t ret;
00255
00256
00257 if (NULL == info) {
00258 return __UNW_NULL_ERROR;
00259 } else if (_unwind_info + _unwind_info_size != info) {
00260 return __UNW_INV_ARG_ERROR;
00261 }
00262
00263
00264
00265 if ((__UNW_PROLOGUE == _current_region_id) && (0L != _imask_size)) {
00266 unwind_info_add_imask(info);
00267 }
00268
00269
00270 if (0L == _current_unwind_info_size) {
00271 #ifdef DEBUG
00272 fprintf(stderr, "unwind_info_finalize(): ");
00273 fprintf(stderr, "_current_unwind_info @ 0x%llx has 0 size\n",
00274 (unsigned long long)_current_unwind_info);
00275 #endif
00276 return __UNW_OK;
00277 }
00278
00279
00280 if (_unwind_table_size + 1 >= _unwind_table_total_size) {
00281 _unwind_table_total_size *= 2;
00282 if (NULL == (_unwind_table =
00283 (__unw_table_entry_t *)realloc((void *)_unwind_table,
00284 (size_t)(_unwind_table_total_size *
00285 sizeof(__unw_table_entry_t))))) {
00286 unwind_cleanup();
00287 return __UNW_REALLOC_ERROR;
00288 }
00289 #ifdef DEBUG
00290 fprintf(stderr, "unwind_info_finalize(): ");
00291 fprintf(stderr, "reallocated _unwind_table @ 0x%llx, ",
00292 (unsigned long long)_unwind_table);
00293 fprintf(stderr, "total_size=%llu*%u\n",
00294 (unsigned long long)_unwind_table_total_size,
00295 sizeof(__unw_table_entry_t));
00296 #endif
00297 }
00298 _unwind_table[_unwind_table_size++] = _current_unwind_table_entry;
00299 #ifdef DEBUG
00300 fprintf(stderr, "unwind_info_finalize(): ");
00301 fprintf(stderr, "updated _unwind_table @ 0x%llx, ",
00302 (unsigned long long)_unwind_table);
00303 fprintf(stderr, "size=(%llu+1)*%u, total_size=%llu*%u\n",
00304 (unsigned long long)_unwind_table_size-1,
00305 sizeof(__unw_table_entry_t),
00306 (unsigned long long)_unwind_table_total_size,
00307 sizeof(__unw_table_entry_t));
00308 #endif
00309
00310
00311 real_size = (_current_unwind_info_size + sizeof(__unw_dbl_word_t) - 1) /
00312 sizeof(__unw_dbl_word_t);
00313
00314
00315 _current_unwind_info->_header = __UNW_VERSION;
00316 _current_unwind_info->_header <<= 48;
00317 if (_ehandler) {
00318 _current_unwind_info->_header |= 0x0000000100000000LL;
00319 }
00320 if (_uhandler) {
00321 _current_unwind_info->_header |= 0x0000000200000000LL;
00322 }
00323 _current_unwind_info->_header |= (__uint32_t)(real_size - 1);
00324
00325
00326 real_size *= sizeof(__unw_dbl_word_t);
00327 if (real_size != _current_unwind_info_size) {
00328 unwind_info_add_desc((__uint64_t)(real_size -
00329 _current_unwind_info_size), (char *)_null_array);
00330 }
00331
00332
00333
00334 if (_personality) {
00335 ret = unwind_info_add_desc((__uint64_t)sizeof(__unw_addr_t),
00336 (char *)&_personality);
00337
00338
00339 real_size = (sizeof(__unw_addr_t) + sizeof(__unw_dbl_word_t) - 1) /
00340 sizeof(__unw_dbl_word_t);
00341 real_size *= sizeof(__unw_dbl_word_t);
00342 if (real_size != sizeof(__unw_addr_t)) {
00343 unwind_info_add_desc((__uint64_t)(real_size -
00344 sizeof(__unw_addr_t)), (char *)_null_array);
00345 }
00346
00347
00348 if (__UNW_OK != ret) {
00349 return ret;
00350 }
00351 }
00352
00353
00354
00355 if (_lang_spec_data_size) {
00356 ret = unwind_info_add_desc(_lang_spec_data_size,
00357 (char *)_lang_spec_data);
00358
00359
00360 real_size = (_lang_spec_data_size + sizeof(__unw_dbl_word_t) - 1) /
00361 sizeof(__unw_dbl_word_t);
00362 real_size *= sizeof(__unw_dbl_word_t);
00363 if (real_size != _lang_spec_data_size) {
00364 unwind_info_add_desc((__uint64_t)(real_size -
00365 _lang_spec_data_size), (char *)_null_array);
00366 }
00367
00368
00369 if (__UNW_OK != ret) {
00370 return ret;
00371 }
00372 }
00373
00374
00375 if (_current_unwind_info_size % sizeof(__unw_dbl_word_t) != 0) {
00376 return __UNW_INV_ALIGNMENT_ERROR;
00377 }
00378 _unwind_info_size += _current_unwind_info_size;
00379 while (_unwind_info_size >= _unwind_info_total_size) {
00380 _unwind_info_total_size *= 2;
00381 if (NULL == (_unwind_info =
00382 (__unw_info_t *)realloc((void *)_unwind_info,
00383 (size_t)_unwind_info_total_size))) {
00384 unwind_cleanup();
00385 return __UNW_REALLOC_ERROR;
00386 }
00387 #ifdef DEBUG
00388 fprintf(stderr, "unwind_info_finalize(): ");
00389 fprintf(stderr, "reallocated _unwind_info @ 0x%llx, ",
00390 (unsigned long long)_unwind_info);
00391 fprintf(stderr, "total_size=%llu\n",
00392 (unsigned long long)_unwind_info_total_size);
00393 #endif
00394 }
00395 bcopy((const void *)_current_unwind_info,
00396 (void *)((char *)_unwind_info + _unwind_info_size - _current_unwind_info_size),
00397 (size_t)_current_unwind_info_size);
00398 #ifdef DEBUG
00399 fprintf(stderr, "unwind_info_finalize(): ");
00400 fprintf(stderr, "updated _unwind_info @ 0x%llx, ",
00401 (unsigned long long)_unwind_info);
00402 fprintf(stderr, "size=%llu+%llu total_size=%llu\n",
00403 (unsigned long long)_unwind_info_size -
00404 (unsigned long long)_current_unwind_info_size,
00405 (unsigned long long)_current_unwind_info_size,
00406 (unsigned long long)_unwind_info_total_size);
00407 #endif
00408
00409 return __UNW_OK;
00410 }
00411
00412
00413
00414
00415 __unw_error_t unwind_cleanup(void) {
00416
00417
00418 if (_unwind_table) {
00419 free(_unwind_table);
00420 #ifdef DEBUG
00421 fprintf(stderr, "unwind_cleanup(): ");
00422 fprintf(stderr, "deallocated _unwind_table @ 0x%llx\n",
00423 (unsigned long long)_unwind_table);
00424 #endif
00425 }
00426
00427
00428 if (_unwind_info) {
00429 free(_unwind_info);
00430 #ifdef DEBUG
00431 fprintf(stderr, "unwind_cleanup(): ");
00432 fprintf(stderr, "deallocated _unwind_info @ 0x%llx\n",
00433 (unsigned long long)_unwind_info);
00434 #endif
00435 }
00436
00437
00438 if (_current_unwind_info) {
00439 free(_current_unwind_info);
00440 #ifdef DEBUG
00441 fprintf(stderr, "unwind_cleanup(): ");
00442 fprintf(stderr, "deallocated _current_unwind_info @ 0x%llx\n",
00443 (unsigned long long)_current_unwind_info);
00444 #endif
00445 }
00446
00447
00448 if (_lang_spec_data) {
00449 free(_lang_spec_data);
00450 #ifdef DEBUG
00451 fprintf(stderr, "unwind_cleanup(): ");
00452 fprintf(stderr, "deallocated _lang_spec_data @ 0x%llx\n",
00453 (unsigned long long)_lang_spec_data);
00454 #endif
00455 }
00456
00457
00458 if (_imask) {
00459 free(_imask);
00460 #ifdef DEBUG
00461 fprintf(stderr, "unwind_cleanup(): ");
00462 fprintf(stderr, "deallocated _imask @ 0x%llx\n",
00463 (unsigned long long)_imask);
00464 #endif
00465 }
00466
00467 return __UNW_OK;
00468 }
00469
00470
00471
00472
00473 __unw_error_t unwind_info_add_personality_routine_info(__unw_info_t *info,
00474 __unw_addr_t personality, __uint32_t ehandler, __uint32_t uhandler) {
00475
00476
00477 if (NULL == info) {
00478 return __UNW_NULL_ERROR;
00479 } else if (_unwind_info + _unwind_info_size != info) {
00480 return __UNW_INV_ARG_ERROR;
00481 }
00482
00483
00484 _personality = personality;
00485
00486
00487 _ehandler = ehandler;
00488 _uhandler = uhandler;
00489
00490 return __UNW_OK;
00491 }
00492
00493
00494
00495
00496 __unw_error_t unwind_info_add_language_specific_info(__unw_info_t *info,
00497 void *ptr, __uint64_t size) {
00498
00499
00500 if (NULL == info) {
00501 return __UNW_NULL_ERROR;
00502 } else if (_unwind_info + _unwind_info_size != info) {
00503 return __UNW_INV_ARG_ERROR;
00504 }
00505
00506
00507 if (NULL == _lang_spec_data) {
00508 _lang_spec_data_total_size = __UNW_LANG_SPEC_SIZE;
00509 if (NULL == (_lang_spec_data =
00510 (void *)malloc((size_t)
00511 _lang_spec_data_total_size))) {
00512 unwind_cleanup();
00513 return __UNW_MALLOC_ERROR;
00514 }
00515 #ifdef DEBUG
00516 fprintf(stderr, "unwind_info_add_language_specific_info(): ");
00517 fprintf(stderr, "allocated _lang_spec_data @ 0x%llx, ",
00518 (unsigned long long)_lang_spec_data);
00519 fprintf(stderr, "total_size=%llu\n",
00520 (unsigned long long)_lang_spec_data_total_size);
00521 #endif
00522 }
00523
00524
00525 _lang_spec_data_size += size;
00526 while (_lang_spec_data_size >= _lang_spec_data_total_size) {
00527 _lang_spec_data_total_size *= 2;
00528 if (NULL == (_lang_spec_data =
00529 (void *)realloc((void *)_lang_spec_data,
00530 (size_t)_lang_spec_data_total_size))) {
00531 unwind_cleanup();
00532 return __UNW_REALLOC_ERROR;
00533 }
00534 #ifdef DEBUG
00535 fprintf(stderr, "unwind_info_add_language_specific_info(): ");
00536 fprintf(stderr, "reallocated _lang_spec_data @ 0x%llx, ",
00537 (unsigned long long)_lang_spec_data);
00538 fprintf(stderr, "total_size=%llu\n",
00539 (unsigned long long)_lang_spec_data_total_size);
00540 #endif
00541 }
00542 bcopy((const void *)ptr, (void *)((char *)_lang_spec_data +
00543 _lang_spec_data_size - size), (size_t)size);
00544
00545 return __UNW_OK;
00546 }