1 /** @file
2 
3   A brief file description
4 
5   @section license License
6 
7   Licensed to the Apache Software Foundation (ASF) under one
8   or more contributor license agreements.  See the NOTICE file
9   distributed with this work for additional information
10   regarding copyright ownership.  The ASF licenses this file
11   to you under the Apache License, Version 2.0 (the
12   "License"); you may not use this file except in compliance
13   with the License.  You may obtain a copy of the License at
14 
15       http://www.apache.org/licenses/LICENSE-2.0
16 
17   Unless required by applicable law or agreed to in writing, software
18   distributed under the License is distributed on an "AS IS" BASIS,
19   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
20   See the License for the specific language governing permissions and
21   limitations under the License.
22  */
23 
24 /****************************************************************************
25 
26    CoreUtils.cc
27 
28    Description:  Automated processing of core files on Linux
29  ****************************************************************************/
30 
31 /*
32    Stack Unwinding procedure on ix86 architecture on Linux :
33    Get the first frame pointer in $ebp.
34    The value stored in $ebp is the address of prev frame pointer.
35    Keep on unwinding till it is Ox0.
36    $ebp+4 in each frame represents $eip.(PC)
37 */
38 
39 /*
40  *  Accessing arguments on 386 :
41  *  ----------------------------
42  *  We need to start from $ebp+4 and then keep on reading args
43  *  till we reach the base pointer for prev. frame
44  *
45  *
46  *        (high memory)
47  *    +                     +
48  *    | Callers Stack Frame |
49  *    +---------------------+
50  *    |   function call     |
51  *    |     arguments       |
52  *    +---------------------+
53  *    |   Return Address    +
54  *    +-------------------- +
55  *    |    Old base pointer + Base pointer BP
56  *    +-------------------- +
57  *    |                     |
58  *    |                     |
59  *    |                     | Local (automatic) variables
60  *    |                     |
61  *    |                     |
62  *    |                     |
63  *    |                     |
64  *    |                     |
65  *    |                     |
66  *    +---------------------+ Stack pointer SP
67  *    |     free stack      | (low memory, top of the stack)
68  *    |    begins here      |
69  *    +                     +
70  *
71  *
72  *	  +-----------------+     +-----------------+
73  *  FP -> | previous FP --------> | previous FP ------>...
74  *	  |                 |     |                 |
75  *        | return address  |     | return address  |
76  *        +-----------------+     +-----------------+
77  */
78 
79 /* 32-bit arguments are pushed down stack in reverse syntactic order (hence accessed/popped in the right order), above the 32-bit
80  * near return address. %ebp, %esi, %edi, %ebx are callee-saved, other registers are caller-saved; %eax is to hold the result, or
81  * %edx:%eax for 64-bit results */
82 
83 /*    has -fomit-frame-pointer has any repercussions??
84       We assume that all the code is generated with frame pointers set.  */
85 
86 /* modify the "note" in process_core */
87 /* Document properly */
88 
89 #include "tscore/ink_config.h"
90 
91 #if defined(linux)
92 #include "CoreUtils.h"
93 
94 #define __p_type p_type // ugly hack? - see resolv.h
95 #define D(x) x          /* for debugging */
96 intptr_t f1, f2;
97 int framepointer    = 0;
98 int program_counter = 0;
99 #endif // linux check
100 
101 #if defined(darwin) || defined(freebsd) || defined(solaris) || defined(openbsd) // FIXME: solaris x86
102 // TODO: Cleanup multiple includes
103 #include <cstdio>
104 #include <cstdlib>
105 #include <cstdint>
106 #include "tscore/ink_platform.h"
107 #include "CoreUtils.h"
108 #endif /* darwin || freebsd || solaris */
109 
110 #include "EventName.h"
111 #include "http/HttpSM.h"
112 
113 #include <cstdlib>
114 #include <cmath>
115 
116 bool inTable;
117 FILE *fp;
118 memTable default_memTable = {0, 0, 0};
119 std::vector<struct memTable> arrayMem(0, default_memTable);
120 
121 HTTPHdrImpl *global_http;
122 HttpSM *last_seen_http_sm = nullptr;
123 
124 char ethread_ptr_str[256] = "";
125 char netvc_ptr_str[256]   = "";
126 
127 HdrHeap *swizzle_heap;
128 char *ptr_data;
129 
130 // returns the index of the vaddr or the index after where it should be
131 intptr_t
find_vaddr(intptr_t vaddr,intptr_t upper,intptr_t lower)132 CoreUtils::find_vaddr(intptr_t vaddr, intptr_t upper, intptr_t lower)
133 {
134   intptr_t index = static_cast<intptr_t>(floor(static_cast<double>((upper + lower) / 2)));
135 
136   // match in table, returns index to be inserted into
137   if (arrayMem[index].vaddr == vaddr) {
138     inTable = true;
139     return index + 1;
140     // no match
141   } else if (upper == lower) {
142     inTable = false;
143     return upper;
144     // no match
145   } else if (index == lower) {
146     inTable = false;
147     if ((index == 0) && (arrayMem[index].vaddr > vaddr)) {
148       return 0;
149     } else {
150       return index + 1;
151     }
152   } else {
153     if (arrayMem[index].vaddr > vaddr) {
154       return find_vaddr(vaddr, index, lower);
155     } else {
156       return find_vaddr(vaddr, upper, index);
157     }
158   }
159   assert(0);
160   return -1;
161 }
162 
163 // inserts virtual address struct into the list
164 void
insert_table(intptr_t vaddr1,intptr_t offset1,intptr_t fsize1)165 CoreUtils::insert_table(intptr_t vaddr1, intptr_t offset1, intptr_t fsize1)
166 {
167   if (arrayMem.empty()) {
168     arrayMem.push_back({vaddr1, offset1, fsize1});
169   } else {
170     unsigned index = find_vaddr(vaddr1, arrayMem.size(), 0);
171     arrayMem.insert(arrayMem.begin() + index, {vaddr1, offset1, fsize1});
172   }
173 }
174 
175 // returns -1 on failure otherwise fills the buffer and
176 // returns the number of bytes read
177 intptr_t
read_from_core(intptr_t vaddr,intptr_t bytes,char * buf)178 CoreUtils::read_from_core(intptr_t vaddr, intptr_t bytes, char *buf)
179 {
180   intptr_t index   = find_vaddr(vaddr, arrayMem.size(), 0);
181   intptr_t vadd    = arrayMem[index - 1].vaddr;
182   intptr_t offset  = arrayMem[index - 1].offset;
183   intptr_t size    = arrayMem[index - 1].fsize;
184   intptr_t offset2 = std::abs(vaddr - vadd);
185 
186   if (bytes > (size - offset2)) {
187     return -1;
188   } else {
189     if (fseek(fp, offset2 + offset, SEEK_SET) != -1) {
190       char *frameoff;
191       if ((frameoff = (char *)ats_malloc(sizeof(char) * bytes))) {
192         if (fread(frameoff, bytes, 1, fp) == 1) {
193           memcpy(buf, frameoff, bytes);
194           /*for(int j =0; j < bytes; j++) {
195            *buf++ = getc(fp);
196            }
197            buf -= bytes;*/
198           ats_free(frameoff);
199           return bytes;
200         }
201         ats_free(frameoff);
202       }
203     } else {
204       return -1;
205     }
206   }
207 
208   return -1;
209 }
210 
211 /* Linux Specific functions */
212 
213 #if defined(linux)
214 // copies stack info for the thread's base frame to the given
215 // core_stack_state pointer
216 void
get_base_frame(intptr_t framep,core_stack_state * coress)217 CoreUtils::get_base_frame(intptr_t framep, core_stack_state *coress)
218 {
219   // finds vaddress less than framep
220   intptr_t index = find_vaddr(framep, arrayMem.size(), 0);
221   intptr_t vadd  = arrayMem[index - 1].vaddr;
222   intptr_t off   = arrayMem[index - 1].offset;
223   intptr_t off2  = std::abs(vadd - framep);
224   intptr_t size  = arrayMem[index - 1].fsize;
225   intptr_t i     = 0;
226 
227   memset(coress, 0, sizeof(*coress));
228   D(printf("stkbase=%p\n", (void *)(vadd + size)));
229   // seek to the framep offset
230   if (fseek(fp, off + off2, SEEK_SET) != -1) {
231     void **frameoff;
232     if ((frameoff = (void **)ats_malloc(sizeof(long)))) {
233       if (fread(frameoff, 4, 1, fp) == 1) {
234         coress->framep = (intptr_t)*frameoff;
235         if (fread(frameoff, 4, 1, fp) == 1) {
236           coress->pc = (intptr_t)*frameoff;
237         }
238         // read register arguments
239         for (i = 0; i < NO_OF_ARGS; i++) {
240           if (fread(frameoff, 4, 1, fp) == 1) {
241             coress->arg[i] = (intptr_t)*frameoff;
242           }
243         }
244       }
245       ats_free(frameoff);
246     }
247   } else {
248     printf("Failed to seek to top of the stack\n");
249   }
250   // coress->stkbase = vadd+size;
251 }
252 
253 // returns 0 if current frame is already at the top of the stack
254 // or returns 1 and moves up the stack once
255 int
get_next_frame(core_stack_state * coress)256 CoreUtils::get_next_frame(core_stack_state *coress)
257 {
258   intptr_t i      = 0;
259   intptr_t framep = coress->framep;
260 
261   intptr_t index = find_vaddr(framep, arrayMem.size(), 0);
262 
263   // finds vaddress less than framep
264   intptr_t vadd = arrayMem[index - 1].vaddr;
265   intptr_t off  = arrayMem[index - 1].offset;
266   intptr_t off2 = std::abs(vadd - framep);
267 
268   // seek to the framep offset
269   if (fseek(fp, off + off2, SEEK_SET) != -1) {
270     void **frameoff;
271     if ((frameoff = (void **)ats_malloc(sizeof(long)))) {
272       if (fread(frameoff, 4, 1, fp) == 1) {
273         coress->framep = (intptr_t)*frameoff;
274         if (*frameoff == nullptr) {
275           ats_free(frameoff);
276           return 0;
277         }
278         if (fread(frameoff, 4, 1, fp) == 1) {
279           coress->pc = (intptr_t)*frameoff;
280         }
281         for (i = 0; i < NO_OF_ARGS; i++) {
282           if (fread(frameoff, 4, 1, fp) == 1) {
283             coress->arg[i] = (intptr_t)*frameoff;
284           }
285         }
286       }
287       ats_free(frameoff);
288     }
289     return 1;
290   }
291 
292   return 0;
293 }
294 
295 // prints the http header
296 void
find_stuff(StuffTest_f f)297 CoreUtils::find_stuff(StuffTest_f f)
298 {
299   intptr_t framep = framepointer;
300   intptr_t pc     = program_counter;
301   core_stack_state coress;
302   intptr_t i;
303   void *test_val;
304   int framecount = 0;
305 
306   // Unwinding the stack
307   D(printf("\nStack Trace:\n"));
308   D(printf("stack frame#%d framep=%p pc=%p\n", framecount, (void *)framep, (void *)pc));
309   framecount++;
310   get_base_frame(framep, &coress);
311   f2 = framep;
312   do {
313     f1 = f2;
314     f2 = coress.framep;
315     D(printf("stack frame#%d framep=%p pc=%p f1-f2=%p coress=%p %p %p %p %p\n", framecount, (void *)coress.framep,
316              (void *)coress.pc, (void *)(f2 - f1), (void *)coress.arg[0], (void *)coress.arg[1], (void *)coress.arg[2],
317              (void *)coress.arg[3], (void *)coress.arg[4]));
318 
319     for (i = 0; i < NO_OF_ARGS; i++) {
320       test_val = (void *)coress.arg[i];
321       f(test_val);
322     }
323     framecount++;
324   } while (get_next_frame(&coress) != 0);
325 }
326 #endif // linux check
327 
328 // test whether a given register is an HttpSM
329 //   if it is, call process_HttpSM on it
330 void
test_HdrHeap(void * arg)331 CoreUtils::test_HdrHeap(void *arg)
332 {
333   HdrHeap *hheap_test = static_cast<HdrHeap *>(arg);
334   uint32_t *magic_ptr = &(hheap_test->m_magic);
335   uint32_t magic      = 0;
336 
337   if (read_from_core((intptr_t)magic_ptr, sizeof(uint32_t), reinterpret_cast<char *>(&magic)) != 0) {
338     if (magic == HDR_BUF_MAGIC_ALIVE || magic == HDR_BUF_MAGIC_DEAD || magic == HDR_BUF_MAGIC_CORRUPT ||
339         magic == HDR_BUF_MAGIC_MARSHALED) {
340       printf("Found Hdr Heap @ 0x%p\n", arg);
341     }
342   }
343 }
344 
345 // test whether a given register is an HttpSM
346 //   if it is, call process_HttpSM on it
347 //
348 // This code generates errors from Clang, on hsm_test not being initialized
349 // properly. Currently this is not used, so ifdef'ing out to suppress.
350 #ifndef __clang_analyzer__
351 void
test_HttpSM_from_tunnel(void * arg)352 CoreUtils::test_HttpSM_from_tunnel(void *arg)
353 {
354   char *tmp        = (char *)arg;
355   intptr_t offset  = (intptr_t) & (((HttpTunnel *)nullptr)->sm);
356   HttpSM **hsm_ptr = (HttpSM **)(tmp + offset);
357   HttpSM *hsm_test = nullptr;
358 
359   if (read_from_core((intptr_t)hsm_ptr, sizeof(HttpSM *), (char *)&hsm_test) == 0) {
360     return;
361   }
362 
363   unsigned int *magic_ptr = &(hsm_test->magic);
364   unsigned int magic      = 0;
365 
366   if (read_from_core((intptr_t)magic_ptr, sizeof(int), (char *)&magic) != 0) {
367     if (magic == HTTP_SM_MAGIC_ALIVE || magic == HTTP_SM_MAGIC_DEAD) {
368       process_HttpSM(hsm_test);
369     }
370   }
371 }
372 #endif
373 
374 // test whether a given register is an HttpSM
375 //   if it is, call process_HttpSM on it
376 void
test_HttpSM(void * arg)377 CoreUtils::test_HttpSM(void *arg)
378 {
379   HttpSM *hsm_test        = static_cast<HttpSM *>(arg);
380   unsigned int *magic_ptr = &(hsm_test->magic);
381   unsigned int magic      = 0;
382 
383   if (read_from_core((intptr_t)magic_ptr, sizeof(int), reinterpret_cast<char *>(&magic)) != 0) {
384     if (magic == HTTP_SM_MAGIC_ALIVE || magic == HTTP_SM_MAGIC_DEAD) {
385       printf("test_HttpSM:******MATCH*****\n");
386       process_HttpSM(hsm_test);
387     }
388   }
389 }
390 
391 void
process_HttpSM(HttpSM * core_ptr)392 CoreUtils::process_HttpSM(HttpSM *core_ptr)
393 {
394   // extracting the HttpSM from the core file
395   if (last_seen_http_sm != core_ptr) {
396     HttpSM *http_sm = (HttpSM *)ats_malloc(sizeof(HttpSM));
397 
398     if (read_from_core((intptr_t)core_ptr, sizeof(HttpSM), (char *)http_sm) < 0) {
399       printf("ERROR: Failed to read httpSM @ 0x%p from core\n", core_ptr);
400       ats_free(http_sm);
401       return;
402     }
403 
404     if (http_sm->magic == HTTP_SM_MAGIC_ALIVE) {
405       last_seen_http_sm = core_ptr;
406 
407       if (is_debug_tag_set("magic")) {
408 #if defined(linux)
409         printf("\n*****match-ALIVE*****\n");
410 #endif
411       }
412       printf("---- Found HttpSM --- id %" PRId64 "  ------ @ 0x%p -----\n\n", http_sm->sm_id, http_sm);
413 
414       print_http_hdr(&http_sm->t_state.hdr_info.client_request, "Client Request");
415       print_http_hdr(&http_sm->t_state.hdr_info.server_request, "Server Request");
416       print_http_hdr(&http_sm->t_state.hdr_info.server_response, "Server Response");
417       print_http_hdr(&http_sm->t_state.hdr_info.client_response, "Client Response");
418 
419       dump_history(http_sm);
420 
421       printf("------------------------------------------------\n\n\n");
422     } else if (http_sm->magic == HTTP_SM_MAGIC_DEAD) {
423       if (is_debug_tag_set("magic")) {
424 #if defined(linux)
425         printf("\n*****match-DEAD*****\n");
426 #endif
427       }
428     }
429     ats_free(http_sm);
430   } else {
431     printf("process_HttpSM : last_seen_http_sm == core_ptr\n");
432   }
433 }
434 
435 void
print_http_hdr(HTTPHdr * h,const char * name)436 CoreUtils::print_http_hdr(HTTPHdr *h, const char *name)
437 {
438   HTTPHdr new_handle;
439 
440   if (h->m_heap && h->m_http) {
441     int r = load_http_hdr(h, &new_handle);
442 
443     if (r > 0 && new_handle.m_http) {
444       printf("----------- %s  ------------\n", name);
445       new_handle.m_mime = new_handle.m_http->m_fields_impl;
446       new_handle.print(nullptr, 0, nullptr, nullptr);
447       printf("-----------------------------\n\n");
448     }
449   }
450 }
451 
452 int
load_http_hdr(HTTPHdr * core_hdr,HTTPHdr * live_hdr)453 CoreUtils::load_http_hdr(HTTPHdr *core_hdr, HTTPHdr *live_hdr)
454 {
455   char buf[sizeof(char) * sizeof(HdrHeap)];
456   // Load HdrHeap chain
457   HTTPHdr *http_hdr      = core_hdr;
458   HdrHeap *heap          = (HdrHeap *)core_hdr->m_heap;
459   HdrHeap *heap_ptr      = (HdrHeap *)http_hdr->m_heap;
460   intptr_t ptr_heaps     = 0;
461   intptr_t ptr_heap_size = 0;
462   intptr_t str_size      = 0;
463   intptr_t str_heaps     = 0;
464   std::vector<MarshalXlate> ptr_xlation(2);
465   intptr_t i;
466   intptr_t copy_size;
467 
468   // extracting the header heap from the core file
469   do {
470     if (read_from_core((intptr_t)heap, sizeof(HdrHeap), buf) == -1) {
471       printf("Cannot read from core\n");
472       ::exit(0);
473     }
474     heap      = (HdrHeap *)buf;
475     copy_size = (int)(heap->m_free_start - heap->m_data_start);
476     ptr_heap_size += copy_size;
477     heap = heap->m_next;
478   } while (heap && ((intptr_t)heap != 0x1));
479 
480   swizzle_heap     = (HdrHeap *)ats_malloc(sizeof(HdrHeap));
481   live_hdr->m_heap = swizzle_heap;
482   ptr_data         = (char *)ats_malloc(sizeof(char) * ptr_heap_size);
483   // heap = (HdrHeap*)http_hdr->m_heap;
484 
485   //  Build Hdr Heap Translation Table
486   do {
487     if (read_from_core((intptr_t)heap_ptr, sizeof(HdrHeap), buf) == -1) {
488       printf("Cannot read from core\n");
489       ::exit(0);
490     }
491     heap_ptr  = (HdrHeap *)buf;
492     copy_size = (int)(heap_ptr->m_free_start - heap_ptr->m_data_start);
493 
494     if (read_from_core((intptr_t)heap_ptr->m_data_start, copy_size, ptr_data) == -1) {
495       printf("Cannot read from core\n");
496       ::exit(0);
497     }
498     // Expand ptr xlation table if necessary
499     if (static_cast<unsigned>(ptr_heaps) >= ptr_xlation.size()) {
500       ptr_xlation.resize(ptr_heaps + 1);
501     }
502 
503     char *data, *free, *off;
504     data = heap_ptr->m_data_start;
505     free = heap_ptr->m_free_start;
506     off  = (char *)(heap_ptr->m_data_start - ptr_data);
507 
508     ptr_xlation[ptr_heaps].start  = data;
509     ptr_xlation[ptr_heaps].end    = free;
510     ptr_xlation[ptr_heaps].offset = off;
511     ptr_data += copy_size;
512     ptr_heaps++;
513     heap_ptr = heap_ptr->m_next;
514   } while (heap_ptr && ((intptr_t)heap_ptr != 0x1));
515 
516   heap = (HdrHeap *)http_hdr->m_heap;
517   if (read_from_core((intptr_t)heap, sizeof(HdrHeap), buf) == -1) {
518     printf("Cannot read from core\n");
519     ::exit(0);
520   }
521   heap = (HdrHeap *)buf;
522   // filling in the live_hdr
523   swizzle_heap->m_free_start            = nullptr;
524   swizzle_heap->m_data_start            = (char *)ptr_data - ptr_heap_size; // offset
525   swizzle_heap->m_magic                 = HDR_BUF_MAGIC_ALIVE;
526   swizzle_heap->m_writeable             = false;
527   swizzle_heap->m_size                  = ptr_heap_size;
528   swizzle_heap->m_next                  = nullptr;
529   swizzle_heap->m_free_size             = 0;
530   swizzle_heap->m_read_write_heap.m_ptr = nullptr;
531 
532   // We'have one read-only string heap after marshalling
533   swizzle_heap->m_ronly_heap[0].m_heap_start          = (char *)(intptr_t)swizzle_heap->m_size; // offset
534   swizzle_heap->m_ronly_heap[0].m_ref_count_ptr.m_ptr = nullptr;
535 
536   for (unsigned i = 1; i < HDR_BUF_RONLY_HEAPS; ++i) {
537     swizzle_heap->m_ronly_heap[i].m_heap_start = nullptr;
538   }
539 
540   // Next order of business is to copy over string heaps
541   //   As we are copying over the string heaps, build
542   //   translation table for string marshaling in the heap
543   //   objects
544   MarshalXlate str_xlation[HDR_BUF_RONLY_HEAPS + 1];
545 
546   // Local String Heaps, building translation table
547   if (heap->m_read_write_heap) {
548     HdrStrHeap *hdr  = (HdrStrHeap *)heap->m_read_write_heap.m_ptr;
549     char *copy_start = ((char *)heap->m_read_write_heap.m_ptr) + sizeof(HdrStrHeap);
550     char *str_hdr    = (char *)ats_malloc(sizeof(char) * sizeof(HdrStrHeap));
551     if (read_from_core((intptr_t)hdr, sizeof(HdrStrHeap), str_hdr) == -1) {
552       printf("Cannot read from core\n");
553       ::exit(0);
554     }
555 
556     char *free_start = (char *)(((HdrStrHeap *)str_hdr)->m_free_start);
557     int nto_copy     = std::abs(copy_start - free_start);
558     ats_free(str_hdr);
559     char rw_heap[sizeof(char) * nto_copy];
560     if (read_from_core((intptr_t)copy_start, nto_copy, rw_heap) == -1) {
561       printf("Cannot read from core\n");
562       ::exit(0);
563     }
564     // FIX ME - possible offset overflow issues?
565     str_xlation[str_heaps].start  = copy_start;
566     str_xlation[str_heaps].end    = copy_start + nto_copy;
567     str_xlation[str_heaps].offset = (char *)(copy_start - rw_heap);
568 
569     str_size += nto_copy;
570     str_heaps++;
571   }
572 
573   for (i = 0; i < HDR_BUF_RONLY_HEAPS; i++) {
574     if (heap->m_ronly_heap[i].m_heap_start != nullptr) {
575       char ro_heap[sizeof(char) * heap->m_ronly_heap[i].m_heap_len];
576       if (read_from_core((intptr_t)heap->m_ronly_heap[i].m_heap_start, heap->m_ronly_heap[i].m_heap_len, ro_heap) == -1) {
577         printf("Cannot read from core\n");
578         ::exit(0);
579       }
580       // Add translation table entry for string heaps
581       str_xlation[str_heaps].start  = heap->m_ronly_heap[i].m_heap_start;
582       str_xlation[str_heaps].end    = heap->m_ronly_heap[i].m_heap_start + heap->m_ronly_heap[i].m_heap_len;
583       str_xlation[str_heaps].offset = (char *)(heap->m_ronly_heap[i].m_heap_start - ro_heap);
584 
585       ink_assert(str_xlation[str_heaps].start <= str_xlation[str_heaps].end);
586 
587       str_heaps++;
588       str_size += heap->m_ronly_heap[i].m_heap_len;
589     }
590   }
591 
592   // Patch the str heap len
593   swizzle_heap->m_ronly_heap[0].m_heap_len = str_size;
594 
595   char *obj_data  = swizzle_heap->m_data_start;
596   char *mheap_end = swizzle_heap->m_data_start + swizzle_heap->m_size;
597 
598   while (obj_data < mheap_end) {
599     HdrHeapObjImpl *obj = (HdrHeapObjImpl *)obj_data;
600     ink_assert(obj_is_aligned(obj));
601 
602     switch (obj->m_type) {
603     case HDR_HEAP_OBJ_URL:
604       if (((URLImpl *)obj)->marshal(str_xlation, str_heaps) < 0) {
605         goto Failed;
606       }
607       break;
608     case HDR_HEAP_OBJ_HTTP_HEADER:
609       if (((HTTPHdrImpl *)obj)->marshal(&ptr_xlation[0], ptr_heaps, str_xlation, str_heaps) < 0) {
610         goto Failed;
611       }
612       live_hdr->m_http = (HTTPHdrImpl *)obj;
613       break;
614     case HDR_HEAP_OBJ_FIELD_BLOCK:
615       if (((MIMEFieldBlockImpl *)obj)->marshal(&ptr_xlation[0], ptr_heaps, str_xlation, str_heaps) < 0) {
616         goto Failed;
617       }
618       break;
619     case HDR_HEAP_OBJ_MIME_HEADER:
620       if (((MIMEHdrImpl *)obj)->marshal(&ptr_xlation[0], ptr_heaps, str_xlation, str_heaps)) {
621         goto Failed;
622       }
623       break;
624     case HDR_HEAP_OBJ_EMPTY:
625       break;
626     case HDR_HEAP_OBJ_RAW:
627       // Check to make sure we aren't stuck
628       //   in an infinite loop
629       if (obj->m_length <= 0) {
630         ink_assert(0);
631         goto Failed;
632       }
633       // Nothing to do
634       break;
635     default:
636       ink_release_assert(0);
637     }
638     obj_data = obj_data + obj->m_length;
639   }
640 
641   // Add up the total bytes used
642   return HdrHeapMarshalBlocks{ts::round_up(ptr_heap_size + str_size + HDR_HEAP_HDR_SIZE)};
643 
644 Failed:
645   swizzle_heap->m_magic = HDR_BUF_MAGIC_CORRUPT;
646   return -1;
647 }
648 
649 void
dump_history(HttpSM * hsm)650 CoreUtils::dump_history(HttpSM *hsm)
651 {
652   printf("-------- Begin History -------------\n");
653 
654   // Loop through the history and dump it
655   for (unsigned int i = 0; i < hsm->history.size(); i++) {
656     char loc[256];
657     int r          = (int)hsm->history[i].reentrancy;
658     int e          = (int)hsm->history[i].event;
659     char *fileline = load_string(hsm->history[i].location.str(loc, sizeof(loc)));
660 
661     fileline = (fileline != nullptr) ? fileline : ats_strdup("UNKNOWN");
662 
663     printf("%d   %d   %s", e, r, fileline);
664 
665     char buffer[32];
666     const char *msg = event_int_to_string(e, sizeof(buffer), buffer);
667     printf("   event string: \"%s\"\n", msg);
668 
669     ats_free(fileline);
670   }
671 
672   printf("-------- End History -----------\n\n");
673 }
674 
675 void
process_EThread(EThread * eth_test)676 CoreUtils::process_EThread(EThread *eth_test)
677 {
678   char *buf = (char *)ats_malloc(sizeof(char) * sizeof(EThread));
679 
680   if (read_from_core((intptr_t)eth_test, sizeof(EThread), buf) != -1) {
681     EThread *loaded_eth = reinterpret_cast<EThread *>(buf);
682 
683     printf("----------- EThread @ 0x%p ----------\n", eth_test);
684 #if !defined(kfreebsd) && (defined(freebsd) || defined(darwin) || defined(openbsd))
685     printf("   thread_id: %p\n", loaded_eth->tid);
686 #else
687     printf("   thread_id: %i\n", (int)loaded_eth->tid);
688 #endif
689     //    printf("   NetHandler: 0x%x\n\n", (int) loaded_eth->netHandler);
690   }
691 
692   ats_free(buf);
693 }
694 
695 void
print_netstate(NetState * n)696 CoreUtils::print_netstate(NetState *n)
697 {
698   printf("      enabled: %d\n", n->enabled);
699   printf("      op: %d  cont: 0x%p\n", n->vio.op, n->vio.cont);
700   printf("      nbytes: %d  done: %d\n", (int)n->vio.nbytes, (int)n->vio.ndone);
701   printf("      vc_server: 0x%p   mutex: 0x%p\n\n", n->vio.vc_server, n->vio.mutex.m_ptr);
702 }
703 
704 void
process_NetVC(UnixNetVConnection * nvc_test)705 CoreUtils::process_NetVC(UnixNetVConnection *nvc_test)
706 {
707   char *buf = (char *)ats_malloc(sizeof(char) * sizeof(UnixNetVConnection));
708 
709   if (read_from_core((intptr_t)nvc_test, sizeof(UnixNetVConnection), buf) != -1) {
710     UnixNetVConnection *loaded_nvc = reinterpret_cast<UnixNetVConnection *>(buf);
711     char addrbuf[INET6_ADDRSTRLEN];
712 
713     printf("----------- UnixNetVConnection @ 0x%p ----------\n", nvc_test);
714     printf("     ip: %s    port: %d\n", ats_ip_ntop(loaded_nvc->get_remote_addr(), addrbuf, sizeof(addrbuf)),
715            ats_ip_port_host_order(loaded_nvc->get_remote_addr()));
716     printf("     closed: %d\n\n", loaded_nvc->closed);
717     printf("     read state: \n");
718     print_netstate(&loaded_nvc->read);
719     printf("     write state: \n");
720     print_netstate(&loaded_nvc->write);
721   }
722 
723   ats_free(buf);
724 }
725 
726 char *
load_string(const char * addr)727 CoreUtils::load_string(const char *addr)
728 {
729   char buf[2048];
730   int index = 0;
731 
732   if (addr == nullptr) {
733     return ats_strdup("NONE");
734   }
735 
736   while (index < 2048) {
737     if (read_from_core((intptr_t)(addr + index), 1, buf + index) < 0) {
738       return nullptr;
739     }
740 
741     if (buf[index] == '\0') {
742       return ats_strdup(buf);
743     }
744     index++;
745   }
746 
747   return nullptr;
748 }
749 
750 // parses core file
751 #if defined(linux)
752 void
process_core(char * fname)753 process_core(char *fname)
754 {
755   Elf32_Ehdr ehdr;
756   Elf32_Phdr phdr;
757   int phoff, phnum, phentsize;
758   int framep = 0, pc = 0;
759 
760   /* Open the input file */
761   if (!(fp = fopen(fname, "r"))) {
762     printf("cannot open file\n");
763     ::exit(1);
764   }
765 
766   /* Obtain the .shstrtab data buffer */
767   if (fread(&ehdr, sizeof ehdr, 1, fp) != 1) {
768     printf("Unable to read ehdr\n");
769     ::exit(1);
770   }
771   // program header offset
772   phoff = ehdr.e_phoff;
773   // number of program headers
774   phnum = ehdr.e_phnum;
775   // size of each program header
776   phentsize = ehdr.e_phentsize;
777 
778   for (int i = 0; i < phnum; i++) {
779     if (fseek(fp, phoff + i * phentsize, SEEK_SET) == -1) {
780       fprintf(stderr, "Unable to seek to Phdr %d\n", i);
781       ::exit(1);
782     }
783 
784     if (fread(&phdr, sizeof phdr, 1, fp) != 1) {
785       fprintf(stderr, "Unable to read Phdr %d\n", i);
786       ::exit(1);
787     }
788     int poffset, psize;
789     int pvaddr;
790     /* This member gives the virtual address at which the first byte of the
791        segment resides in memory. */
792     pvaddr = phdr.p_vaddr;
793     /* This member gives the offset from the beginning of the file at which
794        the first byte of the segment resides. */
795     poffset = phdr.p_offset;
796     /* This member gives the number of bytes in the file image of the
797        segment; it may be zero. */
798     psize = phdr.p_filesz;
799 
800     if (pvaddr != 0) {
801       CoreUtils::insert_table(pvaddr, poffset, psize);
802     }
803 
804     if (is_debug_tag_set("phdr")) {
805       printf("\n******* PHDR %d *******\n", i);
806       printf("p_type = %u  ", phdr.p_type);
807       printf("p_offset = %u  ", phdr.p_offset);
808       printf("p_vaddr = %#x  ", pvaddr);
809 
810       printf("p_paddr = %#x\n", phdr.p_paddr);
811       printf("p_filesz = %u  ", phdr.p_filesz);
812       printf("p_memsz = %u  ", phdr.p_memsz);
813       printf("p_flags = %u  ", phdr.p_flags);
814       printf("p_align = %u\n", phdr.p_align);
815     }
816 
817     if (phdr.p_type == PT_NOTE) {
818       printf("NOTE\n");
819       if (fseek(fp, phdr.p_offset, SEEK_SET) != -1) {
820         Elf32_Nhdr *nhdr, *thdr;
821         if ((nhdr = (Elf32_Nhdr *)ats_malloc(sizeof(Elf32_Nhdr) * phdr.p_filesz))) {
822           if (fread(nhdr, phdr.p_filesz, 1, fp) == 1) {
823             int size = phdr.p_filesz;
824             int sum  = 0;
825             thdr     = nhdr;
826             while (size) {
827               int len;
828 
829               len = sizeof *thdr + ((thdr->n_namesz + 3) & ~3) + ((thdr->n_descsz + 3) & ~3);
830               // making sure the offset is byte aligned
831               char *offset = reinterpret_cast<char *>(thdr + 1) + ((thdr->n_namesz + 3) & ~3);
832 
833               if (len < 0 || len > size) {
834                 ::exit(1);
835               }
836               printf("size=%d, len=%d\n", size, len);
837 
838               prstatus_t pstat;
839               prstatus_t *ps;
840               prpsinfo_t infostat, *ist;
841               elf_gregset_t rinfo;
842               unsigned int j;
843 
844               switch (thdr->n_type) {
845               case NT_PRSTATUS:
846                 ps = reinterpret_cast<prstatus_t *>(offset);
847                 memcpy(&pstat, ps, sizeof(prstatus_t));
848                 printf("\n*** printing registers****\n");
849                 for (j = 0; j < ELF_NGREG; j++) {
850                   rinfo[j] = pstat.pr_reg[j];
851                   printf("%#x ", static_cast<unsigned int>(rinfo[j]));
852                 }
853                 printf("\n");
854 
855                 printf("\n**** NT_PRSTATUS ****\n");
856 
857                 printf("Process id = %d\n", pstat.pr_pid);
858                 printf("Parent Process id = %d\n", pstat.pr_ppid);
859 
860                 printf("Signal that caused this core dump is signal  = %d\n", pstat.pr_cursig);
861 
862                 printf("stack pointer = %#x\n", static_cast<unsigned int>(pstat.pr_reg[SP_REGNUM])); // UESP
863                 framep = pstat.pr_reg[FP_REGNUM];
864                 pc     = pstat.pr_reg[PC_REGNUM];
865                 printf("frame pointer = %#x\n", static_cast<unsigned int>(pstat.pr_reg[FP_REGNUM])); // EBP
866                 printf("program counter if no save = %#x\n", static_cast<unsigned int>(pstat.pr_reg[PC_REGNUM]));
867                 break;
868 
869               case NT_PRPSINFO:
870                 ist = reinterpret_cast<prpsinfo_t *>(offset);
871                 memcpy(&infostat, ist, sizeof(prpsinfo_t));
872 
873                 if (is_debug_tag_set("note")) {
874                   printf("\n**** NT_PRPSINFO of active process****\n");
875                   printf("process state = %c\n", infostat.pr_state);
876                   printf("Name of the executable = %s\n", infostat.pr_fname);
877                   printf("Arg List = %s\n", infostat.pr_psargs);
878 
879                   printf("process id = %d\n", infostat.pr_pid);
880                 }
881                 break;
882               }
883               thdr = reinterpret_cast<Elf32_Nhdr *>(reinterpret_cast<char *>(thdr) + len);
884               sum += len;
885               size -= len;
886             }
887           }
888           ats_free(nhdr);
889         }
890       }
891     }
892   }
893   framepointer    = framep;
894   program_counter = pc;
895 
896   // Write your actual tests here
897   CoreUtils::find_stuff(&CoreUtils::test_HdrHeap);
898   CoreUtils::find_stuff(&CoreUtils::test_HttpSM);
899 
900   fclose(fp);
901 }
902 #endif
903 
904 #if !defined(linux)
905 void
process_core(char * fname)906 process_core(char *fname)
907 {
908   // do not make it fatal!!!!
909   Warning("Only supported on Sparc Solaris and Linux");
910 }
911 #endif
912