1 /*
2  * Copyright (c) 2013-2019, Intel Corporation
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions are met:
6  *
7  *  * Redistributions of source code must retain the above copyright notice,
8  *    this list of conditions and the following disclaimer.
9  *  * Redistributions in binary form must reproduce the above copyright notice,
10  *    this list of conditions and the following disclaimer in the documentation
11  *    and/or other materials provided with the distribution.
12  *  * Neither the name of Intel Corporation nor the names of its contributors
13  *    may be used to endorse or promote products derived from this software
14  *    without specific prior written permission.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
20  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26  * POSSIBILITY OF SUCH DAMAGE.
27  */
28 
29 #include "pt_last_ip.h"
30 
31 #include "intel-pt.h"
32 
33 
pt_last_ip_init(struct pt_last_ip * last_ip)34 void pt_last_ip_init(struct pt_last_ip *last_ip)
35 {
36 	if (!last_ip)
37 		return;
38 
39 	last_ip->ip = 0ull;
40 	last_ip->have_ip = 0;
41 	last_ip->suppressed = 0;
42 }
43 
pt_last_ip_query(uint64_t * ip,const struct pt_last_ip * last_ip)44 int pt_last_ip_query(uint64_t *ip, const struct pt_last_ip *last_ip)
45 {
46 	if (!last_ip)
47 		return -pte_internal;
48 
49 	if (!last_ip->have_ip) {
50 		if (ip)
51 			*ip = 0ull;
52 		return -pte_noip;
53 	}
54 
55 	if (last_ip->suppressed) {
56 		if (ip)
57 			*ip = 0ull;
58 		return -pte_ip_suppressed;
59 	}
60 
61 	if (ip)
62 		*ip = last_ip->ip;
63 
64 	return 0;
65 }
66 
67 /* Sign-extend a uint64_t value. */
sext(uint64_t val,uint8_t sign)68 static uint64_t sext(uint64_t val, uint8_t sign)
69 {
70 	uint64_t signbit, mask;
71 
72 	signbit = 1ull << (sign - 1);
73 	mask = ~0ull << sign;
74 
75 	return val & signbit ? val | mask : val & ~mask;
76 }
77 
pt_last_ip_update_ip(struct pt_last_ip * last_ip,const struct pt_packet_ip * packet,const struct pt_config * config)78 int pt_last_ip_update_ip(struct pt_last_ip *last_ip,
79 			 const struct pt_packet_ip *packet,
80 			 const struct pt_config *config)
81 {
82 	(void) config;
83 
84 	if (!last_ip || !packet)
85 		return -pte_internal;
86 
87 	switch (packet->ipc) {
88 	case pt_ipc_suppressed:
89 		last_ip->suppressed = 1;
90 		return 0;
91 
92 	case pt_ipc_sext_48:
93 		last_ip->ip = sext(packet->ip, 48);
94 		last_ip->have_ip = 1;
95 		last_ip->suppressed = 0;
96 		return 0;
97 
98 	case pt_ipc_update_16:
99 		last_ip->ip = (last_ip->ip & ~0xffffull)
100 			| (packet->ip & 0xffffull);
101 		last_ip->have_ip = 1;
102 		last_ip->suppressed = 0;
103 		return 0;
104 
105 	case pt_ipc_update_32:
106 		last_ip->ip = (last_ip->ip & ~0xffffffffull)
107 			| (packet->ip & 0xffffffffull);
108 		last_ip->have_ip = 1;
109 		last_ip->suppressed = 0;
110 		return 0;
111 
112 	case pt_ipc_update_48:
113 		last_ip->ip = (last_ip->ip & ~0xffffffffffffull)
114 			| (packet->ip & 0xffffffffffffull);
115 		last_ip->have_ip = 1;
116 		last_ip->suppressed = 0;
117 		return 0;
118 
119 	case pt_ipc_full:
120 		last_ip->ip = packet->ip;
121 		last_ip->have_ip = 1;
122 		last_ip->suppressed = 0;
123 		return 0;
124 	}
125 
126 	return -pte_bad_packet;
127 }
128